From 39ca7355201accac98172d7ae12cd75bf5be68a2 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Fri, 5 Oct 2012 13:45:20 +0300 Subject: [PATCH] suppress actions for groovy 'unused declarations' --- plugins/groovy/src/META-INF/plugin.xml | 2 +- .../GroovySuppressableInspectionTool.java | 6 ++- .../GroovyUnusedDeclarationInspection.java | 17 +++++++- .../local/GroovyPostHighlightingPass.java | 43 +++++++++++-------- .../groovy/lang/GroovyHighlightingTest.groovy | 17 +++++++- 5 files changed, 64 insertions(+), 21 deletions(-) diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index a4b2104dd0dd..446a60139ca4 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -478,7 +478,7 @@ - diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java index 1c060d80e94d..3db32d7e7936 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java @@ -61,7 +61,11 @@ public abstract class GroovySuppressableInspectionTool extends LocalInspectionTo } public boolean isSuppressedFor(final PsiElement element) { - return getElementToolSuppressedIn(element, getID()) != null; + return isElementToolSuppressedIn(element, getID()); + } + + public static boolean isElementToolSuppressedIn(final PsiElement place, final String toolId) { + return getElementToolSuppressedIn(place, toolId) != null; } @Nullable diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyUnusedDeclarationInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyUnusedDeclarationInspection.java index 7e9b9549b300..518bc941a2f4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyUnusedDeclarationInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyUnusedDeclarationInspection.java @@ -16,18 +16,23 @@ package org.jetbrains.plugins.groovy.codeInspection; import com.intellij.analysis.AnalysisScope; +import com.intellij.codeInspection.CustomSuppressableInspectionTool; import com.intellij.codeInspection.GlobalInspectionContext; import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.SuppressIntentionAction; import com.intellij.codeInspection.ex.DescriptorProviderInspection; import com.intellij.codeInspection.ex.JobDescriptor; import com.intellij.codeInspection.ex.UnfairLocalInspectionTool; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author peter */ -public class GroovyUnusedDeclarationInspection extends DescriptorProviderInspection implements UnfairLocalInspectionTool { +public class GroovyUnusedDeclarationInspection extends DescriptorProviderInspection implements UnfairLocalInspectionTool, + CustomSuppressableInspectionTool { public static final String SHORT_NAME = "GroovyUnusedDeclaration"; @Override @@ -47,4 +52,14 @@ public class GroovyUnusedDeclarationInspection extends DescriptorProviderInspect return JobDescriptor.EMPTY_ARRAY; } + @Nullable + @Override + public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) { + return GroovySuppressableInspectionTool.getSuppressActions(SHORT_NAME); + } + + @Override + public boolean isSuppressedFor(PsiElement element) { + return GroovySuppressableInspectionTool.isElementToolSuppressedIn(element, SHORT_NAME); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index 471224f71585..91b12bf090b4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -49,6 +49,7 @@ import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; +import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool; import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection; import org.jetbrains.plugins.groovy.editor.GroovyImportOptimizer; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -84,13 +85,15 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { } public void doCollectInformation(@NotNull final ProgressIndicator progress) { - final InspectionProfile profile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile(); - final boolean deadCodeEnabled = profile.isToolEnabled(HighlightDisplayKey.find(GroovyUnusedDeclarationInspection.SHORT_NAME), myFile); ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); VirtualFile virtualFile = myFile.getViewProvider().getVirtualFile(); if (!fileIndex.isInContent(virtualFile)) { return; } + + final InspectionProfile profile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile(); + final HighlightDisplayKey unusedDefKey = HighlightDisplayKey.find(GroovyUnusedDeclarationInspection.SHORT_NAME); + final boolean deadCodeEnabled = profile.isToolEnabled(unusedDefKey, myFile); final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getUnwrappedTool(UnusedDeclarationInspection.SHORT_NAME, myFile); final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { @@ -122,13 +125,16 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { } } - if (deadCodeEnabled && element instanceof GrNamedElement && !PostHighlightingPass.isImplicitUsage((GrNamedElement)element, progress)) { + if (deadCodeEnabled && + element instanceof GrNamedElement && + !PostHighlightingPass.isImplicitUsage((GrNamedElement)element, progress) && + !GroovySuppressableInspectionTool.isElementToolSuppressedIn(element, GroovyUnusedDeclarationInspection.SHORT_NAME)) { 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)) { HighlightInfo highlightInfo = PostHighlightingPass.createUnusedSymbolInfo(nameId, "Class " + name + " is unused", HighlightInfoType.UNUSED_SYMBOL); - QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(element)); + QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(element), unusedDefKey); unusedDeclarations.add(highlightInfo); } else if (element instanceof GrMethod) { @@ -136,14 +142,14 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!PostHighlightingPass.isMethodReferenced(method, progress, usageHelper)) { String message = (method.isConstructor() ? "Constructor" : "Method") + " " + name + " is unused"; HighlightInfo highlightInfo = PostHighlightingPass.createUnusedSymbolInfo(nameId, message, HighlightInfoType.UNUSED_SYMBOL); - QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(method)); + QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(method), unusedDefKey); unusedDeclarations.add(highlightInfo); } } else if (element instanceof GrField && isFieldUnused((GrField)element, progress, usageHelper)) { HighlightInfo highlightInfo = PostHighlightingPass.createUnusedSymbolInfo(nameId, "Property " + name + " is unused", HighlightInfoType.UNUSED_SYMBOL); - QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(element)); + QuickFixAction.registerQuickFixAction(highlightInfo, new SafeDeleteFix(element), unusedDefKey); unusedDeclarations.add(highlightInfo); } else if (element instanceof GrParameter) { @@ -168,18 +174,11 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { PsiElement scope = parameter.getDeclarationScope(); if (scope instanceof GrMethod) { GrMethod method = (GrMethod)scope; - if ((method.isConstructor() || - method.hasModifierProperty(PsiModifier.PRIVATE) || - method.hasModifierProperty(PsiModifier.STATIC) || - !method.hasModifierProperty(PsiModifier.ABSTRACT) && - !isOverriddenOrOverrides(method)) && - !method.hasModifierProperty(PsiModifier.NATIVE) && - !HighlightMethodUtil.isSerializationRelatedMethod(method, method.getContainingClass()) && - !PsiClassImplUtil.isMainOrPremainMethod(method)) { + if (methodMayHaveUnusedParameters(method)) { + PsiElement identifier = parameter.getNameIdentifierGroovy(); HighlightInfo highlightInfo = PostHighlightingPass - .createUnusedSymbolInfo(parameter.getNameIdentifierGroovy(), "Parameter " + parameter.getName() + " is unused", - HighlightInfoType.UNUSED_SYMBOL); - QuickFixAction.registerQuickFixAction(highlightInfo, new RemoveUnusedGrParameterFix(parameter)); + .createUnusedSymbolInfo(identifier, "Parameter " + parameter.getName() + " is unused", HighlightInfoType.UNUSED_SYMBOL); + QuickFixAction.registerQuickFixAction(highlightInfo, new RemoveUnusedGrParameterFix(parameter), unusedDefKey); unusedDeclarations.add(highlightInfo); } } @@ -206,6 +205,16 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { } + private static boolean methodMayHaveUnusedParameters(GrMethod method) { + return (method.isConstructor() || + method.hasModifierProperty(PsiModifier.PRIVATE) || + method.hasModifierProperty(PsiModifier.STATIC) || + !method.hasModifierProperty(PsiModifier.ABSTRACT) && !isOverriddenOrOverrides(method)) && + !method.hasModifierProperty(PsiModifier.NATIVE) && + !HighlightMethodUtil.isSerializationRelatedMethod(method, method.getContainingClass()) && + !PsiClassImplUtil.isMainOrPremainMethod(method); + } + private static boolean isFieldUnused(GrField field, ProgressIndicator progress, GlobalUsageHelper usageHelper) { if (!PostHighlightingPass.isFieldUnused(field, progress, usageHelper)) return false; final GrAccessorMethod[] getters = field.getGetters(); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 8e06733c95d8..4a95a884d75f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -151,7 +151,7 @@ public class GroovyHighlightingTest extends LightGroovyTestCase { public void testDefinitionUsedInClosure() { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testDefinitionUsedInClosure2() { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testDefinitionUsedInSwitchCase() { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } - public void testUnusedDefinitionForMethodMissing() {doTest(new GroovyUnusedDeclarationInspection())} + public void testUnusedDefinitionForMethodMissing() {doTest(new GroovyUnusedDeclarationInspection(), new UnusedDeclarationInspection())} public void testDuplicateInnerClass() {doTest();} public void testThisInStaticContext() {doTest();} @@ -677,6 +677,21 @@ List list2 doTest(new GroovyUnusedDeclarationInspection(), new UnusedDeclarationInspection()) } + public void testSuppressUnusedMethod() { + myFixture.configureByText('_.groovy', '''\ +class Foo { + @SuppressWarnings("GroovyUnusedDeclaration") + static def foo(int x) { + print 2 + } + + static def bar() {} +} +''') + myFixture.enableInspections(new UnusedDeclarationInspection(), new GroovyUnusedDeclarationInspection()) + myFixture.testHighlighting(true, false, true) + } + public void testAliasInParameterType() { myFixture.configureByText('a_.groovy', '''\ import java.awt.event.ActionListener