Skip to main content

jdc_core/
ctx.rs

1//! What the core needs to ask the front-end.
2//!
3//! Everything in this crate works on machine-neutral IR; the few questions
4//! that depend on the machine's *class metadata* — how nested classes are
5//! related, what a method's signature says, how a nested method body looks —
6//! go through [`Ctx`]. A front-end implements it once (JVM: over its class
7//! pool; DEX: over its class definitions) and every shared pass/emitter works.
8//!
9//! The trait is deliberately *semantic*, not a raw pool: the core never sees
10//! a constant pool, a `Signature` attribute, or an `InnerClasses` table.
11
12use std::collections::{HashMap, HashSet};
13
14use crate::ir::expr::Expr;
15use crate::ir::stmt::Stmt;
16use crate::ir::expr::TypeRef;
17use crate::types::{ClassAccessFlags, MethodDescriptor};
18
19/// How a nested class was classified.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum NestedKind {
22    /// Declared as a member of its outer class.
23    Member,
24    /// An anonymous class: inlined at its `new` site, never printed separately.
25    Anonymous,
26    /// A local class: declared at its use site inside a method.
27    Local,
28    /// A lambda implementation class: skipped entirely.
29    Lambda,
30}
31
32/// One nested class of a family.
33#[derive(Debug, Clone)]
34pub struct NestedClass {
35    /// Internal name (e.g. `p/Outer$Inner`).
36    pub name: String,
37    /// Source-visible simple name (`Inner`, or a synthesized name for locals).
38    pub simple: String,
39    pub kind: NestedKind,
40    pub access: ClassAccessFlags,
41    /// Source header rendered from the class's generic signature when the
42    /// container records one; `None` for front-ends without signature info
43    /// (DEX), in which case tracking falls back to the erased rendering.
44    pub sig_header: Option<String>,
45}
46
47/// The nested-class family of one top-level class.
48#[derive(Debug, Default, Clone)]
49pub struct Family {
50    pub root: String,
51    /// All nested classes (any depth) keyed by internal name.
52    pub nested: HashMap<String, NestedClass>,
53    /// Anonymous classes inlined at `new` sites.
54    pub anonymous: HashSet<String>,
55    /// Local classes declared at their use site.
56    pub locals: HashSet<String>,
57    /// Lambda implementation classes (skipped).
58    pub lambdas: HashSet<String>,
59}
60
61/// A decompiled nested method body (lambda body, anonymous-class method, ...).
62pub struct MethodBody {
63    /// Final statement tree.
64    pub body: Stmt,
65    pub vt: crate::var::VarTable,
66    pub desc: MethodDescriptor,
67}
68
69/// Front-end services used by the shared passes and the emitter.
70pub trait Ctx {
71    /// Internal name of the class currently being emitted
72    /// (e.g. `java/util/ArrayList`).
73    fn class_name(&self) -> &str;
74
75    /// Source level gate for version-dependent rendering: the JVM front-end
76    /// returns the class-file major version; a DEX front-end returns the
77    /// equivalent language level it decided to target. `52` means "Java 8
78    /// features available" (lambdas, diamond, ...).
79    fn source_level(&self) -> u16 {
80        52
81    }
82
83    /// The class that `internal` is nested in, when the container records the
84    /// nesting (JVM `InnerClasses`/`NestHost`; DEX inner-class annotations).
85    /// `None` for a top-level class — including literal-`$` names that only
86    /// *look* nested.
87    fn find_outer(&self, internal: &str) -> Option<String>;
88
89    /// Nested-class family of `root`, as far as the container records it.
90    fn family(&self, root: &str) -> Family;
91
92    /// True when a nested class is static (`Outer$Inner` with ACC_STATIC), so
93    /// it is not constructed with an enclosing instance.
94    fn nested_is_static(&self, internal: &str) -> bool;
95
96    /// True when the class carries a synthetic `this$0` field (an inner class
97    /// with an enclosing instance parameter).
98    fn class_has_this0(&self, internal: &str) -> bool;
99
100    /// True when `sub` is assignable to `sup` (both internal names).
101    fn is_subtype_of(&self, sub: &crate::types::JavaType, sup: &str) -> bool;
102
103    /// Superclasses/interfaces of `internal` with the given type arguments
104    /// applied: `[(java/lang/Object, []), ...]`, most-derived first.
105    fn class_supers_args(
106        &self,
107        internal: &str,
108        args: &[crate::types::GenericType],
109    ) -> Vec<(String, Vec<crate::types::GenericType>)>;
110
111    /// True when the call carries inferred type arguments that the source
112    /// must spell out.
113    fn is_generic_call(&self, e: &Expr) -> bool;
114
115    /// Instantiated formal parameter types of a generic call plus the callee's
116    /// own method type variables (for witness casts). `None` when the call has
117    /// no inferred type arguments to spell out.
118    fn generic_call_formals(
119        &self,
120        e: &Expr,
121    ) -> Option<(Vec<crate::types::GenericType>, Vec<String>)>;
122
123    /// The instantiated return type of a call whose methodref owner redeclares
124    /// the method with a self-covariant return (Stream over BaseStream).
125    fn polymorphic_ret_cast(&self, cls: &str, name: &str, desc: &MethodDescriptor) -> Option<crate::types::JavaType>;
126
127    /// Constructor parameter types of `internal` matching `arity`, for
128    /// rendering `new` arguments against the right overload.
129    fn ctor_formals_by_arity(
130        &self,
131        internal: &str,
132        arity: usize,
133    ) -> Option<Vec<crate::types::GenericType>>;
134
135    /// Local-class name recorded for a `$`-style synthetic marker, when the
136    /// container records one (`Outer$1Local` -> `Local`).
137    fn local_class_internal(&self, simple: &str) -> Option<String> {
138        let _ = simple;
139        None
140    }
141
142    /// Generic type parameters declared by `internal` (from its class
143    /// signature); empty when the container records none.
144    fn class_type_params(&self, internal: &str) -> Vec<crate::types::TypeParam> {
145        let _ = internal;
146        Vec::new()
147    }
148
149    /// Type variables of the *method* the call refers to (used to decide
150    /// whether a formal still carries the callee's own typevars).
151    fn generic_call_mt_typevars(&self, e: &Expr) -> Vec<String> {
152        let _ = e;
153        Vec::new()
154    }
155
156    /// Superclass of `internal` (internal name); `None` at `Object`/unknown.
157    fn super_name(&self, internal: &str) -> Option<String> {
158        let _ = internal;
159        None
160    }
161
162    /// Access flags of the field `internal.name`; `None` when absent.
163    fn field_flags(&self, internal: &str, name: &str) -> Option<crate::types::FieldAccessFlags> {
164        let _ = (internal, name);
165        None
166    }
167
168    /// Access flags of the method `internal.name(desc)`; `None` when absent.
169    fn method_flags(
170        &self,
171        internal: &str,
172        name: &str,
173        desc: &str,
174    ) -> Option<crate::types::MethodAccessFlags> {
175        let _ = (internal, name, desc);
176        None
177    }
178
179    /// True when `internal` declares any field named `name`.
180    fn declares_field(&self, internal: &str, name: &str) -> bool {
181        self.field_flags(internal, name).is_some()
182    }
183
184    /// True when `internal` declares a method named `name` (any descriptor).
185    fn declares_method_named(&self, internal: &str, name: &str) -> bool {
186        let _ = (internal, name);
187        false
188    }
189
190    /// True when `internal` is an interface.
191    fn is_interface(&self, internal: &str) -> bool;
192
193    /// True when `internal` is sealed (its permitted subclasses are recorded).
194    fn is_sealed(&self, internal: &str) -> bool;
195
196    /// True when the container holds this class at all (naming probes use
197    /// it to test `Outer$1Local`-style candidates).
198    fn has_class(&self, internal: &str) -> bool;
199
200    /// Interfaces and superclass of `internal` (internal names, declaration
201    /// order). `None` when the class is unknown to the front-end.
202    fn class_bases(&self, internal: &str) -> Option<(Vec<String>, Option<String>)>;
203
204    /// True when `internal` is an inner class whose constructor forwards its
205    /// enclosing instance straight to `super` (javac 21+ drops `this$0` in
206    /// that case, but call sites still need the qualified-new form).
207    fn outer_param_via_super(&self, internal: &str) -> bool;
208
209    /// Decompile the nested method a lambda site refers to — a lambda body,
210    /// an anonymous-class method, or a local-class method — and run the
211    /// front-end's own idiom recovery on it.
212    ///
213    /// This is where machine-specific desugaring lives: the shared emitter
214    /// asks for a finished statement tree and prints it. The `LambdaExpr`
215    /// carries the call-site facts (impl owner/name/descriptor, the SAM's
216    /// parameter names, the capture expressions, and any front-end
217    /// annotations it attached, e.g. capture snapshots); `outer_vt` is the
218    /// enclosing method's variable table — the lexical scope the body will be
219    /// printed in.
220    fn nested_method(
221        &self,
222        l: &crate::ir::expr::LambdaExpr,
223        outer_vt: &crate::var::VarTable,
224    ) -> Option<MethodBody>;
225
226    /// Parameter types of the `<init>` of `internal` matching `skip + n`
227    /// descriptor args, with `skip` leading synthetic parameters removed.
228    /// Used to print `new` arguments with boolean/char constant adjustment.
229    fn ctor_param_types(
230        &self,
231        internal: &str,
232        skip: usize,
233        n: usize,
234        args: &[Expr],
235    ) -> Option<Vec<crate::types::JavaType>> {
236        let _ = (internal, skip, n, args);
237        None
238    }
239
240    /// Instantiated SAM return of a functional interface's method, resolved
241    /// against a cast's type arguments (`(Function<I,R>) lambda` needs
242    /// `(R) value` witnesses on the impl body's returns).
243    fn sam_ret_cast(
244        &self,
245        g: &crate::types::GenericType,
246        sam_name: &str,
247    ) -> Option<TypeRef> {
248        let _ = (g, sam_name);
249        None
250    }
251
252    /// True when `internal` declares class-level type parameters (so
253    /// `new internal<>(...)` should carry a diamond).
254    fn class_declares_generics(&self, internal: &str) -> bool {
255        !self.class_type_params(internal).is_empty()
256    }
257
258}
259
260/// A `Ctx` with no metadata: every query answers "unknown".
261///
262/// Useful for tests and for front-ends that have not implemented a query yet —
263/// the core degrades gracefully (no nesting assumptions, no generic casts).
264pub struct NullCtx {
265    pub class_name: String,
266    pub level: u16,
267}
268
269impl Default for NullCtx {
270    fn default() -> Self {
271        NullCtx { class_name: String::new(), level: 52 }
272    }
273}
274
275impl Ctx for NullCtx {
276    fn class_name(&self) -> &str {
277        &self.class_name
278    }
279    fn source_level(&self) -> u16 {
280        self.level
281    }
282    fn find_outer(&self, _internal: &str) -> Option<String> {
283        None
284    }
285    fn family(&self, root: &str) -> Family {
286        Family { root: root.to_string(), ..Default::default() }
287    }
288    fn nested_is_static(&self, _internal: &str) -> bool {
289        true
290    }
291    fn class_has_this0(&self, _internal: &str) -> bool {
292        false
293    }
294    fn is_subtype_of(&self, _sub: &crate::types::JavaType, _sup: &str) -> bool {
295        false
296    }
297    fn class_supers_args(
298        &self,
299        _internal: &str,
300        _args: &[crate::types::GenericType],
301    ) -> Vec<(String, Vec<crate::types::GenericType>)> {
302        Vec::new()
303    }
304    fn is_generic_call(&self, _e: &Expr) -> bool {
305        false
306    }
307    fn generic_call_formals(
308        &self,
309        _e: &Expr,
310    ) -> Option<(Vec<crate::types::GenericType>, Vec<String>)> {
311        None
312    }
313    fn polymorphic_ret_cast(&self, _cls: &str, _name: &str, _desc: &MethodDescriptor) -> Option<crate::types::JavaType> {
314        None
315    }
316    fn ctor_formals_by_arity(
317        &self,
318        _internal: &str,
319        _arity: usize,
320    ) -> Option<Vec<crate::types::GenericType>> {
321        None
322    }
323    fn is_interface(&self, _internal: &str) -> bool {
324        false
325    }
326    fn is_sealed(&self, _internal: &str) -> bool {
327        false
328    }
329    fn has_class(&self, _internal: &str) -> bool {
330        false
331    }
332    fn class_bases(&self, _internal: &str) -> Option<(Vec<String>, Option<String>)> {
333        None
334    }
335    fn outer_param_via_super(&self, _internal: &str) -> bool {
336        false
337    }
338    fn nested_method(
339        &self,
340        _l: &crate::ir::expr::LambdaExpr,
341        _outer_vt: &crate::var::VarTable,
342    ) -> Option<MethodBody> {
343        None
344    }
345}
346
347/// Assemble a [`MethodBody`] (front-ends return these from `Ctx::nested_method`).
348pub fn ctx_method_body(
349    body: crate::ir::stmt::Stmt,
350    vt: crate::var::VarTable,
351    desc: MethodDescriptor,
352) -> MethodBody {
353    MethodBody { body, vt, desc }
354}