Search in sources :

Example 16 with LambdaExpressionTree

use of com.sun.source.tree.LambdaExpressionTree in project checker-framework by typetools.

the class DependentTypesHelper method atVariableDeclaration.

/**
 * Standardize the Java expressions in annotations in a variable declaration. Converts the
 * parameter syntax, e.g "#1", to the parameter name.
 *
 * @param type the type of the variable declaration; is side-effected by this method
 * @param declarationTree the variable declaration
 * @param variableElt the element of the variable declaration
 */
public void atVariableDeclaration(AnnotatedTypeMirror type, Tree declarationTree, VariableElement variableElt) {
    if (!hasDependentType(type)) {
        return;
    }
    TreePath pathToVariableDecl = factory.getPath(declarationTree);
    if (pathToVariableDecl == null) {
        // If this is a synthetic created by dataflow, the path will be null.
        return;
    }
    ElementKind variableKind = variableElt.getKind();
    if (ElementUtils.isBindingVariable(variableElt)) {
        // Treat binding variables the same as local variables.
        variableKind = ElementKind.LOCAL_VARIABLE;
    }
    switch(variableKind) {
        case PARAMETER:
            TreePath pathTillEnclTree = TreePathUtil.pathTillOfKind(pathToVariableDecl, METHOD_OR_LAMBDA);
            if (pathTillEnclTree == null) {
                throw new BugInCF("no enclosing method or lambda found for " + variableElt);
            }
            Tree enclTree = pathTillEnclTree.getLeaf();
            if (enclTree.getKind() == Tree.Kind.METHOD) {
                MethodTree methodDeclTree = (MethodTree) enclTree;
                StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodBody(stringExpr, methodDeclTree, factory.getChecker());
                if (debugStringToJavaExpression) {
                    System.out.printf("atVariableDeclaration(%s, %s, %s) 1 created %s%n", type, TreeUtils.toStringTruncated(declarationTree, 65), variableElt, stringToJavaExpr);
                }
                convertAnnotatedTypeMirror(stringToJavaExpr, type);
            } else {
                // Lambdas can use local variables defined in the enclosing method, so allow
                // identifiers to be locals in scope at the location of the lambda.
                StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atLambdaParameter(stringExpr, (LambdaExpressionTree) enclTree, pathToVariableDecl.getParentPath(), factory.getChecker());
                if (debugStringToJavaExpression) {
                    System.out.printf("atVariableDeclaration(%s, %s, %s) 2 created %s%n", type, TreeUtils.toStringTruncated(declarationTree, 65), variableElt, stringToJavaExpr);
                }
                convertAnnotatedTypeMirror(stringToJavaExpr, type);
            }
            break;
        case LOCAL_VARIABLE:
        case RESOURCE_VARIABLE:
        case EXCEPTION_PARAMETER:
            StringToJavaExpression stringToJavaExprVar = stringExpr -> StringToJavaExpression.atPath(stringExpr, pathToVariableDecl, factory.getChecker());
            if (debugStringToJavaExpression) {
                System.out.printf("atVariableDeclaration(%s, %s, %s) 3 created %s%n", type, TreeUtils.toStringTruncated(declarationTree, 65), variableElt, stringToJavaExprVar);
            }
            convertAnnotatedTypeMirror(stringToJavaExprVar, type);
            break;
        case FIELD:
        case ENUM_CONSTANT:
            StringToJavaExpression stringToJavaExprField = stringExpr -> StringToJavaExpression.atFieldDecl(stringExpr, variableElt, factory.getChecker());
            if (debugStringToJavaExpression) {
                System.out.printf("atVariableDeclaration(%s, %s, %s) 4 created %s%n", type, TreeUtils.toStringTruncated(declarationTree, 65), variableElt, stringToJavaExprField);
            }
            convertAnnotatedTypeMirror(stringToJavaExprField, type);
            break;
        default:
            throw new BugInCF("unexpected element kind " + variableElt.getKind() + " for " + variableElt);
    }
}
Also used : ElementKind(javax.lang.model.element.ElementKind) BugInCF(org.checkerframework.javacutil.BugInCF) TypeElement(javax.lang.model.element.TypeElement) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) Map(java.util.Map) Method(java.lang.reflect.Method) EnumSet(java.util.EnumSet) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) TreePath(com.sun.source.util.TreePath) Set(java.util.Set) Element(javax.lang.model.element.Element) MemberSelectTree(com.sun.source.tree.MemberSelectTree) TreeUtils(org.checkerframework.javacutil.TreeUtils) AnnotatedTypeParameterBounds(org.checkerframework.framework.type.AnnotatedTypeParameterBounds) Unknown(org.checkerframework.dataflow.expression.Unknown) TypeKind(javax.lang.model.type.TypeKind) TreeAnnotator(org.checkerframework.framework.type.treeannotator.TreeAnnotator) List(java.util.List) LocalVariable(org.checkerframework.dataflow.expression.LocalVariable) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) Annotation(java.lang.annotation.Annotation) ModifiersTree(com.sun.source.tree.ModifiersTree) TypesUtils(org.checkerframework.javacutil.TypesUtils) DoubleAnnotatedTypeScanner(org.checkerframework.framework.type.visitor.DoubleAnnotatedTypeScanner) AnnotatedTypeScanner(org.checkerframework.framework.type.visitor.AnnotatedTypeScanner) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) SourceChecker(org.checkerframework.framework.source.SourceChecker) VariableElement(javax.lang.model.element.VariableElement) VariableTree(com.sun.source.tree.VariableTree) HashMap(java.util.HashMap) Function(java.util.function.Function) ArrayList(java.util.ArrayList) NewClassTree(com.sun.source.tree.NewClassTree) TreePathUtil(org.checkerframework.javacutil.TreePathUtil) AnnotationBuilder(org.checkerframework.javacutil.AnnotationBuilder) Tree(com.sun.source.tree.Tree) AnnotationUtils(org.checkerframework.javacutil.AnnotationUtils) ClassTree(com.sun.source.tree.ClassTree) Nullable(org.checkerframework.checker.nullness.qual.Nullable) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) JavaExpressionParseException(org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException) ElementKind(javax.lang.model.element.ElementKind) ExpressionTree(com.sun.source.tree.ExpressionTree) ExecutableElement(javax.lang.model.element.ExecutableElement) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) JavaExpressionConverter(org.checkerframework.dataflow.expression.JavaExpressionConverter) JCTree(com.sun.tools.javac.tree.JCTree) AnnotationMirror(javax.lang.model.element.AnnotationMirror) SimpleAnnotatedTypeScanner(org.checkerframework.framework.type.visitor.SimpleAnnotatedTypeScanner) StringToJavaExpression(org.checkerframework.framework.util.StringToJavaExpression) AnnotatedTypeFactory(org.checkerframework.framework.type.AnnotatedTypeFactory) TypeMirror(javax.lang.model.type.TypeMirror) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment) FormalParameter(org.checkerframework.dataflow.expression.FormalParameter) Collections(java.util.Collections) ElementUtils(org.checkerframework.javacutil.ElementUtils) CollectionsPlume(org.plumelib.util.CollectionsPlume) TreePath(com.sun.source.util.TreePath) MethodTree(com.sun.source.tree.MethodTree) StringToJavaExpression(org.checkerframework.framework.util.StringToJavaExpression) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ModifiersTree(com.sun.source.tree.ModifiersTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ExpressionTree(com.sun.source.tree.ExpressionTree) JCTree(com.sun.tools.javac.tree.JCTree) BugInCF(org.checkerframework.javacutil.BugInCF)

Example 17 with LambdaExpressionTree

use of com.sun.source.tree.LambdaExpressionTree in project checker-framework by typetools.

the class AnnotatedTypeFactory method getFunctionalInterfaceType.

/**
 * Get the AnnotatedDeclaredType for the FunctionalInterface from assignment context of the method
 * reference or lambda expression which may be a variable assignment, a method call, or a cast.
 *
 * <p>The assignment context is not always correct, so we must search up the AST. It will
 * recursively search for lambdas nested in lambdas.
 *
 * @param tree the tree of the lambda or method reference
 * @return the functional interface type or an uninferred type argument
 */
private AnnotatedTypeMirror getFunctionalInterfaceType(Tree tree) {
    Tree parentTree = getPath(tree).getParentPath().getLeaf();
    switch(parentTree.getKind()) {
        case PARENTHESIZED:
            return getFunctionalInterfaceType(parentTree);
        case TYPE_CAST:
            TypeCastTree cast = (TypeCastTree) parentTree;
            assert isFunctionalInterface(trees.getTypeMirror(getPath(cast.getType())), parentTree, tree);
            AnnotatedTypeMirror castATM = getAnnotatedType(cast.getType());
            if (castATM.getKind() == TypeKind.INTERSECTION) {
                AnnotatedIntersectionType itype = (AnnotatedIntersectionType) castATM;
                for (AnnotatedTypeMirror t : itype.directSupertypes()) {
                    if (TypesUtils.isFunctionalInterface(t.getUnderlyingType(), getProcessingEnv())) {
                        return t;
                    }
                }
                // and would have raised an error already.
                throw new BugInCF("Expected the type of a cast tree in an assignment context to contain a functional" + " interface bound. Found type: %s for tree: %s in lambda tree: %s", castATM, cast, tree);
            }
            return castATM;
        case NEW_CLASS:
            NewClassTree newClass = (NewClassTree) parentTree;
            int indexOfLambda = newClass.getArguments().indexOf(tree);
            ParameterizedExecutableType con = this.constructorFromUse(newClass);
            AnnotatedTypeMirror constructorParam = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(con.executableType, indexOfLambda);
            assert isFunctionalInterface(constructorParam.getUnderlyingType(), parentTree, tree);
            return constructorParam;
        case NEW_ARRAY:
            NewArrayTree newArray = (NewArrayTree) parentTree;
            AnnotatedArrayType newArrayATM = getAnnotatedType(newArray);
            AnnotatedTypeMirror elementATM = newArrayATM.getComponentType();
            assert isFunctionalInterface(elementATM.getUnderlyingType(), parentTree, tree);
            return elementATM;
        case METHOD_INVOCATION:
            MethodInvocationTree method = (MethodInvocationTree) parentTree;
            int index = method.getArguments().indexOf(tree);
            ParameterizedExecutableType exe = this.methodFromUse(method);
            AnnotatedTypeMirror param = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(exe.executableType, index);
            if (param.getKind() == TypeKind.WILDCARD) {
                // param is an uninferred wildcard.
                TypeMirror typeMirror = TreeUtils.typeOf(tree);
                param = AnnotatedTypeMirror.createType(typeMirror, this, false);
                addDefaultAnnotations(param);
            }
            assert isFunctionalInterface(param.getUnderlyingType(), parentTree, tree);
            return param;
        case VARIABLE:
            VariableTree varTree = (VariableTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(varTree), parentTree, tree);
            return getAnnotatedType(varTree.getType());
        case ASSIGNMENT:
            AssignmentTree assignmentTree = (AssignmentTree) parentTree;
            assert isFunctionalInterface(TreeUtils.typeOf(assignmentTree), parentTree, tree);
            return getAnnotatedType(assignmentTree.getVariable());
        case RETURN:
            Tree enclosing = TreePathUtil.enclosingOfKind(getPath(parentTree), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
            if (enclosing.getKind() == Tree.Kind.METHOD) {
                MethodTree enclosingMethod = (MethodTree) enclosing;
                return getAnnotatedType(enclosingMethod.getReturnType());
            } else {
                LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) enclosing;
                AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
                return methodExe.getReturnType();
            }
        case LAMBDA_EXPRESSION:
            LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) parentTree;
            AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
            return methodExe.getReturnType();
        case CONDITIONAL_EXPRESSION:
            ConditionalExpressionTree conditionalExpressionTree = (ConditionalExpressionTree) parentTree;
            final AnnotatedTypeMirror falseType = getAnnotatedType(conditionalExpressionTree.getFalseExpression());
            final AnnotatedTypeMirror trueType = getAnnotatedType(conditionalExpressionTree.getTrueExpression());
            // Known cases where we must use LUB because falseType/trueType will not be equal:
            // a) when one of the types is a type variable that extends a functional interface
            // or extends a type variable that extends a functional interface
            // b) When one of the two sides of the expression is a reference to a sub-interface.
            // e.g.   interface ConsumeStr {
            // public void consume(String s)
            // }
            // interface SubConsumer extends ConsumeStr {
            // default void someOtherMethod() { ... }
            // }
            // SubConsumer s = ...;
            // ConsumeStr stringConsumer = (someCondition) ? s : System.out::println;
            AnnotatedTypeMirror conditionalType = AnnotatedTypes.leastUpperBound(this, trueType, falseType);
            assert isFunctionalInterface(conditionalType.getUnderlyingType(), parentTree, tree);
            return conditionalType;
        default:
            throw new BugInCF("Could not find functional interface from assignment context. " + "Unexpected tree type: " + parentTree.getKind() + " For lambda tree: " + tree);
    }
}
Also used : TypeCastTree(com.sun.source.tree.TypeCastTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) NewClassTree(com.sun.source.tree.NewClassTree) BugInCF(org.checkerframework.javacutil.BugInCF) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedIntersectionType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType) NewArrayTree(com.sun.source.tree.NewArrayTree) TypeMirror(javax.lang.model.type.TypeMirror) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) 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) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) NewArrayTree(com.sun.source.tree.NewArrayTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 18 with LambdaExpressionTree

use of com.sun.source.tree.LambdaExpressionTree in project checker-framework by typetools.

the class GenericAnnotatedTypeFactory method performFlowAnalysis.

/**
 * Perform a org.checkerframework.dataflow analysis over a single class tree and its nested
 * classes.
 *
 * @param classTree the class to analyze
 */
protected void performFlowAnalysis(ClassTree classTree) {
    if (flowResult == null) {
        regularExitStores = new IdentityHashMap<>();
        exceptionalExitStores = new IdentityHashMap<>();
        returnStatementStores = new IdentityHashMap<>();
        flowResult = new AnalysisResult<>(flowResultAnalysisCaches);
    }
    // no need to scan annotations
    if (classTree.getKind() == Tree.Kind.ANNOTATION_TYPE) {
        // Mark finished so that default annotations will be applied.
        scannedClasses.put(classTree, ScanState.FINISHED);
        return;
    }
    Queue<Pair<ClassTree, Store>> queue = new ArrayDeque<>();
    List<FieldInitialValue<Value>> fieldValues = new ArrayList<>();
    // No captured store for top-level classes.
    queue.add(Pair.of(classTree, null));
    while (!queue.isEmpty()) {
        final Pair<ClassTree, Store> qel = queue.remove();
        final ClassTree ct = qel.first;
        final Store capturedStore = qel.second;
        scannedClasses.put(ct, ScanState.IN_PROGRESS);
        TreePath preTreePath = getVisitorTreePath();
        // Don't use getPath, because that depends on the assignmentContext path.
        setVisitorTreePath(TreePath.getPath(this.root, ct));
        // start with the captured store as initialization store
        initializationStaticStore = capturedStore;
        initializationStore = capturedStore;
        Queue<Pair<LambdaExpressionTree, Store>> lambdaQueue = new ArrayDeque<>();
        try {
            List<CFGMethod> methods = new ArrayList<>();
            List<? extends Tree> members = ct.getMembers();
            if (!Ordering.from(sortVariablesFirst).isOrdered(members)) {
                members = new ArrayList<>(members);
                // Process variables before methods, so all field initializers are observed before the
                // constructor is analyzed and reports uninitialized variables.
                members.sort(sortVariablesFirst);
            }
            for (Tree m : members) {
                switch(TreeUtils.getKindRecordAsClass(m)) {
                    case METHOD:
                        MethodTree mt = (MethodTree) m;
                        // Skip abstract and native methods because they have no body.
                        Set<Modifier> flags = mt.getModifiers().getFlags();
                        if (flags.contains(Modifier.ABSTRACT) || flags.contains(Modifier.NATIVE)) {
                            break;
                        }
                        // ABSTRACT flag.
                        if (mt.getBody() == null) {
                            break;
                        }
                        // Wait with scanning the method until all other members
                        // have been processed.
                        CFGMethod met = new CFGMethod(mt, ct);
                        methods.add(met);
                        break;
                    case VARIABLE:
                        VariableTree vt = (VariableTree) m;
                        ExpressionTree initializer = vt.getInitializer();
                        AnnotatedTypeMirror declaredType = getAnnotatedTypeLhs(vt);
                        Value declaredValue = analysis.createAbstractValue(declaredType);
                        FieldAccess fieldExpr = (FieldAccess) JavaExpression.fromVariableTree(vt);
                        // analyze initializer if present
                        if (initializer != null) {
                            boolean isStatic = vt.getModifiers().getFlags().contains(Modifier.STATIC);
                            analyze(queue, lambdaQueue, new CFGStatement(vt, ct), fieldValues, classTree, true, true, isStatic, capturedStore);
                            Value initializerValue = flowResult.getValue(initializer);
                            if (initializerValue != null) {
                                fieldValues.add(new FieldInitialValue<>(fieldExpr, declaredValue, initializerValue));
                                break;
                            }
                        }
                        fieldValues.add(new FieldInitialValue<>(fieldExpr, declaredValue, null));
                        break;
                    // Including RECORD
                    case CLASS:
                    case ANNOTATION_TYPE:
                    case INTERFACE:
                    case ENUM:
                        // Visit inner and nested class trees.
                        // TODO: Use no store for them? What can be captured?
                        queue.add(Pair.of((ClassTree) m, capturedStore));
                        break;
                    case BLOCK:
                        BlockTree b = (BlockTree) m;
                        analyze(queue, lambdaQueue, new CFGStatement(b, ct), fieldValues, ct, true, true, b.isStatic(), capturedStore);
                        break;
                    default:
                        assert false : "Unexpected member: " + m.getKind();
                        break;
                }
            }
            // fields of superclasses.
            for (CFGMethod met : methods) {
                analyze(queue, lambdaQueue, met, fieldValues, classTree, TreeUtils.isConstructor(met.getMethod()), false, false, capturedStore);
            }
            while (!lambdaQueue.isEmpty()) {
                Pair<LambdaExpressionTree, Store> lambdaPair = lambdaQueue.poll();
                MethodTree mt = (MethodTree) TreePathUtil.enclosingOfKind(getPath(lambdaPair.first), Tree.Kind.METHOD);
                analyze(queue, lambdaQueue, new CFGLambda(lambdaPair.first, classTree, mt), fieldValues, classTree, false, false, false, lambdaPair.second);
            }
            // See InitializationVisitor.visitClass().
            if (initializationStaticStore == null) {
                regularExitStores.put(ct, emptyStore);
            } else {
                regularExitStores.put(ct, initializationStaticStore);
            }
        } finally {
            setVisitorTreePath(preTreePath);
        }
        scannedClasses.put(ct, ScanState.FINISHED);
    }
}
Also used : CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) MethodTree(com.sun.source.tree.MethodTree) CFGStatement(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement) ArrayList(java.util.ArrayList) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) VariableTree(com.sun.source.tree.VariableTree) CFStore(org.checkerframework.framework.flow.CFStore) CFAbstractStore(org.checkerframework.framework.flow.CFAbstractStore) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) BlockTree(com.sun.source.tree.BlockTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) MethodTree(com.sun.source.tree.MethodTree) ClassTree(com.sun.source.tree.ClassTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) BlockTree(com.sun.source.tree.BlockTree) Modifier(javax.lang.model.element.Modifier) Pair(org.checkerframework.javacutil.Pair) ArrayDeque(java.util.ArrayDeque) TreePath(com.sun.source.util.TreePath) FieldInitialValue(org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue) CFAbstractValue(org.checkerframework.framework.flow.CFAbstractValue) CFValue(org.checkerframework.framework.flow.CFValue) FieldInitialValue(org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue) CFGLambda(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess)

