IDEA-153358 Inspection Declaration access can be weaker: false positive for lambda usage

This commit is contained in:
Alexey Kudravtsev
2016-04-11 18:30:42 +03:00
parent 561f3b5630
commit 5d161e24fb
2 changed files with 77 additions and 26 deletions
@@ -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,
@@ -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();