1use std::collections::HashSet;
2
3use crate::{
4 class_info::{ClassInfo, ClassRef, Constructor, Flags, Method, RefType, RootMap, Type},
5 reflect::Reflector,
6};
7
8impl RootMap {
9 pub fn check(&self, reflector: &mut Reflector) -> syn::Result<()> {
10 let mut errors = vec![];
11
12 for class_name in &self.class_names() {
13 let ci = self.find_class(class_name).unwrap();
14 ci.check(self, reflector, &mut |e| errors.push(e))?;
15 }
16
17 match errors.into_iter().reduce(|mut error, next| {
18 error.combine(next);
19 error
20 }) {
21 Some(e) => Err(e),
22 None => Ok(()),
23 }
24 }
25}
26
27impl ClassInfo {
28 fn check(
29 &self,
30 root_map: &RootMap,
31 reflector: &mut Reflector,
32 push_error: &mut dyn FnMut(syn::Error),
33 ) -> syn::Result<()> {
34 let info = reflector.reflect(&self.name, self.span)?;
35
36 let mut push_error_message = |m: String| {
37 push_error(syn::Error::new(
38 self.span,
39 format!("error in class `{}`: {m}", self.name),
40 ));
41 };
42
43 if self.kind != info.kind {
44 push_error_message(format!(
45 "class `{}` should be type `{}`",
46 self.name,
47 format!("{:?}", info.kind).to_lowercase()
48 ));
49 }
50
51 if !self.generics.is_empty() {
57 if self.generics != info.generics {
59 push_error_message(format!(
60 "class `{}` should have generic parameters `<{}>`",
61 self.name,
62 info.generics
63 .iter()
64 .map(|g| g.to_string())
65 .collect::<Vec<_>>()
66 .join(", "),
67 ));
68 }
69 }
70
71 for cref in &self.extends {
72 if !info.extends.iter().any(|c| c == cref) {
73 let extends_list: String = info
74 .extends
75 .iter()
76 .map(|c| format!("`{}`", c))
77 .collect::<Vec<String>>()
78 .join(", ");
79 push_error_message(format!(
80 "declared interface `{cref}` not found in the reflected superclasses ({})",
81 extends_list
82 ));
83 }
84
85 cref.check(root_map, &mut |m| {
86 push_error_message(format!("{m}, but is extended by `{}`", self.name))
87 });
88 }
89
90 error_on_duplicates(self.extends.as_slice(), "extends", &mut push_error_message);
92
93 for cref in &self.implements {
94 if !info.implements.iter().any(|c| c == cref) {
95 let implements_list: String = info
96 .implements
97 .iter()
98 .map(|c| format!("`{}`", c))
99 .collect::<Vec<String>>()
100 .join(", ");
101 push_error_message(format!(
102 "declared interface `{cref}` not found in the reflected interfaces (`{}`)",
103 implements_list
104 ));
105 }
106
107 cref.check(root_map, &mut |m| {
108 push_error_message(format!("{m}, but is implemented by `{}`", self.name));
109 });
110 }
111
112 error_on_duplicates(
114 self.implements.as_slice(),
115 "implements",
116 &mut push_error_message,
117 );
118
119 for c in &self.constructors {
120 let c_method_sig = c.to_method_sig(self);
121
122 c.check(root_map, &mut |m| {
123 push_error_message(format!(
124 "{m}, which appears in constructor {}",
125 c_method_sig,
126 ));
127 });
128
129 if !info
130 .constructors
131 .iter()
132 .any(|info_c| info_c.to_method_sig(&info) == c_method_sig)
133 {
134 push_error_message(format!(
135 "constructor {} does not match any constructors in the reflected class",
136 c_method_sig,
137 ));
138 }
139 }
140
141 for m in &self.methods {
142 let m_method_sig = m.to_method_sig();
143
144 let mut push_method_error_message = |msg: String| {
145 push_error_message(format!(
146 "{msg}, which appears in method `{}`",
147 m.to_method_sig()
148 ));
149 };
150
151 m.check(root_map, &mut push_method_error_message);
152
153 if let Some(reflected_m) = info
154 .methods
155 .iter()
156 .find(|info_c| info_c.to_method_sig() == m_method_sig)
157 {
158 self.compare_flags(m.flags, reflected_m.flags, &mut push_method_error_message);
159 } else {
160 let same_names: Vec<_> = info
161 .methods
162 .iter()
163 .filter(|info_c| info_c.name == m_method_sig.name)
164 .map(|info_c| info_c.to_method_sig())
165 .map(|info_c| info_c.to_string())
166 .collect();
167 if same_names.is_empty() {
168 push_error_message(format!(
169 "no method named `{}` in the reflected class",
170 m_method_sig,
171 ));
172 } else {
173 push_error_message(format!(
174 "method `{}` does not match any of the methods in the reflected class: {}",
175 m_method_sig,
176 same_names.join(", "),
177 ));
178 }
179 }
180 }
181
182 Ok(())
183 }
184
185 fn compare_flags(
186 &self,
187 flags: Flags,
188 reflected_flags: Flags,
189 push_error: &mut dyn FnMut(String),
190 ) {
191 if self.should_mirror_in_rust(flags.privacy)
192 != self.should_mirror_in_rust(reflected_flags.privacy)
193 {
194 push_error(format!(
195 "member declared as {} but it is {} in Java",
196 flags.privacy, reflected_flags.privacy,
197 ));
198 }
199
200 if flags.is_native && !reflected_flags.is_native {
201 push_error(format!(
202 "member declared as native but it is not native in Java",
203 ));
204 }
205
206 if !flags.is_native && reflected_flags.is_native {
207 push_error(format!(
208 "member not declared as native but it is native in Java",
209 ));
210 }
211 }
212}
213
214impl ClassRef {
215 fn check(&self, root_map: &RootMap, push_error: &mut dyn FnMut(String)) {
216 let (package_name, class_id) = self.name.split();
217 if let Some(package) = root_map.find_package(package_name) {
218 if let None = package.find_class(&class_id) {
219 push_error(format!(
220 "class `{}` not in list of classes to be translated",
221 self.name,
222 ))
223 }
224 }
225 }
226}
227
228impl Constructor {
229 fn check(&self, root_map: &RootMap, mut push_error: impl FnMut(String)) {
230 for ty in &self.argument_tys {
231 ty.check(root_map, &mut push_error);
232 }
233 }
234}
235
236impl Method {
237 fn check(&self, root_map: &RootMap, mut push_error: impl FnMut(String)) {
238 for ty in &self.argument_tys {
239 ty.check(root_map, &mut push_error);
240 }
241 }
242}
243
244impl Type {
245 fn check(&self, root_map: &RootMap, push_error: &mut impl FnMut(String)) {
246 match self {
247 Type::Ref(r) => r.check(root_map, push_error),
248 Type::Scalar(_) => (),
249 Type::Repeat(ty) => ty.check(root_map, push_error),
250 }
251 }
252}
253
254impl RefType {
255 fn check(&self, root_map: &RootMap, push_error: &mut impl FnMut(String)) {
256 match self {
257 RefType::Class(cref) => cref.check(root_map, push_error),
258 RefType::Array(array) => array.check(root_map, push_error),
259 RefType::TypeParameter(_) => (),
260 RefType::Extends(ty) => ty.check(root_map, push_error),
261 RefType::Super(ty) => ty.check(root_map, push_error),
262 RefType::Wildcard => (),
263 }
264 }
265}
266
267fn error_on_duplicates(
268 references: &[ClassRef],
269 ref_type: &str,
270 mut push_error: impl FnMut(String),
271) {
272 let mut seen = HashSet::with_capacity(references.len());
273 for class_ref in references.iter() {
274 if seen.contains(&(class_ref.name)) {
275 push_error(format!(
276 "duplicate reference in '{}' to '{}'",
277 ref_type, class_ref.name
278 ));
279 } else {
280 seen.insert(class_ref.name.clone());
281 }
282 }
283}