do not highlight method unused if referenced via overridden
authorAlexey Kudravtsev <cdr@intellij.com>
Tue, 23 Sep 2014 09:50:58 +0000 (13:50 +0400)
committerAlexey Kudravtsev <cdr@intellij.com>
Tue, 23 Sep 2014 12:00:58 +0000 (16:00 +0400)
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/UnusedPublicMethodReferencedViaSubclass.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/I.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/X.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java
java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java

index 23fe242e812cfe4f30b88540c2a7c92816f79400..31ec92b03731d80b91619206f246432dc94aebb4 100644 (file)
@@ -34,6 +34,7 @@ import com.intellij.codeInspection.reference.UnusedDeclarationFixProvider;
 import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection;
 import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase;
 import com.intellij.codeInspection.util.SpecialAnnotationsUtilBase;
+import com.intellij.find.findUsages.*;
 import com.intellij.lang.Language;
 import com.intellij.lang.annotation.HighlightSeverity;
 import com.intellij.openapi.application.ApplicationManager;
@@ -60,12 +61,12 @@ import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor;
 import com.intellij.psi.search.PsiSearchHelper;
 import com.intellij.psi.search.SearchScope;
 import com.intellij.psi.search.searches.OverridingMethodsSearch;
-import com.intellij.psi.search.searches.ReferencesSearch;
 import com.intellij.psi.search.searches.SuperMethodsSearch;
 import com.intellij.psi.util.PropertyUtil;
 import com.intellij.psi.util.PsiModificationTracker;
 import com.intellij.psi.util.PsiUtil;
 import com.intellij.psi.util.PsiUtilCore;
+import com.intellij.usageView.UsageInfo;
 import com.intellij.util.Processor;
 import com.intellij.util.containers.Predicate;
 import gnu.trove.THashSet;
@@ -609,7 +610,7 @@ public class PostHighlightingPass extends ProgressableTextEditorHighlightingPass
     if (name == null) return false;
     SearchScope useScope = member.getUseScope();
     PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(project);
-    PsiFile ignoreFile = helper.isCurrentFileAlreadyChecked() ? containingFile : null;
+    final PsiFile ignoreFile = helper.isCurrentFileAlreadyChecked() ? containingFile : null;
     if (useScope instanceof GlobalSearchScope) {
       // some classes may have references from within XML outside dependent modules, e.g. our actions
       if (member instanceof PsiClass) {
@@ -637,8 +638,39 @@ public class PostHighlightingPass extends ProgressableTextEditorHighlightingPass
         }
       }
     }
