use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method visitReturn.
/**
* Checks that the type of the return expression is a subtype of the enclosing method required
* return type. If not, it issues a "return.type.incompatible" error.
*/
@Override
public Void visitReturn(ReturnTree node, Void p) {
// Don't try to check return expressions for void methods.
if (node.getExpression() == null) {
return super.visitReturn(node, p);
}
Pair<Tree, AnnotatedTypeMirror> preAssCtxt = visitorState.getAssignmentContext();
try {
Tree enclosing = TreeUtils.enclosingOfKind(getCurrentPath(), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
AnnotatedTypeMirror ret = null;
if (enclosing.getKind() == Tree.Kind.METHOD) {
MethodTree enclosingMethod = TreeUtils.enclosingMethod(getCurrentPath());
boolean valid = validateTypeOf(enclosing);
if (valid) {
ret = atypeFactory.getMethodReturnType(enclosingMethod, node);
}
} else {
Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = atypeFactory.getFnInterfaceFromTree((LambdaExpressionTree) enclosing);
ret = result.second.getReturnType();
}
if (ret != null) {
visitorState.setAssignmentContext(Pair.of((Tree) node, ret));
commonAssignmentCheck(ret, node.getExpression(), "return.type.incompatible");
}
return super.visitReturn(node, p);
} finally {
visitorState.setAssignmentContext(preAssCtxt);
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class TypeFromTypeTreeVisitor method forTypeVariable.
private AnnotatedTypeMirror forTypeVariable(AnnotatedTypeMirror type, AnnotatedTypeFactory f) {
if (type.getKind() != TypeKind.TYPEVAR) {
ErrorReporter.errorAbort("TypeFromTree.forTypeVariable: should only be called on type variables");
// dead code
return null;
}
TypeVariable typeVar = (TypeVariable) 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) {
// `forTypeVariable` is called for Identifier, MemberSelect and UnionType trees,
// none of which are declarations. But `cls.getTypeParameters()` returns a list
// of type parameter declarations (`TypeParameterTree`), so this recursive call
// to `visit` will return a declaration ATV. So we must copy the result and set
// its `isDeclaration` field to `false`.
AnnotatedTypeMirror result = visit(cls.getTypeParameters().get(idx), f).shallowCopy();
((AnnotatedTypeVariable) result).setDeclaration(false);
return result;
} else {
// We already have all info from the element -> nothing to do.
return type;
}
} else if (elt instanceof ExecutableElement) {
ExecutableElement exElt = (ExecutableElement) elt;
int idx = exElt.getTypeParameters().indexOf(tpe);
MethodTree meth = (MethodTree) f.declarationFromElement(exElt);
if (meth != null) {
// 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.
AnnotatedTypeMirror result = visit(meth.getTypeParameters().get(idx), f).shallowCopy();
((AnnotatedTypeVariable) result).setDeclaration(false);
return result;
} else {
// " + elt);
return type;
}
} else {
// not an element at all, namely Symtab.noSymbol.
if (TypesUtils.isCaptured(typeVar)) {
return type;
} else {
ErrorReporter.errorAbort("TypeFromTree.forTypeVariable: not a supported element: " + elt);
// dead code
return null;
}
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class TypesIntoElements method store.
/**
* The entry point.
*
* @param processingEnv the environment
* @param atypeFactory the type factory
* @param tree the ClassTree to process
*/
public static void store(ProcessingEnvironment processingEnv, AnnotatedTypeFactory atypeFactory, ClassTree tree) {
Symbol.ClassSymbol csym = (Symbol.ClassSymbol) TreeUtils.elementFromDeclaration(tree);
Types types = processingEnv.getTypeUtils();
storeTypeParameters(processingEnv, types, atypeFactory, tree.getTypeParameters(), csym);
for (Tree mem : tree.getMembers()) {
if (mem.getKind() == Tree.Kind.METHOD) {
storeMethod(processingEnv, types, atypeFactory, (MethodTree) mem);
} else if (mem.getKind() == Tree.Kind.VARIABLE) {
storeVariable(processingEnv, types, atypeFactory, (VariableTree) mem);
} else {
// System.out.println("Unhandled member tree: " + mem);
}
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method visitMethod.
/**
* Performs pseudo-assignment check: checks that the method obeys override and subtype rules to
* all overridden methods.
*
* <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();
AnnotatedDeclaredType preMRT = visitorState.getMethodReceiver();
MethodTree preMT = visitorState.getMethodTree();
visitorState.setMethodReceiver(methodType.getReceiverType());
visitorState.setMethodTree(node);
ExecutableElement methodElement = TreeUtils.elementFromDeclaration(node);
try {
if (TreeUtils.isAnonymousConstructor(node)) {
// We shouldn't dig deeper
return null;
}
// check method purity if needed
{
boolean anyPurityAnnotation = PurityUtils.hasPurityAnnotation(atypeFactory, node);
boolean checkPurityAlways = checker.hasOption("suggestPureMethods");
boolean checkPurityAnnotations = checker.hasOption("checkPurityAnnotations");
if (checkPurityAnnotations && (anyPurityAnnotation || checkPurityAlways)) {
// check "no" purity
List<Pure.Kind> kinds = PurityUtils.getPurityKinds(atypeFactory, node);
// @Deterministic makes no sense for a void method or constructor
boolean isDeterministic = kinds.contains(Pure.Kind.DETERMINISTIC);
if (isDeterministic) {
if (TreeUtils.isConstructor(node)) {
checker.report(Result.warning("purity.deterministic.constructor"), node);
} else if (TreeUtils.typeOf(node.getReturnType()).getKind() == TypeKind.VOID) {
checker.report(Result.warning("purity.deterministic.void.method"), node);
}
}
// Report errors if necessary.
PurityResult r = PurityChecker.checkPurity(atypeFactory.getPath(node.getBody()), atypeFactory, checker.hasOption("assumeSideEffectFree"));
if (!r.isPure(kinds)) {
reportPurityErrors(r, node, kinds);
}
// as such (if the feature is activated).
if (checkPurityAlways) {
Collection<Pure.Kind> additionalKinds = new HashSet<>(r.getTypes());
additionalKinds.removeAll(kinds);
if (TreeUtils.isConstructor(node)) {
additionalKinds.remove(Pure.Kind.DETERMINISTIC);
}
if (!additionalKinds.isEmpty()) {
if (additionalKinds.size() == 2) {
checker.report(Result.warning("purity.more.pure", node.getName()), node);
} else if (additionalKinds.contains(Pure.Kind.SIDE_EFFECT_FREE)) {
checker.report(Result.warning("purity.more.sideeffectfree", node.getName()), node);
} else if (additionalKinds.contains(Pure.Kind.DETERMINISTIC)) {
checker.report(Result.warning("purity.more.deterministic", node.getName()), node);
} else {
assert false : "BaseTypeVisitor reached undesirable state";
}
}
}
}
}
// Passing the whole method/constructor validates the return type
validateTypeOf(node);
// Validate types in throws clauses
for (ExpressionTree thr : node.getThrows()) {
validateTypeOf(thr);
}
if (atypeFactory.getDependentTypesHelper() != null) {
atypeFactory.getDependentTypesHelper().checkMethod(node, methodType);
}
AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(methodElement.getEnclosingElement());
// Find which method this overrides!
Map<AnnotatedDeclaredType, ExecutableElement> overriddenMethods = AnnotatedTypes.overriddenMethods(elements, atypeFactory, methodElement);
for (Map.Entry<AnnotatedDeclaredType, ExecutableElement> pair : overriddenMethods.entrySet()) {
AnnotatedDeclaredType overriddenType = pair.getKey();
AnnotatedExecutableType overriddenMethod = AnnotatedTypes.asMemberOf(types, atypeFactory, overriddenType, pair.getValue());
if (!checkOverride(node, enclosingType, overriddenMethod, overriddenType)) {
// the same method, not adding any value. See Issue 373.
break;
}
}
return super.visitMethod(node, p);
} finally {
boolean abstractMethod = methodElement.getModifiers().contains(Modifier.ABSTRACT) || methodElement.getModifiers().contains(Modifier.NATIVE);
// check well-formedness of pre/postcondition
List<String> formalParamNames = new ArrayList<>();
for (VariableTree param : node.getParameters()) {
formalParamNames.add(param.getName().toString());
}
checkContractsAtMethodDeclaration(node, methodElement, formalParamNames, abstractMethod);
visitorState.setMethodReceiver(preMRT);
visitorState.setMethodTree(preMT);
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class Analysis method init.
/**
* Initialize the analysis with a new control flow graph.
*/
protected void init(ControlFlowGraph cfg) {
this.cfg = cfg;
thenStores = new IdentityHashMap<>();
elseStores = new IdentityHashMap<>();
blockCount = maxCountBeforeWidening == -1 ? null : new IdentityHashMap<>();
inputs = new IdentityHashMap<>();
storesAtReturnStatements = new IdentityHashMap<>();
worklist = new Worklist(cfg);
nodeValues = new IdentityHashMap<>();
finalLocalValues = new HashMap<>();
worklist.add(cfg.getEntryBlock());
List<LocalVariableNode> parameters = null;
UnderlyingAST underlyingAST = cfg.getUnderlyingAST();
if (underlyingAST.getKind() == Kind.METHOD) {
MethodTree tree = ((CFGMethod) underlyingAST).getMethod();
parameters = new ArrayList<>();
for (VariableTree p : tree.getParameters()) {
LocalVariableNode var = new LocalVariableNode(p);
parameters.add(var);
// TODO: document that LocalVariableNode has no block that it
// belongs to
}
} else if (underlyingAST.getKind() == Kind.LAMBDA) {
LambdaExpressionTree lambda = ((CFGLambda) underlyingAST).getLambdaTree();
parameters = new ArrayList<>();
for (VariableTree p : lambda.getParameters()) {
LocalVariableNode var = new LocalVariableNode(p);
parameters.add(var);
// TODO: document that LocalVariableNode has no block that it
// belongs to
}
} else {
// nothing to do
}
S initialStore = transferFunction.initialStore(underlyingAST, parameters);
Block entry = cfg.getEntryBlock();
thenStores.put(entry, initialStore);
elseStores.put(entry, initialStore);
inputs.put(entry, new TransferInput<>(null, this, initialStore));
}
Aggregations