use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class AliasingTransfer method processPostconditions.
/**
* Handling pseudo-assignments. Called by {@code CFAbstractTransfer.visitMethodInvocation()}.
*
* <p>Case 2: Given a method call, traverses all formal parameters of the method declaration,
* and if it doesn't have the {@literal @}NonLeaked or {@literal @}LeakedToResult annotations,
* we remove the node of the respective argument in the method call from the store. If parameter
* has {@literal @}LeakedToResult, {@code visitMethodInvocation()} handles it.
*/
@Override
protected void processPostconditions(MethodInvocationNode n, CFStore store, ExecutableElement methodElement, Tree tree) {
super.processPostconditions(n, store, methodElement, tree);
if (TreeUtils.isEnumSuper(n.getTree())) {
// Skipping the init() method for enums.
return;
}
List<Node> args = n.getArguments();
List<? extends VariableElement> params = methodElement.getParameters();
assert (args.size() == params.size()) : "Number of arguments in " + "the method call " + n.toString() + " is different from the" + " number of parameters for the method declaration: " + methodElement.getSimpleName().toString();
AnnotatedExecutableType annotatedType = factory.getAnnotatedType(methodElement);
List<AnnotatedTypeMirror> paramTypes = annotatedType.getParameterTypes();
for (int i = 0; i < args.size(); i++) {
Node arg = args.get(i);
AnnotatedTypeMirror paramType = paramTypes.get(i);
if (!paramType.hasAnnotation(NonLeaked.class) && !paramType.hasAnnotation(LeakedToResult.class)) {
store.clearValue(FlowExpressions.internalReprOf(factory, arg));
}
}
// Now, doing the same as above for the receiver parameter
Node receiver = n.getTarget().getReceiver();
AnnotatedDeclaredType receiverType = annotatedType.getReceiverType();
if (receiverType != null && !receiverType.hasAnnotation(LeakedToResult.class) && !receiverType.hasAnnotation(NonLeaked.class)) {
store.clearValue(FlowExpressions.internalReprOf(factory, receiver));
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class BaseTypeVisitor method visitAnnotation.
/* TODO: something similar to visitReturn should be done.
* public Void visitThrow(ThrowTree node, Void p) {
* return super.visitThrow(node, p);
* }
*/
/**
* Ensure that the annotation arguments comply to their declarations. This needs some special
* casing, as annotation arguments form special trees.
*/
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
List<? extends ExpressionTree> args = node.getArguments();
if (args.isEmpty()) {
// Nothing to do if there are no annotation arguments.
return null;
}
TypeElement anno = (TypeElement) TreeInfo.symbol((JCTree) node.getAnnotationType());
Name annoName = anno.getQualifiedName();
if (annoName.contentEquals(DefaultQualifier.class.getName()) || annoName.contentEquals(SuppressWarnings.class.getName())) {
// Skip these two annotations, as we don't care about the arguments to them.
return null;
}
// Mapping from argument simple name to its annotated type.
Map<String, AnnotatedTypeMirror> annoTypes = new HashMap<>();
for (Element encl : ElementFilter.methodsIn(anno.getEnclosedElements())) {
AnnotatedExecutableType exeatm = (AnnotatedExecutableType) atypeFactory.getAnnotatedType(encl);
AnnotatedTypeMirror retty = exeatm.getReturnType();
annoTypes.put(encl.getSimpleName().toString(), retty);
}
for (ExpressionTree arg : args) {
if (!(arg instanceof AssignmentTree)) {
// TODO: when can this happen?
continue;
}
AssignmentTree at = (AssignmentTree) arg;
// we don't have a type for annotations.
if (at.getExpression().getKind() == Tree.Kind.ANNOTATION) {
visitAnnotation((AnnotationTree) at.getExpression(), p);
continue;
}
if (at.getExpression().getKind() == Tree.Kind.NEW_ARRAY) {
NewArrayTree nat = (NewArrayTree) at.getExpression();
boolean isAnno = false;
for (ExpressionTree init : nat.getInitializers()) {
if (init.getKind() == Tree.Kind.ANNOTATION) {
visitAnnotation((AnnotationTree) init, p);
isAnno = true;
}
}
if (isAnno) {
continue;
}
}
AnnotatedTypeMirror expected = annoTypes.get(at.getVariable().toString());
Pair<Tree, AnnotatedTypeMirror> preAssCtxt = visitorState.getAssignmentContext();
{
// Determine and set the new assignment context.
ExpressionTree var = at.getVariable();
assert var instanceof IdentifierTree : "Expected IdentifierTree as context. Found: " + var;
AnnotatedTypeMirror meth = atypeFactory.getAnnotatedType(var);
assert meth instanceof AnnotatedExecutableType : "Expected AnnotatedExecutableType as context. Found: " + meth;
AnnotatedTypeMirror newctx = ((AnnotatedExecutableType) meth).getReturnType();
visitorState.setAssignmentContext(Pair.of((Tree) null, newctx));
}
try {
AnnotatedTypeMirror actual = atypeFactory.getAnnotatedType(at.getExpression());
if (expected.getKind() != TypeKind.ARRAY) {
// Expected is not an array -> direct comparison.
commonAssignmentCheck(expected, actual, at.getExpression(), "annotation.type.incompatible");
} else {
if (actual.getKind() == TypeKind.ARRAY) {
// Both actual and expected are arrays.
commonAssignmentCheck(expected, actual, at.getExpression(), "annotation.type.incompatible");
} else {
// The declaration is an array type, but just a single
// element is given.
commonAssignmentCheck(((AnnotatedArrayType) expected).getComponentType(), actual, at.getExpression(), "annotation.type.incompatible");
}
}
} finally {
visitorState.setAssignmentContext(preAssCtxt);
}
}
return null;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class BaseTypeVisitor method visitMethodInvocation.
/**
* Performs a method invocation check.
*
* <p>An invocation of a method, m, on the receiver, r is valid only if:
*
* <ul>
* <li>passed arguments are subtypes of corresponding m parameters
* <li>r is a subtype of m receiver type
* <li>if m is generic, passed type arguments are subtypes of m type variables
* </ul>
*/
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
// hard to check), also see CFGBuilder.visitMethodInvocation.
if (TreeUtils.elementFromUse(node) == null || TreeUtils.isEnumSuper(node)) {
return super.visitMethodInvocation(node, p);
}
if (shouldSkipUses(node)) {
return super.visitMethodInvocation(node, p);
}
Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> mfuPair = atypeFactory.methodFromUse(node);
AnnotatedExecutableType invokedMethod = mfuPair.first;
List<AnnotatedTypeMirror> typeargs = mfuPair.second;
if (!atypeFactory.ignoreUninferredTypeArguments) {
for (AnnotatedTypeMirror typearg : typeargs) {
if (typearg.getKind() == TypeKind.WILDCARD && ((AnnotatedWildcardType) typearg).isUninferredTypeArgument()) {
checker.report(Result.failure("type.arguments.not.inferred", invokedMethod.getElement().getSimpleName()), node);
// only issue error once per method
break;
}
}
}
List<AnnotatedTypeParameterBounds> paramBounds = new ArrayList<>();
for (AnnotatedTypeVariable param : invokedMethod.getTypeVariables()) {
paramBounds.add(param.getBounds());
}
checkTypeArguments(node, paramBounds, typeargs, node.getTypeArguments());
List<AnnotatedTypeMirror> params = AnnotatedTypes.expandVarArgs(atypeFactory, invokedMethod, node.getArguments());
checkArguments(params, node.getArguments());
checkVarargs(invokedMethod, node);
if (isVectorCopyInto(invokedMethod)) {
typeCheckVectorCopyIntoArgument(node, params);
}
ExecutableElement invokedMethodElement = invokedMethod.getElement();
if (!ElementUtils.isStatic(invokedMethodElement) && !TreeUtils.isSuperCall(node)) {
checkMethodInvocability(invokedMethod, node);
}
// check precondition annotations
checkPreconditions(node, contractsUtils.getPreconditions(invokedMethodElement));
// Do not call super, as that would observe the arguments without
// a set assignment context.
scan(node.getMethodSelect(), p);
// super.visitMethodInvocation(node, p);
return null;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class BaseTypeVisitor method visitMethod.
/**
* Performs pseudo-assignment check: checks that the method obeys override and subtype rules to
* all overridden methods.
*
* <p>The override rule specifies that a method, m1, may override a method m2 only if:
*
* <ul>
* <li>m1 return type is a subtype of m2
* <li>m1 receiver type is a supertype of m2
* <li>m1 parameters are supertypes of corresponding m2 parameters
* </ul>
*
* Also, it issues a "missing.this" error for static method annotated receivers.
*/
@Override
public Void visitMethod(MethodTree node, Void p) {
// We copy the result from getAnnotatedType to ensure that
// circular types (e.g. K extends Comparable<K>) are represented
// by circular AnnotatedTypeMirrors, which avoids problems with
// later checks.
// TODO: Find a cleaner way to ensure circular AnnotatedTypeMirrors.
AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType(node).deepCopy();
AnnotatedDeclaredType preMRT = visitorState.getMethodReceiver();
MethodTree preMT = visitorState.getMethodTree();
visitorState.setMethodReceiver(methodType.getReceiverType());
visitorState.setMethodTree(node);
ExecutableElement methodElement = TreeUtils.elementFromDeclaration(node);
try {
if (TreeUtils.isAnonymousConstructor(node)) {
// We shouldn't dig deeper
return null;
}
// check method purity if needed
{
boolean anyPurityAnnotation = PurityUtils.hasPurityAnnotation(atypeFactory, node);
boolean checkPurityAlways = checker.hasOption("suggestPureMethods");
boolean checkPurityAnnotations = checker.hasOption("checkPurityAnnotations");
if (checkPurityAnnotations && (anyPurityAnnotation || checkPurityAlways)) {
// check "no" purity
List<Pure.Kind> kinds = PurityUtils.getPurityKinds(atypeFactory, node);
// @Deterministic makes no sense for a void method or constructor
boolean isDeterministic = kinds.contains(Pure.Kind.DETERMINISTIC);
if (isDeterministic) {
if (TreeUtils.isConstructor(node)) {
checker.report(Result.warning("purity.deterministic.constructor"), node);
} else if (TreeUtils.typeOf(node.getReturnType()).getKind() == TypeKind.VOID) {
checker.report(Result.warning("purity.deterministic.void.method"), node);
}
}
// Report errors if necessary.
PurityResult r = PurityChecker.checkPurity(atypeFactory.getPath(node.getBody()), atypeFactory, checker.hasOption("assumeSideEffectFree"));
if (!r.isPure(kinds)) {
reportPurityErrors(r, node, kinds);
}
// as such (if the feature is activated).
if (checkPurityAlways) {
Collection<Pure.Kind> additionalKinds = new HashSet<>(r.getTypes());
additionalKinds.removeAll(kinds);
if (TreeUtils.isConstructor(node)) {
additionalKinds.remove(Pure.Kind.DETERMINISTIC);
}
if (!additionalKinds.isEmpty()) {
if (additionalKinds.size() == 2) {
checker.report(Result.warning("purity.more.pure", node.getName()), node);
} else if (additionalKinds.contains(Pure.Kind.SIDE_EFFECT_FREE)) {
checker.report(Result.warning("purity.more.sideeffectfree", node.getName()), node);
} else if (additionalKinds.contains(Pure.Kind.DETERMINISTIC)) {
checker.report(Result.warning("purity.more.deterministic", node.getName()), node);
} else {
assert false : "BaseTypeVisitor reached undesirable state";
}
}
}
}
}
// Passing the whole method/constructor validates the return type
validateTypeOf(node);
// Validate types in throws clauses
for (ExpressionTree thr : node.getThrows()) {
validateTypeOf(thr);
}
if (atypeFactory.getDependentTypesHelper() != null) {
atypeFactory.getDependentTypesHelper().checkMethod(node, methodType);
}
AnnotatedDeclaredType enclosingType = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(methodElement.getEnclosingElement());
// Find which method this overrides!
Map<AnnotatedDeclaredType, ExecutableElement> overriddenMethods = AnnotatedTypes.overriddenMethods(elements, atypeFactory, methodElement);
for (Map.Entry<AnnotatedDeclaredType, ExecutableElement> pair : overriddenMethods.entrySet()) {
AnnotatedDeclaredType overriddenType = pair.getKey();
AnnotatedExecutableType overriddenMethod = AnnotatedTypes.asMemberOf(types, atypeFactory, overriddenType, pair.getValue());
if (!checkOverride(node, enclosingType, overriddenMethod, overriddenType)) {
// the same method, not adding any value. See Issue 373.
break;
}
}
return super.visitMethod(node, p);
} finally {
boolean abstractMethod = methodElement.getModifiers().contains(Modifier.ABSTRACT) || methodElement.getModifiers().contains(Modifier.NATIVE);
// check well-formedness of pre/postcondition
List<String> formalParamNames = new ArrayList<>();
for (VariableTree param : node.getParameters()) {
formalParamNames.add(param.getName().toString());
}
checkContractsAtMethodDeclaration(node, methodElement, formalParamNames, abstractMethod);
visitorState.setMethodReceiver(preMRT);
visitorState.setMethodTree(preMT);
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType in project checker-framework by typetools.
the class BaseTypeVisitor method visitNewClass.
/**
* Performs a new class invocation check.
*
* <p>An invocation of a constructor, c, is valid only if:
*
* <ul>
* <li>passed arguments are subtypes of corresponding c parameters
* <li>if c is generic, passed type arguments are subtypes of c type variables
* </ul>
*/
@Override
public Void visitNewClass(NewClassTree node, Void p) {
if (checker.shouldSkipUses(TreeUtils.constructor(node))) {
return super.visitNewClass(node, p);
}
Pair<AnnotatedExecutableType, List<AnnotatedTypeMirror>> fromUse = atypeFactory.constructorFromUse(node);
AnnotatedExecutableType constructor = fromUse.first;
List<AnnotatedTypeMirror> typeargs = fromUse.second;
List<? extends ExpressionTree> passedArguments = node.getArguments();
List<AnnotatedTypeMirror> params = AnnotatedTypes.expandVarArgs(atypeFactory, constructor, passedArguments);
checkArguments(params, passedArguments);
checkVarargs(constructor, node);
List<AnnotatedTypeParameterBounds> paramBounds = new ArrayList<>();
for (AnnotatedTypeVariable param : constructor.getTypeVariables()) {
paramBounds.add(param.getBounds());
}
checkTypeArguments(node, paramBounds, typeargs, node.getTypeArguments());
boolean valid = validateTypeOf(node);
if (valid) {
AnnotatedDeclaredType dt = atypeFactory.getAnnotatedType(node);
if (atypeFactory.getDependentTypesHelper() != null) {
atypeFactory.getDependentTypesHelper().checkType(dt, node);
}
checkConstructorInvocation(dt, constructor, node);
}
// Do not call super, as that would observe the arguments without
// a set assignment context.
scan(node.getEnclosingExpression(), p);
scan(node.getIdentifier(), p);
scan(node.getClassBody(), p);
return null;
}
Aggregations