Java: Handle type parameter and type use annotations in the inspection "Non-accessible type is exposed" (IDEA-162768)

This commit is contained in:
Pavel Dolgov
2016-11-10 16:50:58 +03:00
parent 5f52d0539a
commit a1a9155c9c
2 changed files with 55 additions and 9 deletions
@@ -25,6 +25,7 @@ import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
@@ -109,16 +110,19 @@ public class Java9NonAccessibleTypeExposedInspection extends BaseJavaLocalInspec
PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null) {
PsiElement resolved = referenceElement.resolve();
if (resolved instanceof PsiClass && !isModulePublicApi((PsiClass)resolved)) {
PsiAnnotationOwner owner = annotation.getOwner();
if (isModulePublicApi(owner)) {
myHolder.registerProblem(referenceElement, CLASS_IS_NOT_EXPORTED);
}
if (owner instanceof PsiParameter) {
PsiElement parent = ((PsiParameter)owner).getParent();
if (parent instanceof PsiMember && isModulePublicApi((PsiMember)parent)) {
if (resolved instanceof PsiClass) {
PsiClass annotationClass = (PsiClass)resolved;
if (isInModuleSource(annotationClass) && !isModulePublicApi(annotationClass)) {
PsiAnnotationOwner owner = annotation.getOwner();
if (isModulePublicApi(owner)) {
myHolder.registerProblem(referenceElement, CLASS_IS_NOT_EXPORTED);
}
if (owner instanceof PsiParameter) {
PsiElement parent = ((PsiParameter)owner).getParent();
if (parent instanceof PsiMember && isModulePublicApi((PsiMember)parent)) {
myHolder.registerProblem(referenceElement, CLASS_IS_NOT_EXPORTED);
}
}
}
}
}
@@ -132,7 +136,7 @@ public class Java9NonAccessibleTypeExposedInspection extends BaseJavaLocalInspec
}
private void checkType(PsiClass psiClass, @NotNull PsiElement typeElement) {
if (psiClass != null && isInModuleSource(psiClass) && !isModulePublicApi(psiClass)) {
if (psiClass != null && !(psiClass instanceof PsiTypeParameter) && isInModuleSource(psiClass) && !isModulePublicApi(psiClass)) {
myHolder.registerProblem(typeElement, CLASS_IS_NOT_EXPORTED);
}
}
@@ -171,6 +175,19 @@ public class Java9NonAccessibleTypeExposedInspection extends BaseJavaLocalInspec
if (parent instanceof PsiMember) {
return isModulePublicApi((PsiMember)parent);
}
if (parent instanceof PsiReferenceParameterList) {
PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
return isModulePublicApi(method);
}
}
else if (owner instanceof PsiTypeParameter) {
PsiElement parent = ((PsiTypeParameter)owner).getParent();
if (parent instanceof PsiTypeParameterList) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiMember) {
return isModulePublicApi((PsiMember)grandParent);
}
}
}
return false;
}
@@ -217,6 +217,7 @@ public class Highlighted {
fun testPublicAnnotation() {
add("apiPkg", "MyAnnotation", "public @interface MyAnnotation {}")
highlight("""package apiPkg;
@MyAnnotation
public class Highlighted {
@MyAnnotation public PublicApi field;
@MyAnnotation public Highlighted() {}
@@ -231,6 +232,7 @@ public class Highlighted {
fun testPackageLocalAnnotation() {
add("apiPkg", "MyAnnotation", "@interface MyAnnotation {}")
highlight("""package apiPkg;
@<warning descr="The class is not exported from the module">MyAnnotation</warning>
public class Highlighted {
@<warning descr="The class is not exported from the module">MyAnnotation</warning> public PublicApi field;
@<warning descr="The class is not exported from the module">MyAnnotation</warning> public Highlighted() {}
@@ -246,6 +248,7 @@ public class Highlighted {
add("implPkg", "MyAnnotation", "public @interface MyAnnotation {}")
highlight("""package apiPkg;
import implPkg.MyAnnotation;
@<warning descr="The class is not exported from the module">MyAnnotation</warning>
public class Highlighted {
@<warning descr="The class is not exported from the module">MyAnnotation</warning> public PublicApi field;
@<warning descr="The class is not exported from the module">MyAnnotation</warning> public Highlighted() {}
@@ -257,6 +260,32 @@ public class Highlighted {
""")
}
fun testTypeParameterAndUseAnnotation() {
highlight("""package apiPkg;
import java.lang.annotation.*;
import java.util.*;
@Highlighted.PublicAnnotation
@<warning descr="The class is not exported from the module">Highlighted.PackageLocalAnnotation</warning>
public class Highlighted {
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) public @interface PublicAnnotation {}
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @interface PackageLocalAnnotation {}
public class C1<@PublicAnnotation T> {
public void foo(Set<@PublicAnnotation String> s) {}
protected <@PublicAnnotation X> void bar(X x) {}
protected List<@PublicAnnotation T> baz() { return new ArrayList<@PublicAnnotation T>();}
}
public class C2<@<warning descr="The class is not exported from the module">PackageLocalAnnotation</warning> T> {
public void foo(Set<@<warning descr="The class is not exported from the module">PackageLocalAnnotation</warning> String> s) {}
protected <@<warning descr="The class is not exported from the module">PackageLocalAnnotation</warning> X> void bar(X x) {}
protected List<@<warning descr="The class is not exported from the module">PackageLocalAnnotation</warning> T> baz() {
return new ArrayList<@<warning descr="The class is not exported from the module">PackageLocalAnnotation</warning> T>();
}
}
}
""")
}
private fun highlight(@Language("JAVA") @NotNull @NonNls text: String) {
val file = addFile("apiPkg/Highlighted.java", text, MAIN)
myFixture.configureFromExistingVirtualFile(file)