Example 19 with LambdaExpressionTree

use of com.sun.source.tree.LambdaExpressionTree in project checker-framework by typetools.

the class GenericAnnotatedTypeFactory method analyze.

/**
 * Analyze the AST {@code ast} and store the result. Additional operations that should be
 * performed after analysis should be implemented in {@link #postAnalyze(ControlFlowGraph)}.
 *
 * @param queue the queue for encountered class trees and their initial stores
 * @param lambdaQueue the queue for encountered lambda expression trees and their initial stores
 * @param ast the AST to analyze
 * @param fieldValues the abstract values for all fields of the same class
 * @param currentClass the class we are currently looking at
 * @param isInitializationCode are we analyzing a (static/non-static) initializer block of a class
 * @param updateInitializationStore should the initialization store be updated
 * @param isStatic are we analyzing a static construct
 * @param capturedStore the input Store to use for captured variables, e.g. in a lambda
 * @see #postAnalyze(org.checkerframework.dataflow.cfg.ControlFlowGraph)
 */
protected void analyze(Queue<Pair<ClassTree, Store>> queue, Queue<Pair<LambdaExpressionTree, Store>> lambdaQueue, UnderlyingAST ast, List<FieldInitialValue<Value>> fieldValues, ClassTree currentClass, boolean isInitializationCode, boolean updateInitializationStore, boolean isStatic, Store capturedStore) {
    ControlFlowGraph cfg = CFCFGBuilder.build(root, ast, checker, this, processingEnv);
    if (isInitializationCode) {
        Store initStore = !isStatic ? initializationStore : initializationStaticStore;
        if (initStore != null) {
            // we have already seen initialization code and analyzed it, and
            // the analysis ended with the store initStore.
            // use it to start the next analysis.
            transfer.setFixedInitialStore(initStore);
        } else {
            transfer.setFixedInitialStore(capturedStore);
        }
    } else {
        transfer.setFixedInitialStore(capturedStore);
    }
    analysis.performAnalysis(cfg, fieldValues);
    AnalysisResult<Value, Store> result = analysis.getResult();
    // store result
    flowResult.combine(result);
    if (ast.getKind() == UnderlyingAST.Kind.METHOD) {
        // store exit store (for checking postconditions)
        CFGMethod mast = (CFGMethod) ast;
        MethodTree method = mast.getMethod();
        Store regularExitStore = analysis.getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(method, regularExitStore);
        }
        Store exceptionalExitStore = analysis.getExceptionalExitStore();
        if (exceptionalExitStore != null) {
            exceptionalExitStores.put(method, exceptionalExitStore);
        }
        returnStatementStores.put(method, analysis.getReturnStatementStores());
    } else if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) {
        CFGStatement block = (CFGStatement) ast;
        Store regularExitStore = analysis.getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(block.getCode(), regularExitStore);
        }
        Store exceptionalExitStore = analysis.getExceptionalExitStore();
        if (exceptionalExitStore != null) {
            exceptionalExitStores.put(block.getCode(), exceptionalExitStore);
        }
    } else if (ast.getKind() == UnderlyingAST.Kind.LAMBDA) {
        // TODO: Postconditions?
        CFGLambda block = (CFGLambda) ast;
        Store regularExitStore = analysis.getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(block.getCode(), regularExitStore);
        }
        Store exceptionalExitStore = analysis.getExceptionalExitStore();
        if (exceptionalExitStore != null) {
            exceptionalExitStores.put(block.getCode(), exceptionalExitStore);
        }
    } else {
        assert false : "Unexpected AST kind: " + ast.getKind();
    }
    if (isInitializationCode && updateInitializationStore) {
        Store newInitStore = analysis.getRegularExitStore();
        if (!isStatic) {
            initializationStore = newInitStore;
        } else {
            initializationStaticStore = newInitStore;
        }
    }
    // add classes declared in CFG
    for (ClassTree cls : cfg.getDeclaredClasses()) {
        queue.add(Pair.of(cls, getStoreBefore(cls)));
    }
    // add lambdas declared in CFG
    for (LambdaExpressionTree lambda : cfg.getDeclaredLambdas()) {
        lambdaQueue.add(Pair.of(lambda, getStoreBefore(lambda)));
    }
    postAnalyze(cfg);
}
Also used : LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) MethodTree(com.sun.source.tree.MethodTree) CFGStatement(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement) ControlFlowGraph(org.checkerframework.dataflow.cfg.ControlFlowGraph) CFAbstractValue(org.checkerframework.framework.flow.CFAbstractValue) CFValue(org.checkerframework.framework.flow.CFValue) FieldInitialValue(org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) CFStore(org.checkerframework.framework.flow.CFStore) CFAbstractStore(org.checkerframework.framework.flow.CFAbstractStore) CFGLambda(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda)

