Search in sources :

Example 16 with MethodTree

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);
    }
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) MethodTree(com.sun.source.tree.MethodTree) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ThrowTree(com.sun.source.tree.ThrowTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ReturnTree(com.sun.source.tree.ReturnTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) TypeParameterTree(com.sun.source.tree.TypeParameterTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) NewArrayTree(com.sun.source.tree.NewArrayTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) JCTree(com.sun.tools.javac.tree.JCTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 17 with MethodTree

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;
        }
    }
}
Also used : AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeVariable(javax.lang.model.type.TypeVariable) MethodTree(com.sun.source.tree.MethodTree) TypeElement(javax.lang.model.element.TypeElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ClassTree(com.sun.source.tree.ClassTree) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 18 with MethodTree

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);
        }
    }
}
Also used : Types(javax.lang.model.util.Types) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) Symbol(com.sun.tools.javac.code.Symbol) VariableTree(com.sun.source.tree.VariableTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) TypeParameterTree(com.sun.source.tree.TypeParameterTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) JCTree(com.sun.tools.javac.tree.JCTree)

Example 19 with MethodTree

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);
    }
}
Also used : PurityResult(org.checkerframework.dataflow.util.PurityChecker.PurityResult) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) VariableTree(com.sun.source.tree.VariableTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) Collection(java.util.Collection) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map) HashMap(java.util.HashMap) Pure(org.checkerframework.dataflow.qual.Pure)

Example 20 with MethodTree

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));
}
Also used : MethodTree(com.sun.source.tree.MethodTree) CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) IdentityHashMap(java.util.IdentityHashMap) VariableTree(com.sun.source.tree.VariableTree) ArrayList(java.util.ArrayList) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) SpecialBlock(org.checkerframework.dataflow.cfg.block.SpecialBlock) Block(org.checkerframework.dataflow.cfg.block.Block) RegularBlock(org.checkerframework.dataflow.cfg.block.RegularBlock) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) UnderlyingAST(org.checkerframework.dataflow.cfg.UnderlyingAST)

Aggregations

MethodTree (com.sun.source.tree.MethodTree)91 Tree (com.sun.source.tree.Tree)46 ClassTree (com.sun.source.tree.ClassTree)45 VariableTree (com.sun.source.tree.VariableTree)39 ExpressionTree (com.sun.source.tree.ExpressionTree)36 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)28 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)22 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)20 TreePath (com.sun.source.util.TreePath)20 IdentifierTree (com.sun.source.tree.IdentifierTree)19 NewClassTree (com.sun.source.tree.NewClassTree)19 ReturnTree (com.sun.source.tree.ReturnTree)18 ExecutableElement (javax.lang.model.element.ExecutableElement)17 Symbol (com.sun.tools.javac.code.Symbol)16 ArrayList (java.util.ArrayList)15 AssignmentTree (com.sun.source.tree.AssignmentTree)14 BlockTree (com.sun.source.tree.BlockTree)14 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)14 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)14 MemberSelectTree (com.sun.source.tree.MemberSelectTree)14