aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java')
-rw-r--r--third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java628
1 files changed, 372 insertions, 256 deletions
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
index a3ae88fa31..4da97b400d 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
@@ -4,25 +4,13 @@ package org.checkerframework.javacutil;
import org.checkerframework.checker.nullness.qual.*;
*/
-import java.util.EnumSet;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementFilter;
-
import com.sun.source.tree.AnnotatedTypeTree;
import com.sun.source.tree.ArrayAccessTree;
-import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompoundAssignmentTree;
+import com.sun.source.tree.ConditionalExpressionTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
@@ -30,14 +18,13 @@ import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.ParenthesizedTree;
import com.sun.source.tree.PrimitiveTypeTree;
-import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
@@ -45,21 +32,34 @@ import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.tree.JCTree;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.util.ElementFilter;
-/**
- * A utility class made for helping to analyze a given {@code Tree}.
- */
+/** A utility class made for helping to analyze a given {@code Tree}. */
// TODO: This class needs significant restructuring
public final class TreeUtils {
// Class cannot be instantiated.
- private TreeUtils() { throw new AssertionError("Class TreeUtils cannot be instantiated."); }
+ private TreeUtils() {
+ throw new AssertionError("Class TreeUtils cannot be instantiated.");
+ }
/**
* Checks if the provided method is a constructor method or no.
*
- * @param tree
- * a tree defining the method
+ * @param tree a tree defining the method
* @return true iff tree describes a constructor
*/
public static boolean isConstructor(final MethodTree tree) {
@@ -69,39 +69,50 @@ public final class TreeUtils {
/**
* Checks if the method invocation is a call to super.
*
- * @param tree
- * a tree defining a method invocation
- *
+ * @param tree a tree defining a method invocation
* @return true iff tree describes a call to super
*/
public static boolean isSuperCall(MethodInvocationTree tree) {
+ return isNamedMethodCall("super", tree);
+ }
+
+ /**
+ * Checks if the method invocation is a call to this.
+ *
+ * @param tree a tree defining a method invocation
+ * @return true iff tree describes a call to this
+ */
+ public static boolean isThisCall(MethodInvocationTree tree) {
+ return isNamedMethodCall("this", tree);
+ }
+
+ protected static boolean isNamedMethodCall(String name, MethodInvocationTree tree) {
/*@Nullable*/ ExpressionTree mst = tree.getMethodSelect();
assert mst != null; /*nninvariant*/
- if (mst.getKind() == Tree.Kind.IDENTIFIER ) {
- return ((IdentifierTree)mst).getName().contentEquals("super");
+ if (mst.getKind() == Tree.Kind.IDENTIFIER) {
+ return ((IdentifierTree) mst).getName().contentEquals(name);
}
if (mst.getKind() == Tree.Kind.MEMBER_SELECT) {
- MemberSelectTree selectTree = (MemberSelectTree)mst;
+ MemberSelectTree selectTree = (MemberSelectTree) mst;
if (selectTree.getExpression().getKind() != Tree.Kind.IDENTIFIER) {
return false;
}
- return ((IdentifierTree) selectTree.getExpression()).getName()
- .contentEquals("super");
+ return ((IdentifierTree) selectTree.getExpression()).getName().contentEquals(name);
}
return false;
}
/**
- * Returns true if the tree is a tree that 'looks like' either an access
- * of a field or an invocation of a method that are owned by the same
- * accessing instance.
+ * Returns true if the tree is a tree that 'looks like' either an access of a field or an
+ * invocation of a method that are owned by the same accessing instance.
+ *
+ * <p>It would only return true if the access tree is of the form:
*
- * It would only return true if the access tree is of the form:
* <pre>
* field
* this.field
@@ -110,35 +121,37 @@ public final class TreeUtils {
* this.method()
* </pre>
*
- * It does not perform any semantical check to differentiate between
- * fields and local variables; local methods or imported static methods.
+ * It does not perform any semantical check to differentiate between fields and local variables;
+ * local methods or imported static methods.
*
- * @param tree expression tree representing an access to object member
+ * @param tree expression tree representing an access to object member
* @return {@code true} iff the member is a member of {@code this} instance
*/
public static boolean isSelfAccess(final ExpressionTree tree) {
ExpressionTree tr = TreeUtils.skipParens(tree);
// If method invocation check the method select
- if (tr.getKind() == Tree.Kind.ARRAY_ACCESS)
+ if (tr.getKind() == Tree.Kind.ARRAY_ACCESS) {
return false;
+ }
if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
- tr = ((MethodInvocationTree)tree).getMethodSelect();
+ tr = ((MethodInvocationTree) tree).getMethodSelect();
}
tr = TreeUtils.skipParens(tr);
- if (tr.getKind() == Tree.Kind.TYPE_CAST)
- tr = ((TypeCastTree)tr).getExpression();
+ if (tr.getKind() == Tree.Kind.TYPE_CAST) {
+ tr = ((TypeCastTree) tr).getExpression();
+ }
tr = TreeUtils.skipParens(tr);
- if (tr.getKind() == Tree.Kind.IDENTIFIER)
+ if (tr.getKind() == Tree.Kind.IDENTIFIER) {
return true;
+ }
if (tr.getKind() == Tree.Kind.MEMBER_SELECT) {
- tr = ((MemberSelectTree)tr).getExpression();
+ tr = ((MemberSelectTree) tr).getExpression();
if (tr.getKind() == Tree.Kind.IDENTIFIER) {
- Name ident = ((IdentifierTree)tr).getName();
- return ident.contentEquals("this") ||
- ident.contentEquals("super");
+ Name ident = ((IdentifierTree) tr).getName();
+ return ident.contentEquals("this") || ident.contentEquals("super");
}
}
@@ -148,8 +161,8 @@ public final class TreeUtils {
/**
* Gets the first enclosing tree in path, of the specified kind.
*
- * @param path the path defining the tree node
- * @param kind the kind of the desired tree
+ * @param path the path defining the tree node
+ * @param kind the kind of the desired tree
* @return the enclosing tree of the given type as given by the path
*/
public static Tree enclosingOfKind(final TreePath path, final Tree.Kind kind) {
@@ -159,8 +172,8 @@ public final class TreeUtils {
/**
* Gets the first enclosing tree in path, with any one of the specified kinds.
*
- * @param path the path defining the tree node
- * @param kinds the set of kinds of the desired tree
+ * @param path the path defining the tree node
+ * @param kinds the set of kinds of the desired tree
* @return the enclosing tree of the given type as given by the path
*/
public static Tree enclosingOfKind(final TreePath path, final Set<Tree.Kind> kinds) {
@@ -169,8 +182,9 @@ public final class TreeUtils {
while (p != null) {
Tree leaf = p.getLeaf();
assert leaf != null; /*nninvariant*/
- if (kinds.contains(leaf.getKind()))
+ if (kinds.contains(leaf.getKind())) {
return leaf;
+ }
p = p.getParentPath();
}
@@ -178,10 +192,10 @@ public final class TreeUtils {
}
/**
- * Gets path to the the first enclosing class tree, where class is
- * defined by the classTreeKinds method.
+ * Gets path to the first enclosing class tree, where class is defined by the classTreeKinds
+ * method.
*
- * @param path the path defining the tree node
+ * @param path the path defining the tree node
* @return the path to the enclosing class tree
*/
public static TreePath pathTillClass(final TreePath path) {
@@ -189,10 +203,10 @@ public final class TreeUtils {
}
/**
- * Gets path to the the first enclosing tree of the specified kind.
+ * Gets path to the first enclosing tree of the specified kind.
*
- * @param path the path defining the tree node
- * @param kind the kind of the desired tree
+ * @param path the path defining the tree node
+ * @param kind the kind of the desired tree
* @return the path to the enclosing tree of the given type
*/
public static TreePath pathTillOfKind(final TreePath path, final Tree.Kind kind) {
@@ -200,10 +214,10 @@ public final class TreeUtils {
}
/**
- * Gets path to the the first enclosing tree with any one of the specified kinds.
+ * Gets path to the first enclosing tree with any one of the specified kinds.
*
- * @param path the path defining the tree node
- * @param kinds the set of kinds of the desired tree
+ * @param path the path defining the tree node
+ * @param kinds the set of kinds of the desired tree
* @return the path to the enclosing tree of the given type
*/
public static TreePath pathTillOfKind(final TreePath path, final Set<Tree.Kind> kinds) {
@@ -212,8 +226,9 @@ public final class TreeUtils {
while (p != null) {
Tree leaf = p.getLeaf();
assert leaf != null; /*nninvariant*/
- if (kinds.contains(leaf.getKind()))
+ if (kinds.contains(leaf.getKind())) {
return p;
+ }
p = p.getParentPath();
}
@@ -223,17 +238,19 @@ public final class TreeUtils {
/**
* Gets the first enclosing tree in path, of the specified class
*
- * @param path the path defining the tree node
+ * @param path the path defining the tree node
* @param treeClass the class of the desired tree
* @return the enclosing tree of the given type as given by the path
*/
- public static <T extends Tree> T enclosingOfClass(final TreePath path, final Class<T> treeClass) {
+ public static <T extends Tree> T enclosingOfClass(
+ final TreePath path, final Class<T> treeClass) {
TreePath p = path;
while (p != null) {
Tree leaf = p.getLeaf();
- if (treeClass.isInstance(leaf))
+ if (treeClass.isInstance(leaf)) {
return treeClass.cast(leaf);
+ }
p = p.getParentPath();
}
@@ -241,22 +258,20 @@ public final class TreeUtils {
}
/**
- * Gets the enclosing class of the tree node defined by the given
- * {@code {@link TreePath}}. It returns a {@link Tree}, from which
- * {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
+ * Gets the enclosing class of the tree node defined by the given {@link TreePath}. It returns a
+ * {@link Tree}, from which {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
* obtained.
*
* @param path the path defining the tree node
- * @return the enclosing class (or interface) as given by the path, or null
- * if one does not exist.
+ * @return the enclosing class (or interface) as given by the path, or null if one does not
+ * exist
*/
public static /*@Nullable*/ ClassTree enclosingClass(final /*@Nullable*/ TreePath path) {
return (ClassTree) enclosingOfKind(path, classTreeKinds());
}
/**
- * Gets the enclosing variable of a tree node defined by the given
- * {@link TreePath}.
+ * Gets the enclosing variable of a tree node defined by the given {@link TreePath}.
*
* @param path the path defining the tree node
* @return the enclosing variable as given by the path, or null if one does not exist
@@ -266,14 +281,12 @@ public final class TreeUtils {
}
/**
- * Gets the enclosing method of the tree node defined by the given
- * {@code {@link TreePath}}. It returns a {@link Tree}, from which an
- * {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
- * obtained.
+ * Gets the enclosing method of the tree node defined by the given {@link TreePath}. It returns
+ * a {@link Tree}, from which an {@code checkers.types.AnnotatedTypeMirror} or {@link Element}
+ * can be obtained.
*
* @param path the path defining the tree node
- * @return the enclosing method as given by the path, or null if one does
- * not exist
+ * @return the enclosing method as given by the path, or null if one does not exist
*/
public static /*@Nullable*/ MethodTree enclosingMethod(final /*@Nullable*/ TreePath path) {
return (MethodTree) enclosingOfKind(path, Tree.Kind.METHOD);
@@ -281,7 +294,7 @@ public final class TreeUtils {
public static /*@Nullable*/ BlockTree enclosingTopLevelBlock(TreePath path) {
TreePath parpath = path.getParentPath();
- while (parpath!=null && parpath.getLeaf().getKind() != Tree.Kind.CLASS) {
+ while (parpath != null && !classTreeKinds.contains(parpath.getLeaf().getKind())) {
path = parpath;
parpath = parpath.getParentPath();
}
@@ -291,61 +304,89 @@ public final class TreeUtils {
return null;
}
-
/**
- * If the given tree is a parenthesized tree, it returns the enclosed
- * non-parenthesized tree. Otherwise, it returns the same tree.
+ * If the given tree is a parenthesized tree, it returns the enclosed non-parenthesized tree.
+ * Otherwise, it returns the same tree.
*
- * @param tree an expression tree
- * @return the outermost non-parenthesized tree enclosed by the given tree
+ * @param tree an expression tree
+ * @return the outermost non-parenthesized tree enclosed by the given tree
*/
public static ExpressionTree skipParens(final ExpressionTree tree) {
ExpressionTree t = tree;
- while (t.getKind() == Tree.Kind.PARENTHESIZED)
- t = ((ParenthesizedTree)t).getExpression();
+ while (t.getKind() == Tree.Kind.PARENTHESIZED) {
+ t = ((ParenthesizedTree) t).getExpression();
+ }
return t;
}
/**
- * Returns the tree with the assignment context for the treePath
- * leaf node.
+ * Returns the tree with the assignment context for the treePath leaf node. (Does not handle
+ * pseudo-assignment of an argument to a parameter or a receiver expression to a receiver.)
+ *
+ * <p>The assignment context for the {@code treePath} is the leaf of its parent, if the parent
+ * is one of the following trees:
*
- * The assignment context for the treepath is the most enclosing
- * tree of type:
* <ul>
- * <li>AssignmentTree </li>
- * <li>CompoundAssignmentTree </li>
- * <li>MethodInvocationTree</li>
- * <li>NewArrayTree</li>
- * <li>NewClassTree</li>
- * <li>ReturnTree</li>
- * <li>VariableTree</li>
+ * <li>AssignmentTree
+ * <li>CompoundAssignmentTree
+ * <li>MethodInvocationTree
+ * <li>NewArrayTree
+ * <li>NewClassTree
+ * <li>ReturnTree
+ * <li>VariableTree
* </ul>
*
- * @param treePath
- * @return the assignment context as described.
+ * If the parent is a ConditionalExpressionTree we need to distinguish two cases: If the leaf is
+ * either the then or else branch of the ConditionalExpressionTree, then recurse on the parent.
+ * If the leaf is the condition of the ConditionalExpressionTree, then return null to not
+ * consider this assignment context.
+ *
+ * <p>If the leaf is a ParenthesizedTree, then recurse on the parent.
+ *
+ * <p>Otherwise, null is returned.
+ *
+ * @return the assignment context as described
*/
public static Tree getAssignmentContext(final TreePath treePath) {
- TreePath path = treePath.getParentPath();
+ TreePath parentPath = treePath.getParentPath();
- if (path == null)
+ if (parentPath == null) {
return null;
- Tree node = path.getLeaf();
- if ((node instanceof AssignmentTree) ||
- (node instanceof CompoundAssignmentTree) ||
- (node instanceof MethodInvocationTree) ||
- (node instanceof NewArrayTree) ||
- (node instanceof NewClassTree) ||
- (node instanceof ReturnTree) ||
- (node instanceof VariableTree))
- return node;
- return null;
+ }
+
+ Tree parent = parentPath.getLeaf();
+ switch (parent.getKind()) {
+ case PARENTHESIZED:
+ return getAssignmentContext(parentPath);
+ case CONDITIONAL_EXPRESSION:
+ ConditionalExpressionTree cet = (ConditionalExpressionTree) parent;
+ if (cet.getCondition() == treePath.getLeaf()) {
+ // The assignment context for the condition is simply boolean.
+ // No point in going on.
+ return null;
+ }
+ // Otherwise use the context of the ConditionalExpressionTree.
+ return getAssignmentContext(parentPath);
+ case ASSIGNMENT:
+ case METHOD_INVOCATION:
+ case NEW_ARRAY:
+ case NEW_CLASS:
+ case RETURN:
+ case VARIABLE:
+ return parent;
+ default:
+ // 11 Tree.Kinds are CompoundAssignmentTrees,
+ // so use instanceof rather than listing all 11.
+ if (parent instanceof CompoundAssignmentTree) {
+ return parent;
+ }
+ return null;
+ }
}
/**
* Gets the element for a class corresponding to a declaration.
*
- * @param node
* @return the element for the given class
*/
public static final TypeElement elementFromDeclaration(ClassTree node) {
@@ -356,7 +397,6 @@ public final class TreeUtils {
/**
* Gets the element for a method corresponding to a declaration.
*
- * @param node
* @return the element for the given method
*/
public static final ExecutableElement elementFromDeclaration(MethodTree node) {
@@ -367,7 +407,6 @@ public final class TreeUtils {
/**
* Gets the element for a variable corresponding to its declaration.
*
- * @param node
* @return the element for the given variable
*/
public static final VariableElement elementFromDeclaration(VariableTree node) {
@@ -376,11 +415,10 @@ public final class TreeUtils {
}
/**
- * Gets the element for the declaration corresponding to this use of an element.
- * To get the element for a declaration, use {@link
- * Trees#getElement(TreePath)} instead.
+ * Gets the element for the declaration corresponding to this use of an element. To get the
+ * element for a declaration, use {@link Trees#getElement(TreePath)} instead.
*
- * TODO: remove this method, as it really doesn't do anything.
+ * <p>TODO: remove this method, as it really doesn't do anything.
*
* @param node the tree corresponding to a use of an element
* @return the element for the corresponding declaration
@@ -390,8 +428,14 @@ public final class TreeUtils {
}
// Specialization for return type.
+ // Might return null if element wasn't found.
public static final ExecutableElement elementFromUse(MethodInvocationTree node) {
- return (ExecutableElement) elementFromUse((ExpressionTree) node);
+ Element el = elementFromUse((ExpressionTree) node);
+ if (el instanceof ExecutableElement) {
+ return (ExecutableElement) el;
+ } else {
+ return null;
+ }
}
// Specialization for return type.
@@ -399,12 +443,11 @@ public final class TreeUtils {
return (ExecutableElement) elementFromUse((ExpressionTree) node);
}
-
/**
* Determine whether the given ExpressionTree has an underlying element.
*
* @param node the ExpressionTree to test
- * @return whether the tree refers to an identifier, member select, or method invocation.
+ * @return whether the tree refers to an identifier, member select, or method invocation
*/
public static final boolean isUseOfElement(ExpressionTree node) {
node = TreeUtils.skipParens(node);
@@ -419,35 +462,35 @@ public final class TreeUtils {
}
}
- /**
- * @return the name of the invoked method
- */
+ /** @return the name of the invoked method */
public static final Name methodName(MethodInvocationTree node) {
ExpressionTree expr = node.getMethodSelect();
- if (expr.getKind() == Tree.Kind.IDENTIFIER)
- return ((IdentifierTree)expr).getName();
- else if (expr.getKind() == Tree.Kind.MEMBER_SELECT)
- return ((MemberSelectTree)expr).getIdentifier();
+ if (expr.getKind() == Tree.Kind.IDENTIFIER) {
+ return ((IdentifierTree) expr).getName();
+ } else if (expr.getKind() == Tree.Kind.MEMBER_SELECT) {
+ return ((MemberSelectTree) expr).getIdentifier();
+ }
ErrorReporter.errorAbort("TreeUtils.methodName: cannot be here: " + node);
return null; // dead code
}
/**
- * @return true if the first statement in the body is a self constructor
- * invocation within a constructor
+ * @return true if the first statement in the body is a self constructor invocation within a
+ * constructor
*/
public static final boolean containsThisConstructorInvocation(MethodTree node) {
- if (!TreeUtils.isConstructor(node)
- || node.getBody().getStatements().isEmpty())
+ if (!TreeUtils.isConstructor(node) || node.getBody().getStatements().isEmpty())
return false;
StatementTree st = node.getBody().getStatements().get(0);
if (!(st instanceof ExpressionStatementTree)
- || !(((ExpressionStatementTree)st).getExpression() instanceof MethodInvocationTree))
+ || !(((ExpressionStatementTree) st).getExpression()
+ instanceof MethodInvocationTree)) {
return false;
+ }
- MethodInvocationTree invocation = (MethodInvocationTree)
- ((ExpressionStatementTree)st).getExpression();
+ MethodInvocationTree invocation =
+ (MethodInvocationTree) ((ExpressionStatementTree) st).getExpression();
return "this".contentEquals(TreeUtils.methodName(invocation));
}
@@ -455,11 +498,12 @@ public final class TreeUtils {
public static final Tree firstStatement(Tree tree) {
Tree first;
if (tree.getKind() == Tree.Kind.BLOCK) {
- BlockTree block = (BlockTree)tree;
- if (block.getStatements().isEmpty())
+ BlockTree block = (BlockTree) tree;
+ if (block.getStatements().isEmpty()) {
first = block;
- else
+ } else {
first = block.getStatements().iterator().next();
+ }
} else {
first = tree;
}
@@ -469,13 +513,13 @@ public final class TreeUtils {
/**
* Determine whether the given class contains an explicit constructor.
*
- * @param node A class tree.
- * @return True, iff there is an explicit constructor.
+ * @param node a class tree
+ * @return true, iff there is an explicit constructor
*/
public static boolean hasExplicitConstructor(ClassTree node) {
TypeElement elem = TreeUtils.elementFromDeclaration(node);
- for ( ExecutableElement ee : ElementFilter.constructorsIn(elem.getEnclosedElements())) {
+ for (ExecutableElement ee : ElementFilter.constructorsIn(elem.getEnclosedElements())) {
MethodSymbol ms = (MethodSymbol) ee;
long mod = ms.flags();
@@ -487,33 +531,31 @@ public final class TreeUtils {
}
/**
- * Returns true if the tree is of a diamond type.
- * In contrast to the implementation in TreeInfo, this version
- * works on Trees.
+ * Returns true if the tree is of a diamond type. In contrast to the implementation in TreeInfo,
+ * this version works on Trees.
*
* @see com.sun.tools.javac.tree.TreeInfo#isDiamond(JCTree)
*/
public static final boolean isDiamondTree(Tree tree) {
switch (tree.getKind()) {
- case ANNOTATED_TYPE: return isDiamondTree(((AnnotatedTypeTree)tree).getUnderlyingType());
- case PARAMETERIZED_TYPE: return ((ParameterizedTypeTree)tree).getTypeArguments().isEmpty();
- case NEW_CLASS: return isDiamondTree(((NewClassTree)tree).getIdentifier());
- default: return false;
+ case ANNOTATED_TYPE:
+ return isDiamondTree(((AnnotatedTypeTree) tree).getUnderlyingType());
+ case PARAMETERIZED_TYPE:
+ return ((ParameterizedTypeTree) tree).getTypeArguments().isEmpty();
+ case NEW_CLASS:
+ return isDiamondTree(((NewClassTree) tree).getIdentifier());
+ default:
+ return false;
}
}
- /**
- * Returns true if the tree represents a {@code String} concatenation
- * operation
- */
+ /** Returns true if the tree represents a {@code String} concatenation operation */
public static final boolean isStringConcatenation(Tree tree) {
return (tree.getKind() == Tree.Kind.PLUS
&& TypesUtils.isString(InternalUtils.typeOf(tree)));
}
- /**
- * Returns true if the compound assignment tree is a string concatenation
- */
+ /** Returns true if the compound assignment tree is a string concatenation */
public static final boolean isStringCompoundConcatenation(CompoundAssignmentTree tree) {
return (tree.getKind() == Tree.Kind.PLUS_ASSIGNMENT
&& TypesUtils.isString(InternalUtils.typeOf(tree)));
@@ -522,18 +564,19 @@ public final class TreeUtils {
/**
* Returns true if the node is a constant-time expression.
*
- * A tree is a constant-time expression if it is:
+ * <p>A tree is a constant-time expression if it is:
+ *
* <ol>
- * <li>a literal tree
- * <li>a reference to a final variable initialized with a compile time
- * constant
- * <li>a String concatenation of two compile time constants
+ * <li>a literal tree
+ * <li>a reference to a final variable initialized with a compile time constant
+ * <li>a String concatenation of two compile time constants
* </ol>
*/
public static boolean isCompileTimeString(ExpressionTree node) {
ExpressionTree tree = TreeUtils.skipParens(node);
- if (tree instanceof LiteralTree)
+ if (tree instanceof LiteralTree) {
return true;
+ }
if (TreeUtils.isUseOfElement(tree)) {
Element elt = TreeUtils.elementFromUse(tree);
@@ -541,15 +584,13 @@ public final class TreeUtils {
} else if (TreeUtils.isStringConcatenation(tree)) {
BinaryTree binOp = (BinaryTree) tree;
return isCompileTimeString(binOp.getLeftOperand())
- && isCompileTimeString(binOp.getRightOperand());
+ && isCompileTimeString(binOp.getRightOperand());
} else {
return false;
}
}
- /**
- * Returns the receiver tree of a field access or a method invocation
- */
+ /** Returns the receiver tree of a field access or a method invocation */
public static ExpressionTree getReceiverTree(ExpressionTree expression) {
ExpressionTree receiver = TreeUtils.skipParens(expression);
@@ -565,13 +606,13 @@ public final class TreeUtils {
// Trying to handle receiver calls to trees of the form
// ((m).getArray())
// returns the type of 'm' in this case
- receiver = ((MethodInvocationTree)receiver).getMethodSelect();
+ receiver = ((MethodInvocationTree) receiver).getMethodSelect();
if (receiver.getKind() == Tree.Kind.IDENTIFIER) {
// It's a method call "m(foo)" without an explicit receiver
return null;
} else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) {
- receiver = ((MemberSelectTree)receiver).getExpression();
+ receiver = ((MemberSelectTree) receiver).getExpression();
} else {
// Otherwise, e.g. a NEW_CLASS: nothing to do.
}
@@ -579,9 +620,9 @@ public final class TreeUtils {
// It's a field access on implicit this or a local variable/parameter.
return null;
} else if (receiver.getKind() == Tree.Kind.ARRAY_ACCESS) {
- return TreeUtils.skipParens(((ArrayAccessTree)receiver).getExpression());
+ return TreeUtils.skipParens(((ArrayAccessTree) receiver).getExpression());
} else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) {
- receiver = ((MemberSelectTree)receiver).getExpression();
+ receiver = ((MemberSelectTree) receiver).getExpression();
// Avoid int.class
if (receiver instanceof PrimitiveTypeTree) {
return null;
@@ -596,20 +637,19 @@ public final class TreeUtils {
// Adding Tree.Kind.NEW_CLASS here doesn't work, because then a
// tree gets cast to ClassTree when it is actually a NewClassTree,
// for example in enclosingClass above.
- private final static Set<Tree.Kind> classTreeKinds = EnumSet.of(
- Tree.Kind.CLASS,
- Tree.Kind.ENUM,
- Tree.Kind.INTERFACE,
- Tree.Kind.ANNOTATION_TYPE
- );
+ private static final Set<Tree.Kind> classTreeKinds =
+ EnumSet.of(
+ Tree.Kind.CLASS,
+ Tree.Kind.ENUM,
+ Tree.Kind.INTERFACE,
+ Tree.Kind.ANNOTATION_TYPE);
public static Set<Tree.Kind> classTreeKinds() {
return classTreeKinds;
}
/**
- * Is the given tree kind a class, i.e. a class, enum,
- * interface, or annotation type.
+ * Is the given tree kind a class, i.e. a class, enum, interface, or annotation type.
*
* @param tree the tree to test
* @return true, iff the given kind is a class kind
@@ -618,16 +658,16 @@ public final class TreeUtils {
return classTreeKinds().contains(tree.getKind());
}
- private final static Set<Tree.Kind> typeTreeKinds = EnumSet.of(
- Tree.Kind.PRIMITIVE_TYPE,
- Tree.Kind.PARAMETERIZED_TYPE,
- Tree.Kind.TYPE_PARAMETER,
- Tree.Kind.ARRAY_TYPE,
- Tree.Kind.UNBOUNDED_WILDCARD,
- Tree.Kind.EXTENDS_WILDCARD,
- Tree.Kind.SUPER_WILDCARD,
- Tree.Kind.ANNOTATED_TYPE
- );
+ private static final Set<Tree.Kind> typeTreeKinds =
+ EnumSet.of(
+ Tree.Kind.PRIMITIVE_TYPE,
+ Tree.Kind.PARAMETERIZED_TYPE,
+ Tree.Kind.TYPE_PARAMETER,
+ Tree.Kind.ARRAY_TYPE,
+ Tree.Kind.UNBOUNDED_WILDCARD,
+ Tree.Kind.EXTENDS_WILDCARD,
+ Tree.Kind.SUPER_WILDCARD,
+ Tree.Kind.ANNOTATED_TYPE);
public static Set<Tree.Kind> typeTreeKinds() {
return typeTreeKinds;
@@ -636,8 +676,8 @@ public final class TreeUtils {
/**
* Is the given tree a type instantiation?
*
- * TODO: this is an under-approximation: e.g. an identifier could
- * be either a type use or an expression. How can we distinguish.
+ * <p>TODO: this is an under-approximation: e.g. an identifier could be either a type use or an
+ * expression. How can we distinguish.
*
* @param tree the tree to test
* @return true, iff the given tree is a type
@@ -647,54 +687,60 @@ public final class TreeUtils {
}
/**
- * Returns true if the given element is an invocation of the method, or
- * of any method that overrides that one.
+ * Returns true if the given element is an invocation of the method, or of any method that
+ * overrides that one.
*/
- public static boolean isMethodInvocation(Tree tree, ExecutableElement method, ProcessingEnvironment env) {
- if (!(tree instanceof MethodInvocationTree))
+ public static boolean isMethodInvocation(
+ Tree tree, ExecutableElement method, ProcessingEnvironment env) {
+ if (!(tree instanceof MethodInvocationTree)) {
return false;
- MethodInvocationTree methInvok = (MethodInvocationTree)tree;
+ }
+ MethodInvocationTree methInvok = (MethodInvocationTree) tree;
ExecutableElement invoked = TreeUtils.elementFromUse(methInvok);
- return isMethod(invoked, method, env);
- }
-
- /** Returns true if the given element is, or overrides, method. */
- private static boolean isMethod(ExecutableElement questioned, ExecutableElement method, ProcessingEnvironment env) {
- return (questioned.equals(method)
- || env.getElementUtils().overrides(questioned, method,
- (TypeElement)questioned.getEnclosingElement()));
+ return ElementUtils.isMethod(invoked, method, env);
}
/**
- * Returns the ExecutableElement for a method declaration of
- * methodName, in class typeName, with params parameters.
+ * Returns the ExecutableElement for a method declaration of methodName, in class typeName, with
+ * params parameters.
*
- * TODO: to precisely resolve method overloading, we should use parameter types and not just
+ * <p>TODO: to precisely resolve method overloading, we should use parameter types and not just
* the number of parameters!
*/
- public static ExecutableElement getMethod(String typeName, String methodName, int params, ProcessingEnvironment env) {
- TypeElement mapElt = env.getElementUtils().getTypeElement(typeName);
- for (ExecutableElement exec : ElementFilter.methodsIn(mapElt.getEnclosedElements())) {
+ public static ExecutableElement getMethod(
+ String typeName, String methodName, int params, ProcessingEnvironment env) {
+ TypeElement typeElt = env.getElementUtils().getTypeElement(typeName);
+ for (ExecutableElement exec : ElementFilter.methodsIn(typeElt.getEnclosedElements())) {
if (exec.getSimpleName().contentEquals(methodName)
- && exec.getParameters().size() == params)
+ && exec.getParameters().size() == params) {
return exec;
+ }
}
ErrorReporter.errorAbort("TreeUtils.getMethod: shouldn't be here!");
return null; // dead code
}
+ public static List<ExecutableElement> getMethodList(
+ String typeName, String methodName, int params, ProcessingEnvironment env) {
+ List<ExecutableElement> methods = new ArrayList<>();
+ TypeElement typeElement = env.getElementUtils().getTypeElement(typeName);
+ for (ExecutableElement exec : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
+ if (exec.getSimpleName().contentEquals(methodName)
+ && exec.getParameters().size() == params) {
+ methods.add(exec);
+ }
+ }
+ return methods;
+ }
+
/**
- * Determine whether the given expression is either "this" or an outer
- * "C.this".
+ * Determine whether the given expression is either "this" or an outer "C.this".
*
- * TODO: Should this also handle "super"?
- *
- * @param tree
- * @return
+ * <p>TODO: Should this also handle "super"?
*/
public static final boolean isExplicitThisDereference(ExpressionTree tree) {
if (tree.getKind() == Tree.Kind.IDENTIFIER
- && ((IdentifierTree)tree).getName().contentEquals("this")) {
+ && ((IdentifierTree) tree).getName().contentEquals("this")) {
// Explicit this reference "this"
return true;
}
@@ -712,16 +758,30 @@ public final class TreeUtils {
}
/**
- * Determine whether <code>tree</code> is a field access expressions, such
- * as
+ * Determine whether {@code tree} is a class literal, such as
+ *
+ * <pre>
+ * <em>Object</em> . <em>class</em>
+ * </pre>
+ *
+ * @return true iff if tree is a class literal
+ */
+ public static boolean isClassLiteral(Tree tree) {
+ if (tree.getKind() != Tree.Kind.MEMBER_SELECT) {
+ return false;
+ }
+ return "class".equals(((MemberSelectTree) tree).getIdentifier().toString());
+ }
+
+ /**
+ * Determine whether {@code tree} is a field access expressions, such as
*
* <pre>
* <em>f</em>
* <em>obj</em> . <em>f</em>
* </pre>
*
- * @return true iff if tree is a field access expression (implicit or
- * explicit).
+ * @return true iff if tree is a field access expression (implicit or explicit)
*/
public static boolean isFieldAccess(Tree tree) {
if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) {
@@ -734,17 +794,17 @@ public final class TreeUtils {
IdentifierTree ident = (IdentifierTree) tree;
Element el = TreeUtils.elementFromUse(ident);
return el.getKind().isField()
- && !ident.getName().contentEquals("this") && !ident.getName().contentEquals("super");
+ && !ident.getName().contentEquals("this")
+ && !ident.getName().contentEquals("super");
}
return false;
}
/**
- * Compute the name of the field that the field access <code>tree</code>
- * accesses. Requires <code>tree</code> to be a field access, as determined
- * by <code>isFieldAccess</code>.
+ * Compute the name of the field that the field access {@code tree} accesses. Requires {@code
+ * tree} to be a field access, as determined by {@code isFieldAccess}.
*
- * @return The name of the field accessed by <code>tree</code>.
+ * @return the name of the field accessed by {@code tree}.
*/
public static String getFieldName(Tree tree) {
assert isFieldAccess(tree);
@@ -758,45 +818,39 @@ public final class TreeUtils {
}
/**
- * Determine whether <code>tree</code> refers to a method element, such
- * as
+ * Determine whether {@code tree} refers to a method element, such as
*
* <pre>
* <em>m</em>(...)
* <em>obj</em> . <em>m</em>(...)
* </pre>
*
- * @return true iff if tree is a method access expression (implicit or
- * explicit).
+ * @return true iff if tree is a method access expression (implicit or explicit)
*/
public static boolean isMethodAccess(Tree tree) {
if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) {
// explicit method access
MemberSelectTree memberSelect = (MemberSelectTree) tree;
Element el = TreeUtils.elementFromUse(memberSelect);
- return el.getKind() == ElementKind.METHOD
- || el.getKind() == ElementKind.CONSTRUCTOR;
+ return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR;
} else if (tree.getKind().equals(Tree.Kind.IDENTIFIER)) {
// implicit method access
IdentifierTree ident = (IdentifierTree) tree;
// The field "super" and "this" are also legal methods
- if (ident.getName().contentEquals("super")
- || ident.getName().contentEquals("this")) {
+ if (ident.getName().contentEquals("super") || ident.getName().contentEquals("this")) {
return true;
}
Element el = TreeUtils.elementFromUse(ident);
- return el.getKind() == ElementKind.METHOD
- || el.getKind() == ElementKind.CONSTRUCTOR;
+ return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR;
}
return false;
}
/**
- * Compute the name of the method that the method access <code>tree</code>
- * accesses. Requires <code>tree</code> to be a method access, as determined
- * by <code>isMethodAccess</code>.
+ * Compute the name of the method that the method access {@code tree} accesses. Requires {@code
+ * tree} to be a method access, as determined by {@code isMethodAccess}.
*
- * @return The name of the method accessed by <code>tree</code>.
+ * @return the name of the method accessed by {@code tree}.
*/
public static String getMethodName(Tree tree) {
assert isMethodAccess(tree);
@@ -810,19 +864,17 @@ public final class TreeUtils {
}
/**
- * @return {@code true} if and only if {@code tree} can have a type
- * annotation.
- *
- * TODO: is this implementation precise enough? E.g. does
- * a .class literal work correctly?
+ * @return {@code true} if and only if {@code tree} can have a type annotation.
+ * <p>TODO: is this implementation precise enough? E.g. does a .class literal work
+ * correctly?
*/
public static boolean canHaveTypeAnnotation(Tree tree) {
return ((JCTree) tree).type != null;
}
/**
- * Returns true if and only if the given {@code tree} represents a field
- * access of the given {@link VariableElement}.
+ * Returns true if and only if the given {@code tree} represents a field access of the given
+ * {@link VariableElement}.
*/
public static boolean isSpecificFieldAccess(Tree tree, VariableElement var) {
if (tree instanceof MemberSelectTree) {
@@ -841,12 +893,13 @@ public final class TreeUtils {
/**
* Returns the VariableElement for a field declaration.
*
- * @param typeName the class where the field is declared.
- * @param fieldName the name of the field.
- * @param env the processing environment.
+ * @param typeName the class where the field is declared
+ * @param fieldName the name of the field
+ * @param env the processing environment
* @return the VariableElement for typeName.fieldName
*/
- public static VariableElement getField(String typeName, String fieldName, ProcessingEnvironment env) {
+ public static VariableElement getField(
+ String typeName, String fieldName, ProcessingEnvironment env) {
TypeElement mapElt = env.getElementUtils().getTypeElement(typeName);
for (VariableElement var : ElementFilter.fieldsIn(mapElt.getEnclosedElements())) {
if (var.getSimpleName().contentEquals(fieldName)) {
@@ -857,11 +910,12 @@ public final class TreeUtils {
return null; // dead code
}
- /** Determine whether the given tree represents an ExpressionTree.
+ /**
+ * Determine whether the given tree represents an ExpressionTree.
*
- * TODO: is there a nicer way than an instanceof?
+ * <p>TODO: is there a nicer way than an instanceof?
*
- * @param tree the Tree to test.
+ * @param tree the Tree to test
* @return whether the tree is an ExpressionTree
*/
public static boolean isExpressionTree(Tree tree) {
@@ -880,16 +934,17 @@ public final class TreeUtils {
return correctClass && correctMethod;
}
- /** Determine whether the given tree represents a declaration of a type
- * (including type parameters).
+ /**
+ * Determine whether the given tree represents a declaration of a type (including type
+ * parameters).
*
- * @param node the Tree to test
+ * @param node the Tree to test
* @return true if the tree is a type declaration
*/
public static boolean isTypeDeclaration(Tree node) {
switch (node.getKind()) {
- // These tree kinds are always declarations. Uses of the declared
- // types have tree kind IDENTIFIER.
+ // These tree kinds are always declarations. Uses of the declared
+ // types have tree kind IDENTIFIER.
case ANNOTATION_TYPE:
case CLASS:
case ENUM:
@@ -901,4 +956,65 @@ public final class TreeUtils {
return false;
}
}
+
+ /**
+ * @see Object#getClass()
+ * @return true iff invocationTree is an instance of getClass()
+ */
+ public static boolean isGetClassInvocation(MethodInvocationTree invocationTree) {
+ final Element declarationElement = elementFromUse(invocationTree);
+ String ownerName =
+ ElementUtils.getQualifiedClassName(declarationElement.getEnclosingElement())
+ .toString();
+ return ownerName.equals("java.lang.Object")
+ && declarationElement.getSimpleName().toString().equals("getClass");
+ }
+
+ /**
+ * Returns whether or not the leaf of the tree path is in a static scope.
+ *
+ * @param path TreePath whose leaf may or may not be in static scope
+ * @return returns whether or not the leaf of the tree path is in a static scope
+ */
+ public static boolean isTreeInStaticScope(TreePath path) {
+ MethodTree enclosingMethod = TreeUtils.enclosingMethod(path);
+
+ if (enclosingMethod != null) {
+ return enclosingMethod.getModifiers().getFlags().contains(Modifier.STATIC);
+ }
+ // no enclosing method, check for static or initializer block
+ BlockTree block = enclosingTopLevelBlock(path);
+ if (block != null) {
+ return block.isStatic();
+ }
+
+ // check if its in a variable initializer
+ Tree t = enclosingVariable(path);
+ if (t != null) {
+ return ((VariableTree) t).getModifiers().getFlags().contains((Modifier.STATIC));
+ }
+ ClassTree classTree = enclosingClass(path);
+ if (classTree != null) {
+ return classTree.getModifiers().getFlags().contains((Modifier.STATIC));
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether or not tree is an access of array length.
+ *
+ * @param tree tree to check
+ * @return true if tree is an access of array length
+ */
+ public static boolean isArrayLengthAccess(Tree tree) {
+ if (tree.getKind() == Kind.MEMBER_SELECT
+ && isFieldAccess(tree)
+ && getFieldName(tree).equals("length")) {
+ ExpressionTree expressionTree = ((MemberSelectTree) tree).getExpression();
+ if (InternalUtils.typeOf(expressionTree).getKind() == TypeKind.ARRAY) {
+ return true;
+ }
+ }
+ return false;
+ }
}