Search in sources :

Example 1 with CFGLambda

use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda in project checker-framework by typetools.

the class CFAbstractTransfer method initialStore.

/**
 * The initial store maps method formal parameters to their currently most refined type.
 */
@Override
public S initialStore(UnderlyingAST underlyingAST, @Nullable List<LocalVariableNode> parameters) {
    if (fixedInitialStore != null && underlyingAST.getKind() != Kind.LAMBDA && underlyingAST.getKind() != Kind.METHOD) {
        return fixedInitialStore;
    }
    S info = analysis.createEmptyStore(sequentialSemantics);
    if (underlyingAST.getKind() == Kind.METHOD) {
        if (fixedInitialStore != null) {
            // copy knowledge
            info = analysis.createCopiedStore(fixedInitialStore);
        }
        AnnotatedTypeFactory factory = analysis.getTypeFactory();
        for (LocalVariableNode p : parameters) {
            AnnotatedTypeMirror anno = factory.getAnnotatedType(p.getElement());
            info.initializeMethodParameter(p, analysis.createAbstractValue(anno));
        }
        // add properties known through precondition
        CFGMethod method = (CFGMethod) underlyingAST;
        MethodTree methodTree = method.getMethod();
        ExecutableElement methodElem = TreeUtils.elementFromDeclaration(methodTree);
        addInformationFromPreconditions(info, factory, method, methodTree, methodElem);
        final ClassTree classTree = method.getClassTree();
        addFieldValues(info, factory, classTree, methodTree);
        addFinalLocalValues(info, methodElem);
        if (shouldPerformWholeProgramInference(methodTree, methodElem)) {
            Map<AnnotatedDeclaredType, ExecutableElement> overriddenMethods = AnnotatedTypes.overriddenMethods(analysis.atypeFactory.getElementUtils(), analysis.atypeFactory, methodElem);
            for (Map.Entry<AnnotatedDeclaredType, ExecutableElement> pair : overriddenMethods.entrySet()) {
                AnnotatedExecutableType overriddenMethod = AnnotatedTypes.asMemberOf(analysis.atypeFactory.getProcessingEnv().getTypeUtils(), analysis.atypeFactory, pair.getKey(), pair.getValue());
                // Infers parameter and receiver types of the method based
                // on the overridden method.
                analysis.atypeFactory.getWholeProgramInference().updateInferredMethodParameterTypes(methodTree, methodElem, overriddenMethod, analysis.getTypeFactory());
                analysis.atypeFactory.getWholeProgramInference().updateInferredMethodReceiverType(methodTree, methodElem, overriddenMethod, analysis.getTypeFactory());
            }
        }
        return info;
    } else if (underlyingAST.getKind() == Kind.LAMBDA) {
        // Create a copy and keep only the field values (nothing else applies).
        info = analysis.createCopiedStore(fixedInitialStore);
        info.localVariableValues.clear();
        info.classValues.clear();
        info.arrayValues.clear();
        info.methodValues.clear();
        AnnotatedTypeFactory factory = analysis.getTypeFactory();
        for (LocalVariableNode p : parameters) {
            AnnotatedTypeMirror anno = factory.getAnnotatedType(p.getElement());
            info.initializeMethodParameter(p, analysis.createAbstractValue(anno));
        }
        CFGLambda lambda = (CFGLambda) underlyingAST;
        Tree enclosingTree = TreeUtils.enclosingOfKind(factory.getPath(lambda.getLambdaTree()), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, // Tree.Kind for which TreeUtils.isClassTree is true
        Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.ENUM)));
        Element enclosingElement = null;
        if (enclosingTree.getKind() == Tree.Kind.METHOD) {
            // If it is in an initializer, we need to use locals from the initializer.
            enclosingElement = TreeUtils.elementFromTree(enclosingTree);
        } else if (TreeUtils.isClassTree(enclosingTree)) {
            // Try to find an enclosing initializer block
            // Would love to know if there was a better way
            // Find any enclosing element of the lambda (using trees)
            // Then go up the elements to find an initializer element (which can't be found with
            // the tree).
            TreePath loopTree = factory.getPath(lambda.getLambdaTree()).getParentPath();
            Element anEnclosingElement = null;
            while (loopTree.getLeaf() != enclosingTree) {
                Element sym = TreeUtils.elementFromTree(loopTree.getLeaf());
                if (sym != null) {
                    anEnclosingElement = sym;
                    break;
                }
                loopTree = loopTree.getParentPath();
            }
            while (anEnclosingElement != null && !anEnclosingElement.equals(TreeUtils.elementFromTree(enclosingTree))) {
                if (anEnclosingElement.getKind() == ElementKind.INSTANCE_INIT || anEnclosingElement.getKind() == ElementKind.STATIC_INIT) {
                    enclosingElement = anEnclosingElement;
                    break;
                }
                anEnclosingElement = anEnclosingElement.getEnclosingElement();
            }
        }
        if (enclosingElement != null) {
            addFinalLocalValues(info, enclosingElement);
        }
        // We want the initialization stuff, but need to throw out any refinements.
        Map<FieldAccess, V> fieldValuesClone = new HashMap<>(info.fieldValues);
        for (Entry<FieldAccess, V> fieldValue : fieldValuesClone.entrySet()) {
            AnnotatedTypeMirror declaredType = factory.getAnnotatedType(fieldValue.getKey().getField());
            V lubbedValue = analysis.createAbstractValue(declaredType).leastUpperBound(fieldValue.getValue());
            info.fieldValues.put(fieldValue.getKey(), lubbedValue);
        }
    }
    return info;
}
Also used : CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ClassTree(com.sun.source.tree.ClassTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) Entry(java.util.Map.Entry) TreePath(com.sun.source.util.TreePath) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) GenericAnnotatedTypeFactory(org.checkerframework.framework.type.GenericAnnotatedTypeFactory) AnnotatedTypeFactory(org.checkerframework.framework.type.AnnotatedTypeFactory) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) CFGLambda(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda) Map(java.util.Map) HashMap(java.util.HashMap) HashSet(java.util.HashSet)

