use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class FlowExpressions method getParametersOfEnclosingMethod.
/**
* Returns Receiver objects for the formal parameters of the method in which path is enclosed.
*
* @param annotationProvider annotationProvider
* @param path TreePath that is enclosed by the method
* @return list of Receiver objects for the formal parameters of the method in which path is
* enclosed
*/
public static List<Receiver> getParametersOfEnclosingMethod(AnnotationProvider annotationProvider, TreePath path) {
MethodTree methodTree = TreeUtils.enclosingMethod(path);
if (methodTree == null) {
return null;
}
List<Receiver> internalArguments = new ArrayList<>();
for (VariableTree arg : methodTree.getParameters()) {
internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg)));
}
return internalArguments;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class InterningVisitor method overridesEquals.
// **********************************************************************
// Helper methods
// **********************************************************************
/**
* Returns true if a class overrides Object.equals
*/
private boolean overridesEquals(ClassTree node) {
List<? extends Tree> members = node.getMembers();
for (Tree member : members) {
if (member instanceof MethodTree) {
MethodTree mTree = (MethodTree) member;
ExecutableElement enclosing = TreeUtils.elementFromDeclaration(mTree);
if (overrides(enclosing, Object.class, "equals")) {
return true;
}
}
}
return false;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class LockVisitor method visitSynchronized.
/**
* When visiting a synchronized block, issue an error if the expression has a type that
* implements the java.util.concurrent.locks.Lock interface. This prevents explicit locks from
* being accidentally used as built-in (monitor) locks. This is important because the Lock
* Checker does not have a mechanism to separately keep track of the explicit lock and the
* monitor lock of an expression that implements the Lock interface (i.e. there is a @LockHeld
* annotation used in dataflow, but there are not distinct @MonitorLockHeld
* and @ExplicitLockHeld annotations). It is assumed that both kinds of locks will never be held
* for any expression that implements Lock.
*
* <p>Additionally, a synchronized block may not be present in a method that has a @LockingFree
* guarantee or stronger. An error is issued in this case.
*
* @param node the SynchronizedTree for the synchronized block being visited
*/
@Override
public Void visitSynchronized(SynchronizedTree node, Void p) {
ProcessingEnvironment processingEnvironment = checker.getProcessingEnvironment();
javax.lang.model.util.Types types = processingEnvironment.getTypeUtils();
// TODO: make a type declaration annotation for this rather than looking for Lock.class
// explicitly.
TypeMirror lockInterfaceTypeMirror = TypesUtils.typeFromClass(Lock.class, types, processingEnvironment.getElementUtils());
ExpressionTree synchronizedExpression = node.getExpression();
ensureExpressionIsEffectivelyFinal(synchronizedExpression);
TypeMirror expressionType = types.erasure(atypeFactory.getAnnotatedType(synchronizedExpression).getUnderlyingType());
if (types.isSubtype(expressionType, lockInterfaceTypeMirror)) {
checker.report(Result.failure("explicit.lock.synchronized"), node);
}
MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(node));
ExecutableElement methodElement = null;
if (enclosingMethod != null) {
methodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
SideEffectAnnotation seaOfContainingMethod = atypeFactory.methodSideEffectAnnotation(methodElement, false);
if (!seaOfContainingMethod.isWeakerThan(SideEffectAnnotation.LOCKINGFREE)) {
checker.report(Result.failure("synchronized.block.in.lockingfree.method", seaOfContainingMethod), node);
}
}
return super.visitSynchronized(node, p);
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class LockVisitor method visitMethodInvocation.
/**
* When visiting a method invocation, issue an error if the side effect annotation on the called
* method causes the side effect guarantee of the enclosing method to be violated. For example,
* a method annotated with @ReleasesNoLocks may not call a method annotated
* with @MayReleaseLocks. Also check that matching @GuardSatisfied(index) on a method's formal
* receiver/parameters matches those in corresponding locations on the method call site.
*
* @param node the MethodInvocationTree of the method call being visited
*/
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
ExecutableElement methodElement = TreeUtils.elementFromUse(node);
SideEffectAnnotation seaOfInvokedMethod = atypeFactory.methodSideEffectAnnotation(methodElement, false);
MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(node));
ExecutableElement enclosingMethodElement = null;
if (enclosingMethod != null) {
enclosingMethodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
}
if (enclosingMethodElement != null) {
SideEffectAnnotation seaOfContainingMethod = atypeFactory.methodSideEffectAnnotation(enclosingMethodElement, false);
if (seaOfInvokedMethod.isWeakerThan(seaOfContainingMethod)) {
checker.report(Result.failure("method.guarantee.violated", seaOfContainingMethod.getNameOfSideEffectAnnotation(), enclosingMethodElement.toString(), methodElement.toString(), seaOfInvokedMethod.getNameOfSideEffectAnnotation()), node);
}
}
if (methodElement != null) {
// Handle releasing of explicit locks. Verify that the lock expression is effectively
// final.
ExpressionTree recvTree = getReceiverTree(node);
ensureReceiverOfExplicitUnlockCallIsEffectivelyFinal(node, methodElement, recvTree);
// Handle acquiring of explicit locks. Verify that the lock expression is effectively
// final.
// If the method causes expression "this" or "#1" to be locked, verify that those
// expressions are effectively final. TODO: generalize to any expression. This is
// currently designed only to support methods in ReentrantLock and
// ReentrantReadWriteLock (which use the "this" expression), as well as Thread.holdsLock
// (which uses the "#1" expression).
AnnotationMirror ensuresLockHeldAnno = atypeFactory.getDeclAnnotation(methodElement, EnsuresLockHeld.class);
List<String> expressions = new ArrayList<>();
if (ensuresLockHeldAnno != null) {
expressions.addAll(AnnotationUtils.getElementValueArray(ensuresLockHeldAnno, "value", String.class, false));
}
AnnotationMirror ensuresLockHeldIfAnno = atypeFactory.getDeclAnnotation(methodElement, EnsuresLockHeldIf.class);
if (ensuresLockHeldIfAnno != null) {
expressions.addAll(AnnotationUtils.getElementValueArray(ensuresLockHeldIfAnno, "expression", String.class, false));
}
for (String expr : expressions) {
if (expr.equals("this")) {
// are also final. So nothing to be checked for them.
if (recvTree != null) {
ensureExpressionIsEffectivelyFinal(recvTree);
}
} else if (expr.equals("#1")) {
ExpressionTree firstParameter = node.getArguments().get(0);
if (firstParameter != null) {
ensureExpressionIsEffectivelyFinal(firstParameter);
}
}
}
}
// Check that matching @GuardSatisfied(index) on a method's formal receiver/parameters
// matches
// those in corresponding locations on the method call site.
Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = atypeFactory.methodFromUse(node);
AnnotatedExecutableType invokedMethod = mfuPair.first;
List<AnnotatedTypeMirror> requiredArgs = AnnotatedTypes.expandVarArgs(atypeFactory, invokedMethod, node.getArguments());
// Index on @GuardSatisfied at each location. -1 when no @GuardSatisfied annotation was
// present.
// Note that @GuardSatisfied with no index is normally represented as having index -1.
// We would like to ignore a @GuardSatisfied with no index for these purposes, so if it is
// encountered we leave its index as -1.
// The first element of the array is reserved for the receiver.
int[] guardSatisfiedIndex = // + 1 for the receiver parameter type
new int[requiredArgs.size() + 1];
// Retrieve receiver types from method definition and method call
guardSatisfiedIndex[0] = -1;
AnnotatedTypeMirror methodDefinitionReceiver = null;
AnnotatedTypeMirror methodCallReceiver = null;
ExecutableElement invokedMethodElement = invokedMethod.getElement();
if (!ElementUtils.isStatic(invokedMethodElement) && invokedMethod.getElement().getKind() != ElementKind.CONSTRUCTOR) {
methodDefinitionReceiver = invokedMethod.getReceiverType();
if (methodDefinitionReceiver != null && methodDefinitionReceiver.hasAnnotation(checkerGuardSatisfiedClass)) {
guardSatisfiedIndex[0] = atypeFactory.getGuardSatisfiedIndex(methodDefinitionReceiver);
methodCallReceiver = atypeFactory.getReceiverType(node);
}
}
for (int i = 0; i < requiredArgs.size(); i++) {
guardSatisfiedIndex[i + 1] = -1;
AnnotatedTypeMirror arg = requiredArgs.get(i);
if (arg.hasAnnotation(checkerGuardSatisfiedClass)) {
guardSatisfiedIndex[i + 1] = atypeFactory.getGuardSatisfiedIndex(arg);
}
}
// Combine all of the actual parameters into one list of AnnotationMirrors
ArrayList<AnnotationMirror> passedArgAnnotations = new ArrayList<>(guardSatisfiedIndex.length);
passedArgAnnotations.add(methodCallReceiver == null ? null : methodCallReceiver.getAnnotationInHierarchy(atypeFactory.GUARDEDBYUNKNOWN));
for (ExpressionTree tree : node.getArguments()) {
passedArgAnnotations.add(atypeFactory.getAnnotatedType(tree).getAnnotationInHierarchy(atypeFactory.GUARDEDBYUNKNOWN));
}
for (int i = 0; i < guardSatisfiedIndex.length; i++) {
if (guardSatisfiedIndex[i] != -1) {
for (int j = i + 1; j < guardSatisfiedIndex.length; j++) {
if (guardSatisfiedIndex[i] == guardSatisfiedIndex[j]) {
// The @GuardedBy/@GuardSatisfied/@GuardedByUnknown/@GuardedByBottom
// annotations must be identical on the corresponding actual parameters.
AnnotationMirror arg1Anno = passedArgAnnotations.get(i);
AnnotationMirror arg2Anno = passedArgAnnotations.get(j);
if (arg1Anno != null && arg2Anno != null) {
boolean bothAreGSwithNoIndex = false;
if (AnnotationUtils.areSameByClass(arg1Anno, checkerGuardSatisfiedClass) && AnnotationUtils.areSameByClass(arg2Anno, checkerGuardSatisfiedClass)) {
if (atypeFactory.getGuardSatisfiedIndex(arg1Anno) == -1 && atypeFactory.getGuardSatisfiedIndex(arg2Anno) == -1) {
// Generally speaking, two @GuardSatisfied annotations with no
// index are incomparable.
// TODO: If they come from the same variable, they are
// comparable. Fix and add a test case.
bothAreGSwithNoIndex = true;
}
}
if (bothAreGSwithNoIndex || !(atypeFactory.getQualifierHierarchy().isSubtype(arg1Anno, arg2Anno) || atypeFactory.getQualifierHierarchy().isSubtype(arg2Anno, arg1Anno))) {
// TODO: allow these strings to be localized
String formalParam1 = null;
if (i == 0) {
formalParam1 = "The receiver type";
} else {
formalParam1 = "Parameter #" + // i, not i-1, so the index is 1-based
i;
}
String formalParam2 = // j, not j-1, so the index is 1-based
"parameter #" + j;
checker.report(Result.failure("guardsatisfied.parameters.must.match", formalParam1, formalParam2, invokedMethod.toString(), guardSatisfiedIndex[i], arg1Anno, arg2Anno), node);
}
}
}
}
}
}
return super.visitMethodInvocation(node, p);
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class FormatterVisitor method isWrappedFormatCall.
/**
* Returns true if fc is within a method m annotated as {@code @FormatMethod}, and fc's
* arguments are m's formal parameters. In other words, fc forwards m's arguments to another
* format method.
*/
private boolean isWrappedFormatCall(FormatCall fc) {
MethodTree enclosingMethod = TreeUtils.enclosingMethod(atypeFactory.getPath(fc.node));
if (enclosingMethod == null) {
return false;
}
ExecutableElement enclosingMethodElement = TreeUtils.elementFromDeclaration(enclosingMethod);
boolean withinFormatMethod = (atypeFactory.getDeclAnnotation(enclosingMethodElement, FormatMethod.class) != null);
if (!withinFormatMethod) {
return false;
}
List<? extends ExpressionTree> args = fc.node.getArguments();
List<? extends VariableTree> params = enclosingMethod.getParameters();
List<? extends VariableElement> paramElements = enclosingMethodElement.getParameters();
// Strip off leading Locale arguments.
if (args.size() > 0 && FormatterTreeUtil.isLocale(args.get(0), atypeFactory)) {
args = args.subList(1, args.size());
}
if (params.size() > 0 && TypesUtils.isDeclaredOfName(paramElements.get(0).asType(), "java.util.Locale")) {
params = params.subList(1, params.size());
}
if (args.size() == params.size()) {
for (int i = 0; i < args.size(); i++) {
ExpressionTree arg = args.get(i);
if (!(arg instanceof IdentifierTree && ((IdentifierTree) arg).getName().equals(params.get(i).getName()))) {
return false;
}
}
}
return true;
}
Aggregations