correctly report private methods' unusedness (IDEA-75803)
authorpeter <peter@jetbrains.com>
Tue, 31 Jan 2012 12:41:04 +0000 (13:41 +0100)
committerpeter <peter@jetbrains.com>
Tue, 31 Jan 2012 17:30:25 +0000 (18:30 +0100)
java/java-impl/src/com/intellij/codeInsight/daemon/impl/GlobalUsageHelper.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java
plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java
plugins/groovy/testdata/highlighting/GloballyUnusedSymbols.groovy

index 18a363133c01ec714e622eaaa8caeea3a7e9e5fd..4f4e3e87c356337eb1ec740c020a3727a7e2a345 100644 (file)
@@ -30,11 +30,6 @@ public abstract class GlobalUsageHelper {
   final Map<PsiClass,Boolean> unusedClassCache = new HashMap<PsiClass, Boolean>();
 
   public abstract boolean shouldCheckUsages(@NotNull PsiMember member);
-  public boolean isLocallyUsed(@NotNull PsiNamedElement member) {
-    return false;
-  }
-
-  public boolean shouldIgnoreUsagesInCurrentFile() {
-    return false;
-  }
+  public abstract boolean isLocallyUsed(@NotNull PsiNamedElement member);
+  public abstract boolean shouldIgnoreUsagesInCurrentFile();
 }
index 531bc286acfd45de211f2adfde8e8b10cd88f5de..6ab7b118c92f30a52e7d52184639a9e015f95eb7 100644 (file)
@@ -260,9 +260,14 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
         return true;
       }
 
+      @Override
+      public boolean shouldIgnoreUsagesInCurrentFile() {
+        return true;
+      }
+
       @Override
       public boolean isLocallyUsed(@NotNull PsiNamedElement member) {
-        return myRefCountHolder.isReferenced(myFile);
+        return myRefCountHolder.isReferenced(member);
       }
     };
 
@@ -390,7 +395,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
     return UnusedSymbolLocalInspection.isInjected(element);
   }
 