Example 2 with CFGLambda

use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda in project checker-framework by typetools.

the class GenericAnnotatedTypeFactory method analyze.

protected void analyze(Queue<ClassTree> queue, Queue<Pair<LambdaExpressionTree, Store>> lambdaQueue, UnderlyingAST ast, List<Pair<VariableElement, Value>> fieldValues, ClassTree currentClass, boolean isInitializationCode, boolean updateInitializationStore, boolean isStatic, Store lambdaStore) {
    CFGBuilder builder = new CFCFGBuilder(checker, this);
    ControlFlowGraph cfg = builder.run(root, processingEnv, ast);
    FlowAnalysis newAnalysis = createFlowAnalysis(fieldValues);
    TransferFunction transfer = newAnalysis.getTransferFunction();
    if (emptyStore == null) {
        emptyStore = newAnalysis.createEmptyStore(transfer.usesSequentialSemantics());
    }
    analyses.addFirst(newAnalysis);
    if (lambdaStore != null) {
        transfer.setFixedInitialStore(lambdaStore);
    } else {
        Store initStore = !isStatic ? initializationStore : initializationStaticStore;
        if (isInitializationCode) {
            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);
            }
        }
    }
    analyses.getFirst().performAnalysis(cfg);
    AnalysisResult<Value, Store> result = analyses.getFirst().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 = analyses.getFirst().getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(method, regularExitStore);
        }
        returnStatementStores.put(method, analyses.getFirst().getReturnStatementStores());
    } else if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) {
        CFGStatement block = (CFGStatement) ast;
        Store regularExitStore = analyses.getFirst().getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(block.getCode(), regularExitStore);
        }
    } else if (ast.getKind() == UnderlyingAST.Kind.LAMBDA) {
        // TODO: Postconditions?
        CFGLambda block = (CFGLambda) ast;
        Store regularExitStore = analyses.getFirst().getRegularExitStore();
        if (regularExitStore != null) {
            regularExitStores.put(block.getCode(), regularExitStore);
        }
    }
    if (isInitializationCode && updateInitializationStore) {
        Store newInitStore = analyses.getFirst().getRegularExitStore();
        if (!isStatic) {
            initializationStore = newInitStore;
        } else {
            initializationStaticStore = newInitStore;
        }
    }
    if (checker.hasOption("flowdotdir") || checker.hasOption("cfgviz")) {
        handleCFGViz();
    }
    analyses.removeFirst();
    // add classes declared in method
    queue.addAll(builder.getDeclaredClasses());
    for (LambdaExpressionTree lambda : builder.getDeclaredLambdas()) {
        lambdaQueue.add(Pair.of(lambda, getStoreBefore(lambda)));
    }
}
Also used : CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) MethodTree(com.sun.source.tree.MethodTree) CFGStatement(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement) CFCFGBuilder(org.checkerframework.framework.flow.CFCFGBuilder) CFGBuilder(org.checkerframework.dataflow.cfg.CFGBuilder) CFStore(org.checkerframework.framework.flow.CFStore) CFAbstractStore(org.checkerframework.framework.flow.CFAbstractStore) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ControlFlowGraph(org.checkerframework.dataflow.cfg.ControlFlowGraph) CFAbstractValue(org.checkerframework.framework.flow.CFAbstractValue) CFValue(org.checkerframework.framework.flow.CFValue) CFGLambda(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda) CFCFGBuilder(org.checkerframework.framework.flow.CFCFGBuilder)

Example 3 with CFGLambda

use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda 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.
 */
