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::expr::TypeRef;
16use crate::ir::stmt::Stmt;
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 front-end's render-time import map: when a referenced
84    /// internal name is OBSCURED in the current compilation unit (its
85    /// qualified form's first segment binds to an in-scope class name
86    /// — JLS 6.4.2), the front-end emits a single-type import for it
87    /// and the render must use the SIMPLE name. Returns the simple
88    /// name when so; `None` renders normally. Default None (no import
89    /// machinery).
90    /// 静态成员引用的遮蔽逃逸:owner 点分渲染的首段被作用域内的
91    /// 名字(字段/继承成员)遮蔽、且类型导入的简单名同样会被捕获时,
92    /// 成员引用改走**单静态导入**(渲染为裸成员名,前端记录
93    /// `import static owner.member;`)。JLS 6.4.2:表达式名解析优先
94    /// 绑定变量——`d.j.v` 的 d 绑定到继承字段 d 后成员链断裂
95    /// (找不到符号 变量 j)。默认 false(无该机制的前端)。
96    fn obscured_member_escape(&self, _owner: &str, _member: &str) -> bool {
97        false
98    }
99
100    fn obscured_simple(&self, _internal: &str) -> Option<String> {
101        None
102    }
103
104    /// Identity of the backing container (pool), for caches keyed on
105    /// pool-dependent pure queries (`Printer::shorten` memoization).
106    /// Default 0 is safe only for single-pool processes; multi-pool
107    /// front-ends (ddc/jcdc) override with the pool pointer so a second
108    /// pool never reads the first pool's cached shortenings.
109    fn pool_id(&self) -> u64 {
110        0
111    }
112
113    /// The class that `internal` is nested in, when the container records the
114    /// nesting (JVM `InnerClasses`/`NestHost`; DEX inner-class annotations).
115    /// `None` for a top-level class — including literal-`$` names that only
116    /// *look* nested.
117    fn find_outer(&self, internal: &str) -> Option<String>;
118
119    /// Nested-class family of `root`, as far as the container records it.
120    fn family(&self, root: &str) -> Family;
121
122    /// True when a nested class is static (`Outer$Inner` with ACC_STATIC), so
123    /// it is not constructed with an enclosing instance.
124    fn nested_is_static(&self, internal: &str) -> bool;
125
126    /// True when the class carries a synthetic `this$0` field (an inner class
127    /// with an enclosing instance parameter).
128    fn class_has_this0(&self, internal: &str) -> bool;
129
130    /// True when `sub` is assignable to `sup` (both internal names).
131    fn is_subtype_of(&self, sub: &crate::types::JavaType, sup: &str) -> bool;
132
133    /// Superclasses/interfaces of `internal` with the given type arguments
134    /// applied: `[(java/lang/Object, []), ...]`, most-derived first.
135    fn class_supers_args(
136        &self,
137        internal: &str,
138        args: &[crate::types::GenericType],
139    ) -> Vec<(String, Vec<crate::types::GenericType>)>;
140
141    /// True when the call carries inferred type arguments that the source
142    /// must spell out.
143    fn is_generic_call(&self, e: &Expr) -> bool;
144
145    /// Instantiated formal parameter types of a generic call plus the callee's
146    /// own method type variables (for witness casts). `None` when the call has
147    /// no inferred type arguments to spell out.
148    fn generic_call_formals(
149        &self,
150        e: &Expr,
151    ) -> Option<(Vec<crate::types::GenericType>, Vec<String>)>;
152
153    /// The instantiated return type of a call whose methodref owner redeclares
154    /// the method with a self-covariant return (Stream over BaseStream).
155    fn polymorphic_ret_cast(
156        &self,
157        cls: &str,
158        name: &str,
159        desc: &MethodDescriptor,
160    ) -> Option<crate::types::JavaType>;
161
162    /// Constructor parameter types of `internal` matching `arity`, for
163    /// rendering `new` arguments against the right overload.
164    fn ctor_formals_by_arity(
165        &self,
166        internal: &str,
167        arity: usize,
168    ) -> Option<Vec<crate::types::GenericType>>;
169
170    /// Local-class name recorded for a `$`-style synthetic marker, when the
171    /// container records one (`Outer$1Local` -> `Local`).
172    fn local_class_internal(&self, simple: &str) -> Option<String> {
173        let _ = simple;
174        None
175    }
176
177    /// Generic type parameters declared by `internal` (from its class
178    /// signature); empty when the container records none.
179    fn class_type_params(&self, internal: &str) -> Vec<crate::types::TypeParam> {
180        let _ = internal;
181        Vec::new()
182    }
183
184    /// Type variables of the *method* the call refers to (used to decide
185    /// whether a formal still carries the callee's own typevars).
186    fn generic_call_mt_typevars(&self, e: &Expr) -> Vec<String> {
187        let _ = e;
188        Vec::new()
189    }
190
191    /// Superclass of `internal` (internal name); `None` at `Object`/unknown.
192    fn super_name(&self, internal: &str) -> Option<String> {
193        let _ = internal;
194        None
195    }
196
197    /// Access flags of the field `internal.name`; `None` when absent.
198    fn field_flags(&self, internal: &str, name: &str) -> Option<crate::types::FieldAccessFlags> {
199        let _ = (internal, name);
200        None
201    }
202
203    /// Access flags of the method `internal.name(desc)`; `None` when absent.
204    fn method_flags(
205        &self,
206        internal: &str,
207        name: &str,
208        desc: &str,
209    ) -> Option<crate::types::MethodAccessFlags> {
210        let _ = (internal, name, desc);
211        None
212    }
213
214    /// True when `internal` declares any field named `name`.
215    fn declares_field(&self, internal: &str, name: &str) -> bool {
216        self.field_flags(internal, name).is_some()
217    }
218
219    /// True when `internal` declares any field whose RENDERED display
220    /// equals `display` (the registry's rename applied; the raw name
221    /// when no entry exists). Field references carry the DISPLAY name
222    /// at emit time, so shadow checks must compare in display space —
223    /// a raw-named field can render exactly the name another class's
224    /// field displays.
225    fn declares_field_display(&self, internal: &str, display: &str) -> bool {
226        let _ = (internal, display);
227        false
228    }
229
230    /// True when `internal` declares a method named `name` (any descriptor).
231    fn declares_method_named(&self, internal: &str, name: &str) -> bool {
232        let _ = (internal, name);
233        false
234    }
235
236    /// True when `internal` is a framework-shadow stub class (the
237    /// front-end relocates its FILE identity; references render the raw
238    /// framework FQN — the platform class is what the bytecode means).
239    fn is_fw_shadow(&self, internal: &str) -> bool {
240        let _ = internal;
241        false
242    }
243
244    /// True when `internal` is an interface.
245    fn is_interface(&self, internal: &str) -> bool;
246
247    /// True when `internal` is sealed (its permitted subclasses are recorded).
248    fn is_sealed(&self, internal: &str) -> bool;
249
250    /// True when the container holds this class at all (naming probes use
251    /// it to test `Outer$1Local`-style candidates).
252    fn has_class(&self, internal: &str) -> bool;
253
254    /// Interfaces and superclass of `internal` (internal names, declaration
255    /// order). `None` when the class is unknown to the front-end.
256    fn class_bases(&self, internal: &str) -> Option<(Vec<String>, Option<String>)>;
257
258    /// True when `internal` is an inner class whose constructor forwards its
259    /// enclosing instance straight to `super` (javac 21+ drops `this$0` in
260    /// that case, but call sites still need the qualified-new form).
261    fn outer_param_via_super(&self, internal: &str) -> bool;
262
263    /// Decompile the nested method a lambda site refers to — a lambda body,
264    /// an anonymous-class method, or a local-class method — and run the
265    /// front-end's own idiom recovery on it.
266    ///
267    /// This is where machine-specific desugaring lives: the shared emitter
268    /// asks for a finished statement tree and prints it. The `LambdaExpr`
269    /// carries the call-site facts (impl owner/name/descriptor, the SAM's
270    /// parameter names, the capture expressions, and any front-end
271    /// annotations it attached, e.g. capture snapshots); `outer_vt` is the
272    /// enclosing method's variable table — the lexical scope the body will be
273    /// printed in.
274    fn nested_method(
275        &self,
276        l: &crate::ir::expr::LambdaExpr,
277        outer_vt: &crate::var::VarTable,
278    ) -> Option<MethodBody>;
279
280    /// Parameter types of the `<init>` of `internal` matching `skip + n`
281    /// descriptor args, with `skip` leading synthetic parameters removed.
282    /// Used to print `new` arguments with boolean/char constant adjustment.
283    fn ctor_param_types(
284        &self,
285        internal: &str,
286        skip: usize,
287        n: usize,
288        args: &[Expr],
289    ) -> Option<Vec<crate::types::JavaType>> {
290        let _ = (internal, skip, n, args);
291        None
292    }
293
294    /// Instantiated SAM return of a functional interface's method, resolved
295    /// against a cast's type arguments (`(Function<I,R>) lambda` needs
296    /// `(R) value` witnesses on the impl body's returns).
297    fn sam_ret_cast(&self, g: &crate::types::GenericType, sam_name: &str) -> Option<TypeRef> {
298        let _ = (g, sam_name);
299        None
300    }
301
302    /// True when `internal` declares class-level type parameters (so
303    /// `new internal<>(...)` should carry a diamond).
304    fn class_declares_generics(&self, internal: &str) -> bool {
305        !self.class_type_params(internal).is_empty()
306    }
307}
308
309/// A `Ctx` with no metadata: every query answers "unknown".
310///
311/// Useful for tests and for front-ends that have not implemented a query yet —
312/// the core degrades gracefully (no nesting assumptions, no generic casts).
313pub struct NullCtx {
314    pub class_name: String,
315    pub level: u16,
316}
317
318impl Default for NullCtx {
319    fn default() -> Self {
320        NullCtx {
321            class_name: String::new(),
322            level: 52,
323        }
324    }
325}
326
327impl Ctx for NullCtx {
328    fn class_name(&self) -> &str {
329        &self.class_name
330    }
331    fn source_level(&self) -> u16 {
332        self.level
333    }
334    fn find_outer(&self, _internal: &str) -> Option<String> {
335        None
336    }
337    fn family(&self, root: &str) -> Family {
338        Family {
339            root: root.to_string(),
340            ..Default::default()
341        }
342    }
343    fn nested_is_static(&self, _internal: &str) -> bool {
344        true
345    }
346    fn class_has_this0(&self, _internal: &str) -> bool {
347        false
348    }
349    fn is_subtype_of(&self, _sub: &crate::types::JavaType, _sup: &str) -> bool {
350        false
351    }
352    fn class_supers_args(
353        &self,
354        _internal: &str,
355        _args: &[crate::types::GenericType],
356    ) -> Vec<(String, Vec<crate::types::GenericType>)> {
357        Vec::new()
358    }
359    fn is_generic_call(&self, _e: &Expr) -> bool {
360        false
361    }
362    fn generic_call_formals(
363        &self,
364        _e: &Expr,
365    ) -> Option<(Vec<crate::types::GenericType>, Vec<String>)> {
366        None
367    }
368    fn polymorphic_ret_cast(
369        &self,
370        _cls: &str,
371        _name: &str,
372        _desc: &MethodDescriptor,
373    ) -> Option<crate::types::JavaType> {
374        None
375    }
376    fn ctor_formals_by_arity(
377        &self,
378        _internal: &str,
379        _arity: usize,
380    ) -> Option<Vec<crate::types::GenericType>> {
381        None
382    }
383    fn is_interface(&self, _internal: &str) -> bool {
384        false
385    }
386    fn is_sealed(&self, _internal: &str) -> bool {
387        false
388    }
389    fn has_class(&self, _internal: &str) -> bool {
390        false
391    }
392    fn class_bases(&self, _internal: &str) -> Option<(Vec<String>, Option<String>)> {
393        None
394    }
395    fn outer_param_via_super(&self, _internal: &str) -> bool {
396        false
397    }
398    fn nested_method(
399        &self,
400        _l: &crate::ir::expr::LambdaExpr,
401        _outer_vt: &crate::var::VarTable,
402    ) -> Option<MethodBody> {
403        None
404    }
405}
406
407/// Assemble a [`MethodBody`] (front-ends return these from `Ctx::nested_method`).
408pub fn ctx_method_body(
409    body: crate::ir::stmt::Stmt,
410    vt: crate::var::VarTable,
411    desc: MethodDescriptor,
412) -> MethodBody {
413    MethodBody { body, vt, desc }
414}