use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class BaseTypeVisitor method visitLambdaExpression.
@Override
public Void visitLambdaExpression(LambdaExpressionTree node, Void p) {
Pair<AnnotatedDeclaredType, AnnotatedExecutableType> result = atypeFactory.getFnInterfaceFromTree(node);
AnnotatedExecutableType functionType = result.second;
if (node.getBody().getKind() != Tree.Kind.BLOCK) {
// Check return type for single statement returns here.
AnnotatedTypeMirror ret = functionType.getReturnType();
if (ret.getKind() != TypeKind.VOID) {
visitorState.setAssignmentContext(Pair.of((Tree) node, ret));
commonAssignmentCheck(ret, (ExpressionTree) node.getBody(), "return.type.incompatible");
}
}
// Check parameters
for (int i = 0; i < functionType.getParameterTypes().size(); ++i) {
AnnotatedTypeMirror lambdaParameter = atypeFactory.getAnnotatedType(node.getParameters().get(i));
commonAssignmentCheck(lambdaParameter, functionType.getParameterTypes().get(i), node.getParameters().get(i), "lambda.param.type.incompatible");
}
return super.visitLambdaExpression(node, p);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType 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 org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class CFAbstractTransfer method getValueFromFactory.
/**
* @return the abstract value of a non-leaf tree {@code tree}, as computed by the {@link
* AnnotatedTypeFactory}.
*/
protected V getValueFromFactory(Tree tree, Node node) {
GenericAnnotatedTypeFactory<V, S, T, ? extends CFAbstractAnalysis<V, S, T>> factory = analysis.atypeFactory;
Tree preTree = analysis.getCurrentTree();
Pair<Tree, AnnotatedTypeMirror> preCtxt = factory.getVisitorState().getAssignmentContext();
analysis.setCurrentTree(tree);
// is there an assignment context node available?
if (node != null && node.getAssignmentContext() != null) {
// get the declared type of the assignment context by looking up the
// assignment context tree's type in the factory while flow is
// disabled.
Tree contextTree = node.getAssignmentContext().getContextTree();
AnnotatedTypeMirror assCtxt = null;
if (contextTree != null) {
assCtxt = factory.getAnnotatedTypeLhs(contextTree);
} else {
Element assCtxtElement = node.getAssignmentContext().getElementForType();
if (assCtxtElement != null) {
// if contextTree is null, use the element to get the type
assCtxt = factory.getAnnotatedType(assCtxtElement);
}
}
if (assCtxt != null) {
if (assCtxt instanceof AnnotatedExecutableType) {
// For a MethodReturnContext, we get the full type of the
// method, but we only want the return type.
assCtxt = ((AnnotatedExecutableType) assCtxt).getReturnType();
}
factory.getVisitorState().setAssignmentContext(Pair.of(node.getAssignmentContext().getContextTree(), assCtxt));
}
}
AnnotatedTypeMirror at = factory.getAnnotatedType(tree);
analysis.setCurrentTree(preTree);
factory.getVisitorState().setAssignmentContext(preCtxt);
return analysis.createAbstractValue(at);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class StubParser method processCallableDeclaration.
/**
* Adds type and declaration annotations from {@code decl}.
*/
private void processCallableDeclaration(CallableDeclaration<?> decl, ExecutableElement elt) {
// Declaration annotations
annotateDecl(declAnnos, elt, decl.getAnnotations());
if (decl.isMethodDeclaration()) {
// StubParser parses all annotations in type annotation position as type annotations
annotateDecl(declAnnos, elt, ((MethodDeclaration) decl).getType().getAnnotations());
}
addDeclAnnotations(declAnnos, elt);
AnnotatedExecutableType methodType = atypeFactory.fromElement(elt);
// Type Parameters
annotateTypeParameters(decl, elt, atypes, methodType.getTypeVariables(), decl.getTypeParameters());
typeParameters.addAll(methodType.getTypeVariables());
// Type annotations
if (decl.isMethodDeclaration()) {
annotate(methodType.getReturnType(), ((MethodDeclaration) decl).getType(), decl.getAnnotations());
} else {
annotate(methodType.getReturnType(), decl.getAnnotations());
}
// Parameters
processParameters(decl, elt, declAnnos, methodType);
// Receiver
if (decl.getReceiverParameter().isPresent() && !decl.getReceiverParameter().get().getAnnotations().isEmpty()) {
if (methodType.getReceiverType() == null) {
if (decl.isConstructorDeclaration()) {
stubWarn("parseParameter: constructor of a top-level class cannot have receiver annotations%n" + "Constructor: %s%n" + "Receiver annotations: %s", methodType, decl.getReceiverParameter().get().getAnnotations());
} else {
stubWarn("parseParameter: static methods cannot have receiver annotations%n" + "Method: %s%n" + "Receiver annotations: %s", methodType, decl.getReceiverParameter().get().getAnnotations());
}
} else {
annotate(methodType.getReceiverType(), decl.getReceiverParameter().get().getAnnotations());
}
}
// Store the type.
putNew(atypes, elt, methodType);
typeParameters.removeAll(methodType.getTypeVariables());
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class AnnotatedTypeCopier method visitExecutable.
@Override
public AnnotatedTypeMirror visitExecutable(AnnotatedExecutableType original, IdentityHashMap<AnnotatedTypeMirror, AnnotatedTypeMirror> originalToCopy) {
if (originalToCopy.containsKey(original)) {
return originalToCopy.get(original);
}
final AnnotatedExecutableType copy = (AnnotatedExecutableType) AnnotatedTypeMirror.createType(original.getUnderlyingType(), original.atypeFactory, original.isDeclaration());
maybeCopyPrimaryAnnotations(original, copy);
originalToCopy.put(original, copy);
copy.setElement(original.getElement());
if (original.receiverType != null) {
copy.receiverType = (AnnotatedDeclaredType) visit(original.receiverType, originalToCopy);
}
for (final AnnotatedTypeMirror param : original.paramTypes) {
copy.paramTypes.add(visit(param, originalToCopy));
}
for (final AnnotatedTypeMirror thrown : original.throwsTypes) {
copy.throwsTypes.add(visit(thrown, originalToCopy));
}
copy.returnType = visit(original.returnType, originalToCopy);
for (final AnnotatedTypeVariable typeVariable : original.typeVarTypes) {
// This field is needed to identify exactly when the declaration of an executable's
// type parameter is visited. When subtypes of this class visit the type parameter's
// component types, they will likely set visitingExecutableTypeParam to false.
// Therefore, we set this variable on each iteration of the loop.
// See TypeVariableSubstitutor.Visitor.visitTypeVariable for an example of this.
visitingExecutableTypeParam = true;
copy.typeVarTypes.add((AnnotatedTypeVariable) visit(typeVariable, originalToCopy));
}
visitingExecutableTypeParam = false;
return copy;
}
Aggregations