public static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) { final HighlightInfo[] infos = new HighlightInfo[1]; final PsiAnnotationOwner owner = annotation.getOwner(); if (owner instanceof PsiModifierList) { final PsiElement parent = ((PsiModifierList) owner).getParent(); if (parent instanceof PsiClass) { annotation.accept( new JavaRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { if (infos[0] != null) return; super.visitElement(element); } @Override public void visitClassObjectAccessExpression( PsiClassObjectAccessExpression expression) { super.visitClassObjectAccessExpression(expression); final PsiTypeElement operand = expression.getOperand(); final PsiClass classType = PsiUtil.resolveClassInType(operand.getType()); if (classType != null) { checkAccessibility(expression, classType, HighlightUtil.formatClass(classType)); } } @Override public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); final PsiElement resolve = expression.resolve(); if (resolve instanceof PsiField) { checkAccessibility( expression, (PsiMember) resolve, HighlightUtil.formatField((PsiField) resolve)); } } private void checkAccessibility( PsiExpression expression, PsiMember resolve, String memberString) { if (resolve.hasModifierProperty(PsiModifier.PRIVATE) && PsiTreeUtil.isAncestor(parent, resolve, true)) { String description = JavaErrorMessages.message( "private.symbol", memberString, HighlightUtil.formatClass((PsiClass) parent)); infos[0] = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) .descriptionAndTooltip(description) .create(); } } }); } } return infos[0]; }
@Nullable private static String doCheckRepeatableAnnotation(@NotNull PsiAnnotation annotation) { PsiAnnotationOwner owner = annotation.getOwner(); if (!(owner instanceof PsiModifierList)) return null; PsiElement target = ((PsiModifierList) owner).getParent(); if (!(target instanceof PsiClass) || !((PsiClass) target).isAnnotationType()) return null; PsiClass container = getRepeatableContainer(annotation); if (container == null) return null; PsiMethod[] methods = container.findMethodsByName("value", false); if (methods.length == 0) { return JavaErrorMessages.message( "annotation.container.no.value", container.getQualifiedName()); } if (methods.length == 1) { PsiType expected = new PsiImmediateClassType((PsiClass) target, PsiSubstitutor.EMPTY).createArrayType(); if (!expected.equals(methods[0].getReturnType())) { return JavaErrorMessages.message( "annotation.container.bad.type", container.getQualifiedName(), JavaHighlightUtil.formatType(expected)); } } RetentionPolicy targetPolicy = getRetentionPolicy((PsiClass) target); if (targetPolicy != null) { RetentionPolicy containerPolicy = getRetentionPolicy(container); if (containerPolicy != null && targetPolicy.compareTo(containerPolicy) > 0) { return JavaErrorMessages.message( "annotation.container.low.retention", container.getQualifiedName(), containerPolicy); } } Set<PsiAnnotation.TargetType> repeatableTargets = PsiImplUtil.getAnnotationTargets((PsiClass) target); if (repeatableTargets != null) { Set<PsiAnnotation.TargetType> containerTargets = PsiImplUtil.getAnnotationTargets(container); if (containerTargets != null && !repeatableTargets.containsAll(containerTargets)) { return JavaErrorMessages.message( "annotation.container.wide.target", container.getQualifiedName()); } } return null; }
@Nullable public static HighlightInfo checkApplicability( @NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel, @NotNull PsiFile containingFile) { if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) { return null; } PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) return null; PsiAnnotationOwner owner = annotation.getOwner(); PsiAnnotation.TargetType[] targets = PsiImplUtil.getTargetsForLocation(owner); if (owner == null || targets.length == 0) { String message = JavaErrorMessages.message("annotation.not.allowed.here"); return annotationError(annotation, message); } if (!(owner instanceof PsiModifierList)) { HighlightInfo info = HighlightUtil.checkTypeAnnotationFeature(annotation, languageLevel, containingFile); if (info != null) return info; } PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget(annotation, targets); if (applicable == PsiAnnotation.TargetType.UNKNOWN) return null; if (applicable == null) { String target = JavaErrorMessages.message("annotation.target." + targets[0]); String message = JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), target); return annotationError(annotation, message); } if (applicable == PsiAnnotation.TargetType.TYPE_USE) { if (owner instanceof PsiClassReferenceType) { PsiJavaCodeReferenceElement ref = ((PsiClassReferenceType) owner).getReference(); HighlightInfo info = checkReferenceTarget(annotation, ref); if (info != null) return info; } else if (owner instanceof PsiModifierList) { PsiElement nextElement = PsiTreeUtil.skipSiblingsForward( (PsiModifierList) owner, PsiComment.class, PsiWhiteSpace.class, PsiTypeParameterList.class); if (nextElement instanceof PsiTypeElement) { PsiTypeElement typeElement = (PsiTypeElement) nextElement; PsiType type = typeElement.getType(); if (PsiType.VOID.equals(type)) { String message = JavaErrorMessages.message("annotation.not.allowed.void"); return annotationError(annotation, message); } if (!(type instanceof PsiPrimitiveType)) { PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement()); HighlightInfo info = checkReferenceTarget(annotation, ref); if (info != null) return info; } } } else if (owner instanceof PsiTypeElement) { PsiElement context = PsiTreeUtil.skipParentsOfType((PsiTypeElement) owner, PsiTypeElement.class); if (context instanceof PsiClassObjectAccessExpression) { String message = JavaErrorMessages.message("annotation.not.allowed.class"); return annotationError(annotation, message); } } } return null; }
static HighlightInfo checkDuplicateAnnotations(@NotNull PsiAnnotation annotationToCheck) { PsiAnnotationOwner owner = annotationToCheck.getOwner(); if (owner == null) return null; PsiJavaCodeReferenceElement element = annotationToCheck.getNameReferenceElement(); if (element == null) return null; PsiElement resolved = element.resolve(); if (!(resolved instanceof PsiClass)) return null; PsiClass annotationType = (PsiClass) resolved; PsiClass contained = contained(annotationType); String containedElementFQN = contained == null ? null : contained.getQualifiedName(); if (containedElementFQN != null) { PsiClass container = annotationType; String containerName = container.getQualifiedName(); if (isAnnotationRepeatedTwice(owner, containedElementFQN)) { String description = JavaErrorMessages.message("annotation.container.wrong.place", containerName); return annotationError(annotationToCheck, description); } } else if (isAnnotationRepeatedTwice(owner, annotationType.getQualifiedName())) { if (!PsiUtil.isLanguageLevel8OrHigher(annotationToCheck)) { String description = JavaErrorMessages.message("annotation.duplicate.annotation"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) .descriptionAndTooltip(description) .create(); } PsiAnnotation metaAnno = PsiImplUtil.findAnnotation( annotationType.getModifierList(), CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE); if (metaAnno == null) { String explanation = JavaErrorMessages.message( "annotation.non.repeatable", annotationType.getQualifiedName()); String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) .descriptionAndTooltip(description) .create(); } String explanation = doCheckRepeatableAnnotation(metaAnno); if (explanation != null) { String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(element) .descriptionAndTooltip(description) .create(); } PsiClass container = getRepeatableContainer(metaAnno); if (container != null) { PsiAnnotation.TargetType[] targets = PsiImplUtil.getTargetsForLocation(owner); PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget(container, targets); if (applicable == null) { String target = JavaErrorMessages.message("annotation.target." + targets[0]); String message = JavaErrorMessages.message( "annotation.container.not.applicable", container.getName(), target); return annotationError(annotationToCheck, message); } } } for (PsiAnnotation annotation : owner.getAnnotations()) { if (annotation == annotationToCheck) continue; PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) continue; PsiElement aClass = nameRef.resolve(); if (!resolved.equals(aClass)) continue; } return null; }