Skip to content

Commit

Permalink
Allow DataFlow to work on initializers (inline field initializers or
Browse files Browse the repository at this point in the history
initializer blocks).

RELNOTES: It's now valid to call DataFlow.expressionDataflow() on an
expression inside an initializer (inline field initializer or
initializer block). Previously, dataflow didn't run and null was
returned for expressions in initializers.

MOE_MIGRATED_REVID=163772811
  • Loading branch information
xgnehz authored and cushon committed Aug 10, 2017
1 parent a8123cc commit e4a1fe4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
Expand Up @@ -22,11 +22,14 @@
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.common.util.concurrent.UncheckedExecutionException;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LambdaExpressionTree; import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.MethodTree; import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree; import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath; import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.processing.JavacProcessingEnvironment;
Expand Down Expand Up @@ -95,9 +98,12 @@ public ControlFlowGraph load(CfgParams key) {
final UnderlyingAST ast; final UnderlyingAST ast;
if (methodPath.getLeaf() instanceof LambdaExpressionTree) { if (methodPath.getLeaf() instanceof LambdaExpressionTree) {
ast = new UnderlyingAST.CFGLambda((LambdaExpressionTree) methodPath.getLeaf()); ast = new UnderlyingAST.CFGLambda((LambdaExpressionTree) methodPath.getLeaf());
} else { // must be a method per findEnclosingMethodOrLambda } else if (methodPath.getLeaf() instanceof MethodTree) {
MethodTree method = (MethodTree) methodPath.getLeaf(); MethodTree method = (MethodTree) methodPath.getLeaf();
ast = new UnderlyingAST.CFGMethod(method, /*classTree*/ null); ast = new UnderlyingAST.CFGMethod(method, /*classTree*/ null);
} else {
// must be an initializer per findEnclosingMethodOrLambdaOrInitializer
ast = new UnderlyingAST.CFGStatement(methodPath.getLeaf());
} }
final ProcessingEnvironment env = key.environment(); final ProcessingEnvironment env = key.environment();


Expand All @@ -109,12 +115,24 @@ public ControlFlowGraph load(CfgParams key) {
}); });


// TODO(user), remove once we merge jdk8 specific's with core // TODO(user), remove once we merge jdk8 specific's with core
private static <T> TreePath findEnclosingMethodOrLambda(TreePath path) { private static <T> TreePath findEnclosingMethodOrLambdaOrInitializer(TreePath path) {
while (path != null) { while (path != null) {
if (path.getLeaf() instanceof MethodTree || path.getLeaf() instanceof LambdaExpressionTree) { if (path.getLeaf() instanceof MethodTree || path.getLeaf() instanceof LambdaExpressionTree) {
return path; return path;
} }
path = path.getParentPath(); TreePath parent = path.getParentPath();
if (parent != null && parent.getLeaf() instanceof ClassTree) {
if (path.getLeaf() instanceof BlockTree) {
// this is a class or instance initializer block
return path;
}
if (path.getLeaf() instanceof VariableTree
&& ((VariableTree) path.getLeaf()).getInitializer() != null) {
// this is a field with an inline initializer
return path;
}
}
path = parent;
} }
return null; return null;
} }
Expand Down Expand Up @@ -156,11 +174,18 @@ public ControlFlowGraph getControlFlowGraph() {
} }


/** /**
* Run the {@code transfer} dataflow analysis to compute the abstract value of the expression * Runs the {@code transfer} dataflow analysis to compute the abstract value of the expression
* which is the leaf of {@code exprPath}. * which is the leaf of {@code exprPath}.
* *
* <p>The expression must be part of a method, lambda, or initializer (inline field initializer or
* initializer block). Example of an expression outside of such constructs is the identifier in an
* import statement.
*
* <p>Note that for intializers, each inline field initializer or initializer block is treated
* separately. I.e., we don't merge all initializers into one virtual block for dataflow.
*
* @return dataflow result for the given expression or {@code null} if the expression is not part * @return dataflow result for the given expression or {@code null} if the expression is not part
* of a method or lambda * of a method, lambda or initializer
*/ */
@Nullable @Nullable
public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
Expand All @@ -172,10 +197,9 @@ A expressionDataflow(TreePath exprPath, Context context, T transfer) {
leaf.getClass().getName()); leaf.getClass().getName());


final ExpressionTree expr = (ExpressionTree) leaf; final ExpressionTree expr = (ExpressionTree) leaf;
final TreePath enclosingMethodPath = findEnclosingMethodOrLambda(exprPath); final TreePath enclosingMethodPath = findEnclosingMethodOrLambdaOrInitializer(exprPath);
if (enclosingMethodPath == null) { if (enclosingMethodPath == null) {
// TODO(user) this can happen in field initialization. // expression is not part of a method, lambda, or initializer
// Currently not supported because it only happens in ~2% of cases.
return null; return null;
} }


Expand Down
Expand Up @@ -56,6 +56,7 @@
import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
Expand Down Expand Up @@ -602,6 +603,9 @@ private static Symbol tryGetSymbol(Tree tree) {
if (tree instanceof JCFieldAccess) { if (tree instanceof JCFieldAccess) {
return ((JCFieldAccess) tree).sym; return ((JCFieldAccess) tree).sym;
} }
if (tree instanceof JCVariableDecl) {
return ((JCVariableDecl) tree).sym;
}
return null; return null;
} }


Expand Down

0 comments on commit e4a1fe4

Please sign in to comment.