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

pack-priv Class ThisEscapeAnalyzer

extends TreeScanner
Class Inheritance
Imports
java.util.ArrayDeque, .ArrayList, .Comparator, .LinkedHashMap, .EnumSet, .HashSet, .Map.Entry, .Map, .Objects, .Optional, .Set, java.util.concurrent.atomic.AtomicBoolean, java.util.function.BiPredicate, .Consumer, .Function, .Predicate, java.util.stream.Collector, .Collectors, .Stream, com.sun.tools.javac.code.Directive, .Flags, .Lint, .Symbol, com.sun.tools.javac.code.Symbol.*, .Symtab, .Type, .Types, com.sun.tools.javac.resources.CompilerProperties.Warnings, com.sun.tools.javac.tree.JCTree, com.sun.tools.javac.tree.JCTree.*, .TreeInfo, .TreeScanner, com.sun.tools.javac.util.Assert, .JCDiagnostic, .JCDiagnostic.DiagnosticPosition, .List, .Log, .Name, .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:

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 static class
ThisEscapeAnalyzer.ThisRef

A reference originating from the current 'this' instance.

private static class
ThisEscapeAnalyzer.VarRef

A reference from a variable.

private static class
ThisEscapeAnalyzer.YieldRef

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

Field Summary

Modifier and TypeField and Description
private Env<AttrContext>
attrEnv

Environment for symbol lookup.

private final ArrayDeque<JCDiagnostic.DiagnosticPosition>
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<Pair<JCTree.JCMethodDecl, ThisEscapeAnalyzer.RefSet<ThisEscapeAnalyzer.Ref>>>
invocations

Used to terminate recursion in invokeInvokable().

private Lint
private final Log
private JCTree.JCClassDecl
methodClass

The declaring class of the "invoked" method we're currently analyzing.

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 JCDiagnostic.DiagnosticPosition[]
pendingWarning

Snapshot of callStack where a possible 'this' escape occurs.

private ThisEscapeAnalyzer.RefSet<ThisEscapeAnalyzer.Ref>
refs

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

private final Resolve
private final Set<Symbol>
suppressed

Contains symbols of fields and constructors that have warnings suppressed.

private final Symtab
private JCTree.JCClassDecl
targetClass

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

private final Types
private final ArrayList<JCDiagnostic.DiagnosticPosition[]>
warningList

Snapshots of callStack where possible 'this' escapes occur.

Constructor Summary

AccessConstructor and Description
pack-priv
ThisEscapeAnalyzer(Names names, Symtab syms, Types types, Resolve rs, Log log, Lint lint)

Method Summary

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

private boolean
private boolean
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
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
Inherited from com.sun.tools.javac.tree.TreeScanner:
scanvisitAnyPatternvisitBindingPatternvisitBreakvisitCatchvisitContinuevisitDefaultCaseLabelvisitErroneousvisitExportsvisitImportvisitLabelledvisitLiteralvisitModuleDefvisitModuleImportvisitOpensvisitPackageDefvisitParensvisitProvidesvisitRequiresvisitSkipvisitTopLevelvisitTreevisitTryvisitTypeIdentvisitUses