From 9f00b76c0c097bd10500587fe6b3f6eb6b62680b Mon Sep 17 00:00:00 2001 From: Mikhail Pyltsin Date: Wed, 14 Dec 2022 12:09:29 +0100 Subject: [PATCH] [java-inspections] IDEA-288910 avoid warning if two classes with the same simple name are used GitOrigin-RevId: f2048ea5840ae36ee92c40826a078e7eb3e8243a --- .../fixAll/afterFullyQualifiedName.java | 2 +- .../fixAll/beforeFullyQualifiedName.java | 2 +- ...necessaryFullyQualifiedNameInspection.java | 77 +++++++++++++++---- .../Test.java | 6 ++ .../expected.xml | 3 + ...ssaryFullyQualifiedNameInspectionTest.java | 4 + 6 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/Test.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/expected.xml diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterFullyQualifiedName.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterFullyQualifiedName.java index 2b13c1abaa10..fd5aff11ea37 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterFullyQualifiedName.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterFullyQualifiedName.java @@ -4,6 +4,6 @@ import java.util.Date; class FullyQualifiedName { void m(Object value) { - value = new java.sql.Date(((Date) value).getTime()); + value = ((Date) value).getTime(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeFullyQualifiedName.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeFullyQualifiedName.java index 67d656fe3e9d..b9f0ef44b459 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeFullyQualifiedName.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeFullyQualifiedName.java @@ -2,6 +2,6 @@ class FullyQualifiedName { void m(Object value) { - value = new java.sql.Date(((java.util.Date) value).getTime()); + value = ((java.util.Date) value).getTime(); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java index 427c6be56592..38b846737110 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java @@ -20,7 +20,6 @@ import com.intellij.codeInspection.CleanupLocalInspectionTool; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.options.OptPane; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.WindowManager; @@ -30,6 +29,9 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.impl.source.codeStyle.ImportHelper; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.SmartList; import com.siyeh.InspectionGadgetsBundle; @@ -40,15 +42,11 @@ import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.HighlightUtils; import com.siyeh.ig.psiutils.ImportUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; -import static com.intellij.codeInspection.options.OptPane.*; +import static com.intellij.codeInspection.options.OptPane.checkbox; +import static com.intellij.codeInspection.options.OptPane.pane; public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection implements CleanupLocalInspectionTool { @@ -220,8 +218,7 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl if (element != null && !(element instanceof PsiAnnotation)) { return; } - final PsiFile containingFile = reference.getContainingFile(); - if (!(containingFile instanceof PsiJavaFile)) { + if (!(reference.getContainingFile() instanceof PsiJavaFile containingFile)) { return; } final PsiElement target = reference.resolve(); @@ -232,12 +229,12 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl final PsiDocComment containingComment = PsiTreeUtil.getParentOfType(reference, PsiDocComment.class); boolean reportAsInformationInsideJavadoc = false; if (containingComment != null) { - if (acceptFqnInJavadoc((PsiJavaFile)containingFile, styleSettings)) { + if (acceptFqnInJavadoc(containingFile, styleSettings)) { return; } JavaCodeStyleSettings javaSettings = styleSettings.getCustomSettings(JavaCodeStyleSettings.class); if (javaSettings.CLASS_NAMES_IN_JAVADOC == JavaCodeStyleSettings.FULLY_QUALIFY_NAMES_IF_NOT_IMPORTED) { - reportAsInformationInsideJavadoc = !ImportHelper.isAlreadyImported((PsiJavaFile)containingFile, reference.getQualifiedName()); + reportAsInformationInsideJavadoc = !ImportHelper.isAlreadyImported(containingFile, reference.getQualifiedName()); } } final PsiJavaCodeReferenceElement qualifierReference = (PsiJavaCodeReferenceElement)qualifier; @@ -270,6 +267,12 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl } final PsiElement qualifier1 = aReference.getQualifier(); if (qualifier1 != null) { + Map> allReferencesByName = getReferencesFromCache(containingFile); + Collection classesWithReferenceName = allReferencesByName.get(aReference.getReferenceName()); + if (classesWithReferenceName.size() > 1) { + continue; + } + PsiElement elementToHighlight = qualifier1; final ProblemHighlightType highlightType; if (reportAsInformationInsideJavadoc || @@ -284,14 +287,14 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl } final boolean inSameFile = aClass.getContainingFile() == containingFile || - ImportHelper.isAlreadyImported((PsiJavaFile)containingFile, qualifiedName); + ImportHelper.isAlreadyImported(containingFile, qualifiedName); registerError(elementToHighlight, highlightType, inSameFile); } break; } } - private void collectInnerClassNames(PsiJavaCodeReferenceElement reference, List references) { + private static void collectInnerClassNames(PsiJavaCodeReferenceElement reference, List references) { PsiElement rParent = reference.getParent(); while (rParent instanceof PsiJavaCodeReferenceElement) { final PsiJavaCodeReferenceElement parentReference = (PsiJavaCodeReferenceElement)rParent; @@ -303,11 +306,55 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl } } - private boolean acceptFqnInJavadoc(PsiJavaFile javaFile, CodeStyleSettings styleSettings) { + private static boolean acceptFqnInJavadoc(PsiJavaFile javaFile, CodeStyleSettings styleSettings) { if ("package-info.java".equals(javaFile.getName())) { return true; } return styleSettings.getCustomSettings(JavaCodeStyleSettings.class).useFqNamesInJavadocAlways(); } } + + private static Map> getReferencesFromCache(PsiJavaFile file) { + return CachedValuesManager.getCachedValue(file, () -> { + ReferenceCollector referenceCollector = new ReferenceCollector(); + file.accept(referenceCollector); + return CachedValueProvider.Result.create(referenceCollector.getReferences(), PsiModificationTracker.MODIFICATION_COUNT); + }); + } + + private static class ReferenceCollector extends JavaRecursiveElementWalkingVisitor { + private final Map> referencesByName = new HashMap<>(); + + @Override + public void visitImportList(@NotNull PsiImportList list) { } + + @Override + public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + + if (!reference.isQualified()) { + return; + } + final PsiElement target = reference.resolve(); + if (!(target instanceof final PsiClass aClass)) { + return; + } + referencesByName.compute(reference.getReferenceName(), (k, elements) -> { + if (elements == null) { + elements = new HashSet<>(); + } + elements.add(aClass.getQualifiedName()); + return elements; + }); + } + + @Override + public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) { + visitReferenceElement(expression); + } + + public Map> getReferences() { + return referencesByName; + } + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/Test.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/Test.java new file mode 100644 index 000000000000..062e8f23d80c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/Test.java @@ -0,0 +1,6 @@ +class Test { + + void m(Object value) { + value = new java.sql.Date(((java.util.Date) value).getTime()); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_skip_warn_if_confusing/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java index 2a89e83f3a9a..b341581dba8d 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java @@ -31,6 +31,10 @@ public class UnnecessaryFullyQualifiedNameInspectionTest extends IGInspectionTes doTest(BASE_DIR + "unnecessary_fqn_type_parameter_conflict", new UnnecessaryFullyQualifiedNameInspection()); } + public void testSkipWarningIfThereIsSameNames() { + doTest(BASE_DIR + "unnecessary_fqn_skip_warn_if_confusing", new UnnecessaryFullyQualifiedNameInspection()); + } + private void doTestWithFqnInJavadocSetting(String dirPath, int classNamesInJavadoc) { JavaCodeStyleSettings javaSettings = JavaCodeStyleSettings.getInstance(getProject());