Search in sources :

Example 1 with FieldInitialValue

use of org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue in project checker-framework by typetools.

the class InitializationVisitor method processClassTree.

@Override
public void processClassTree(ClassTree node) {
    // them later when checking constructors.
    for (Tree member : node.getMembers()) {
        if (member.getKind() == Tree.Kind.BLOCK && !((BlockTree) member).isStatic()) {
            BlockTree block = (BlockTree) member;
            Store store = atypeFactory.getRegularExitStore(block);
            // Add field values for fields with an initializer.
            for (FieldInitialValue<Value> fieldInitialValue : store.getAnalysis().getFieldInitialValues()) {
                if (fieldInitialValue.initializer != null) {
                    store.addInitializedField(fieldInitialValue.fieldDecl.getField());
                }
            }
            final List<VariableTree> init = atypeFactory.getInitializedInvariantFields(store, getCurrentPath());
            initializedFields.addAll(init);
        }
    }
    super.processClassTree(node);
    // Warn about uninitialized static fields.
    Tree.Kind nodeKind = node.getKind();
    // must be initialized.  Java forbids uninitialized variables and static initalizer blocks.
    if (nodeKind != Tree.Kind.INTERFACE && nodeKind != Tree.Kind.ANNOTATION_TYPE) {
        boolean isStatic = true;
        // See GenericAnnotatedTypeFactory.performFlowAnalysis for why we use
        // the regular exit store of the class here.
        Store store = atypeFactory.getRegularExitStore(node);
        // Add field values for fields with an initializer.
        for (FieldInitialValue<Value> fieldInitialValue : store.getAnalysis().getFieldInitialValues()) {
            if (fieldInitialValue.initializer != null) {
                store.addInitializedField(fieldInitialValue.fieldDecl.getField());
            }
        }
        List<AnnotationMirror> receiverAnnotations = Collections.emptyList();
        checkFieldsInitialized(node, isStatic, store, receiverAnnotations);
    }
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) CFAbstractValue(org.checkerframework.framework.flow.CFAbstractValue) FieldInitialValue(org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue) VariableTree(com.sun.source.tree.VariableTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) TypeCastTree(com.sun.source.tree.TypeCastTree) NewClassTree(com.sun.source.tree.NewClassTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) BlockTree(com.sun.source.tree.BlockTree) BlockTree(com.sun.source.tree.BlockTree) CFAbstractStore(org.checkerframework.framework.flow.CFAbstractStore)

Example 2 with FieldInitialValue

use of org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue 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 3 with FieldInitialValue

use of org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue 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)

Aggregations

ClassTree (com.sun.source.tree.ClassTree)3 MethodTree (com.sun.source.tree.MethodTree)3 NewClassTree (com.sun.source.tree.NewClassTree)3 FieldInitialValue (org.checkerframework.framework.flow.CFAbstractAnalysis.FieldInitialValue)3 CFAbstractStore (org.checkerframework.framework.flow.CFAbstractStore)3 CFAbstractValue (org.checkerframework.framework.flow.CFAbstractValue)3 BlockTree (com.sun.source.tree.BlockTree)2 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)2 ExpressionTree (com.sun.source.tree.ExpressionTree)2 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)2 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)2 Tree (com.sun.source.tree.Tree)2 VariableTree (com.sun.source.tree.VariableTree)2 CFGLambda (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda)2 CFGMethod (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod)2 CFGStatement (org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement)2 CFStore (org.checkerframework.framework.flow.CFStore)2 CFValue (org.checkerframework.framework.flow.CFValue)2 MemberReferenceTree (com.sun.source.tree.MemberReferenceTree)1 TypeCastTree (com.sun.source.tree.TypeCastTree)1