use of com.sun.source.util.TreePath in project checker-framework by typetools.
the class AnnotatedTypeFactory method getImplicitReceiverType.
// **********************************************************************
// Utilities method for getting specific types from trees or elements
// **********************************************************************
/**
* Return the implicit receiver type of an expression tree.
*
* <p>The result is null for expressions that don't have a receiver, e.g. for a local variable
* or method parameter access.
*
* @param tree the expression that might have an implicit receiver
* @return the type of the receiver
*/
/*
* TODO: receiver annotations on outer this.
* TODO: Better document the difference between getImplicitReceiverType and getSelfType?
* TODO: this method assumes that the tree is within the current
* Compilation Unit. This assumption fails in testcase Bug109_A/B, where
* a chain of dependencies leads into a different compilation unit.
* I didn't find a way how to handle this better and conservatively
* return null. See TODO comment below.
*
*/
protected AnnotatedDeclaredType getImplicitReceiverType(ExpressionTree tree) {
assert (tree.getKind() == Tree.Kind.IDENTIFIER || tree.getKind() == Tree.Kind.MEMBER_SELECT || tree.getKind() == Tree.Kind.METHOD_INVOCATION || tree.getKind() == Tree.Kind.NEW_CLASS) : "Unexpected tree kind: " + tree.getKind();
Element element = TreeUtils.elementFromTree(tree);
assert element != null : "Unexpected null element for tree: " + tree;
// Return null if the element kind has no receiver.
if (!ElementUtils.hasReceiver(element)) {
return null;
}
ExpressionTree receiver = TreeUtils.getReceiverTree(tree);
if (receiver == null) {
if (isMostEnclosingThisDeref(tree)) {
// TODO: is this fixed?
return getSelfType(tree);
} else {
TreePath path = getPath(tree);
if (path == null) {
// This only arises in the Nullness Checker when substituting rawness.
return null;
}
TypeElement typeElt = ElementUtils.enclosingClass(element);
if (typeElt == null) {
ErrorReporter.errorAbort("AnnotatedTypeFactory.getImplicitReceiver: enclosingClass()==null for element: " + element);
}
// TODO: method receiver annotations on outer this
return getEnclosingType(typeElt, tree);
}
}
Element rcvelem = TreeUtils.elementFromTree(receiver);
assert rcvelem != null : "Unexpected null element for receiver: " + receiver;
if (!ElementUtils.hasReceiver(rcvelem)) {
return null;
}
if (receiver.getKind() == Tree.Kind.IDENTIFIER && ((IdentifierTree) receiver).getName().contentEquals("this")) {
// TODO: also "super"?
return this.getSelfType(tree);
}
TypeElement typeElt = ElementUtils.enclosingClass(rcvelem);
if (typeElt == null) {
ErrorReporter.errorAbort("AnnotatedTypeFactory.getImplicitReceiver: enclosingClass()==null for element: " + rcvelem);
}
AnnotatedDeclaredType type = getAnnotatedType(typeElt);
// TODO: go through _all_ enclosing methods to see whether any of them has a
// receiver annotation of the correct type.
// TODO: Can we reuse getSelfType for outer this accesses?
AnnotatedDeclaredType methodReceiver = getCurrentMethodReceiver(tree);
if (shouldTakeFromReceiver(methodReceiver)) {
// TODO: this only takes the main annotations.
// What about other annotations (annotations on the type argument, outer types, ...)
type.clearAnnotations();
type.addAnnotations(methodReceiver.getAnnotations());
}
return type;
}
use of com.sun.source.util.TreePath in project checker-framework by typetools.
the class InitializationAnnotatedTypeFactory method findTopLevelClassMemberForTree.
/**
* In the first enclosing class, find the top-level member that contains tree. TODO: should we
* look whether these elements are enclosed within another class that is itself under
* construction.
*
* <p>Are there any other type of top level objects?
*/
private Tree findTopLevelClassMemberForTree(TreePath path) {
ClassTree enclosingClass = TreeUtils.enclosingClass(path);
if (enclosingClass != null) {
List<? extends Tree> classMembers = enclosingClass.getMembers();
TreePath searchPath = path;
while (searchPath.getParentPath() != null && searchPath.getParentPath() != enclosingClass) {
searchPath = searchPath.getParentPath();
if (classMembers.contains(searchPath.getLeaf())) {
return searchPath.getLeaf();
}
}
}
return null;
}
use of com.sun.source.util.TreePath in project checker-framework by typetools.
the class InitializationAnnotatedTypeFactory method getSelfType.
@Override
public AnnotatedDeclaredType getSelfType(Tree tree) {
AnnotatedDeclaredType selfType = super.getSelfType(tree);
TreePath path = getPath(tree);
Tree topLevelMember = findTopLevelClassMemberForTree(path);
if (topLevelMember != null) {
if (topLevelMember.getKind() != Kind.METHOD || TreeUtils.isConstructor((MethodTree) topLevelMember)) {
setSelfTypeInInitializationCode(tree, selfType, path);
}
}
return selfType;
}
use of com.sun.source.util.TreePath in project checker-framework by typetools.
the class InterningVisitor method suppressInsideComparison.
/**
* Pattern matches particular comparisons to avoid common false positives in the {@link
* Comparable#compareTo(Object)} and {@link Object#equals(Object)}.
*
* <p>Specifically, this method tests if: the comparison is a == comparison, it is the test of
* an if statement that's the first statement in the method, and one of the following is true:
*
* <ol>
* <li>the method overrides {@link Comparator#compare}, the "then" branch of the if statement
* returns zero, and the comparison tests equality of the method's two parameters
* <li>the method overrides {@link Object#equals(Object)} and the comparison tests "this"
* against the method's parameter
* <li>the method overrides {@link Comparable#compareTo(Object)}, the "then" branch of the if
* statement returns zero, and the comparison tests "this" against the method's parameter
* </ol>
*
* @param node the comparison to check
* @return true if one of the supported heuristics is matched, false otherwise
*/
// TODO: handle != comparisons too!
// TODO: handle more methods, such as early return from addAll when this == arg
private boolean suppressInsideComparison(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
Tree left = node.getLeftOperand();
Tree right = node.getRightOperand();
// Only valid if we're comparing identifiers.
if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER))
return false;
// parens and blocks), terminate.
if (!Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
return false;
}
// Ensure the if statement is the first statement in the method
TreePath parentPath = getCurrentPath().getParentPath();
// Retrieve the enclosing if statement tree and method tree
Tree tree, ifStatementTree = null;
MethodTree methodTree = null;
while ((tree = parentPath.getLeaf()) != null) {
if (tree.getKind() == Tree.Kind.IF) {
ifStatementTree = tree;
} else if (tree.getKind() == Tree.Kind.METHOD) {
methodTree = (MethodTree) tree;
break;
}
parentPath = parentPath.getParentPath();
}
// The call to Heuristics.matchParents already ensured there is an enclosing if statement
assert ifStatementTree != null;
// The call to Heuristics.matchParents already ensured there is an enclosing method
assert methodTree != null;
StatementTree stmnt = methodTree.getBody().getStatements().get(0);
// The call to Heuristics.matchParents already ensured the enclosing method has at least one statement (an if statement) in the body
assert stmnt != null;
if (stmnt != ifStatementTree) {
// The if statement is not the first statement in the method.
return false;
}
ExecutableElement enclosing = TreeUtils.elementFromDeclaration(visitorState.getMethodTree());
assert enclosing != null;
final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);
// Matcher to check for if statement that returns zero
Heuristics.Matcher matcherIfReturnsZero = new Heuristics.Matcher() {
@Override
public Boolean visitIf(IfTree tree, Void p) {
return visit(tree.getThenStatement(), p);
}
@Override
public Boolean visitBlock(BlockTree tree, Void p) {
if (tree.getStatements().size() > 0) {
return visit(tree.getStatements().get(0), p);
}
return false;
}
@Override
public Boolean visitReturn(ReturnTree tree, Void p) {
ExpressionTree expr = tree.getExpression();
return (expr != null && expr.getKind() == Tree.Kind.INT_LITERAL && ((LiteralTree) expr).getValue().equals(0));
}
};
// "return 0" statement (for the Comparator.compare heuristic).
if (overrides(enclosing, Comparator.class, "compare")) {
final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert enclosing.getParameters().size() == 2;
Element p1 = enclosing.getParameters().get(0);
Element p2 = enclosing.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs));
} else if (overrides(enclosing, Object.class, "equals")) {
assert enclosing.getParameters().size() == 1;
Element param = enclosing.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
} else if (overrides(enclosing, Comparable.class, "compareTo")) {
final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert enclosing.getParameters().size() == 1;
Element param = enclosing.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
}
return false;
}
use of com.sun.source.util.TreePath in project checker-framework by typetools.
the class LockAnnotatedTypeFactory method createDependentTypesHelper.
@Override
protected DependentTypesHelper createDependentTypesHelper() {
return new DependentTypesHelper(this) {
@Override
protected void reportErrors(Tree errorTree, List<DependentTypesError> errors) {
// If the error message is NOT_EFFECTIVELY_FINAL, then report lock.expression.not
// .final instead of an expression.unparsable.type.invalid error.
List<DependentTypesError> superErrors = new ArrayList<>();
for (DependentTypesError error : errors) {
if (error.error.equals(NOT_EFFECTIVELY_FINAL)) {
checker.report(Result.failure("lock.expression.not.final", error.expression), errorTree);
} else {
superErrors.add(error);
}
}
super.reportErrors(errorTree, superErrors);
}
@Override
protected String standardizeString(String expression, FlowExpressionContext context, TreePath localScope, boolean useLocalScope) {
if (DependentTypesError.isExpressionError(expression)) {
return expression;
}
// Adds logic to parse <self> expression, which only the Lock Checker uses.
if (LockVisitor.selfReceiverPattern.matcher(expression).matches()) {
return expression;
}
try {
FlowExpressions.Receiver result = FlowExpressionParseUtil.parse(expression, context, localScope, useLocalScope);
if (result == null) {
return new DependentTypesError(expression, " ").toString();
}
if (!isExpressionEffectivelyFinal(result)) {
// NOT_EFFECTIVELY_FINAL error string.
return new DependentTypesError(expression, NOT_EFFECTIVELY_FINAL).toString();
}
return result.toString();
} catch (FlowExpressionParseUtil.FlowExpressionParseException e) {
return new DependentTypesError(expression, e).toString();
}
}
};
}
Aggregations