1use jdc_core::ir::expr::{Expr, TypeRef};
8use jdc_core::types::{
9 ClassAccessFlags, FieldAccessFlags, GenericType, JavaType, MethodAccessFlags, MethodDescriptor,
10};
11use jdc_core::{Ctx, Family, NestedClass, NestedKind};
12
13use crate::access::*;
14use crate::{desc_type, DexPool, PoolClass};
15
16pub struct DexCtx<'a> {
18 pub pool: &'a DexPool,
19 pub class: &'a PoolClass,
20}
21
22impl<'a> DexCtx<'a> {
23 pub fn new(pool: &'a DexPool, class: &'a PoolClass) -> Self {
24 DexCtx { pool, class }
25 }
26
27 fn find_class(&self, internal: &str) -> Option<&PoolClass> {
28 self.pool.get(internal)
29 }
30
31 fn outer_of(&self, internal: &str) -> Option<String> {
33 crate::find_outer_name(self.pool, internal)
34 }
35
36 fn class_access_flags(&self, internal: &str) -> ClassAccessFlags {
37 let mut f = ClassAccessFlags::empty();
38 let Some(pc) = self.find_class(internal) else {
39 return f;
40 };
41 let a = pc.access;
42 if a & ACC_PUBLIC != 0 {
43 f |= ClassAccessFlags::PUBLIC;
44 }
45 if a & ACC_FINAL != 0 {
46 f |= ClassAccessFlags::FINAL;
47 }
48 if a & ACC_INTERFACE != 0 {
49 f |= ClassAccessFlags::INTERFACE;
50 }
51 if a & ACC_ABSTRACT != 0 {
52 f |= ClassAccessFlags::ABSTRACT;
53 }
54 if a & ACC_SYNTHETIC != 0 {
55 f |= ClassAccessFlags::SYNTHETIC;
56 }
57 if a & ACC_ANNOTATION != 0 {
58 f |= ClassAccessFlags::ANNOTATION;
59 }
60 if a & ACC_ENUM != 0 {
61 f |= ClassAccessFlags::ENUM;
62 }
63 f
64 }
65}
66
67impl<'a> Ctx for DexCtx<'a> {
68 fn class_name(&self) -> &str {
69 &self.class.name
70 }
71
72 fn source_level(&self) -> u16 {
73 52
74 }
75
76 fn find_outer(&self, internal: &str) -> Option<String> {
77 if internal == self.class.name {
78 return self.outer_of(internal);
79 }
80 self.outer_of(internal)
81 }
82
83 fn family(&self, root: &str) -> Family {
84 let mut fam = Family {
85 root: root.to_string(),
86 ..Default::default()
87 };
88 let mut queue: std::collections::VecDeque<String> =
90 self.pool.children_of(root).iter().cloned().collect();
91 let mut seen: std::collections::HashSet<String> = queue.iter().cloned().collect();
92 while let Some(name) = queue.pop_front() {
93 for c in self.pool.children_of(&name) {
94 if seen.insert(c.clone()) {
95 queue.push_back(c.clone());
96 }
97 }
98 let Some(_) = self.find_class(&name) else {
99 continue;
100 };
101 let root_prefix = format!("{}$", root);
102 let rest: String = if name.starts_with(&root_prefix) {
103 name[root_prefix.len()..].to_string()
104 } else {
105 name.rsplit('$').next().unwrap_or(&name).to_string()
106 };
107 let simple = rest.rsplit('$').next().unwrap_or(&rest).to_string();
108 let kind = classify_nested(&rest);
109 let access = self.class_access_flags(&name);
110 fam.nested.insert(
111 name.clone(),
112 NestedClass {
113 name: name.clone(),
114 simple,
115 kind,
116 access,
117 sig_header: None,
118 },
119 );
120 match kind {
121 NestedKind::Anonymous => {
122 fam.anonymous.insert(name.clone());
123 }
124 NestedKind::Local => {
125 fam.locals.insert(name.clone());
126 }
127 NestedKind::Lambda => {
128 fam.lambdas.insert(name.clone());
129 }
130 NestedKind::Member => {}
131 }
132 }
133 fam
134 }
135
136 fn nested_is_static(&self, internal: &str) -> bool {
137 match self.find_class(internal) {
138 Some(pc) => pc.is_static_nested(),
139 None => true,
140 }
141 }
142
143 fn class_has_this0(&self, internal: &str) -> bool {
144 match self.find_class(internal) {
146 Some(pc) => self.find_outer(internal).is_some() && !pc.is_static_nested(),
147 None => false,
148 }
149 }
150
151 fn is_subtype_of(&self, sub: &JavaType, sup: &str) -> bool {
152 if let JavaType::Object(n) = sub {
153 self.pool.is_subtype(n, sup)
154 } else {
155 false
156 }
157 }
158
159 fn is_interface(&self, internal: &str) -> bool {
160 self.find_class(internal)
161 .map(|pc| pc.is_interface())
162 .unwrap_or(false)
163 }
164
165 fn is_sealed(&self, _internal: &str) -> bool {
166 false
167 }
168
169 fn super_name(&self, internal: &str) -> Option<String> {
170 self.find_class(internal)
171 .and_then(|pc| pc.super_name.clone())
172 }
173
174 fn has_class(&self, internal: &str) -> bool {
175 self.pool.get(internal).is_some() || internal == self.class.name
176 }
177
178 fn class_supers_args(
179 &self,
180 internal: &str,
181 _args: &[GenericType],
182 ) -> Vec<(String, Vec<GenericType>)> {
183 let mut out = Vec::new();
184 let mut cur = self.find_class(internal).map(|pc| pc.name.clone());
185 let mut hops = 0;
186 while let Some(name) = cur {
187 hops += 1;
188 if hops > 64 {
189 break;
190 }
191 if name == "java/lang/Object" {
192 break;
193 }
194 out.push((name.clone(), Vec::new()));
195 cur = self.find_class(&name).and_then(|pc| pc.super_name.clone());
196 }
197 out
198 }
199
200 fn class_bases(&self, internal: &str) -> Option<(Vec<String>, Option<String>)> {
201 let pc = self.find_class(internal)?;
202 Some((pc.interfaces.clone(), pc.super_name.clone()))
203 }
204
205 fn field_flags(&self, internal: &str, name: &str) -> Option<FieldAccessFlags> {
206 let pc = self.find_class(internal)?;
207 let raw = pc
208 .static_fields
209 .iter()
210 .chain(pc.instance_fields.iter())
211 .find(|f| f.name == name)?
212 .access;
213 Some(raw_field_flags(raw))
214 }
215
216 fn method_flags(&self, internal: &str, name: &str, desc: &str) -> Option<MethodAccessFlags> {
217 let pc = self.find_class(internal)?;
218 let m = pc.find_method(name, desc)?;
219 Some(raw_method_flags(m.access))
220 }
221
222 fn declares_field(&self, internal: &str, name: &str) -> bool {
223 self.find_class(internal)
224 .map(|pc| pc.field_flags_of(name).is_some())
225 .unwrap_or(false)
226 }
227
228 fn declares_method_named(&self, internal: &str, name: &str) -> bool {
229 self.find_class(internal)
230 .map(|pc| pc.all_methods().any(|m| &*m.name == name))
231 .unwrap_or(false)
232 }
233
234 fn is_generic_call(&self, _e: &Expr) -> bool {
235 false
236 }
237
238 fn generic_call_formals(&self, _e: &Expr) -> Option<(Vec<GenericType>, Vec<String>)> {
239 None
240 }
241
242 fn polymorphic_ret_cast(
243 &self,
244 _cls: &str,
245 _name: &str,
246 _desc: &MethodDescriptor,
247 ) -> Option<JavaType> {
248 None
249 }
250
251 fn ctor_formals_by_arity(&self, internal: &str, arity: usize) -> Option<Vec<GenericType>> {
252 let pc = self.find_class(internal)?;
253 let ctors = pc.ctors_by_arity(arity);
254 let m = ctors.first()?;
255 let md = m.parsed_desc()?;
256 Some(md.args.iter().map(java_type_to_generic).collect())
257 }
258
259 fn ctor_param_types(
260 &self,
261 internal: &str,
262 skip: usize,
263 n: usize,
264 args: &[Expr],
265 ) -> Option<Vec<JavaType>> {
266 let _ = args;
267 let pc = self.find_class(internal)?;
268 let ctors = pc.ctors_by_arity(skip + n);
269 let m = ctors.first()?;
270 let md = m.parsed_desc()?;
271 Some(md.args.iter().skip(skip).cloned().collect())
272 }
273
274 fn outer_param_via_super(&self, _internal: &str) -> bool {
275 false
276 }
277
278 fn nested_method(
279 &self,
280 _l: &jdc_core::ir::expr::LambdaExpr,
281 _outer_vt: &jdc_core::var::VarTable,
282 ) -> Option<jdc_core::MethodBody> {
283 None
284 }
285}
286
287fn classify_nested(rest: &str) -> NestedKind {
289 let tail = rest.rsplit('$').next().unwrap_or(rest);
291 if rest.starts_with("-$$Lambda$") || tail.starts_with("-$$Lambda$") {
292 return NestedKind::Lambda;
293 }
294 if !tail.is_empty() && tail.chars().all(|c| c.is_ascii_digit()) {
295 return NestedKind::Anonymous;
296 }
297 if tail.starts_with(|c: char| c.is_ascii_digit()) {
298 return NestedKind::Local;
299 }
300 NestedKind::Member
301}
302
303fn raw_field_flags(raw: u32) -> FieldAccessFlags {
304 let mut f = FieldAccessFlags::empty();
305 if raw & ACC_PUBLIC != 0 {
306 f |= FieldAccessFlags::PUBLIC;
307 }
308 if raw & ACC_PRIVATE != 0 {
309 f |= FieldAccessFlags::PRIVATE;
310 }
311 if raw & ACC_PROTECTED != 0 {
312 f |= FieldAccessFlags::PROTECTED;
313 }
314 if raw & ACC_STATIC != 0 {
315 f |= FieldAccessFlags::STATIC;
316 }
317 if raw & ACC_FINAL != 0 {
318 f |= FieldAccessFlags::FINAL;
319 }
320 if raw & ACC_SYNTHETIC != 0 {
321 f |= FieldAccessFlags::SYNTHETIC;
322 }
323 if raw & ACC_ENUM != 0 {
324 f |= FieldAccessFlags::ENUM;
325 }
326 f
327}
328
329fn raw_method_flags(raw: u32) -> MethodAccessFlags {
330 let mut f = MethodAccessFlags::empty();
331 if raw & ACC_PUBLIC != 0 {
332 f |= MethodAccessFlags::PUBLIC;
333 }
334 if raw & ACC_PRIVATE != 0 {
335 f |= MethodAccessFlags::PRIVATE;
336 }
337 if raw & ACC_PROTECTED != 0 {
338 f |= MethodAccessFlags::PROTECTED;
339 }
340 if raw & ACC_STATIC != 0 {
341 f |= MethodAccessFlags::STATIC;
342 }
343 if raw & ACC_FINAL != 0 {
344 f |= MethodAccessFlags::FINAL;
345 }
346 if raw & ACC_SYNCHRONIZED != 0 || raw & ACC_DECLARED_SYNCHRONIZED != 0 {
347 f |= MethodAccessFlags::SYNCHRONIZED;
348 }
349 if raw & ACC_BRIDGE != 0 {
350 f |= MethodAccessFlags::BRIDGE;
351 }
352 if raw & ACC_VARARGS != 0 {
353 f |= MethodAccessFlags::VARARGS;
354 }
355 if raw & ACC_NATIVE != 0 {
356 f |= MethodAccessFlags::NATIVE;
357 }
358 if raw & ACC_ABSTRACT != 0 {
359 f |= MethodAccessFlags::ABSTRACT;
360 }
361 if raw & ACC_STRICT != 0 {
362 f |= MethodAccessFlags::STRICT;
363 }
364 if raw & ACC_SYNTHETIC != 0 {
365 f |= MethodAccessFlags::SYNTHETIC;
366 }
367 f
368}
369
370pub fn java_type_to_generic(t: &JavaType) -> GenericType {
372 match t {
373 JavaType::Object(n) => GenericType::Class(class_sig_of(n)),
374 JavaType::Array(inner) => GenericType::Array(Box::new(java_type_to_generic(inner))),
375 other => GenericType::Primitive(other.primitive_char().unwrap_or('V')),
376 }
377}
378
379fn class_sig_of(internal: &str) -> jdc_core::types::ClassSig {
380 let (package, name) = match internal.rfind('/') {
381 Some(i) => (internal[..i].to_string(), internal[i + 1..].to_string()),
382 None => (String::new(), internal.to_string()),
383 };
384 jdc_core::types::ClassSig {
385 package,
386 parts: vec![jdc_core::types::ClassSigPart { name, args: vec![] }],
387 }
388}
389
390pub fn type_ref_of(desc: &str) -> TypeRef {
392 TypeRef::J(desc_type(desc))
393}