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