-  public static HighlightInfo createUnusedSymbolInfo(PsiElement element, String message, final HighlightInfoType highlightInfoType) {
+  public static HighlightInfo createUnusedSymbolInfo(@NotNull PsiElement element, @Nullable String message, @NotNull final HighlightInfoType highlightInfoType) {
     HighlightInfo info = HighlightInfo.createHighlightInfo(highlightInfoType, element, message);
     UnusedDeclarationFixProvider[] fixProviders = Extensions.getExtensions(UnusedDeclarationFixProvider.EP_NAME);
     for (UnusedDeclarationFixProvider provider : fixProviders) {
@@ -580,6 +585,9 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
       if (isImplicitUsage(method, progress)) {
         return true;
       }
+      if (!helper.shouldIgnoreUsagesInCurrentFile()) {
+        return !weAreSureThereAreNoUsages(method, progress, helper);
+      }
     }
     else {
       //class maybe used in some weird way, e.g. from XML, therefore the only constructor is used too
@@ -606,26 +614,27 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
     String name = member.getName();
     if (name == null) return false;
     SearchScope useScope = member.getUseScope();
-    if (!(useScope instanceof GlobalSearchScope)) return false;
-    GlobalSearchScope scope = (GlobalSearchScope)useScope;
-    // some classes may have references from within XML outside dependent modules, e.g. our actions
     Project project = member.getProject();
-    if (member instanceof PsiClass) scope = GlobalSearchScope.projectScope(project).uniteWith(scope);
-
-    PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(project).isCheapEnoughToSearch(name, scope,
-                                                                                                                      helper.shouldIgnoreUsagesInCurrentFile() ? member.getContainingFile() : null,
-                                                                                                                      progress);
-    if (cheapEnough == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES) return false;
-
-    //search usages if it cheap
-    //if count is 0 there is no usages since we've called myRefCountHolder.isReferenced() before
-    if (cheapEnough == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) {
-      if (!canBeReferencedViaWeirdNames(member)) return true;
+    if (useScope instanceof GlobalSearchScope) {
+      GlobalSearchScope scope = (GlobalSearchScope)useScope;
+      // some classes may have references from within XML outside dependent modules, e.g. our actions
+      if (member instanceof PsiClass) scope = GlobalSearchScope.projectScope(project).uniteWith(scope);
+
+      PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(project).isCheapEnoughToSearch(name, scope,
+                                                                                                                        helper.shouldIgnoreUsagesInCurrentFile() ? member.getContainingFile() : null,
+                                                                                                                        progress);
+      if (cheapEnough == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES) return false;
+
+      //search usages if it cheap
+      //if count is 0 there is no usages since we've called myRefCountHolder.isReferenced() before
+      if (cheapEnough == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) {
+        if (!canBeReferencedViaWeirdNames(member)) return true;
+      }
     }
     FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager();
     FindUsagesHandler handler = new JavaFindUsagesHandler(member, new JavaFindUsagesHandlerFactory(project));
     FindUsagesOptions findUsagesOptions = handler.getFindUsagesOptions();
-    findUsagesOptions.searchScope = scope;
+    findUsagesOptions.searchScope = useScope;
     return !findUsagesManager.isUsed(member, findUsagesOptions);
   }
 
@@ -684,7 +693,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
     if (aClass == null) return true;
     Boolean result = helper.unusedClassCache.get(aClass);
     if (result == null) {
-      result = !isReallyUsed(aClass, progress, helper);
+      result = isReallyUsed(aClass, progress, helper);
       helper.unusedClassCache.put(aClass, result);
     }
     return result;
index 49c4c67fcec4bcbbefc9c74940af5359829e2f0a..7476a4ed4648a58b08703a1d1ea3a4610058979f 100644 (file)
@@ -39,10 +39,7 @@ import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiMember;
-import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
+import com.intellij.psi.*;
 import com.intellij.util.Processor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
@@ -90,6 +87,14 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass {
     }
     final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile);
     final GlobalUsageHelper usageHelper = new GlobalUsageHelper() {
+      public boolean shouldIgnoreUsagesInCurrentFile() {
+        return false;
+      }
+
+      public boolean isLocallyUsed(@NotNull PsiNamedElement member) {
+        return false;
+      }
+
       @Override
       public boolean shouldCheckUsages(@NotNull PsiMember member) {
         return deadCodeInspection == null || !deadCodeInspection.isEntryPoint(member);
@@ -115,7 +120,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass {
           PsiElement nameId = ((GrNamedElement)element).getNameIdentifierGroovy();
           if (nameId.getNode().getElementType() == GroovyTokenTypes.mIDENT) {
             String name = ((GrNamedElement)element).getName();
-            if (element instanceof GrTypeDefinition && PostHighlightingPass.isClassUsed((GrTypeDefinition)element, progress, usageHelper)) {
+            if (element instanceof GrTypeDefinition && !PostHighlightingPass.isClassUsed((GrTypeDefinition)element, progress, usageHelper)) {
               unusedDeclarations.add(
                 PostHighlightingPass.createUnusedSymbolInfo(nameId, "Class " + name + " is unused", HighlightInfoType.UNUSED_SYMBOL));
             }
index 5ad85a2c8f6be50af9f235560a2d564304c44427..af47b7500098bab5cc27785e3a2c5b5040dc090b 100644 (file)
@@ -10,7 +10,10 @@ class Bar {
 
   Bar getUsedPropertyGetter() {}
 
-  public static void main(String[] args) {}
+  public static void main(String[] args) { usedPrivately() }
+
+  private static void usedPrivately() {}
+  private void <warning descr="Method unusedPrivately is unused">unusedPrivately</warning>() {}
 
 }
 println new Bar().usedMethod().usedProperty