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 38084ab8ac94..465279bbc5d6 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 @@ -26,6 +26,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.util.ClassUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -145,34 +146,23 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool { PsiDirectory memberDirectory = memberFile.getContainingDirectory(); final PsiPackage memberPackage = memberDirectory == null ? null : JavaDirectoryService.getInstance().getPackage(memberDirectory); log(member.getName()+ ": checking effective level for "+member); - boolean result = - UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, info -> { - foundUsage.set(true); - PsiFile psiFile = info.getFile(); - if (psiFile == null) return true; - if (!(psiFile instanceof PsiJavaFile)) { - log(" refd from " + psiFile.getName() + "; set to public"); - maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC); - if (memberClass != null) { - childMembersAreUsedOutsideMyPackage.add(memberClass); - } - return false; // referenced from XML, has to be public - } - //int offset = info.getNavigationOffset(); - //if (offset == -1) return true; - PsiElement element = info.getElement(); - if (element == null) return true; - @PsiUtil.AccessLevel - int level = getEffectiveLevel(element, psiFile, member, memberFile, memberClass, memberPackage); - log(" ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")"); - maxLevel.getAndAccumulate(level, Math::max); - if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) { - childMembersAreUsedOutsideMyPackage.add(memberClass); - } - return level != PsiUtil.ACCESS_LEVEL_PUBLIC; + UnusedSymbolUtil.processUsages(project, memberFile, member, new EmptyProgressIndicator(), null, info -> { + PsiElement element = info.getElement(); + if (element == null) return true; + PsiFile psiFile = info.getFile(); + if (psiFile == null) return true; + + return handleUsage(member, memberClass, memberFile, maxLevel, memberPackage, element, psiFile, foundUsage); + }); + + if (member instanceof PsiClass && ((PsiClass)member).isInterface()) { + // there can be lambda implementing this interface implicitly + FunctionalExpressionSearch.search((PsiClass)member).forEach(functionalExpression -> { + PsiFile psiFile = functionalExpression.getContainingFile(); + return handleUsage(member, memberClass, memberFile, maxLevel, memberPackage, functionalExpression, psiFile, foundUsage); }); - + } if (!foundUsage.get()) { log(member.getName() + " unused; ignore"); return; // do not propose private for unused method @@ -199,6 +189,36 @@ class AccessCanBeTightenedInspection extends BaseJavaBatchLocalInspectionTool { } } + private boolean handleUsage(@NotNull PsiMember member, + @Nullable PsiClass memberClass, + @NotNull PsiFile memberFile, + @NotNull AtomicInteger maxLevel, + @Nullable PsiPackage memberPackage, + @NotNull PsiElement element, + @NotNull PsiFile psiFile, + @NotNull AtomicBoolean foundUsage) { + foundUsage.set(true); + if (!(psiFile instanceof PsiJavaFile)) { + log(" refd from " + psiFile.getName() + "; set to public"); + maxLevel.set(PsiUtil.ACCESS_LEVEL_PUBLIC); + if (memberClass != null) { + childMembersAreUsedOutsideMyPackage.add(memberClass); + } + return false; // referenced from XML, has to be public + } + //int offset = info.getNavigationOffset(); + //if (offset == -1) return true; + @PsiUtil.AccessLevel + int level = getEffectiveLevel(element, psiFile, member, memberFile, memberClass, memberPackage); + log(" ref in file " + psiFile.getName() + "; level = " + PsiUtil.getAccessModifier(level) + "; (" + element + ")"); + maxLevel.getAndAccumulate(level, Math::max); + if (level == PsiUtil.ACCESS_LEVEL_PUBLIC && memberClass != null) { + childMembersAreUsedOutsideMyPackage.add(memberClass); + } + + return level != PsiUtil.ACCESS_LEVEL_PUBLIC; + } + @PsiUtil.AccessLevel private int getEffectiveLevel(@NotNull PsiElement element, @NotNull PsiFile file, diff --git a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java index d91f1ec4f85c..1aec8e7853b9 100644 --- a/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/intellij/codeInspection/visibility/AccessCanBeTightenedInspectionTest.java @@ -144,6 +144,37 @@ public class AccessCanBeTightenedInspectionTest extends LightInspectionTestCase myFixture.checkHighlighting(); } + public void testInterfaceIsImplementedByLambda() { + myFixture.allowTreeAccessForAllFiles(); + myFixture.addFileToProject("x/MyInterface.java", + "package x;\n" + + "public interface MyInterface {\n" + + " void doStuff();\n" + + "}\n" + + ""); + myFixture.addFileToProject("x/MyConsumer.java", + "package x;\n" + + "public class MyConsumer {\n" + + " public void doIt(MyInterface i) {\n" + + " i.doStuff();\n" + + " }\n" + + "}" + + ""); + myFixture.addFileToProject("y/Test.java", + "package y;\n" + + "\n" + + "import x.MyConsumer;\n" + + "\n" + + "public class Test {\n" + + " void ddd(MyConsumer consumer) {\n" + + " consumer.doIt(() -> {});\n" + + " }\n" + + "}" + + ""); + myFixture.configureByFiles("x/MyInterface.java", "y/Test.java", "x/MyConsumer.java"); + myFixture.checkHighlighting(); + } + @Override protected LocalInspectionTool getInspection() { VisibilityInspection inspection = new VisibilityInspection();