accessibility check for annotation parameters: treat parameters as they are outside the class (IDEA-165904)

This commit is contained in:
Anna.Kozlova
2016-12-27 14:47:58 +01:00
parent 17093c9f5a
commit a59edc4e4a
8 changed files with 34 additions and 57 deletions
@@ -445,55 +445,6 @@ public class AnnotationsHighlightUtil {
return ref;
}
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(operand.getInnermostComponentReferenceElement(), 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(PsiJavaCodeReferenceElement 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();
HighlightUtil.registerAccessQuickFixAction(resolve, expression, infos[0], null);
}
}
});
}
}
return infos[0];
}
@Nullable
static HighlightInfo checkAnnotationType(PsiAnnotation annotation) {
PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
@@ -241,7 +241,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation));
if (CommonClassNames.JAVA_LANG_OVERRIDE.equals(annotation.getQualifiedName())) {
@@ -122,9 +122,15 @@ public class JavaResolveUtil {
if (memberClass == null) {
return false;
}
// if resolving supertype reference, skip its containing class with getContextClass
PsiClass contextClass = member instanceof PsiClass ? getContextClass(place)
: PsiTreeUtil.getContextOfType(place, PsiClass.class, false);
PsiClass contextClass;
if (member instanceof PsiClass) {
// if resolving supertype reference, skip its containing class with getContextClass
contextClass = getContextClass(place);
}
else {
contextClass = PsiTreeUtil.getContextOfType(place, PsiClass.class, false);
if (isInClassAnnotationParameterList(place, contextClass)) return false;
}
while (contextClass != null) {
if (InheritanceUtil.isInheritorOrSelf(contextClass, memberClass, true)) {
if (member instanceof PsiClass ||
@@ -156,7 +162,8 @@ public class JavaResolveUtil {
if (fileResolveScope == null) {
PsiClass placeTopLevelClass = getTopLevelClass(place, null);
PsiClass memberTopLevelClass = getTopLevelClass(memberClass, null);
return manager.areElementsEquivalent(placeTopLevelClass, memberTopLevelClass);
return manager.areElementsEquivalent(placeTopLevelClass, memberTopLevelClass) &&
!isInClassAnnotationParameterList(place, PsiTreeUtil.getContextOfType(place, PsiClass.class, false));
}
else {
return fileResolveScope instanceof PsiClass &&
@@ -186,6 +193,16 @@ public class JavaResolveUtil {
return true;
}
private static boolean isInClassAnnotationParameterList(@NotNull PsiElement place, @Nullable PsiClass contextClass) {
if (contextClass != null) {
PsiAnnotation annotation = PsiTreeUtil.getContextOfType(place, PsiAnnotation.class, true);
if (annotation != null && contextClass.getModifierList() == annotation.getOwner()) {
return true;
}
}
return false;
}
private static boolean ignoreReferencedElementAccessibility(PsiFile placeFile) {
return placeFile instanceof FileResolveScopeProvider &&
((FileResolveScopeProvider) placeFile).ignoreReferencedElementAccessibility() &&
@@ -0,0 +1,4 @@
import a.A;
@SuppressWarnings(A.<error descr="'A_FOO' has protected access in 'a.A'">A_FOO</error>)
class B extends A {}
@@ -1,4 +1,4 @@
@SomeAnnotation(<error descr="'Foo.Bar' has private access in 'Foo'">Foo.Bar</error>.class)
@SomeAnnotation(Foo.<error descr="'Foo.Bar' has private access in 'Foo'">Bar</error>.class)
public class Foo{
private static class Bar {
}
@@ -1,4 +1,4 @@
@SuppressWarnings(<error descr="'ThisClass.FOO' has private access in 'ThisClass'">ThisClass.FOO</error>)
@SuppressWarnings(ThisClass.<error descr="'FOO' has private access in 'ThisClass'">FOO</error>)
public class ThisClass {
private static final String FOO = "foo";
}
@@ -1,4 +1,4 @@
@FooAnnotation(<error descr="'Foo.BAR' has private access in 'Foo'">Foo.BAR</error>)
@FooAnnotation(Foo.<error descr="'BAR' has private access in 'Foo'">BAR</error>)
class Foo {
private static final String BAR = "bar";
}
@@ -99,6 +99,12 @@ public class LightAdvHighlightingFixtureTest extends LightCodeInsightFixtureTest
myFixture.checkHighlighting();
}
public void testProtectedFieldUsedInAnnotationParameterOfInheritor() throws Exception {
myFixture.addClass("package a; public class A {protected final static String A_FOO = \"A\";}");
myFixture.configureByFile(getTestName(false) + ".java");
myFixture.checkHighlighting();
}
@Override
protected String getBasePath() {
return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/advFixture";