mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
highlight globally unused groovy classes (IDEA-75803)
This commit is contained in:
@@ -378,7 +378,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
|
||||
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) {
|
||||
@@ -436,6 +436,9 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
|
||||
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;
|
||||
@@ -580,49 +583,31 @@ public class PostHighlightingPass extends TextEditorHighlightingPass {
|
||||
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) {
|
||||
|
||||
@@ -382,6 +382,10 @@
|
||||
<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"/>
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
+33
-6
@@ -19,8 +19,10 @@ package org.jetbrains.plugins.groovy.codeInspection.local;
|
||||
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;
|
||||
@@ -28,24 +30,28 @@ import com.intellij.lang.annotation.AnnotationSession;
|
||||
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;
|
||||
@@ -56,20 +62,30 @@ import java.util.Set;
|
||||
/**
|
||||
* @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
|
||||
@@ -83,10 +99,21 @@ public class GroovyUnusedImportPass extends TextEditorHighlightingPass {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
@@ -143,7 +170,7 @@ public class GroovyUnusedImportPass extends TextEditorHighlightingPass {
|
||||
|
||||
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);
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class GroovyUnusedImportsPassFactory extends AbstractProjectComponent imp
|
||||
@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
|
||||
|
||||
Reference in New Issue
Block a user