suppress actions for groovy 'unused declarations'

This commit is contained in:
Max Medvedev
2012-10-05 14:36:10 +03:00
parent 7d3f5f065f
commit 39ca735520
5 changed files with 64 additions and 21 deletions
+1 -1
View File
@@ -478,7 +478,7 @@
<copyPastePreProcessor implementation="org.jetbrains.plugins.groovy.editor.GroovyLiteralCopyPasteProcessor"/>
<copyPastePostProcessor implementation="org.jetbrains.plugins.groovy.editor.GroovyReferenceCopyPasteProcessor"/>
<specialTool shortName="GroovyUnusedDeclaration" displayName="Unused declaration"
<globalInspection shortName="GroovyUnusedDeclaration" displayName="Unused declaration"
groupPath="Groovy"
groupName="Declaration redundancy" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection"/>
@@ -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
@@ -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);
}
}
@@ -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();
@@ -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 <warning descr="Class Foo is unused">Foo</warning> {
@SuppressWarnings("GroovyUnusedDeclaration")
static def foo(int x) {
print 2
}
static def <warning descr="Method bar is unused">bar</warning>() {}
}
''')
myFixture.enableInspections(new UnusedDeclarationInspection(), new GroovyUnusedDeclarationInspection())
myFixture.testHighlighting(true, false, true)
}
public void testAliasInParameterType() {
myFixture.configureByText('a_.groovy', '''\
import java.awt.event.ActionListener