use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class AnnotatedTypes method addTypeVarMappings.
private static void addTypeVarMappings(Types types, AnnotatedTypeFactory atypeFactory, AnnotatedTypeMirror t, TypeElement enclosingClassOfElem, Map<TypeVariable, AnnotatedTypeMirror> mappings) {
if (enclosingClassOfElem.getTypeParameters().isEmpty()) {
return;
}
AnnotatedDeclaredType enclosingType = atypeFactory.getAnnotatedType(enclosingClassOfElem);
AnnotatedDeclaredType base = (AnnotatedDeclaredType) asOuterSuper(types, atypeFactory, t, enclosingType);
final List<AnnotatedTypeVariable> ownerParams = new ArrayList<>(enclosingType.getTypeArguments().size());
for (final AnnotatedTypeMirror typeParam : enclosingType.getTypeArguments()) {
if (typeParam.getKind() != TypeKind.TYPEVAR) {
ErrorReporter.errorAbort("Type arguments of a declaration should be type variables\n" + "enclosingClassOfElem=" + enclosingClassOfElem + "\n" + "enclosingType=" + enclosingType + "\n" + "typeMirror=" + t);
}
ownerParams.add((AnnotatedTypeVariable) typeParam);
}
List<AnnotatedTypeMirror> baseParams = base.getTypeArguments();
if (ownerParams.size() != baseParams.size() && !base.wasRaw()) {
ErrorReporter.errorAbort("Unexpected number of parameters.\n" + "enclosingType=" + enclosingType + "\n" + "baseType=" + base);
}
if (!ownerParams.isEmpty() && baseParams.isEmpty() && base.wasRaw()) {
List<AnnotatedTypeMirror> newBaseParams = new ArrayList<>();
for (AnnotatedTypeVariable arg : ownerParams) {
// If base type was raw and the type arguments are missing,
// set them to the erased type of the type variable.
// (which is the erased type of the upper bound.)
newBaseParams.add(arg.getErased());
}
baseParams = newBaseParams;
}
for (int i = 0; i < ownerParams.size(); ++i) {
mappings.put(ownerParams.get(i).getUnderlyingType(), baseParams.get(i));
}
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType in project checker-framework by typetools.
the class AnnotatedTypes method getSuperTypes.
/**
* Returns all the super types of the given declared type.
*
* @param type a declared type
* @return all the supertypes of the given type
*/
public static Set<AnnotatedDeclaredType> getSuperTypes(AnnotatedDeclaredType type) {
Set<AnnotatedDeclaredType> supertypes = new LinkedHashSet<>();
if (type == null) {
return supertypes;
}
// Set up a stack containing the type mirror of subtype, which
// is our starting point.
Deque<AnnotatedDeclaredType> stack = new ArrayDeque<>();
stack.push(type);
while (!stack.isEmpty()) {
AnnotatedDeclaredType current = stack.pop();
// add it to our supertypes set.
for (AnnotatedDeclaredType supertype : current.directSuperTypes()) {
if (!supertypes.contains(supertype)) {
stack.push(supertype);
supertypes.add(supertype);
}
}
}
return Collections.unmodifiableSet(supertypes);
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType 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.AnnotatedDeclaredType in project checker-framework by typetools.
the class BaseTypeValidator method visitDeclared.
@Override
public Void visitDeclared(AnnotatedDeclaredType type, Tree tree) {
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
final boolean skipChecks = checker.shouldSkipUses(type.getUnderlyingType().asElement());
if (!skipChecks) {
// Ensure that type use is a subtype of the element type
// isValidUse determines the erasure of the types.
AnnotatedDeclaredType elemType = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(type.getUnderlyingType().asElement());
if (!visitor.isValidUse(elemType, type, tree)) {
reportInvalidAnnotationsOnUse(type, tree);
}
}
/*
* Try to reconstruct the ParameterizedTypeTree from the given tree.
* TODO: there has to be a nicer way to do this...
*/
Pair<ParameterizedTypeTree, AnnotatedDeclaredType> p = extractParameterizedTypeTree(tree, type);
ParameterizedTypeTree typeArgTree = p.first;
type = p.second;
if (typeArgTree == null) {
return super.visitDeclared(type, tree);
}
// else
// We put this here because we don't want to put it in visitedNodes before calling
// super (in the else branch) because that would cause the super implementation
// to detect that we've already visited type and to immediately return
visitedNodes.put(type, null);
// We have a ParameterizedTypeTree -> visit it.
visitParameterizedType(type, typeArgTree);
/*
* Instead of calling super with the unchanged "tree", adapt the
* second argument to be the corresponding type argument tree. This
* ensures that the first and second parameter to this method always
* correspond. visitDeclared is the only method that had this
* problem.
*/
List<? extends AnnotatedTypeMirror> tatypes = type.getTypeArguments();
if (tatypes == null) {
return null;
}
// May be zero for a "diamond" (inferred type args in constructor
// invocation).
int numTypeArgs = typeArgTree.getTypeArguments().size();
if (numTypeArgs != 0) {
// but I didn't manage to reduce it to a test case.
assert tatypes.size() <= numTypeArgs || skipChecks : "size mismatch for type arguments: " + type + " and " + typeArgTree;
for (int i = 0; i < tatypes.size(); ++i) {
scan(tatypes.get(i), typeArgTree.getTypeArguments().get(i));
}
}
return null;
}
use of org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType 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);
}
}
Aggregations