use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class DOTCFGVisualizer method dotOutputFileName.
/**
* Create a dot file and return its name.
*
* @param ast an abstract syntax tree
* @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 cfgStatement = (CFGStatement) ast;
String clsName = cfgStatement.getSimpleClassName();
outFile.append(clsName);
outFile.append("-initializer-");
outFile.append(ast.getUid());
srcLoc.append("<");
srcLoc.append(clsName);
srcLoc.append("::initializer::");
srcLoc.append(((JCTree) cfgStatement.getCode()).pos);
srcLoc.append(">");
} else if (ast.getKind() == UnderlyingAST.Kind.METHOD) {
CFGMethod cfgMethod = (CFGMethod) ast;
String clsName = cfgMethod.getSimpleClassName();
String methodName = cfgMethod.getMethodName();
StringJoiner params = new StringJoiner(",");
for (VariableTree tree : cfgMethod.getMethod().getParameters()) {
params.add(tree.getType().toString());
}
outFile.append(clsName);
outFile.append("-");
outFile.append(methodName);
if (params.length() != 0) {
outFile.append("-");
outFile.append(params);
}
srcLoc.append("<");
srcLoc.append(clsName);
srcLoc.append("::");
srcLoc.append(methodName);
srcLoc.append("(");
srcLoc.append(params);
srcLoc.append(")::");
srcLoc.append(((JCTree) cfgMethod.getMethod()).pos);
srcLoc.append(">");
} else if (ast.getKind() == UnderlyingAST.Kind.LAMBDA) {
CFGLambda cfgLambda = (CFGLambda) ast;
String clsName = cfgLambda.getSimpleClassName();
String enclosingMethodName = cfgLambda.getEnclosingMethodName();
long uid = TreeUtils.treeUids.get(cfgLambda.getCode());
outFile.append(clsName);
outFile.append("-");
if (enclosingMethodName != null) {
outFile.append(enclosingMethodName);
outFile.append("-");
}
outFile.append(uid);
srcLoc.append("<");
srcLoc.append(clsName);
if (enclosingMethodName != null) {
srcLoc.append("::");
srcLoc.append(enclosingMethodName);
srcLoc.append("(");
// enclosingMethodName != null => getEnclosingMethod() != null
@SuppressWarnings("nullness") @NonNull MethodTree method = cfgLambda.getEnclosingMethod();
srcLoc.append(method.getParameters());
srcLoc.append(")");
}
srcLoc.append("::");
srcLoc.append(((JCTree) cfgLambda.getCode()).pos);
srcLoc.append(">");
} else {
throw new BugInCF("Unexpected AST kind: " + ast.getKind() + " value: " + ast);
}
if (checkerName != null && !checkerName.isEmpty()) {
outFile.append('-');
outFile.append(checkerName);
}
outFile.append(".dot");
// make path safe for Windows
String outFileName = outFile.toString().replace("<", "_").replace(">", "");
generated.put(srcLoc.toString(), outFileName);
return outFileName;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class AnnotatedTypeFactory method fromElement.
// **********************************************************************
// Factories for annotated types that do not account for default qualifiers.
// They only include qualifiers explicitly inserted by the user.
// **********************************************************************
/**
* Creates an AnnotatedTypeMirror for {@code elt} that includes: annotations explicitly written on
* the element and annotations from stub files.
*
* <p>Does not include default qualifiers. To obtain them, use {@link #getAnnotatedType(Element)}.
*
* <p>Does not include fake overrides from the stub file.
*
* @param elt the element
* @return AnnotatedTypeMirror of the element with explicitly-written and stub file annotations
*/
public AnnotatedTypeMirror fromElement(Element elt) {
if (shouldCache && elementCache.containsKey(elt)) {
return elementCache.get(elt).deepCopy();
}
if (elt.getKind() == ElementKind.PACKAGE) {
return toAnnotatedType(elt.asType(), false);
}
AnnotatedTypeMirror type;
// Because of a bug in Java 8, annotations on type parameters are not stored in elements, so get
// explicit annotations from the tree. (This bug has been fixed in Java 9.) Also, since
// annotations computed by the AnnotatedTypeFactory are stored in the element, the annotations
// have to be retrieved from the tree so that only explicit annotations are returned.
Tree decl = declarationFromElement(elt);
if (decl == null) {
type = stubTypes.getAnnotatedTypeMirror(elt);
if (type == null) {
type = toAnnotatedType(elt.asType(), ElementUtils.isTypeDeclaration(elt));
ElementAnnotationApplier.apply(type, elt, this);
}
} else if (decl instanceof ClassTree) {
type = fromClass((ClassTree) decl);
} else if (decl instanceof VariableTree) {
type = fromMember(decl);
} else if (decl instanceof MethodTree) {
type = fromMember(decl);
} else if (decl.getKind() == Tree.Kind.TYPE_PARAMETER) {
type = fromTypeTree(decl);
} else {
throw new BugInCF("AnnotatedTypeFactory.fromElement: cannot be here. decl: " + decl.getKind() + " elt: " + elt);
}
type = mergeAnnotationFileAnnosIntoType(type, elt, ajavaTypes);
if (currentFileAjavaTypes != null) {
type = mergeAnnotationFileAnnosIntoType(type, elt, currentFileAjavaTypes);
}
if (checker.hasOption("mergeStubsWithSource")) {
if (debugStubParser) {
System.out.printf("fromElement: mergeStubsIntoType(%s, %s)", type, elt);
}
type = mergeAnnotationFileAnnosIntoType(type, elt, stubTypes);
if (debugStubParser) {
System.out.printf(" => %s%n", type);
}
}
// method before the annotation files are fully read can return incorrect results.
if (shouldCache && !stubTypes.isParsing() && !ajavaTypes.isParsing() && (currentFileAjavaTypes == null || !currentFileAjavaTypes.isParsing())) {
elementCache.put(elt, type.deepCopy());
}
return type;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class AnnotatedTypeFactory method getFunctionalInterfaceType.
/**
* Get the AnnotatedDeclaredType for the FunctionalInterface from assignment context of the method
* reference or lambda expression which may be a variable assignment, a method call, or a cast.
*
* <p>The assignment context is not always correct, so we must search up the AST. It will
* recursively search for lambdas nested in lambdas.
*
* @param tree the tree of the lambda or method reference
* @return the functional interface type or an uninferred type argument
*/
private AnnotatedTypeMirror getFunctionalInterfaceType(Tree tree) {
Tree parentTree = getPath(tree).getParentPath().getLeaf();
switch(parentTree.getKind()) {
case PARENTHESIZED:
return getFunctionalInterfaceType(parentTree);
case TYPE_CAST:
TypeCastTree cast = (TypeCastTree) parentTree;
assert isFunctionalInterface(trees.getTypeMirror(getPath(cast.getType())), parentTree, tree);
AnnotatedTypeMirror castATM = getAnnotatedType(cast.getType());
if (castATM.getKind() == TypeKind.INTERSECTION) {
AnnotatedIntersectionType itype = (AnnotatedIntersectionType) castATM;
for (AnnotatedTypeMirror t : itype.directSupertypes()) {
if (TypesUtils.isFunctionalInterface(t.getUnderlyingType(), getProcessingEnv())) {
return t;
}
}
// and would have raised an error already.
throw new BugInCF("Expected the type of a cast tree in an assignment context to contain a functional" + " interface bound. Found type: %s for tree: %s in lambda tree: %s", castATM, cast, tree);
}
return castATM;
case NEW_CLASS:
NewClassTree newClass = (NewClassTree) parentTree;
int indexOfLambda = newClass.getArguments().indexOf(tree);
ParameterizedExecutableType con = this.constructorFromUse(newClass);
AnnotatedTypeMirror constructorParam = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(con.executableType, indexOfLambda);
assert isFunctionalInterface(constructorParam.getUnderlyingType(), parentTree, tree);
return constructorParam;
case NEW_ARRAY:
NewArrayTree newArray = (NewArrayTree) parentTree;
AnnotatedArrayType newArrayATM = getAnnotatedType(newArray);
AnnotatedTypeMirror elementATM = newArrayATM.getComponentType();
assert isFunctionalInterface(elementATM.getUnderlyingType(), parentTree, tree);
return elementATM;
case METHOD_INVOCATION:
MethodInvocationTree method = (MethodInvocationTree) parentTree;
int index = method.getArguments().indexOf(tree);
ParameterizedExecutableType exe = this.methodFromUse(method);
AnnotatedTypeMirror param = AnnotatedTypes.getAnnotatedTypeMirrorOfParameter(exe.executableType, index);
if (param.getKind() == TypeKind.WILDCARD) {
// param is an uninferred wildcard.
TypeMirror typeMirror = TreeUtils.typeOf(tree);
param = AnnotatedTypeMirror.createType(typeMirror, this, false);
addDefaultAnnotations(param);
}
assert isFunctionalInterface(param.getUnderlyingType(), parentTree, tree);
return param;
case VARIABLE:
VariableTree varTree = (VariableTree) parentTree;
assert isFunctionalInterface(TreeUtils.typeOf(varTree), parentTree, tree);
return getAnnotatedType(varTree.getType());
case ASSIGNMENT:
AssignmentTree assignmentTree = (AssignmentTree) parentTree;
assert isFunctionalInterface(TreeUtils.typeOf(assignmentTree), parentTree, tree);
return getAnnotatedType(assignmentTree.getVariable());
case RETURN:
Tree enclosing = TreePathUtil.enclosingOfKind(getPath(parentTree), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
if (enclosing.getKind() == Tree.Kind.METHOD) {
MethodTree enclosingMethod = (MethodTree) enclosing;
return getAnnotatedType(enclosingMethod.getReturnType());
} else {
LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) enclosing;
AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
return methodExe.getReturnType();
}
case LAMBDA_EXPRESSION:
LambdaExpressionTree enclosingLambda = (LambdaExpressionTree) parentTree;
AnnotatedExecutableType methodExe = getFunctionTypeFromTree(enclosingLambda);
return methodExe.getReturnType();
case CONDITIONAL_EXPRESSION:
ConditionalExpressionTree conditionalExpressionTree = (ConditionalExpressionTree) parentTree;
final AnnotatedTypeMirror falseType = getAnnotatedType(conditionalExpressionTree.getFalseExpression());
final AnnotatedTypeMirror trueType = getAnnotatedType(conditionalExpressionTree.getTrueExpression());
// Known cases where we must use LUB because falseType/trueType will not be equal:
// a) when one of the types is a type variable that extends a functional interface
// or extends a type variable that extends a functional interface
// b) When one of the two sides of the expression is a reference to a sub-interface.
// e.g. interface ConsumeStr {
// public void consume(String s)
// }
// interface SubConsumer extends ConsumeStr {
// default void someOtherMethod() { ... }
// }
// SubConsumer s = ...;
// ConsumeStr stringConsumer = (someCondition) ? s : System.out::println;
AnnotatedTypeMirror conditionalType = AnnotatedTypes.leastUpperBound(this, trueType, falseType);
assert isFunctionalInterface(conditionalType.getUnderlyingType(), parentTree, tree);
return conditionalType;
default:
throw new BugInCF("Could not find functional interface from assignment context. " + "Unexpected tree type: " + parentTree.getKind() + " For lambda tree: " + tree);
}
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class AnnotatedTypeFactory method getCurrentMethodReceiver.
/**
* Returns the receiver type of the method enclosing {@code tree}.
*
* <p>The method uses the parameter only if the most enclosing method cannot be found directly.
*
* @param tree the tree used to find the enclosing method.
* @return receiver type of the most enclosing method being visited
* @deprecated Use {@link #getSelfType(Tree)} instead.
*/
@Deprecated
@Nullable
protected final AnnotatedDeclaredType getCurrentMethodReceiver(Tree tree) {
TreePath path = getPath(tree);
if (path == null) {
return null;
}
// used for == test
@SuppressWarnings("interning:assignment") @InternedDistinct MethodTree enclosingMethod = TreePathUtil.enclosingMethod(path);
ClassTree enclosingClass = TreePathUtil.enclosingClass(path);
boolean found = false;
for (Tree member : enclosingClass.getMembers()) {
if (member.getKind() == Tree.Kind.METHOD) {
if (member == enclosingMethod) {
found = true;
}
}
}
if (found && enclosingMethod != null) {
AnnotatedExecutableType method = getAnnotatedType(enclosingMethod);
return method.getReceiverType();
} else {
// We are within an anonymous class or field initializer
return this.getAnnotatedType(enclosingClass);
}
}
use of com.sun.source.tree.MethodTree 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);
}
}
Aggregations