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/tdef.rs b/engine/src/conversion/analysis/tdef.rs
new file mode 100644
index 0000000..5a635f8
--- /dev/null
+++ b/engine/src/conversion/analysis/tdef.rs
@@ -0,0 +1,128 @@
+// 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::set::IndexSet as HashSet;
+
+use autocxx_parser::IncludeCppConfig;
+use syn::ItemType;
+
+use crate::{
+    conversion::{
+        analysis::type_converter::{add_analysis, Annotated, TypeConversionContext, TypeConverter},
+        api::{AnalysisPhase, Api, ApiName, NullPhase, TypedefKind},
+        apivec::ApiVec,
+        convert_error::{ConvertErrorWithContext, ErrorContext},
+        error_reporter::convert_apis,
+        parse::BindgenSemanticAttributes,
+        ConvertError,
+    },
+    types::QualifiedName,
+};
+
+pub(crate) struct TypedefAnalysis {
+    pub(crate) kind: TypedefKind,
+    pub(crate) deps: HashSet<QualifiedName>,
+}
+
+/// Analysis phase where typedef analysis has been performed but no other
+/// analyses just yet.
+pub(crate) struct TypedefPhase;
+
+impl AnalysisPhase for TypedefPhase {
+    type TypedefAnalysis = TypedefAnalysis;
+    type StructAnalysis = ();
+    type FunAnalysis = ();
+}
+
+#[allow(clippy::needless_collect)] // we need the extra collect because the closure borrows extra_apis
+pub(crate) fn convert_typedef_targets(
+    config: &IncludeCppConfig,
+    apis: ApiVec<NullPhase>,
+) -> ApiVec<TypedefPhase> {
+    let mut type_converter = TypeConverter::new(config, &apis);
+    let mut extra_apis = ApiVec::new();
+    let mut results = ApiVec::new();
+    convert_apis(
+        apis,
+        &mut results,
+        Api::fun_unchanged,
+        Api::struct_unchanged,
+        Api::enum_unchanged,
+        |name, item, old_tyname, _| {
+            Ok(Box::new(std::iter::once(match item {
+                TypedefKind::Type(ity) => get_replacement_typedef(
+                    name,
+                    ity,
+                    old_tyname,
+                    &mut type_converter,
+                    &mut extra_apis,
+                )?,
+                TypedefKind::Use { .. } => Api::Typedef {
+                    name,
+                    item: item.clone(),
+                    old_tyname,
+                    analysis: TypedefAnalysis {
+                        kind: item,
+                        deps: HashSet::new(),
+                    },
+                },
+            })))
+        },
+    );
+    results.extend(extra_apis.into_iter().map(add_analysis));
+    results
+}
+
+fn get_replacement_typedef(
+    name: ApiName,
+    ity: ItemType,
+    old_tyname: Option<QualifiedName>,
+    type_converter: &mut TypeConverter,
+    extra_apis: &mut ApiVec<NullPhase>,
+) -> Result<Api<TypedefPhase>, ConvertErrorWithContext> {
+    if !ity.generics.params.is_empty() {
+        return Err(ConvertErrorWithContext(
+            ConvertError::TypedefTakesGenericParameters,
+            Some(ErrorContext::new_for_item(name.name.get_final_ident())),
+        ));
+    }
+    let mut converted_type = ity.clone();
+    let metadata = BindgenSemanticAttributes::new_retaining_others(&mut converted_type.attrs);
+    metadata.check_for_fatal_attrs(&ity.ident)?;
+    let type_conversion_results = type_converter.convert_type(
+        (*ity.ty).clone(),
+        name.name.get_namespace(),
+        &TypeConversionContext::WithinReference,
+    );
+    match type_conversion_results {
+        Err(err) => Err(ConvertErrorWithContext(
+            err,
+            Some(ErrorContext::new_for_item(name.name.get_final_ident())),
+        )),
+        Ok(Annotated {
+            ty: syn::Type::Path(ref typ),
+            ..
+        }) if QualifiedName::from_type_path(typ) == name.name => Err(ConvertErrorWithContext(
+            ConvertError::InfinitelyRecursiveTypedef(name.name.clone()),
+            Some(ErrorContext::new_for_item(name.name.get_final_ident())),
+        )),
+        Ok(mut final_type) => {
+            converted_type.ty = Box::new(final_type.ty.clone());
+            extra_apis.append(&mut final_type.extra_apis);
+            Ok(Api::Typedef {
+                name,
+                item: TypedefKind::Type(ity),
+                old_tyname,
+                analysis: TypedefAnalysis {
+                    kind: TypedefKind::Type(converted_type),
+                    deps: final_type.types_encountered,
+                },
+            })
+        }
+    }
+}