return UnusedSymbolLocalInspection.isInjected(element);
}
- private static HighlightInfo createUnusedSymbolInfo(PsiElement element, String message, final HighlightInfoType highlightInfoType) {
+ public static HighlightInfo createUnusedSymbolInfo(PsiElement element, String message, final HighlightInfoType highlightInfoType) {
HighlightInfo info = HighlightInfo.createHighlightInfo(highlightInfoType, element, message);
UnusedDeclarationFixProvider[] fixProviders = Extensions.getExtensions(UnusedDeclarationFixProvider.EP_NAME);
for (UnusedDeclarationFixProvider provider : fixProviders) {
return null;
}
else if (!myRefCountHolder.isReferenced(field) && weAreSureThereAreNoUsages(field, progress)) {
+ if (field instanceof PsiEnumConstant && isEnumValuesMethodUsed(field, progress)) {
+ return null;
+ }
return formatUnusedSymbolHighlightInfo("field.is.not.used", field, "fields", myDeadCodeKey, myDeadCodeInfoType);
}
return null;
if (!myDeadCodeEnabled) return false;
if (myDeadCodeInspection.isEntryPoint(member)) return false;
- String name = member.getName();
+ return isGloballyUnused(member, progress, myFile, member.getName());
+ }
+
+ public static boolean isGloballyUnused(PsiMember member, ProgressIndicator progress, @Nullable PsiFile fileToIgnoreOccurrencesIn, String name) {
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
- if (member instanceof PsiClass) scope = GlobalSearchScope.projectScope(myProject).uniteWith(scope);
+ Project project = member.getProject();
+ if (member instanceof PsiClass) scope = GlobalSearchScope.projectScope(project).uniteWith(scope);
- PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(myFile.getProject())
- .isCheapEnoughToSearch(name, scope, myFile, progress);
+ PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(project).isCheapEnoughToSearch(name, scope, fileToIgnoreOccurrencesIn, 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 (member instanceof PsiEnumConstant) {
- return !isEnumValuesMethodUsed(member, progress);
- }
if (!canBeReferencedViaWeirdNames(member)) return true;
}
- FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(myProject)).getFindUsagesManager();
- FindUsagesOptions findUsagesOptions;
- if (member instanceof PsiClass) {
- findUsagesOptions = new JavaClassFindUsagesOptions(myProject);
- }
- else if (member instanceof PsiMethod) {
- findUsagesOptions = new JavaMethodFindUsagesOptions(myProject);
- }
- else if (member instanceof PsiField) {
- findUsagesOptions = new JavaVariableFindUsagesOptions(myProject);
- }
- else {
- LOG.error("unknown member: " + member);
- return false;
- }
+ FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager();
+ FindUsagesHandler handler = new JavaFindUsagesHandler(member, new JavaFindUsagesHandlerFactory(project));
+ FindUsagesOptions findUsagesOptions = handler.getFindUsagesOptions();
findUsagesOptions.searchScope = scope;
-
- boolean used = findUsagesManager.isUsed(member, findUsagesOptions);
-
- if (!used && member instanceof PsiEnumConstant) {
- return !isEnumValuesMethodUsed(member, progress);
- }
- return !used;
+ return !findUsagesManager.isUsed(member, findUsagesOptions);
}
private boolean isEnumValuesMethodUsed(PsiMember member, ProgressIndicator progress) {
<copyPastePreProcessor implementation="org.jetbrains.plugins.groovy.lang.editor.GroovyLiteralCopyPasteProcessor"/>
<copyPastePostProcessor implementation="org.jetbrains.plugins.groovy.lang.editor.GroovyReferenceCopyPasteProcessor"/>
+ <specialTool shortName="GroovyUnusedDeclaration" displayName="Unused declaration"
+ groupName="Declaration Redundancy" enabledByDefault="true" level="WARNING"
+ implementationClass="org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection"/>
+
<localInspection language="Groovy" groupPath="Groovy" shortName="SecondUnsafeCall" bundle="org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle"
key="second.unsafe.call" groupName="Probable bugs" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.plugins.groovy.codeInspection.secondUnsafeCall.SecondUnsafeCallInspection"/>
--- /dev/null
+/*
+ * Copyright 2000-2012 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 org.jetbrains.plugins.groovy.codeInspection;
+
+import com.intellij.analysis.AnalysisScope;
+import com.intellij.codeInspection.GlobalInspectionContext;
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ex.DescriptorProviderInspection;
+import com.intellij.codeInspection.ex.JobDescriptor;
+import com.intellij.codeInspection.ex.UnfairLocalInspectionTool;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author peter
+ */
+public class GroovyUnusedDeclarationInspection extends DescriptorProviderInspection implements UnfairLocalInspectionTool {
+ public static final String SHORT_NAME = "GroovyUnusedDeclaration";
+
+ @Override
+ public void runInspection(@NotNull AnalysisScope scope, @NotNull InspectionManager manager) {
+ }
+
+ @NotNull
+ @Override
+ public JobDescriptor[] getJobDescriptors(GlobalInspectionContext globalInspectionContext) {
+ return JobDescriptor.EMPTY_ARRAY;
+ }
+
+}
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
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.PsiRecursiveElementWalkingVisitor;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
+import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection;
import org.jetbrains.plugins.groovy.lang.editor.GroovyImportOptimizer;
+import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import java.util.ArrayList;
/**
* @author ilyas
*/
-public class GroovyUnusedImportPass extends TextEditorHighlightingPass {
+public class GroovyPostHighlightingPass extends TextEditorHighlightingPass {
private final GroovyFile myFile;
private final Editor myEditor;
- public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.codeInspection.local.GroovyUnusedImportsPass");
private volatile Set<GrImportStatement> myUnusedImports;
private volatile Runnable myOptimizeRunnable;
+ private volatile List<HighlightInfo> myUnusedDeclarations;
- public GroovyUnusedImportPass(GroovyFile file, Editor editor) {
+ public GroovyPostHighlightingPass(GroovyFile file, Editor editor) {
super(file.getProject(), editor.getDocument(), true);
myFile = file;
myEditor = editor;
}
- public void doCollectInformation(ProgressIndicator progress) {
+ public void doCollectInformation(final ProgressIndicator progress) {
+ 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 List<HighlightInfo> unusedDeclarations = new ArrayList<HighlightInfo>();
final Set<GrImportStatement> unusedImports = new HashSet<GrImportStatement>(GroovyImportOptimizer.getValidImportStatements(myFile));
myFile.accept(new PsiRecursiveElementWalkingVisitor() {
@Override
}
}
}
+
+ if (deadCodeEnabled && element instanceof GrNamedElement) {
+ PsiElement nameId = ((GrNamedElement)element).getNameIdentifierGroovy();
+ String name = ((GrNamedElement)element).getName();
+ if (element instanceof GrTypeDefinition && PostHighlightingPass.isGloballyUnused((GrTypeDefinition)element, progress, null, name)) {
+ unusedDeclarations.add(
+ PostHighlightingPass.createUnusedSymbolInfo(nameId, "Class " + name + " is unused", HighlightInfoType.UNUSED_SYMBOL));
+ }
+ }
+
super.visitElement(element);
}
});
myUnusedImports = unusedImports;
+ myUnusedDeclarations = unusedDeclarations;
if (!unusedImports.isEmpty() && CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) {
final VirtualFile vfile = myFile.getVirtualFile();
if (vfile != null && ProjectRootManager.getInstance(myFile.getProject()).getFileIndex().isInSource(vfile)) {
public void doApplyInformationToEditor() {
AnnotationHolder annotationHolder = new AnnotationHolderImpl(new AnnotationSession(myFile));
- List<HighlightInfo> infos = new ArrayList<HighlightInfo>(myUnusedImports.size());
+ List<HighlightInfo> infos = new ArrayList<HighlightInfo>(myUnusedDeclarations);
for (GrImportStatement unusedImport : myUnusedImports) {
Annotation annotation = annotationHolder.createWarningAnnotation(unusedImport, GroovyInspectionBundle.message("unused.import"));
annotation.setHighlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL);
@Nullable
public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull Editor editor) {
if (!(file instanceof GroovyFile)) return null;
- return new GroovyUnusedImportPass((GroovyFile)file, editor);
+ return new GroovyPostHighlightingPass((GroovyFile)file, editor);
}
@NonNls