blob: c0172493c3ff2582fe1167a509822c5d61f42772 [file] [log] [blame]
Brian Silverman4e662aa2022-05-11 23:10:19 -07001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use indexmap::map::IndexMap as HashMap;
10
11use syn::{parse_quote, FnArg, PatType, Type, TypePtr};
12
13use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability};
14use crate::conversion::analysis::pod::PodPhase;
15use crate::conversion::api::{
16 CppVisibility, FuncToConvert, Provenance, RustSubclassFnDetails, SubclassConstructorDetails,
17 SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness,
18};
19use crate::conversion::apivec::ApiVec;
20use crate::{
21 conversion::{
22 analysis::fun::function_wrapper::{
23 CppFunction, CppFunctionBody, CppFunctionKind, TypeConversionPolicy,
24 },
25 api::{Api, ApiName},
26 },
27 types::{make_ident, Namespace, QualifiedName},
28};
29
30use super::{FnAnalysis, FnPrePhase1};
31
32pub(super) fn subclasses_by_superclass(
33 apis: &ApiVec<PodPhase>,
34) -> HashMap<QualifiedName, Vec<SubclassName>> {
35 let mut subclasses_per_superclass: HashMap<QualifiedName, Vec<SubclassName>> = HashMap::new();
36
37 for api in apis.iter() {
38 if let Api::Subclass { name, superclass } = api {
39 subclasses_per_superclass
40 .entry(superclass.clone())
41 .or_default()
42 .push(name.clone());
43 }
44 }
45 subclasses_per_superclass
46}
47
48pub(super) fn create_subclass_fn_wrapper(
49 sub: &SubclassName,
50 super_fn_name: &QualifiedName,
51 fun: &FuncToConvert,
52) -> Box<FuncToConvert> {
53 let self_ty = Some(sub.cpp());
54 Box::new(FuncToConvert {
55 synthesized_this_type: self_ty.clone(),
56 self_ty,
57 ident: super_fn_name.get_final_ident(),
58 doc_attrs: fun.doc_attrs.clone(),
59 inputs: fun.inputs.clone(),
60 output: fun.output.clone(),
61 vis: fun.vis.clone(),
62 virtualness: Virtualness::None,
63 cpp_vis: CppVisibility::Public,
64 special_member: None,
65 unused_template_param: fun.unused_template_param,
66 original_name: None,
67 references: fun.references.clone(),
68 add_to_trait: fun.add_to_trait.clone(),
69 is_deleted: fun.is_deleted,
70 synthetic_cpp: None,
71 provenance: Provenance::SynthesizedOther,
72 variadic: fun.variadic,
73 })
74}
75
76pub(super) fn create_subclass_trait_item(
77 name: ApiName,
78 analysis: &FnAnalysis,
79 receiver_mutability: &ReceiverMutability,
80 receiver: QualifiedName,
81 is_pure_virtual: bool,
82) -> Api<FnPrePhase1> {
83 let param_names = analysis
84 .param_details
85 .iter()
86 .map(|pd| pd.name.clone())
87 .collect();
88 Api::SubclassTraitItem {
89 name,
90 details: SuperclassMethod {
91 name: make_ident(&analysis.rust_name),
92 params: analysis.params.clone(),
93 ret_type: analysis.ret_type.clone(),
94 param_names,
95 receiver_mutability: receiver_mutability.clone(),
96 requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
97 is_pure_virtual,
98 receiver,
99 },
100 }
101}
102
103pub(super) fn create_subclass_function(
104 sub: &SubclassName,
105 analysis: &super::FnAnalysis,
106 name: &ApiName,
107 receiver_mutability: &ReceiverMutability,
108 superclass: &QualifiedName,
109 dependencies: Vec<QualifiedName>,
110) -> Api<FnPrePhase1> {
111 let cpp = sub.cpp();
112 let holder_name = sub.holder();
113 let rust_call_name = make_ident(format!(
114 "{}_{}",
115 sub.0.name.get_final_item(),
116 name.name.get_final_item()
117 ));
118 let params = std::iter::once(parse_quote! {
119 me: & #holder_name
120 })
121 .chain(analysis.params.iter().skip(1).cloned())
122 .collect();
123 let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
124 CppFunctionKind::Method
125 } else {
126 CppFunctionKind::ConstMethod
127 };
128 let argument_conversion = analysis
129 .param_details
130 .iter()
131 .skip(1)
132 .map(|p| p.conversion.clone())
133 .collect();
134 Api::RustSubclassFn {
135 name: ApiName::new_in_root_namespace(rust_call_name.clone()),
136 subclass: sub.clone(),
137 details: Box::new(RustSubclassFnDetails {
138 params,
139 ret: analysis.ret_type.clone(),
140 method_name: make_ident(&analysis.rust_name),
141 cpp_impl: CppFunction {
142 payload: CppFunctionBody::FunctionCall(Namespace::new(), rust_call_name),
143 wrapper_function_name: make_ident(&analysis.rust_name),
144 original_cpp_name: name.cpp_name(),
145 return_conversion: analysis.ret_conversion.clone(),
146 argument_conversion,
147 kind,
148 pass_obs_field: true,
149 qualification: Some(cpp),
150 },
151 superclass: superclass.clone(),
152 receiver_mutability: receiver_mutability.clone(),
153 dependencies,
154 requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
155 is_pure_virtual: matches!(
156 analysis.kind,
157 FnKind::Method {
158 method_kind: MethodKind::PureVirtual(..),
159 ..
160 }
161 ),
162 }),
163 }
164}
165
166pub(super) fn create_subclass_constructor(
167 sub: SubclassName,
168 analysis: &FnAnalysis,
169 sup: &QualifiedName,
170 fun: &FuncToConvert,
171) -> (Box<FuncToConvert>, ApiName) {
172 let holder = sub.holder();
173 let cpp = sub.cpp();
174 let wrapper_function_name = cpp.get_final_ident();
175 let initial_arg = TypeConversionPolicy::new_unconverted(parse_quote! {
176 rust::Box< #holder >
177 });
178 let args = std::iter::once(initial_arg).chain(
179 analysis
180 .param_details
181 .iter()
182 .skip(1) // skip placement new destination
183 .map(|aa| aa.conversion.clone()),
184 );
185 let cpp_impl = CppFunction {
186 payload: CppFunctionBody::ConstructSuperclass(sup.to_cpp_name()),
187 wrapper_function_name,
188 return_conversion: None,
189 argument_conversion: args.collect(),
190 kind: CppFunctionKind::SynthesizedConstructor,
191 pass_obs_field: false,
192 qualification: Some(cpp.clone()),
193 original_cpp_name: cpp.to_cpp_name(),
194 };
195 let subclass_constructor_details = Box::new(SubclassConstructorDetails {
196 subclass: sub.clone(),
197 is_trivial: analysis.param_details.len() == 1, // just placement new
198 // destination, no other parameters
199 cpp_impl,
200 });
201 let subclass_constructor_name =
202 make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
203 let mut existing_params = fun.inputs.clone();
204 if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
205 if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
206 *elem = Box::new(Type::Path(sub.cpp().to_type_path()));
207 } else {
208 panic!("Unexpected self type parameter when creating subclass constructor");
209 }
210 } else {
211 panic!("Unexpected self type parameter when creating subclass constructor");
212 }
213 let mut existing_params = existing_params.into_iter();
214 let self_param = existing_params.next();
215 let boxed_holder_param: FnArg = parse_quote! {
216 peer: rust::Box<#holder>
217 };
218 let inputs = self_param
219 .into_iter()
220 .chain(std::iter::once(boxed_holder_param))
221 .chain(existing_params)
222 .collect();
223 let maybe_wrap = Box::new(FuncToConvert {
224 ident: subclass_constructor_name.clone(),
225 doc_attrs: fun.doc_attrs.clone(),
226 inputs,
227 output: fun.output.clone(),
228 vis: fun.vis.clone(),
229 virtualness: Virtualness::None,
230 cpp_vis: CppVisibility::Public,
231 special_member: fun.special_member.clone(),
232 original_name: None,
233 unused_template_param: fun.unused_template_param,
234 references: fun.references.clone(),
235 synthesized_this_type: Some(cpp.clone()),
236 self_ty: Some(cpp),
237 add_to_trait: None,
238 is_deleted: fun.is_deleted,
239 synthetic_cpp: None,
240 provenance: Provenance::SynthesizedSubclassConstructor(subclass_constructor_details),
241 variadic: fun.variadic,
242 });
243 let subclass_constructor_name = ApiName::new_with_cpp_name(
244 &Namespace::new(),
245 subclass_constructor_name,
246 Some(sub.cpp().get_final_item().to_string()),
247 );
248 (maybe_wrap, subclass_constructor_name)
249}