use of com.sun.source.tree.MethodTree 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;
}
TreePath path = getCurrentPath();
TreePath parentPath = path.getParentPath();
Tree parent = parentPath.getLeaf();
// statement in the method.
if (parent.getKind() == Tree.Kind.RETURN) {
// ensure the return statement is the first statement in the method
if (parentPath.getParentPath().getParentPath().getLeaf().getKind() != Tree.Kind.METHOD) {
return false;
}
// maybe set some variables??
} else if (Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
// Ensure the if statement is the first statement in the method
// Retrieve the enclosing if statement tree and method tree
Tree ifStatementTree = null;
MethodTree methodTree = null;
// Set ifStatementTree and methodTree
{
TreePath ppath = parentPath;
Tree tree;
while ((tree = ppath.getLeaf()) != null) {
if (tree.getKind() == Tree.Kind.IF) {
ifStatementTree = tree;
} else if (tree.getKind() == Tree.Kind.METHOD) {
methodTree = (MethodTree) tree;
break;
}
ppath = ppath.getParentPath();
}
}
assert ifStatementTree != null;
assert methodTree != null;
StatementTree firstStmnt = methodTree.getBody().getStatements().get(0);
assert firstStmnt != null;
// comparing AST nodes
@SuppressWarnings("interning:not.interned") boolean notSameNode = firstStmnt != ifStatementTree;
if (notSameNode) {
// The if statement is not the first statement in the method.
return false;
}
} else {
return false;
}
ExecutableElement enclosingMethod = TreeUtils.elementFromDeclaration(methodTree);
assert enclosingMethod != 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().isEmpty()) {
return false;
}
return visit(tree.getStatements().get(0), p);
}
@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));
}
};
boolean hasCompareToMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, CompareToMethod.class) != null;
boolean hasEqualsMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, EqualsMethod.class) != null;
int params = enclosingMethod.getParameters().size();
// "return 0" statement (for the Comparator.compare heuristic).
if (overrides(enclosingMethod, Comparator.class, "compare") || (hasCompareToMethodAnno && params == 2)) {
final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert params == 2;
Element p1 = enclosingMethod.getParameters().get(0);
Element p2 = enclosingMethod.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
} else if (overrides(enclosingMethod, Object.class, "equals") || (hasEqualsMethodAnno && params == 1)) {
assert params == 1;
Element param = enclosingMethod.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
} else if (hasEqualsMethodAnno && params == 2) {
Element p1 = enclosingMethod.getParameters().get(0);
Element p2 = enclosingMethod.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
} else if (overrides(enclosingMethod, Comparable.class, "compareTo") || (hasCompareToMethodAnno && params == 1)) {
final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert params == 1;
Element param = enclosingMethod.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
}
return false;
}
use of com.sun.source.tree.MethodTree 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);
AnnotatedDeclaredType enclosing = selfType;
while (path != null && enclosing != null) {
TreePath topLevelMemberPath = findTopLevelClassMemberForTree(path);
if (topLevelMemberPath != null && topLevelMemberPath.getLeaf() != null) {
Tree topLevelMember = topLevelMemberPath.getLeaf();
if (topLevelMember.getKind() != Tree.Kind.METHOD || TreeUtils.isConstructor((MethodTree) topLevelMember)) {
setSelfTypeInInitializationCode(tree, enclosing, topLevelMemberPath);
}
path = topLevelMemberPath.getParentPath();
enclosing = enclosing.getEnclosingType();
} else {
break;
}
}
return selfType;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class TypeFromTypeTreeVisitor method getTypeVariableFromDeclaration.
/**
* If a tree is can be found for the declaration of the type variable {@code type}, then a {@link
* AnnotatedTypeVariable} is returned with explicit annotations from the type variables declared
* bounds. If a tree cannot be found, then {@code type}, converted to a use, is returned.
*
* @param type type variable used to find declaration tree
* @param f annotated type factory
* @return the AnnotatedTypeVariable from the declaration of {@code type} or {@code type} if no
* tree is found.
*/
private AnnotatedTypeVariable getTypeVariableFromDeclaration(AnnotatedTypeVariable type, AnnotatedTypeFactory f) {
TypeVariable typeVar = type.getUnderlyingType();
TypeParameterElement tpe = (TypeParameterElement) typeVar.asElement();
Element elt = tpe.getGenericElement();
if (elt instanceof TypeElement) {
TypeElement typeElt = (TypeElement) elt;
int idx = typeElt.getTypeParameters().indexOf(tpe);
ClassTree cls = (ClassTree) f.declarationFromElement(typeElt);
if (cls == null || cls.getTypeParameters().isEmpty()) {
// contains all necessary information and we can return that.
return type.asUse();
}
// will return a declaration ATV. So change it to a use.
return visitTypeParameter(cls.getTypeParameters().get(idx), f).asUse();
} else if (elt instanceof ExecutableElement) {
ExecutableElement exElt = (ExecutableElement) elt;
int idx = exElt.getTypeParameters().indexOf(tpe);
MethodTree meth = (MethodTree) f.declarationFromElement(exElt);
if (meth == null) {
// + elt);
return type.asUse();
}
// This works the same as the case above. Even though `meth` itself is not a
// type declaration tree, the elements of `meth.getTypeParameters()` still are.
AnnotatedTypeVariable result = visitTypeParameter(meth.getTypeParameters().get(idx), f).shallowCopy();
result.setDeclaration(false);
return result;
} else if (TypesUtils.isCapturedTypeVariable(typeVar)) {
// not an element at all, namely Symtab.noSymbol.
return type.asUse();
} else {
throw new BugInCF("TypeFromTree.forTypeVariable: not a supported element: " + elt);
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class PropagationTreeAnnotator method visitNewArray.
@Override
public Void visitNewArray(NewArrayTree tree, AnnotatedTypeMirror type) {
assert type.getKind() == TypeKind.ARRAY : "PropagationTreeAnnotator.visitNewArray: should be an array type";
AnnotatedTypeMirror componentType = ((AnnotatedArrayType) type).getComponentType();
// prev is the lub of the initializers if they exist, otherwise the current component type.
Set<? extends AnnotationMirror> prev = null;
if (tree.getInitializers() != null && !tree.getInitializers().isEmpty()) {
// the array.
for (ExpressionTree init : tree.getInitializers()) {
AnnotatedTypeMirror initType = atypeFactory.getAnnotatedType(init);
// initType might be a typeVariable, so use effectiveAnnotations.
Set<AnnotationMirror> annos = initType.getEffectiveAnnotations();
prev = (prev == null) ? annos : qualHierarchy.leastUpperBounds(prev, annos);
}
} else {
prev = componentType.getAnnotations();
}
assert prev != null : "PropagationTreeAnnotator.visitNewArray: violated assumption about qualifiers";
TreePath path = atypeFactory.getPath(tree);
AnnotatedTypeMirror contextType = null;
if (path != null && path.getParentPath() != null) {
Tree parentTree = path.getParentPath().getLeaf();
if (parentTree.getKind() == Kind.ASSIGNMENT) {
Tree var = ((AssignmentTree) parentTree).getVariable();
contextType = atypeFactory.getAnnotatedType(var);
} else if (parentTree.getKind() == Kind.VARIABLE) {
contextType = atypeFactory.getAnnotatedType(parentTree);
} else if (parentTree instanceof CompoundAssignmentTree) {
Tree var = ((CompoundAssignmentTree) parentTree).getVariable();
contextType = atypeFactory.getAnnotatedType(var);
} else if (parentTree.getKind() == Kind.RETURN) {
Tree methodTree = TreePathUtil.enclosingMethodOrLambda(path.getParentPath());
if (methodTree.getKind() == Kind.METHOD) {
AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType((MethodTree) methodTree);
contextType = methodType.getReturnType();
}
} else if (parentTree.getKind() == Kind.METHOD_INVOCATION && useAssignmentContext) {
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) parentTree;
useAssignmentContext = false;
AnnotatedExecutableType m;
try {
if (atypeFactory.shouldCache && methodInvocationToType.containsKey(methodInvocationTree)) {
m = methodInvocationToType.get(methodInvocationTree);
} else {
m = atypeFactory.methodFromUse(methodInvocationTree).executableType;
if (atypeFactory.shouldCache) {
methodInvocationToType.put(methodInvocationTree, m);
}
}
} finally {
useAssignmentContext = true;
}
for (int i = 0; i < m.getParameterTypes().size(); i++) {
// Tree must be exactly the same.
@SuppressWarnings("interning") boolean foundArgument = methodInvocationTree.getArguments().get(i) == tree;
if (foundArgument) {
contextType = m.getParameterTypes().get(i);
break;
}
}
}
}
Set<? extends AnnotationMirror> post;
if (contextType instanceof AnnotatedArrayType) {
AnnotatedTypeMirror contextComponentType = ((AnnotatedArrayType) contextType).getComponentType();
// Only compare the qualifiers that existed in the array type.
// Defaulting wasn't performed yet, so prev might have fewer qualifiers than
// contextComponentType, which would cause a failure.
// TODO: better solution?
boolean prevIsSubtype = true;
for (AnnotationMirror am : prev) {
if (contextComponentType.isAnnotatedInHierarchy(am) && !this.qualHierarchy.isSubtype(am, contextComponentType.getAnnotationInHierarchy(am))) {
prevIsSubtype = false;
}
}
// It fails for array initializer expressions. Those should be handled nicer.
if (contextComponentType.getKind() == componentType.getKind() && (prev.isEmpty() || (!contextComponentType.getAnnotations().isEmpty() && prevIsSubtype))) {
post = contextComponentType.getAnnotations();
} else {
// The type of the array initializers is incompatible with the context type!
// Somebody else will complain.
post = prev;
}
} else {
// No context is available - simply use what we have.
post = prev;
}
// TODO (issue #599): This only works at the top level. It should work at all levels of
// the array.
addAnnoOrBound(componentType, post);
return null;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class StringToJavaExpression method atPath.
/**
* Parses a string as if it were written at {@code localVarPath}.
*
* @param expression a Java expression to parse
* @param localVarPath location at which {@code expression} is parsed
* @param checker checker used to get the {@link
* javax.annotation.processing.ProcessingEnvironment} and current {@link
* com.sun.source.tree.CompilationUnitTree}
* @return a {@code JavaExpression} for {@code expression}
* @throws JavaExpressionParseException if {@code expression} cannot be parsed
*/
static JavaExpression atPath(String expression, TreePath localVarPath, SourceChecker checker) throws JavaExpressionParseException {
TypeMirror enclosingType = TreeUtils.typeOf(TreePathUtil.enclosingClass(localVarPath));
ThisReference thisReference = TreePathUtil.isTreeInStaticScope(localVarPath) ? null : new ThisReference(enclosingType);
MethodTree methodTree = TreePathUtil.enclosingMethod(localVarPath);
if (methodTree == null) {
return JavaExpressionParseUtil.parse(expression, enclosingType, thisReference, null, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment());
}
ExecutableElement methodEle = TreeUtils.elementFromDeclaration(methodTree);
List<FormalParameter> parameters = JavaExpression.getFormalParameters(methodEle);
JavaExpression javaExpr = JavaExpressionParseUtil.parse(expression, enclosingType, thisReference, parameters, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment());
List<JavaExpression> paramsAsLocals = JavaExpression.getParametersAsLocalVariables(methodEle);
return ViewpointAdaptJavaExpression.viewpointAdapt(javaExpr, paramsAsLocals);
}
Aggregations