protected void performFlowAnalysis(ClassTree classTree) {
    if (flowResult == null) {
        regularExitStores = new IdentityHashMap<>();
        returnStatementStores = new IdentityHashMap<>();
        flowResult = new AnalysisResult<>(flowResultAnalysisCaches);
    }
    // no need to scan annotations
    if (classTree.getKind() == Kind.ANNOTATION_TYPE) {
        // Mark finished so that default annotations will be applied.
        scannedClasses.put(classTree, ScanState.FINISHED);
        return;
    }
    Queue<ClassTree> queue = new ArrayDeque<>();
    List<Pair<VariableElement, Value>> fieldValues = new ArrayList<>();
    queue.add(classTree);
    while (!queue.isEmpty()) {
        ClassTree ct = queue.remove();
        scannedClasses.put(ct, ScanState.IN_PROGRESS);
        AnnotatedDeclaredType preClassType = visitorState.getClassType();
        ClassTree preClassTree = visitorState.getClassTree();
        AnnotatedDeclaredType preAMT = visitorState.getMethodReceiver();
        MethodTree preMT = visitorState.getMethodTree();
        visitorState.setClassType(getAnnotatedType(ct));
        visitorState.setClassTree(ct);
        visitorState.setMethodReceiver(null);
        visitorState.setMethodTree(null);
        // start without a initialization store
        initializationStaticStore = null;
        initializationStore = null;
        Queue<Pair<LambdaExpressionTree, Store>> lambdaQueue = new ArrayDeque<>();
        try {
            List<CFGMethod> methods = new ArrayList<>();
            for (Tree m : ct.getMembers()) {
                switch(m.getKind()) {
                    case METHOD:
                        MethodTree mt = (MethodTree) m;
                        // Skip abstract and native methods because they have no body.
                        ModifiersTree modifiers = mt.getModifiers();
                        if (modifiers != null) {
                            Set<Modifier> flags = modifiers.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();
                        // 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);
                            Value value = flowResult.getValue(initializer);
                            if (value != null) {
                                // Store the abstract value for the field.
                                VariableElement element = TreeUtils.elementFromDeclaration(vt);
                                fieldValues.add(Pair.of(element, value));
                            }
                        }
                        break;
                    case CLASS:
                    case ANNOTATION_TYPE:
                    case INTERFACE:
                    case ENUM:
                        // Visit inner and nested class trees.
                        queue.add((ClassTree) m);
                        break;
                    case BLOCK:
                        BlockTree b = (BlockTree) m;
                        analyze(queue, lambdaQueue, new CFGStatement(b, ct), fieldValues, ct, true, true, b.isStatic());
                        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);
            }
            while (!lambdaQueue.isEmpty()) {
                Pair<LambdaExpressionTree, Store> lambdaPair = lambdaQueue.poll();
                analyze(queue, lambdaQueue, new CFGLambda(lambdaPair.first), fieldValues, classTree, false, false, false, lambdaPair.second);
            }
            // see InitializationVisitor.visitClass
            if (initializationStaticStore == null) {
                regularExitStores.put(ct, emptyStore);
            } else {
                regularExitStores.put(ct, initializationStaticStore);
            }
        } finally {
            visitorState.setClassType(preClassType);
            visitorState.setClassTree(preClassTree);
            visitorState.setMethodReceiver(preAMT);
            visitorState.setMethodTree(preMT);
        }
        scannedClasses.put(ct, ScanState.FINISHED);
    }
}
Also used : ModifiersTree(com.sun.source.tree.ModifiersTree) MethodTree(com.sun.source.tree.MethodTree) CFGMethod(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod) CFGStatement(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) ArrayList(java.util.ArrayList) VariableTree(com.sun.source.tree.VariableTree) CFStore(org.checkerframework.framework.flow.CFStore) CFAbstractStore(org.checkerframework.framework.flow.CFAbstractStore) VariableElement(javax.lang.model.element.VariableElement) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) AnnotatedDeclaredType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) BlockTree(com.sun.source.tree.BlockTree) ReturnTree(com.sun.source.tree.ReturnTree) 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) ModifiersTree(com.sun.source.tree.ModifiersTree) 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) CFAbstractValue(org.checkerframework.framework.flow.CFAbstractValue) CFValue(org.checkerframework.framework.flow.CFValue) CFGLambda(org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda)

Aggregations

MethodTree (com.sun.source.tree.MethodTree)3 CFGLambda (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda)3 CFGMethod (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod)3 ClassTree (com.sun.source.tree.ClassTree)2 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)2 Tree (com.sun.source.tree.Tree)2 VariableTree (com.sun.source.tree.VariableTree)2 VariableElement (javax.lang.model.element.VariableElement)2 CFGStatement (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement)2 CFAbstractStore (org.checkerframework.framework.flow.CFAbstractStore)2 CFAbstractValue (org.checkerframework.framework.flow.CFAbstractValue)2 CFStore (org.checkerframework.framework.flow.CFStore)2 CFValue (org.checkerframework.framework.flow.CFValue)2 AnnotatedDeclaredType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType)2 BlockTree (com.sun.source.tree.BlockTree)1 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)1 ExpressionTree (com.sun.source.tree.ExpressionTree)1 MemberReferenceTree (com.sun.source.tree.MemberReferenceTree)1 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)1 ModifiersTree (com.sun.source.tree.ModifiersTree)1