blob: 6383d2c84526ea99e84a001379279911c185e171 [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
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070013use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability, UnsafePolicy};
Brian Silverman4e662aa2022-05-11 23:10:19 -070014use 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,
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070082 unsafe_policy: &UnsafePolicy,
Brian Silverman4e662aa2022-05-11 23:10:19 -070083) -> Api<FnPrePhase1> {
84 let param_names = analysis
85 .param_details
86 .iter()
87 .map(|pd| pd.name.clone())
88 .collect();
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070089 let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) {
90 UnsafetyNeeded::Always
91 } else {
92 UnsafetyNeeded::from_param_details(&analysis.param_details, false)
93 };
Brian Silverman4e662aa2022-05-11 23:10:19 -070094 Api::SubclassTraitItem {
95 name,
96 details: SuperclassMethod {
97 name: make_ident(&analysis.rust_name),
98 params: analysis.params.clone(),
99 ret_type: analysis.ret_type.clone(),
100 param_names,
101 receiver_mutability: receiver_mutability.clone(),
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700102 requires_unsafe,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700103 is_pure_virtual,
104 receiver,
105 },
106 }
107}
108
109pub(super) fn create_subclass_function(
110 sub: &SubclassName,
111 analysis: &super::FnAnalysis,
112 name: &ApiName,
113 receiver_mutability: &ReceiverMutability,
114 superclass: &QualifiedName,
115 dependencies: Vec<QualifiedName>,
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700116 unsafe_policy: &UnsafePolicy,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700117) -> Api<FnPrePhase1> {
118 let cpp = sub.cpp();
119 let holder_name = sub.holder();
120 let rust_call_name = make_ident(format!(
121 "{}_{}",
122 sub.0.name.get_final_item(),
123 name.name.get_final_item()
124 ));
125 let params = std::iter::once(parse_quote! {
126 me: & #holder_name
127 })
128 .chain(analysis.params.iter().skip(1).cloned())
129 .collect();
130 let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
131 CppFunctionKind::Method
132 } else {
133 CppFunctionKind::ConstMethod
134 };
135 let argument_conversion = analysis
136 .param_details
137 .iter()
138 .skip(1)
139 .map(|p| p.conversion.clone())
140 .collect();
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700141 let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) {
142 UnsafetyNeeded::Always
143 } else {
144 UnsafetyNeeded::from_param_details(&analysis.param_details, false)
145 };
Brian Silverman4e662aa2022-05-11 23:10:19 -0700146 Api::RustSubclassFn {
147 name: ApiName::new_in_root_namespace(rust_call_name.clone()),
148 subclass: sub.clone(),
149 details: Box::new(RustSubclassFnDetails {
150 params,
151 ret: analysis.ret_type.clone(),
152 method_name: make_ident(&analysis.rust_name),
153 cpp_impl: CppFunction {
154 payload: CppFunctionBody::FunctionCall(Namespace::new(), rust_call_name),
155 wrapper_function_name: make_ident(&analysis.rust_name),
156 original_cpp_name: name.cpp_name(),
157 return_conversion: analysis.ret_conversion.clone(),
158 argument_conversion,
159 kind,
160 pass_obs_field: true,
161 qualification: Some(cpp),
162 },
163 superclass: superclass.clone(),
164 receiver_mutability: receiver_mutability.clone(),
165 dependencies,
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700166 requires_unsafe,
Brian Silverman4e662aa2022-05-11 23:10:19 -0700167 is_pure_virtual: matches!(
168 analysis.kind,
169 FnKind::Method {
170 method_kind: MethodKind::PureVirtual(..),
171 ..
172 }
173 ),
174 }),
175 }
176}
177
178pub(super) fn create_subclass_constructor(
179 sub: SubclassName,
180 analysis: &FnAnalysis,
181 sup: &QualifiedName,
182 fun: &FuncToConvert,
183) -> (Box<FuncToConvert>, ApiName) {
184 let holder = sub.holder();
185 let cpp = sub.cpp();
186 let wrapper_function_name = cpp.get_final_ident();
187 let initial_arg = TypeConversionPolicy::new_unconverted(parse_quote! {
188 rust::Box< #holder >
189 });
190 let args = std::iter::once(initial_arg).chain(
191 analysis
192 .param_details
193 .iter()
194 .skip(1) // skip placement new destination
195 .map(|aa| aa.conversion.clone()),
196 );
197 let cpp_impl = CppFunction {
198 payload: CppFunctionBody::ConstructSuperclass(sup.to_cpp_name()),
199 wrapper_function_name,
200 return_conversion: None,
201 argument_conversion: args.collect(),
202 kind: CppFunctionKind::SynthesizedConstructor,
203 pass_obs_field: false,
204 qualification: Some(cpp.clone()),
205 original_cpp_name: cpp.to_cpp_name(),
206 };
207 let subclass_constructor_details = Box::new(SubclassConstructorDetails {
208 subclass: sub.clone(),
209 is_trivial: analysis.param_details.len() == 1, // just placement new
210 // destination, no other parameters
211 cpp_impl,
212 });
213 let subclass_constructor_name =
214 make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
215 let mut existing_params = fun.inputs.clone();
216 if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
217 if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
218 *elem = Box::new(Type::Path(sub.cpp().to_type_path()));
219 } else {
220 panic!("Unexpected self type parameter when creating subclass constructor");
221 }
222 } else {
223 panic!("Unexpected self type parameter when creating subclass constructor");
224 }
225 let mut existing_params = existing_params.into_iter();
226 let self_param = existing_params.next();
227 let boxed_holder_param: FnArg = parse_quote! {
228 peer: rust::Box<#holder>
229 };
230 let inputs = self_param
231 .into_iter()
232 .chain(std::iter::once(boxed_holder_param))
233 .chain(existing_params)
234 .collect();
235 let maybe_wrap = Box::new(FuncToConvert {
236 ident: subclass_constructor_name.clone(),
237 doc_attrs: fun.doc_attrs.clone(),
238 inputs,
239 output: fun.output.clone(),
240 vis: fun.vis.clone(),
241 virtualness: Virtualness::None,
242 cpp_vis: CppVisibility::Public,
243 special_member: fun.special_member.clone(),
244 original_name: None,
245 unused_template_param: fun.unused_template_param,
246 references: fun.references.clone(),
247 synthesized_this_type: Some(cpp.clone()),
248 self_ty: Some(cpp),
249 add_to_trait: None,
250 is_deleted: fun.is_deleted,
251 synthetic_cpp: None,
252 provenance: Provenance::SynthesizedSubclassConstructor(subclass_constructor_details),
253 variadic: fun.variadic,
254 });
255 let subclass_constructor_name = ApiName::new_with_cpp_name(
256 &Namespace::new(),
257 subclass_constructor_name,
258 Some(sub.cpp().get_final_item().to_string()),
259 );
260 (maybe_wrap, subclass_constructor_name)
261}