From d8f37a3ea829b22b34c2d1af233ad068e07cb883 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 30 Jan 2018 19:03:52 +0300 Subject: [PATCH] access can be tightened for inner classes (IDEA-185790) check enclosing instance for null qualifiers, if accessed via inheritance, then can't be private --- .../AccessCanBeTightenedInspection.java | 9 ++++++-- .../intellij/psi/util/InheritanceUtil.java | 21 ++++++++++++------- .../AccessCanBeTightenedInspectionTest.java | 7 +++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java index ce6b8d90ab45..3e423ea41bc2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspection.java @@ -10,9 +10,11 @@ import com.intellij.codeInspection.inheritance.ImplicitSubclassProvider; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.util.ClassUtil; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.VisibilityUtil; @@ -255,7 +257,7 @@ class AccessCanBeTightenedInspection extends AbstractBaseJavaLocalInspectionTool PsiClass innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); boolean isAbstractMember = member.hasModifierProperty(PsiModifier.ABSTRACT); if (memberClass != null && PsiTreeUtil.isAncestor(innerClass, memberClass, false) || - innerClass != null && PsiTreeUtil.isAncestor(memberClass, innerClass, false) && !innerClass.hasModifierProperty(PsiModifier.STATIC)) { + innerClass != null && PsiTreeUtil.isAncestor(memberClass, innerClass, false)) { // access from the same file can be via private // except when used in annotation: // @Ann(value = C.VAL) class C { public static final String VAL = "xx"; } @@ -301,7 +303,10 @@ class AccessCanBeTightenedInspection extends AbstractBaseJavaLocalInspectionTool private boolean calledOnInheritor(@NotNull PsiElement element, PsiClass memberClass) { PsiExpression qualifier = getQualifier(element); - if (qualifier == null) return false; + if (qualifier == null) { + PsiClass enclosingInstance = InheritanceUtil.findEnclosingInstanceInScope(memberClass, element, Condition.TRUE, true); + return enclosingInstance != null && enclosingInstance != memberClass; + } PsiClass qClass = PsiUtil.resolveClassInClassTypeOnly(qualifier.getType()); return qClass != null && qClass.isInheritor(memberClass, true); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java index 4f2f65877809..9bab2c728622 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java @@ -142,31 +142,38 @@ public class InheritanceUtil { PsiElement scope, Condition isSuperClassAccepted, boolean isTypeParamsAccepted) { + return findEnclosingInstanceInScope(aClass, scope, isSuperClassAccepted, isTypeParamsAccepted) != null; + } + + public static PsiClass findEnclosingInstanceInScope(PsiClass aClass, + PsiElement scope, + Condition isSuperClassAccepted, + boolean isTypeParamsAccepted) { PsiManager manager = aClass.getManager(); PsiElement place = scope; - while (place != null && place != aClass && !(place instanceof PsiFile)) { + while (place != null && !(place instanceof PsiFile)) { if (place instanceof PsiClass) { if (isSuperClassAccepted.value((PsiClass)place)) { - if (isInheritorOrSelf((PsiClass)place, aClass, true)) return true; + if (isInheritorOrSelf((PsiClass)place, aClass, true)) return (PsiClass)place; } else { - if (manager.areElementsEquivalent(place, aClass)) return true; + if (manager.areElementsEquivalent(place, aClass)) return aClass; } if (isTypeParamsAccepted && place instanceof PsiTypeParameter) { - return true; + return (PsiClass)place; } } if (place instanceof PsiModifierListOwner) { final PsiModifierList modifierList = ((PsiModifierListOwner)place).getModifierList(); if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC)) { - return false; + return null; } } place = place.getParent(); } - return place == aClass; + return null; } - + public static boolean processSuperTypes(@NotNull PsiType type, boolean includeSelf, @NotNull Processor processor) { if (includeSelf && !processor.process(type)) return false; return processSuperTypes(type, processor, new HashSet<>()); diff --git a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java index 081f0147c68b..6abaa9e0cf6f 100644 --- a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java @@ -224,6 +224,13 @@ public class AccessCanBeTightenedInspectionTest extends LightInspectionTestCase " return myElement;\n" + " }\n" + " }\n" + + " protected String myElement1;\n" + + " class B1 {\n" + + " @Override\n" + + " public String toString() {\n" + + " return myElement1;\n" + + " }\n" + + " }\n" + "}"); }