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