Squashed 'third_party/autocxx/' content from commit 629e8fa53

git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/engine/src/conversion/analysis/fun/subclass.rs b/engine/src/conversion/analysis/fun/subclass.rs
new file mode 100644
index 0000000..c017249
--- /dev/null
+++ b/engine/src/conversion/analysis/fun/subclass.rs
@@ -0,0 +1,249 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use indexmap::map::IndexMap as HashMap;
+
+use syn::{parse_quote, FnArg, PatType, Type, TypePtr};
+
+use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability};
+use crate::conversion::analysis::pod::PodPhase;
+use crate::conversion::api::{
+    CppVisibility, FuncToConvert, Provenance, RustSubclassFnDetails, SubclassConstructorDetails,
+    SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness,
+};
+use crate::conversion::apivec::ApiVec;
+use crate::{
+    conversion::{
+        analysis::fun::function_wrapper::{
+            CppFunction, CppFunctionBody, CppFunctionKind, TypeConversionPolicy,
+        },
+        api::{Api, ApiName},
+    },
+    types::{make_ident, Namespace, QualifiedName},
+};
+
+use super::{FnAnalysis, FnPrePhase1};
+
+pub(super) fn subclasses_by_superclass(
+    apis: &ApiVec<PodPhase>,
+) -> HashMap<QualifiedName, Vec<SubclassName>> {
+    let mut subclasses_per_superclass: HashMap<QualifiedName, Vec<SubclassName>> = HashMap::new();
+
+    for api in apis.iter() {
+        if let Api::Subclass { name, superclass } = api {
+            subclasses_per_superclass
+                .entry(superclass.clone())
+                .or_default()
+                .push(name.clone());
+        }
+    }
+    subclasses_per_superclass
+}
+
+pub(super) fn create_subclass_fn_wrapper(
+    sub: &SubclassName,
+    super_fn_name: &QualifiedName,
+    fun: &FuncToConvert,
+) -> Box<FuncToConvert> {
+    let self_ty = Some(sub.cpp());
+    Box::new(FuncToConvert {
+        synthesized_this_type: self_ty.clone(),
+        self_ty,
+        ident: super_fn_name.get_final_ident(),
+        doc_attrs: fun.doc_attrs.clone(),
+        inputs: fun.inputs.clone(),
+        output: fun.output.clone(),
+        vis: fun.vis.clone(),
+        virtualness: Virtualness::None,
+        cpp_vis: CppVisibility::Public,
+        special_member: None,
+        unused_template_param: fun.unused_template_param,
+        original_name: None,
+        references: fun.references.clone(),
+        add_to_trait: fun.add_to_trait.clone(),
+        is_deleted: fun.is_deleted,
+        synthetic_cpp: None,
+        provenance: Provenance::SynthesizedOther,
+        variadic: fun.variadic,
+    })
+}
+
+pub(super) fn create_subclass_trait_item(
+    name: ApiName,
+    analysis: &FnAnalysis,
+    receiver_mutability: &ReceiverMutability,
+    receiver: QualifiedName,
+    is_pure_virtual: bool,
+) -> Api<FnPrePhase1> {
+    let param_names = analysis
+        .param_details
+        .iter()
+        .map(|pd| pd.name.clone())
+        .collect();
+    Api::SubclassTraitItem {
+        name,
+        details: SuperclassMethod {
+            name: make_ident(&analysis.rust_name),
+            params: analysis.params.clone(),
+            ret_type: analysis.ret_type.clone(),
+            param_names,
+            receiver_mutability: receiver_mutability.clone(),
+            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
+            is_pure_virtual,
+            receiver,
+        },
+    }
+}
+
+pub(super) fn create_subclass_function(
+    sub: &SubclassName,
+    analysis: &super::FnAnalysis,
+    name: &ApiName,
+    receiver_mutability: &ReceiverMutability,
+    superclass: &QualifiedName,
+    dependencies: Vec<QualifiedName>,
+) -> Api<FnPrePhase1> {
+    let cpp = sub.cpp();
+    let holder_name = sub.holder();
+    let rust_call_name = make_ident(format!(
+        "{}_{}",
+        sub.0.name.get_final_item(),
+        name.name.get_final_item()
+    ));
+    let params = std::iter::once(parse_quote! {
+        me: & #holder_name
+    })
+    .chain(analysis.params.iter().skip(1).cloned())
+    .collect();
+    let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
+        CppFunctionKind::Method
+    } else {
+        CppFunctionKind::ConstMethod
+    };
+    let argument_conversion = analysis
+        .param_details
+        .iter()
+        .skip(1)
+        .map(|p| p.conversion.clone())
+        .collect();
+    Api::RustSubclassFn {
+        name: ApiName::new_in_root_namespace(rust_call_name.clone()),
+        subclass: sub.clone(),
+        details: Box::new(RustSubclassFnDetails {
+            params,
+            ret: analysis.ret_type.clone(),
+            method_name: make_ident(&analysis.rust_name),
+            cpp_impl: CppFunction {
+                payload: CppFunctionBody::FunctionCall(Namespace::new(), rust_call_name),
+                wrapper_function_name: make_ident(&analysis.rust_name),
+                original_cpp_name: name.cpp_name(),
+                return_conversion: analysis.ret_conversion.clone(),
+                argument_conversion,
+                kind,
+                pass_obs_field: true,
+                qualification: Some(cpp),
+            },
+            superclass: superclass.clone(),
+            receiver_mutability: receiver_mutability.clone(),
+            dependencies,
+            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
+            is_pure_virtual: matches!(
+                analysis.kind,
+                FnKind::Method {
+                    method_kind: MethodKind::PureVirtual(..),
+                    ..
+                }
+            ),
+        }),
+    }
+}
+
+pub(super) fn create_subclass_constructor(
+    sub: SubclassName,
+    analysis: &FnAnalysis,
+    sup: &QualifiedName,
+    fun: &FuncToConvert,
+) -> (Box<FuncToConvert>, ApiName) {
+    let holder = sub.holder();
+    let cpp = sub.cpp();
+    let wrapper_function_name = cpp.get_final_ident();
+    let initial_arg = TypeConversionPolicy::new_unconverted(parse_quote! {
+        rust::Box< #holder >
+    });
+    let args = std::iter::once(initial_arg).chain(
+        analysis
+            .param_details
+            .iter()
+            .skip(1) // skip placement new destination
+            .map(|aa| aa.conversion.clone()),
+    );
+    let cpp_impl = CppFunction {
+        payload: CppFunctionBody::ConstructSuperclass(sup.to_cpp_name()),
+        wrapper_function_name,
+        return_conversion: None,
+        argument_conversion: args.collect(),
+        kind: CppFunctionKind::SynthesizedConstructor,
+        pass_obs_field: false,
+        qualification: Some(cpp.clone()),
+        original_cpp_name: cpp.to_cpp_name(),
+    };
+    let subclass_constructor_details = Box::new(SubclassConstructorDetails {
+        subclass: sub.clone(),
+        is_trivial: analysis.param_details.len() == 1, // just placement new
+        // destination, no other parameters
+        cpp_impl,
+    });
+    let subclass_constructor_name =
+        make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
+    let mut existing_params = fun.inputs.clone();
+    if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
+        if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
+            *elem = Box::new(Type::Path(sub.cpp().to_type_path()));
+        } else {
+            panic!("Unexpected self type parameter when creating subclass constructor");
+        }
+    } else {
+        panic!("Unexpected self type parameter when creating subclass constructor");
+    }
+    let mut existing_params = existing_params.into_iter();
+    let self_param = existing_params.next();
+    let boxed_holder_param: FnArg = parse_quote! {
+        peer: rust::Box<#holder>
+    };
+    let inputs = self_param
+        .into_iter()
+        .chain(std::iter::once(boxed_holder_param))
+        .chain(existing_params)
+        .collect();
+    let maybe_wrap = Box::new(FuncToConvert {
+        ident: subclass_constructor_name.clone(),
+        doc_attrs: fun.doc_attrs.clone(),
+        inputs,
+        output: fun.output.clone(),
+        vis: fun.vis.clone(),
+        virtualness: Virtualness::None,
+        cpp_vis: CppVisibility::Public,
+        special_member: fun.special_member.clone(),
+        original_name: None,
+        unused_template_param: fun.unused_template_param,
+        references: fun.references.clone(),
+        synthesized_this_type: Some(cpp.clone()),
+        self_ty: Some(cpp),
+        add_to_trait: None,
+        is_deleted: fun.is_deleted,
+        synthetic_cpp: None,
+        provenance: Provenance::SynthesizedSubclassConstructor(subclass_constructor_details),
+        variadic: fun.variadic,
+    });
+    let subclass_constructor_name = ApiName::new_with_cpp_name(
+        &Namespace::new(),
+        subclass_constructor_name,
+        Some(sub.cpp().get_final_item().to_string()),
+    );
+    (maybe_wrap, subclass_constructor_name)
+}