diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index 2860c23f0fda..4b886a80666d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -2764,7 +2764,7 @@ implementationClass="com.siyeh.ig.visibility.AnonymousClassVariableHidesContainingMethodVariableInspection"/> checkers = new ArrayList<>(2); - PsiFile file = holder.getFile(); - if (file instanceof PsiJavaFile) { - PsiJavaFile javaFile = (PsiJavaFile)file; - if (javaFile.getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_9)) { - PsiJavaModule psiModule = JavaModuleGraphUtil.findDescriptorByElement(file); - if (psiModule != null) { - VirtualFile vFile = file.getVirtualFile(); - if (vFile != null) { - Module module = ProjectFileIndex.SERVICE.getInstance(holder.getProject()).getModuleForFile(vFile); - if (module != null) { - Set exportedPackageNames = - new THashSet<>(ContainerUtil.mapNotNull(psiModule.getExports(), PsiExportsStatement::getPackageName)); - if (exportedPackageNames.contains(javaFile.getPackageName())) { - checkers.add(new Java9NonAccessibleTypeExposedVisitor(holder, module, exportedPackageNames)); + if (checkModuleApi) { + PsiFile file = holder.getFile(); + if (file instanceof PsiJavaFile) { + PsiJavaFile javaFile = (PsiJavaFile)file; + if (javaFile.getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_9)) { + PsiJavaModule psiModule = JavaModuleGraphUtil.findDescriptorByElement(file); + if (psiModule != null) { + VirtualFile vFile = file.getVirtualFile(); + if (vFile != null) { + Module module = ProjectFileIndex.SERVICE.getInstance(holder.getProject()).getModuleForFile(vFile); + if (module != null) { + Set exportedPackageNames = + new THashSet<>(ContainerUtil.mapNotNull(psiModule.getExports(), PsiExportsStatement::getPackageName)); + if (exportedPackageNames.contains(javaFile.getPackageName())) { + checkers.add(new Java9NonAccessibleTypeExposedVisitor(holder, module, exportedPackageNames)); + } } } } } } } - if (!onlyJava9Modules) { + if (checkPublicApi || checkPackageLocal) { checkers.add(new ClassEscapesItsScopeVisitor(holder)); } - return new VisibilityVisitor(checkers.toArray(VisibilityChecker.EMPTY_ARRAY)); + return !checkers.isEmpty() ? new VisibilityVisitor(checkers.toArray(VisibilityChecker.EMPTY_ARRAY)) : PsiElementVisitor.EMPTY_VISITOR; } private static class VisibilityVisitor extends JavaElementVisitor { @@ -153,21 +157,26 @@ public class ClassEscapesItsScopeInspection extends BaseJavaBatchLocalInspection abstract boolean checkVisibilityIssue(PsiMember member, PsiClass psiClass, PsiJavaCodeReferenceElement reference); } - private static class ClassEscapesItsScopeVisitor extends VisibilityChecker { + private class ClassEscapesItsScopeVisitor extends VisibilityChecker { public ClassEscapesItsScopeVisitor(ProblemsHolder holder) { super(holder); } @Override boolean checkVisibilityIssue(PsiMember member, PsiClass psiClass, PsiJavaCodeReferenceElement reference) { - if (isLessRestrictiveScope(member, psiClass)) { + if (needToCheck(member) && isLessRestrictiveScope(member, psiClass)) { myHolder.registerProblem(reference, InspectionGadgetsBundle.message("class.escapes.defined.scope.problem.descriptor")); return true; } return false; } - private static boolean isLessRestrictiveScope(@NotNull PsiMember member, @NotNull PsiClass aClass) { + private boolean needToCheck(PsiMember member) { + return checkPublicApi && (member.hasModifierProperty(PsiModifier.PUBLIC) || member.hasModifierProperty(PsiModifier.PROTECTED)) || + checkPackageLocal && member.hasModifierProperty(PsiModifier.PACKAGE_LOCAL); + } + + private boolean isLessRestrictiveScope(@NotNull PsiMember member, @NotNull PsiClass aClass) { final int methodScopeOrder = getScopeOrder(member); final int classScopeOrder = getScopeOrder(aClass); final PsiClass containingClass = member.getContainingClass(); @@ -179,7 +188,7 @@ public class ClassEscapesItsScopeInspection extends BaseJavaBatchLocalInspection return methodScopeOrder > classScopeOrder && containingClassScopeOrder > classScopeOrder; } - private static int getScopeOrder(@NotNull PsiModifierListOwner element) { + private int getScopeOrder(@NotNull PsiModifierListOwner element) { if (element.hasModifierProperty(PsiModifier.PUBLIC)) { return 4; } @@ -187,10 +196,10 @@ public class ClassEscapesItsScopeInspection extends BaseJavaBatchLocalInspection return 1; } else if (element.hasModifierProperty(PsiModifier.PROTECTED)) { - return 2; + return 3; } else { - return 3; + return 2; } } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPackageLocal.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPackageLocal.java new file mode 100644 index 000000000000..d3b81cb7ad47 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPackageLocal.java @@ -0,0 +1,44 @@ +import java.util.List; + +public class ExposedByPackageLocal { + public static class NestedPublic { } + protected static class NestedProtected { } + static class NestedPackageLocal { } + private static class NestedPrivate { } + + public NestedPublic withPublic1( + List list) { return list.get(0);} + protected NestedPublic withPublic2( + List list) { return list.get(0);} + NestedPublic withPublic3( + List list) { return list.get(0);} + private NestedPublic withPublic4( + List list) { return list.get(0);} + + public NestedProtected withProtected1( + List list) { return list.get(0);} + protected NestedProtected withProtected2( + List list) { return list.get(0);} + NestedProtected withProtected3( + List list) { return list.get(0);} + private NestedProtected withProtected4( + List list) { return list.get(0);} + + public NestedPackageLocal withPackageLocal1( + List list) { return list.get(0);} + protected NestedPackageLocal withPackageLocal2( + List list) { return list.get(0);} + NestedPackageLocal withPackageLocal3( + List list) { return list.get(0);} + private NestedPackageLocal withPackageLocal4( + List list) { return list.get(0);} + + public NestedPrivate withPrivate1( + List list) { return list.get(0);} + protected NestedPrivate withPrivate2( + List list) { return list.get(0);} + NestedPrivate withPrivate3( + List<NestedPrivate> list) { return list.get(0);} + private NestedPrivate withPrivate4( + List list) { return list.get(0);} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPublic.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPublic.java new file mode 100644 index 000000000000..1fb22d2f17a7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/class_escapes_its_scope/ExposedByPublic.java @@ -0,0 +1,44 @@ +import java.util.List; + +public class ExposedByPublic { + public static class NestedPublic { } + protected static class NestedProtected { } + static class NestedPackageLocal { } + private static class NestedPrivate { } + + public NestedPublic withPublic1( + List list) { return list.get(0);} + protected NestedPublic withPublic2( + List list) { return list.get(0);} + NestedPublic withPublic3( + List list) { return list.get(0);} + private NestedPublic withPublic4( + List list) { return list.get(0);} + + public NestedProtected withProtected1( + List<NestedProtected> list) { return list.get(0);} + protected NestedProtected withProtected2( + List list) { return list.get(0);} + NestedProtected withProtected3( + List list) { return list.get(0);} + private NestedProtected withProtected4( + List list) { return list.get(0);} + + public NestedPackageLocal withPackageLocal1( + List<NestedPackageLocal> list) { return list.get(0);} + protected NestedPackageLocal withPackageLocal2( + List<NestedPackageLocal> list) { return list.get(0);} + NestedPackageLocal withPackageLocal3( + List list) { return list.get(0);} + private NestedPackageLocal withPackageLocal4( + List list) { return list.get(0);} + + public NestedPrivate withPrivate1( + List<NestedPrivate> list) { return list.get(0);} + protected NestedPrivate withPrivate2( + List<NestedPrivate> list) { return list.get(0);} + NestedPrivate withPrivate3( + List list) { return list.get(0);} + private NestedPrivate withPrivate4( + List list) { return list.get(0);} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/ClassEscapesItsScopeInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/ClassEscapesItsScopeInspectionTest.java index 56551611ccd9..c193575bfd93 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/ClassEscapesItsScopeInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/ClassEscapesItsScopeInspectionTest.java @@ -23,16 +23,34 @@ import org.jetbrains.annotations.Nullable; * @author Bas Leijdekkers */ public class ClassEscapesItsScopeInspectionTest extends LightInspectionTestCase { + private ClassEscapesItsScopeInspection myInspection = new ClassEscapesItsScopeInspection(); - public void testClassEscapesItsScope() { doTest(); } + public void testClassEscapesItsScope() { doTest(true, true); } - public void testGenericParameterEscapesItsScope() { doTest(); } + public void testGenericParameterEscapesItsScope() { doTest(true, true); } + + public void testExposedByPublic() { + doTest(true, false); + } + + public void testExposedByPackageLocal() { + doTest(false, true); + } + + private void doTest(boolean checkPublicApi, boolean checkPackageLocal) { + myInspection.checkPublicApi = checkPublicApi; + myInspection.checkPackageLocal = checkPackageLocal; + try { + doTest(); + } + finally { + myInspection.checkPublicApi = myInspection.checkPackageLocal = false; + } + } @Nullable @Override protected InspectionProfileEntry getInspection() { - ClassEscapesItsScopeInspection inspection = new ClassEscapesItsScopeInspection(); - inspection.onlyJava9Modules = false; - return inspection; + return myInspection; } } \ No newline at end of file