Example 20 with LambdaExpressionTree

use of com.sun.source.tree.LambdaExpressionTree in project checker-framework by typetools.

the class TypeFromMemberVisitor method inferLambdaParamAnnotations.

/**
 * Returns the type of the lambda parameter, or null if paramElement is not a lambda parameter.
 *
 * @return the type of the lambda parameter, or null if paramElement is not a lambda parameter
 */
private static AnnotatedTypeMirror inferLambdaParamAnnotations(AnnotatedTypeFactory f, AnnotatedTypeMirror lambdaParam, Element paramElement) {
    if (paramElement.getKind() != ElementKind.PARAMETER || f.declarationFromElement(paramElement) == null || f.getPath(f.declarationFromElement(paramElement)) == null || f.getPath(f.declarationFromElement(paramElement)).getParentPath() == null) {
        return null;
    }
    Tree declaredInTree = f.getPath(f.declarationFromElement(paramElement)).getParentPath().getLeaf();
    if (declaredInTree.getKind() == Tree.Kind.LAMBDA_EXPRESSION) {
        LambdaExpressionTree lambdaDecl = (LambdaExpressionTree) declaredInTree;
        int index = lambdaDecl.getParameters().indexOf(f.declarationFromElement(paramElement));
        AnnotatedExecutableType functionType = f.getFunctionTypeFromTree(lambdaDecl);
        AnnotatedTypeMirror funcTypeParam = functionType.getParameterTypes().get(index);
        if (TreeUtils.isImplicitlyTypedLambda(declaredInTree)) {
            // type arguments are not substituted when the annotated type arguments are.
            if (TypesUtils.isErasedSubtype(funcTypeParam.underlyingType, lambdaParam.underlyingType, f.types)) {
                return AnnotatedTypes.asSuper(f, funcTypeParam, lambdaParam);
            }
            lambdaParam.addMissingAnnotations(funcTypeParam.getAnnotations());
            return lambdaParam;
        } else {
            // The lambda expression is explicitly typed, so the parameters have declared types:
            // (String s) -> ...
            // The declared type may or may not have explicit annotations.
            // If it does not have an annotation for a hierarchy, then copy the annotation from
            // the function type rather than use usual defaulting rules.
            // Note lambdaParam is a super type of funcTypeParam, so only primary annotations
            // can be copied.
            lambdaParam.addMissingAnnotations(funcTypeParam.getAnnotations());
            return lambdaParam;
        }
    }
    return null;
}
Also used : LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) Tree(com.sun.source.tree.Tree)

Aggregations

LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)22 MethodTree (com.sun.source.tree.MethodTree)19 VariableTree (com.sun.source.tree.VariableTree)15 ExpressionTree (com.sun.source.tree.ExpressionTree)14 Tree (com.sun.source.tree.Tree)13 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)12 NewClassTree (com.sun.source.tree.NewClassTree)11 ClassTree (com.sun.source.tree.ClassTree)10 ReturnTree (com.sun.source.tree.ReturnTree)9 AssignmentTree (com.sun.source.tree.AssignmentTree)8 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)7 AnnotationTree (com.sun.source.tree.AnnotationTree)6 MemberReferenceTree (com.sun.source.tree.MemberReferenceTree)6 MemberSelectTree (com.sun.source.tree.MemberSelectTree)6 AnnotatedExecutableType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType)6 TreePath (com.sun.source.util.TreePath)5 CFGMethod (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod)5 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)4 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)4 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)4