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