use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement 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)));
}
}
use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement in project checker-framework by typetools.
the class DOTCFGVisualizer method dotOutputFileName.
/**
* @return the file name used for DOT output.
*/
protected String dotOutputFileName(UnderlyingAST ast) {
StringBuilder srcloc = new StringBuilder();
StringBuilder outfile = new StringBuilder(outdir);
outfile.append('/');
if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) {
CFGStatement cfgs = (CFGStatement) ast;
String clsname = cfgs.getClassTree().getSimpleName().toString();
outfile.append(clsname);
outfile.append("-initializer-");
outfile.append(ast.hashCode());
srcloc.append('<');
srcloc.append(clsname);
srcloc.append("::initializer::");
srcloc.append(((JCTree) cfgs.getCode()).pos);
srcloc.append('>');
} else if (ast.getKind() == UnderlyingAST.Kind.METHOD) {
CFGMethod cfgm = (CFGMethod) ast;
String clsname = cfgm.getClassTree().getSimpleName().toString();
String methname = cfgm.getMethod().getName().toString();
outfile.append(clsname);
outfile.append('-');
outfile.append(methname);
srcloc.append('<');
srcloc.append(clsname);
srcloc.append("::");
srcloc.append(methname);
srcloc.append('(');
srcloc.append(cfgm.getMethod().getParameters());
srcloc.append(")::");
srcloc.append(((JCTree) cfgm.getMethod()).pos);
srcloc.append('>');
} else {
ErrorReporter.errorAbort("Unexpected AST kind: " + ast.getKind() + " value: " + ast.toString());
return null;
}
outfile.append('-');
outfile.append(checkerName);
outfile.append(".dot");
// make path safe for Windows
String out = outfile.toString().replace("<", "_").replace(">", "");
generated.put(srcloc.toString(), out);
return out;
}
use of org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement 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);
}
}
Aggregations