prebindgen_registry/
diagnostics.rs1use std::collections::HashSet;
13
14use prebindgen_flat::flat::Flat;
15
16use crate::{prebindgen::NamePredicate, registry::TypeKey};
17
18#[derive(Default)]
26pub struct Claimed {
27 pub functions: HashSet<syn::Ident>,
29 pub types: HashSet<TypeKey>,
31 pub consts: Option<HashSet<syn::Ident>>,
35 pub ignored_functions: HashSet<syn::Ident>,
36 pub ignored_types: HashSet<TypeKey>,
37 pub ignored_consts: HashSet<syn::Ident>,
38 pub ignored_name_predicates: Vec<NamePredicate>,
41}
42
43impl Claimed {
44 fn predicate_ignored(&self, name: &str) -> bool {
49 !self.ignored_name_predicates.is_empty()
50 && self.ignored_name_predicates.iter().any(|p| p(name))
51 }
52}
53
54pub fn warn_unclaimed(flat: &Flat, claimed: &Claimed) {
57 for line in unclaimed_report(flat, claimed) {
58 println!("cargo:warning={line}");
59 }
60}
61
62pub(crate) fn unclaimed_report(flat: &Flat, claimed: &Claimed) -> Vec<String> {
65 let mut out = Vec::new();
66
67 for ident in sorted(claimed.ignored_functions.iter().map(|i| i.to_string())) {
70 if flat.function(&ident_of(&ident)).is_none() {
71 out.push(format!(
72 "prebindgen: ignored function `{ident}` not found among #[prebindgen] items"
73 ));
74 }
75 }
76 for key in sorted(claimed.ignored_types.iter().map(|k| k.as_str().to_owned())) {
77 let named = TypeKey::parse(&key)
78 .ok()
79 .and_then(|k| k.ident())
80 .is_some_and(|ident| flat.declared_type(&ident).is_some());
81 if !named {
82 out.push(format!(
83 "prebindgen: ignored type `{key}` not found among #[prebindgen] items"
84 ));
85 }
86 }
87 if claimed.consts.is_some() {
88 for ident in sorted(claimed.ignored_consts.iter().map(|i| i.to_string())) {
89 if flat.constant(&ident_of(&ident)).is_none() {
90 out.push(format!(
91 "prebindgen: ignored const `{ident}` not found among #[prebindgen] items"
92 ));
93 }
94 }
95 }
96
97 for name in sorted(
98 flat.functions()
99 .map(|f| &f.name)
100 .filter(|k| !claimed.functions.contains(*k) && !claimed.ignored_functions.contains(*k))
101 .map(|k| k.to_string())
102 .filter(|n| !claimed.predicate_ignored(n)),
103 ) {
104 out.push(format!(
105 "prebindgen: skipping undeclared #[prebindgen] fn `{name}`"
106 ));
107 }
108
109 for name in sorted(
112 struct_enum_idents(flat)
113 .filter(|i| {
114 let key = TypeKey::from_ident(i);
115 !claimed.types.contains(&key) && !claimed.ignored_types.contains(&key)
116 })
117 .map(|i| i.to_string())
118 .filter(|n| !claimed.predicate_ignored(n)),
119 ) {
120 out.push(format!(
121 "prebindgen: skipping undeclared #[prebindgen] struct/enum `{name}`"
122 ));
123 }
124
125 if let Some(declared) = &claimed.consts {
126 for name in sorted(
127 flat.constants()
128 .map(|c| &c.name)
129 .filter(|k| !declared.contains(*k) && !claimed.ignored_consts.contains(*k))
130 .map(|k| k.to_string())
131 .filter(|n| !claimed.predicate_ignored(n)),
132 ) {
133 out.push(format!(
134 "prebindgen: skipping undeclared #[prebindgen] const `{name}`"
135 ));
136 }
137 }
138
139 out
140}
141
142fn struct_enum_idents(flat: &Flat) -> impl Iterator<Item = &syn::Ident> {
144 use prebindgen_flat::flat::Type;
145 flat.types().filter_map(|t| match t {
146 Type::Struct(_) | Type::Variant(_) | Type::Enum(_) => Some(t.name()),
147 Type::Extern(_) => None,
148 })
149}
150
151fn sorted(it: impl Iterator<Item = String>) -> Vec<String> {
152 let mut v: Vec<String> = it.collect();
153 v.sort();
154 v
155}
156
157fn ident_of(name: &str) -> syn::Ident {
158 syn::Ident::new(name, proc_macro2::Span::call_site())
159}
160
161#[cfg(test)]
162mod tests;