APIdia Launch Partner
Top Description Inners Fields Constructors Methods
com.sun.tools.javac.comp

public Class ThisEscapeAnalyzer

extends TreeScanner
Class Inheritance
Imports
java.util.ArrayList, .LinkedHashMap, .EnumSet, .HashSet, .Map, .Objects, .Optional, .Set, java.util.concurrent.atomic.AtomicReference, java.util.function.Consumer, .Function, .Predicate, java.util.stream.Collector, .Collectors, .IntStream, .Stream, com.sun.tools.javac.code.Directive, .Flags, .Lint, .LintMapper, .Symbol, com.sun.tools.javac.code.Symbol.*, .Symtab, .Type, .Types, com.sun.tools.javac.resources.CompilerProperties.LintWarnings, com.sun.tools.javac.tree.JCTree, com.sun.tools.javac.tree.JCTree.*, .TreeInfo, .TreeScanner, com.sun.tools.javac.util.Assert, .Context, .JCDiagnostic.DiagnosticPosition, .JCDiagnostic.LintWarning, .List, .Log, .Names, .Pair

Looks for possible 'this' escapes and generates corresponding warnings.

A 'this' escape occurs in the following scenario:

This represents a problem because the method 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:

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:

This is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This code and its internal interfaces are subject to change or deletion without notice.

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static class
ThisEscapeAnalyzer.ExprRef

A reference originating from the expression that was just evaluated.

pack-priv static enum
ThisEscapeAnalyzer.Indirection

Describes how the 'this' we care about is referenced by a Ref that is being tracked.

private static record
private abstract static class
ThisEscapeAnalyzer.Ref

Represents an object reference that could refer to the 'this' we care about.

private static class
ThisEscapeAnalyzer.RefSet<T extends ThisEscapeAnalyzer.Ref>

Contains locations currently known to hold a possible 'this' reference.

private static class
ThisEscapeAnalyzer.ReturnRef

A reference from the return value of the current method being "invoked".

private class
private static class
ThisEscapeAnalyzer.ThisRef

A reference originating from the current 'this' instance.

private static class
ThisEscapeAnalyzer.VarRef

A reference from a variable.

private class
private static class
ThisEscapeAnalyzer.YieldRef

A reference from the yield value of the current switch expression.

Field Summary

Modifier and TypeField and Description
private final ArrayList<ThisEscapeAnalyzer.StackFrame>
callStack

The current "call stack" during our analysis.

protected static final Context.Key<ThisEscapeAnalyzer>
private ThisEscapeAnalyzer.MethodInfo
currentMethod

The method we're currently analyzing.

private int
depth

Current lexical scope depth in the constructor or method we're currently analyzing.

private final Set<Pair<JCTree.JCMethodDecl, ThisEscapeAnalyzer.RefSet<ThisEscapeAnalyzer.Ref>>>
invocations

Used to terminate recursion in invokeInvokable().

private final LintMapper
private final Log
private final Map<Symbol, ThisEscapeAnalyzer.MethodInfo>
methodMap

Maps symbols of all methods to their corresponding declarations.

private final Names
private final Set<Symbol.ClassSymbol>
nonPublicOuters

Contains classes whose outer instance (if any) is non-public.

private ThisEscapeAnalyzer.RefSet<ThisEscapeAnalyzer.Ref>
refs

Possible 'this' references in the constructor or method we're currently analyzing.

private final Resolve
private final Symtab
private JCTree.JCClassDecl
targetClass

The declaring class of the constructor we're currently analyzing.

private Env<AttrContext>
topLevelEnv

Environment for symbol lookup.

private final Types
private final ArrayList<ThisEscapeAnalyzer.Warning>
warningList

Snapshots of callStack where possible 'this' escapes occur.

Constructor Summary

AccessConstructor and Description
protected

Method Summary

Modifier and TypeMethod and Description
private void
private void
public void
private boolean
checkInvariants(boolean analyzing, boolean allowExpr)

private void
private void
private boolean
public static ThisEscapeAnalyzer
instance(Context context)

private void
private void
private void
private boolean
private boolean
isExplicitOuterThisReference(Types types, Type.ClassType currentClass, JCTree.JCFieldAccess select)

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
leakAt(JCTree tree)

private void
private void
private ThisEscapeAnalyzer.RefSet<ThisEscapeAnalyzer.ThisRef>
public void
scan(JCTree tree)

Overrides com.sun.tools.javac.tree.TreeScanner.scan.

Visitor method: Scan a single node.

private boolean
public void
public void
public void
public void
public void
public void
public void
public void
public void
public void
public void
public void
private <T extends JCTree> void
visitDeferred(Runnable deferredCode)

public void
public void
public void
public void
public void
public void
public void
public void
public void
private <T extends JCTree> void
visitLooped(T tree, Consumer<T> visitor)

public void
public void
public void
public void
public void
public void
public void
public void
private void
visitScoped(boolean promote, Runnable action)

public void
public void
public void
public void
public 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
Inherited from com.sun.tools.javac.tree.TreeScanner:
scanvisitAnyPatternvisitBindingPatternvisitBreakvisitCatchvisitContinuevisitDefaultCaseLabelvisitErroneousvisitExportsvisitImportvisitLabelledvisitLiteralvisitModuleDefvisitModuleImportvisitOpensvisitPackageDefvisitParensvisitProvidesvisitRequiresvisitSkipvisitTopLevelvisitTreevisitTryvisitTypeIdentvisitUsesvisitVarType