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);
}
}
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);
}
}
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);
}
Aggregations