blob: 5a635f86d80bbc5b06563d6de195e4ad290cd3ad [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::set::IndexSet as HashSet;
10
11use autocxx_parser::IncludeCppConfig;
12use syn::ItemType;
13
14use crate::{
15 conversion::{
16 analysis::type_converter::{add_analysis, Annotated, TypeConversionContext, TypeConverter},
17 api::{AnalysisPhase, Api, ApiName, NullPhase, TypedefKind},
18 apivec::ApiVec,
19 convert_error::{ConvertErrorWithContext, ErrorContext},
20 error_reporter::convert_apis,
21 parse::BindgenSemanticAttributes,
22 ConvertError,
23 },
24 types::QualifiedName,
25};
26
27pub(crate) struct TypedefAnalysis {
28 pub(crate) kind: TypedefKind,
29 pub(crate) deps: HashSet<QualifiedName>,
30}
31
32/// Analysis phase where typedef analysis has been performed but no other
33/// analyses just yet.
34pub(crate) struct TypedefPhase;
35
36impl AnalysisPhase for TypedefPhase {
37 type TypedefAnalysis = TypedefAnalysis;
38 type StructAnalysis = ();
39 type FunAnalysis = ();
40}
41
42#[allow(clippy::needless_collect)] // we need the extra collect because the closure borrows extra_apis
43pub(crate) fn convert_typedef_targets(
44 config: &IncludeCppConfig,
45 apis: ApiVec<NullPhase>,
46) -> ApiVec<TypedefPhase> {
47 let mut type_converter = TypeConverter::new(config, &apis);
48 let mut extra_apis = ApiVec::new();
49 let mut results = ApiVec::new();
50 convert_apis(
51 apis,
52 &mut results,
53 Api::fun_unchanged,
54 Api::struct_unchanged,
55 Api::enum_unchanged,
56 |name, item, old_tyname, _| {
57 Ok(Box::new(std::iter::once(match item {
58 TypedefKind::Type(ity) => get_replacement_typedef(
59 name,
60 ity,
61 old_tyname,
62 &mut type_converter,
63 &mut extra_apis,
64 )?,
65 TypedefKind::Use { .. } => Api::Typedef {
66 name,
67 item: item.clone(),
68 old_tyname,
69 analysis: TypedefAnalysis {
70 kind: item,
71 deps: HashSet::new(),
72 },
73 },
74 })))
75 },
76 );
77 results.extend(extra_apis.into_iter().map(add_analysis));
78 results
79}
80
81fn get_replacement_typedef(
82 name: ApiName,
83 ity: ItemType,
84 old_tyname: Option<QualifiedName>,
85 type_converter: &mut TypeConverter,
86 extra_apis: &mut ApiVec<NullPhase>,
87) -> Result<Api<TypedefPhase>, ConvertErrorWithContext> {
88 if !ity.generics.params.is_empty() {
89 return Err(ConvertErrorWithContext(
90 ConvertError::TypedefTakesGenericParameters,
91 Some(ErrorContext::new_for_item(name.name.get_final_ident())),
92 ));
93 }
94 let mut converted_type = ity.clone();
95 let metadata = BindgenSemanticAttributes::new_retaining_others(&mut converted_type.attrs);
96 metadata.check_for_fatal_attrs(&ity.ident)?;
97 let type_conversion_results = type_converter.convert_type(
98 (*ity.ty).clone(),
99 name.name.get_namespace(),
100 &TypeConversionContext::WithinReference,
101 );
102 match type_conversion_results {
103 Err(err) => Err(ConvertErrorWithContext(
104 err,
105 Some(ErrorContext::new_for_item(name.name.get_final_ident())),
106 )),
107 Ok(Annotated {
108 ty: syn::Type::Path(ref typ),
109 ..
110 }) if QualifiedName::from_type_path(typ) == name.name => Err(ConvertErrorWithContext(
111 ConvertError::InfinitelyRecursiveTypedef(name.name.clone()),
112 Some(ErrorContext::new_for_item(name.name.get_final_ident())),
113 )),
114 Ok(mut final_type) => {
115 converted_type.ty = Box::new(final_type.ty.clone());
116 extra_apis.append(&mut final_type.extra_apis);
117 Ok(Api::Typedef {
118 name,
119 item: TypedefKind::Type(ity),
120 old_tyname,
121 analysis: TypedefAnalysis {
122 kind: TypedefKind::Type(converted_type),
123 deps: final_type.types_encountered,
124 },
125 })
126 }
127 }
128}