@Override public Void visitMemberSelect(MemberSelectTree tree, AnnotatedTypeMirror type) { if (TreeUtils.isFieldAccess(tree) && isUnderlyingTypeAValue(type)) { VariableElement elem = (VariableElement) InternalUtils.symbol(tree); Object value = elem.getConstantValue(); if (value != null) { // compile time constant type.replaceAnnotation( resultAnnotationHandler( type.getUnderlyingType(), Collections.singletonList(value), tree)); return null; } if (ElementUtils.isStatic(elem) && ElementUtils.isFinal(elem)) { Element e = InternalUtils.symbol(tree.getExpression()); if (e != null) { String classname = ElementUtils.getQualifiedClassName(e).toString(); String fieldName = tree.getIdentifier().toString(); value = evalutator.evaluateStaticFieldAccess(classname, fieldName, tree); if (value != null) type.replaceAnnotation( resultAnnotationHandler( type.getUnderlyingType(), Collections.singletonList(value), tree)); return null; } } if (tree.getIdentifier().toString().equals("length")) { AnnotatedTypeMirror receiverType = getAnnotatedType(tree.getExpression()); if (receiverType.getKind() == TypeKind.ARRAY) { AnnotationMirror arrayAnno = receiverType.getAnnotation(ArrayLen.class); if (arrayAnno != null) { // array.length, where array : @ArrayLen(x) List<Integer> lengths = ValueAnnotatedTypeFactory.getArrayLength(arrayAnno); type.replaceAnnotation(createNumberAnnotationMirror(new ArrayList<Number>(lengths))); return null; } } } } 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; }