-    if (ReferencesSearch.search(member, useScope, true).findFirst() != null) return false;
-    return !(useScope instanceof GlobalSearchScope) || !foundUsageInText(member, (GlobalSearchScope)useScope, searchHelper, ignoreFile);
+    FindUsagesOptions options;
+    if (member instanceof PsiPackage) {
+      options = new JavaPackageFindUsagesOptions(project);
+    }
+    else if (member instanceof PsiClass) {
+      options = new JavaClassFindUsagesOptions(project);
+    }
+    else if (member instanceof PsiMethod) {
+      JavaMethodFindUsagesOptions o = new JavaMethodFindUsagesOptions(project);
+      //o.isIncludeOverloadUsages = true;
+      options = o;
+    }
+    else if (member instanceof PsiVariable) {
+      options = new JavaVariableFindUsagesOptions(project);
+    }
+    else {
+      options = new FindUsagesOptions(project);
+    }
+    options.isSearchForTextOccurrences = true;
+    options.isUsages = true;
+    boolean foundUsage = !JavaFindUsagesHelper.processElementUsages(member, options, new Processor<UsageInfo>() {
+      @Override
+      public boolean process(UsageInfo info) {
+        PsiFile psiFile = info.getFile();
+        if (psiFile == ignoreFile || psiFile == null) return true; // ignore usages in containingFile because isLocallyUsed() method would have caught that
+        int offset = info.getNavigationOffset();
+        if (offset == -1) return true;
+        PsiElement element = psiFile.findElementAt(offset);
+        return element instanceof PsiComment; // ignore comments
+      }
+    });
+    if (foundUsage) return false;
+    return true;//!(useScope instanceof GlobalSearchScope) || !foundUsageInText(member, (GlobalSearchScope)useScope, searchHelper, ignoreFile);
   }
 
   private static boolean foundUsageInText(@NotNull PsiMember member,
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/UnusedPublicMethodReferencedViaSubclass.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/UnusedPublicMethodReferencedViaSubclass.java
new file mode 100644 (file)
index 0000000..7cffcd3
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package x;
+
+interface I {
+    void <warning descr="Method 'ffffff()' is never used">ffffff</warning>();
+}
+
+class <warning descr="Class 'XI' is never used">XI</warning> implements I {
+    public void ffffff() {
+    }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/I.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/I.java
new file mode 100644 (file)
index 0000000..243f077
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package x;
+
+public interface I {
+    void ffffff();
+}
+
+class XI implements I {
+    public void ffffff() {
+    }
+  public void <warning descr="Method 'ffffff2()' is never used">ffffff2</warning>() {
+  }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/X.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/unusedPublicMethodRefViaSubclass/x/X.java
new file mode 100644 (file)
index 0000000..9ecb95c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package x;
+
+public class X {
+    void g(XI xi) {
+        xi.ffffff();
+    }
+}
index ca258530452f9f0847880b7d9ee2921a861b93a2..154740e6bea2fc50c24a161c16caa7964f816966 100644 (file)
@@ -18,6 +18,9 @@ package com.intellij.codeInsight.daemon;
 import com.intellij.analysis.PackagesScopesProvider;
 import com.intellij.application.options.colors.ScopeAttributesUtil;
 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
+import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
 import com.intellij.openapi.application.ex.PathManagerEx;
 import com.intellij.openapi.editor.colors.EditorColorsManager;
 import com.intellij.openapi.editor.colors.EditorColorsScheme;
@@ -324,4 +327,19 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase {
   public void testPublicClassInRightFile2() throws Exception {
     doTest(BASE_PATH + "/publicClassInRightFile/x/Y.java", BASE_PATH + "/publicClassInRightFile", false, false);
   }
+
+  @Override
+  protected LocalInspectionTool[] configureLocalInspectionTools() {
+    boolean needUnusedSymbol = getTestName(true).toLowerCase().contains("unused");
+    return needUnusedSymbol ? new LocalInspectionTool[]{new UnusedSymbolLocalInspection()} : new LocalInspectionTool[0];
+  }
+
+  public void testUnusedPublicMethodReferencedViaSubclass() throws Exception {
+    UnusedDeclarationInspection deadCodeInspection = new UnusedDeclarationInspection();
+    enableInspectionTool(deadCodeInspection);
+    //String ref = getTestDataPath() + BASE_PATH + "/unusedPublicMethodRefViaSubclass/x/X.java";
+    allowTreeAccessForAllFiles();
+
+    doTest(BASE_PATH + "/unusedPublicMethodRefViaSubclass/x/I.java", BASE_PATH + "/unusedPublicMethodRefViaSubclass", true, false);
+  }
 }
index 7160dc96787dad19265bf9e62fe9eaa8e296961c..5ba9549cc6707e7448ada38879161be6bf48e5d3 100644 (file)
@@ -342,6 +342,9 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
   public void allowTreeAccessForFile(@NotNull VirtualFile file) {
     myFileTreeAccessFilter.allowTreeAccessForFile(file);
   }
+  public void allowTreeAccessForAllFiles() {
+    myFileTreeAccessFilter.allowTreeAccessForAllFiles();
+  }
 
   @NotNull
   protected List<HighlightInfo> highlightErrors() {