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