use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class ReturnsReceiverVisitor method visitAnnotation.
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
AnnotationMirror annot = TreeUtils.annotationFromAnnotationTree(node);
// Warn if a @This annotation is in an illegal location.
if (AnnotationUtils.areSame(annot, getTypeFactory().THIS_ANNOTATION)) {
TreePath parentPath = getCurrentPath().getParentPath();
Tree parent = parentPath.getLeaf();
Tree grandparent = parentPath.getParentPath().getLeaf();
Tree greatGrandparent = parentPath.getParentPath().getParentPath().getLeaf();
boolean isReturnAnnot = grandparent instanceof MethodTree && (parent.equals(((MethodTree) grandparent).getReturnType()) || parent instanceof ModifiersTree);
boolean isReceiverAnnot = greatGrandparent instanceof MethodTree && grandparent.equals(((MethodTree) greatGrandparent).getReceiverParameter()) && parent.equals(((VariableTree) grandparent).getModifiers());
boolean isCastAnnot = grandparent instanceof TypeCastTree && parent.equals(((TypeCastTree) grandparent).getType());
if (!(isReturnAnnot || isReceiverAnnot || isCastAnnot)) {
checker.reportError(node, "this.location");
}
if (isReturnAnnot && ElementUtils.isStatic(TreeUtils.elementFromDeclaration((MethodTree) grandparent))) {
checker.reportError(node, "this.location");
}
}
return super.visitAnnotation(node, p);
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class WholeProgramInferenceImplementation method isRecursiveCall.
/**
* Returns true if the given call is a recursive call.
*
* @param methodInvNode a method invocation
* @return true if the given call is a recursive call
*/
private boolean isRecursiveCall(MethodInvocationNode methodInvNode) {
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(methodInvNode.getTreePath());
if (enclosingMethod == null) {
return false;
}
ExecutableElement methodInvocEle = TreeUtils.elementFromUse(methodInvNode.getTree());
ExecutableElement methodDeclEle = TreeUtils.elementFromDeclaration(enclosingMethod);
return methodDeclEle.equals(methodInvocEle);
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method parseAndLocalizeContracts.
/**
* Localizes some contracts -- that is, viewpoint-adapts them to some method body, according to
* the value of {@link #methodTree}.
*
* <p>The input is a set of {@link Contract}s, each of which contains an expression string and an
* annotation. In a {@link Contract}, Java expressions are exactly as written in source code, not
* standardized or viewpoint-adapted.
*
* <p>The output is a set of pairs of {@link JavaExpression} (parsed expression string) and
* standardized annotation (with respect to the path of {@link #methodTree}. This method discards
* any contract whose expression cannot be parsed into a JavaExpression.
*
* @param contractSet a set of contracts
* @param methodType the type of the method that the contracts are for
* @return pairs of (expression, AnnotationMirror), which are localized contracts
*/
private Set<Pair<JavaExpression, AnnotationMirror>> parseAndLocalizeContracts(Set<? extends Contract> contractSet, AnnotatedExecutableType methodType) {
if (contractSet.isEmpty()) {
return Collections.emptySet();
}
// This is the path to a place where the contract is being used, which might or might not be
// where the contract was defined. For example, methodTree might be an overriding
// definition, and the contract might be for a superclass.
MethodTree methodTree = this.methodTree;
StringToJavaExpression stringToJavaExpr = expression -> {
JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, methodType.getElement(), checker);
// viewpoint-adapt it to methodTree.
return javaExpr.atMethodBody(methodTree);
};
Set<Pair<JavaExpression, AnnotationMirror>> result = new HashSet<>(contractSet.size());
for (Contract p : contractSet) {
String expressionString = p.expressionString;
AnnotationMirror annotation = p.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, methodTree);
JavaExpression exprJe;
try {
// TODO: currently, these expressions are parsed many times.
// This could be optimized to store the result the first time.
// (same for other annotations)
exprJe = stringToJavaExpr.toJavaExpression(expressionString);
} catch (JavaExpressionParseException e) {
// report errors here
checker.report(methodTree, e.getDiagMessage());
continue;
}
result.add(Pair.of(exprJe, annotation));
}
return result;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method checkThisOrSuperConstructorCall.
/**
* Checks that the following rule is satisfied: The type on a constructor declaration must be a
* supertype of the return type of "this()" or "super()" invocation within that constructor.
*
* @param call the AST node for the constructor call
* @param errorKey the error message key to use if the check fails
*/
protected void checkThisOrSuperConstructorCall(MethodInvocationTree call, @CompilerMessageKey String errorKey) {
TreePath path = atypeFactory.getPath(call);
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(path);
AnnotatedTypeMirror superType = atypeFactory.getAnnotatedType(call);
AnnotatedExecutableType constructorType = atypeFactory.getAnnotatedType(enclosingMethod);
Set<? extends AnnotationMirror> topAnnotations = atypeFactory.getQualifierHierarchy().getTopAnnotations();
for (AnnotationMirror topAnno : topAnnotations) {
AnnotationMirror superTypeMirror = superType.getAnnotationInHierarchy(topAnno);
AnnotationMirror constructorTypeMirror = constructorType.getReturnType().getAnnotationInHierarchy(topAnno);
if (!atypeFactory.getQualifierHierarchy().isSubtype(superTypeMirror, constructorTypeMirror)) {
checker.reportError(call, errorKey, constructorTypeMirror, call, superTypeMirror);
}
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method visitMethod.
/**
* Checks that the method obeys override and subtype rules to all overridden methods. (Uses the
* pseudo-assignment logic to do so.)
*
* <p>The override rule specifies that a method, m1, may override a method m2 only if:
*
* <ul>
* <li>m1 return type is a subtype of m2
* <li>m1 receiver type is a supertype of m2
* <li>m1 parameters are supertypes of corresponding m2 parameters
* </ul>
*
* Also, it issues a "missing.this" error for static method annotated receivers.
*/
@Override
public Void visitMethod(MethodTree node, Void p) {
// We copy the result from getAnnotatedType to ensure that circular types (e.g. K extends
// Comparable<K>) are represented by circular AnnotatedTypeMirrors, which avoids problems with
// later checks.
// TODO: Find a cleaner way to ensure circular AnnotatedTypeMirrors.
AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType(node).deepCopy();
MethodTree preMT = methodTree;
methodTree = node;
ExecutableElement methodElement = TreeUtils.elementFromDeclaration(node);
warnAboutTypeAnnotationsTooEarly(node, node.getModifiers());
if (node.getReturnType() != null) {
visitAnnotatedType(node.getModifiers().getAnnotations(), node.getReturnType());
}
try {
if (TreeUtils.isAnonymousConstructor(node)) {
// We shouldn't dig deeper
return null;
}
if (TreeUtils.isConstructor(node)) {
checkConstructorResult(methodType, methodElement);
}
checkPurity(node);
// Passing the whole method/constructor validates the return type
validateTypeOf(node);
// Validate types in throws clauses
for (ExpressionTree thr : node.getThrows()) {
validateTypeOf(thr);
}
atypeFactory.getDependentTypesHelper().checkMethodForErrorExpressions(node, methodType);
// Check method overrides
AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(methodElement.getEnclosingElement());
// Find which methods this method overrides
Map<AnnotatedDeclaredType, ExecutableElement> overriddenMethods = AnnotatedTypes.overriddenMethods(elements, atypeFactory, methodElement);
for (Map.Entry<AnnotatedDeclaredType, ExecutableElement> pair : overriddenMethods.entrySet()) {
AnnotatedDeclaredType overriddenType = pair.getKey();
ExecutableElement overriddenMethodElt = pair.getValue();
AnnotatedExecutableType overriddenMethodType = AnnotatedTypes.asMemberOf(types, atypeFactory, overriddenType, overriddenMethodElt);
if (!checkOverride(node, enclosingType, overriddenMethodType, overriddenType)) {
// the same method, not adding any value. See Issue 373.
break;
}
}
// Check well-formedness of pre/postcondition
boolean abstractMethod = methodElement.getModifiers().contains(Modifier.ABSTRACT) || methodElement.getModifiers().contains(Modifier.NATIVE);
List<String> formalParamNames = CollectionsPlume.mapList((VariableTree param) -> param.getName().toString(), node.getParameters());
checkContractsAtMethodDeclaration(node, methodElement, formalParamNames, abstractMethod);
// Infer postconditions
if (atypeFactory.getWholeProgramInference() != null) {
assert ElementUtils.isElementFromSourceCode(methodElement);
// TODO: Infer conditional postconditions too.
CFAbstractStore<?, ?> store = atypeFactory.getRegularExitStore(node);
// throw statement.
if (store != null) {
atypeFactory.getWholeProgramInference().updateContracts(Analysis.BeforeOrAfter.AFTER, methodElement, store);
}
}
checkForPolymorphicQualifiers(node.getTypeParameters());
return super.visitMethod(node, p);
} finally {
methodTree = preMT;
}
}
Aggregations