A 'this' escape occurs in the following scenario:
A
and some subclass B
that extends it
A
defines an instance method m()
which is overridden in B
B()
invokes some superclass constructor A()
A()
, method m()
is invoked and the
reciever for the instance method is the new instance being constructed by B()
B.m()
will execute before the constructor
B()
has performed any of its own initialization.
This class attempts to identify possible 'this' escapes while also striking a balance between false positives, false negatives, and code complexity. We do this by "executing" the code in candidate constructors and tracking where the original 'this' reference goes. If it passes to code outside of the current module, we declare a possible leak.
As we analyze constructors and the methods they invoke, we track the various object references that
might reference the 'this' instance we are watching (i.e., the one under construction). Such object
references are represented by the Ref
class hierarchy, which models the various ways in which,
at any point during the execution of a constructor or some other method or constructor that it invokes,
there can live references to the object under construction lying around. In a nutshell, the analyzer
keeps track of these references and watches what happens to them as the code executes so it can catch
them in the act of trying to "escape".
The Ref
sub-types are:
ThisRef
- The current 'this' instance of the (instance) method being analyzed
ExprRef
- The current expression being evaluated, i.e., what's on top of the Java stack
VarRef
- Local variables and method parameters currently in scope
YieldRef
- The current switch expression's yield value(s)
ReturnRef
- The current method's return value(s)
Currently we don't attempt to explicitly track references stored in fields (for future study).
For each object reference represented by a Ref
, we track up to three distinct ways in which
it might refer to the new 'this' instance: the reference can be direct, indirect, or via an associated
enclosing instance (see Indirection
).
A few notes on this implementation:
Ref
's evolve as the constructor executes.
Ref
's that are generated.
Ref
's stabilizes; the maximum number of iterations
possible is proportional to the number of variables in scope.
super()
invocations; that's for the superclass analysis to handle.
Modifier and Type | Class and Description |
---|---|
private static class | ThisEscapeAnalyzer.
A reference originating from the expression that was just evaluated. |
pack-priv static enum | ThisEscapeAnalyzer.
Describes how the 'this' we care about is referenced by a |
private static record | |
private abstract static class | ThisEscapeAnalyzer.
Represents an object reference that could refer to the 'this' we care about. |
private static class | ThisEscapeAnalyzer.
Contains locations currently known to hold a possible 'this' reference. |
private static class | ThisEscapeAnalyzer.
A reference from the return value of the current method being "invoked". |
private static class | ThisEscapeAnalyzer.
A reference originating from the current 'this' instance. |
private static class | ThisEscapeAnalyzer.
A reference from a variable. |
private static class | ThisEscapeAnalyzer.
A reference from the yield value of the current switch expression. |
Modifier and Type | Field and Description |
---|---|
private Env | attrEnv
Environment for symbol lookup. |
private final ArrayDeque | callStack
The current "call stack" during our analysis. |
private int | depth
Current lexical scope depth in the constructor or method we're currently analyzing. |
private final Set | invocations
Used to terminate recursion in |
private Lint | |
private final Log | |
private JCTree. | methodClass
The declaring class of the "invoked" method we're currently analyzing. |
private final Map | methodMap
Maps symbols of all methods to their corresponding declarations. |
private final Names | |
private final Set | nonPublicOuters
Contains classes whose outer instance (if any) is non-public. |
private JCDiagnostic. | pendingWarning
Snapshot of |
private ThisEscapeAnalyzer. | refs
Possible 'this' references in the constructor or method we're currently analyzing. |
private final Resolve | |
private final Set | suppressed
Contains symbols of fields and constructors that have warnings suppressed. |
private final Symtab | |
private JCTree. | targetClass
The declaring class of the constructor we're currently analyzing. |
private final Types | |
private final ArrayList | warningList
Snapshots of |
Access | Constructor and Description |
---|---|
pack-priv |
Modifier and Type | Method and Description |
---|---|
private void | |
public void | |
private boolean | |
private boolean | |
private boolean | |
private void | invoke(JCTree site, Symbol sym, List<JCTree.
|
private void | invokeInvokable(JCTree site, List<JCTree.
|
private void | invokeUnknown(JCTree invoke, List<JCTree.
|
private boolean | |
private boolean | isExplicitOuterThisReference(Types types, Type.
Check if the given tree is an explicit reference to the outer 'this' instance of the class currently being compiled. |
private boolean | |
private boolean | |
private void | |
private void | |
private void | |
private ThisEscapeAnalyzer. | |
public void | scan(JCTree tree)
Overrides com. Visitor method: Scan a single node. |
private boolean | |
public void | |
public void | |
public void | visitApply(JCTree.
Overrides com.
|
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
private <T extends JCTree> void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
private <T extends JCTree> void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
private void | |
public void | |
public void | |
public void | |
public void | |
public void | |
private void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
public void | |
private void | |
public void | |
public void | |
public void |