@Override public Void visitNewClass(NewClassTree node, Void p) { AnnotatedDeclaredType type = atypeFactory.getAnnotatedType(node); ExpressionTree identifier = node.getIdentifier(); if (identifier instanceof AnnotatedTypeTree) { AnnotatedTypeTree t = (AnnotatedTypeTree) identifier; for (AnnotationMirror a : atypeFactory.getAnnotatedType(t).getAnnotations()) { // is this an annotation of the nullness checker? boolean nullnessCheckerAnno = containsSameIgnoringValues(atypeFactory.getNullnessAnnotations(), a); if (nullnessCheckerAnno && !AnnotationUtils.areSame(NONNULL, a)) { // The type is not non-null => warning checker.report(Result.warning("new.class.type.invalid", type.getAnnotations()), node); // Note that other consistency checks are made by isValid. } } if (t.toString().contains("@PolyNull")) { // TODO: this is a hack, but PolyNull gets substituted // afterwards checker.report(Result.warning("new.class.type.invalid", type.getAnnotations()), node); } } // TODO: It might be nicer to introduce a framework-level // isValidNewClassType or some such. return super.visitNewClass(node, p); }
@Override public Void visitExecutable(AnnotatedExecutableType t, Void p) { Void result = super.visitExecutable(t, p); Element elem = t.getElement(); if (elem.getKind() == ElementKind.CONSTRUCTOR) { AnnotatedDeclaredType returnType = (AnnotatedDeclaredType) t.getReturnType(); DeclaredType underlyingType = returnType.getUnderlyingType(); returnType.replaceAnnotation(getFreeOrRawAnnotationOfSuperType(underlyingType)); } return result; }
/** * Checks that the annotations on the type arguments supplied to a type or a method invocation are * within the bounds of the type variables as declared, and issues the * "type.argument.type.incompatible" error if they are not. * * <p>This method used to be visitParameterizedType, which incorrectly handles the main annotation * on generic types. */ protected Void visitParameterizedType(AnnotatedDeclaredType type, ParameterizedTypeTree tree) { // System.out.printf("TypeValidator.visitParameterizedType: type: %s, tree: %s\n", // type, tree); if (TreeUtils.isDiamondTree(tree)) return null; final TypeElement element = (TypeElement) type.getUnderlyingType().asElement(); if (checker.shouldSkipUses(element)) return null; List<AnnotatedTypeVariable> typevars = atypeFactory.typeVariablesFromUse(type, element); visitor.checkTypeArguments(tree, typevars, type.getTypeArguments(), tree.getTypeArguments()); return null; }
@Override public boolean isValidUse( AnnotatedDeclaredType declarationType, AnnotatedDeclaredType useType, Tree tree) { // At most a single qualifier on a type, ignoring a possible PolyAll // annotation. boolean foundInit = false; boolean foundNonNull = false; Set<Class<? extends Annotation>> initQuals = atypeFactory.getInitializationAnnotations(); Set<Class<? extends Annotation>> nonNullQuals = atypeFactory.getNullnessAnnotations(); for (AnnotationMirror anno : useType.getAnnotations()) { if (QualifierPolymorphism.isPolyAll(anno)) { // ok. } else if (containsSameIgnoringValues(initQuals, anno)) { if (foundInit) { return false; } foundInit = true; } else if (containsSameIgnoringValues(nonNullQuals, anno)) { if (foundNonNull) { return false; } foundNonNull = true; } } if (tree.getKind() == Tree.Kind.VARIABLE) { Element vs = InternalUtils.symbol(tree); switch (vs.getKind()) { case EXCEPTION_PARAMETER: if (useType.hasAnnotation(NULLABLE)) { // Exception parameters cannot use Nullable // annotations. They default to NonNull. return false; } break; default: // nothing to do break; } } // The super implementation checks that useType is a subtype // of declarationType. However, declarationType by default // is NonNull, which would then forbid Nullable uses. // Therefore, don't perform this check. return true; }
protected void setSelfTypeInInitializationCode( Tree tree, AnnotatedDeclaredType selfType, TreePath path) { ClassTree enclosingClass = TreeUtils.enclosingClass(path); Type classType = ((JCTree) enclosingClass).type; AnnotationMirror annotation = null; // If all fields are committed-only, and they are all initialized, // then it is save to switch to @UnderInitialization(CurrentClass). if (areAllFieldsCommittedOnly(enclosingClass)) { Store store = getStoreBefore(tree); if (store != null) { List<AnnotationMirror> annos = Collections.emptyList(); if (getUninitializedInvariantFields(store, path, false, annos).size() == 0) { if (useFbc) { annotation = createFreeAnnotation(classType); } else { annotation = createUnclassifiedAnnotation(classType); } } } } if (annotation == null) { annotation = getFreeOrRawAnnotationOfSuperType(classType); } selfType.replaceAnnotation(annotation); }
@Override public R visitDeclared(AnnotatedDeclaredType type, P p) { if (visitedNodes.containsKey(type)) { return visitedNodes.get(type); } visitedNodes.put(type, null); R r = scan(type.getTypeArguments(), p); return r; }
/** Adds extends/implements and class annotations to type. Annotates type parameters. */ @Override public void extractAndApply() { // ensures that we check that there only valid target types on this class, there are no // "targeted" locations super.extractAndApply(); // Annotate raw types //TODO: ASK WERNER WHAT THIS MIGHT MEAN? WHAT ACTUALLY GOES HERE? type.addAnnotations(typeSymbol.getAnnotationMirrors()); applyAllElementAnnotations( declaredType.getTypeArguments(), typeSymbol.getTypeParameters(), typeFactory); }
@Override public Void visitDeclared(AnnotatedDeclaredType type, Tree tree) { if (checker.shouldSkipUses(type.getUnderlyingType().asElement())) return super.visitDeclared(type, tree); { // 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)) { reportError(type, tree); } } // System.out.println("Type: " + type); // System.out.println("Tree: " + tree); // System.out.println("Tree kind: " + tree.getKind()); /* * 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) { // 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) { // TODO: this should be an equality, but in // http://buffalo.cs.washington.edu:8080/job/jdk6-daikon-typecheck/2061/console // it failed with: // daikon/Debug.java; message: size mismatch for type arguments: // @NonNull Object and Class<?> // but I didn't manage to reduce it to a test case. assert tatypes.size() <= numTypeArgs : "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; // Don't call the super version, because it creates a mismatch // between // the first and second parameters. // return super.visitDeclared(type, tree); } return super.visitDeclared(type, tree); }