import com.intellij.refactoring.changeSignature.ChangeSignatureGestureDetector;
import com.intellij.util.Processor;
import gnu.trove.THashSet;
-import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
myDeadCodeInfoType = myDeadCodeKey == null ? null : new HighlightInfoType.HighlightInfoTypeImpl(profile.getErrorLevel(myDeadCodeKey, myFile).getSeverity(), HighlightInfoType.UNUSED_SYMBOL.getAttributesKey());
+ GlobalUsageHelper helper = new GlobalUsageHelper() {
+ @Override
+ public boolean shouldCheckUsages(@NotNull PsiMember member) {
+ if (myInLibrary) return false;
+ if (!myDeadCodeEnabled) return false;
+ if (myDeadCodeInspection.isEntryPoint(member)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean isLocallyUsed(@NotNull PsiNamedElement member) {
+ return myRefCountHolder.isReferenced(myFile);
+ }
+ };
+
boolean errorFound = false;
if (unusedSymbolEnabled) {
for (PsiElement element : elements) {
progress.checkCanceled();
if (element instanceof PsiIdentifier) {
PsiIdentifier identifier = (PsiIdentifier)element;
- HighlightInfo info = processIdentifier(identifier, progress);
+ HighlightInfo info = processIdentifier(identifier, progress, helper);
if (info != null) {
errorFound |= info.getSeverity() == HighlightSeverity.ERROR;
result.add(info);
}
@Nullable
- private HighlightInfo processIdentifier(PsiIdentifier identifier, ProgressIndicator progress) {
+ private HighlightInfo processIdentifier(PsiIdentifier identifier, ProgressIndicator progress, GlobalUsageHelper helper) {
if (InspectionManagerEx.inspectionResultSuppressed(identifier, myUnusedSymbolInspection)) return null;
PsiElement parent = identifier.getParent();
if (PsiUtilCore.hasErrorElementChild(parent)) return null;
return processLocalVariable((PsiLocalVariable)parent, progress);
}
if (parent instanceof PsiField && myUnusedSymbolInspection.FIELD) {
- return processField((PsiField)parent, identifier, progress);
+ return processField((PsiField)parent, identifier, progress, helper);
}
if (parent instanceof PsiParameter && myUnusedSymbolInspection.PARAMETER) {
if (InspectionManagerEx.isSuppressed(identifier, UnusedParametersInspection.SHORT_NAME)) return null;
return processParameter((PsiParameter)parent, progress);
}
if (parent instanceof PsiMethod && myUnusedSymbolInspection.METHOD) {
- return processMethod((PsiMethod)parent, progress);
+ return processMethod((PsiMethod)parent, progress, helper);
}
if (parent instanceof PsiClass && myUnusedSymbolInspection.CLASS) {
- return processClass((PsiClass)parent, progress);
+ return processClass((PsiClass)parent, progress, helper);
}
return null;
}
}
@Nullable
- private HighlightInfo processField(final PsiField field, final PsiIdentifier identifier, ProgressIndicator progress) {
+ private HighlightInfo processField(final PsiField field, final PsiIdentifier identifier, ProgressIndicator progress, GlobalUsageHelper helper) {
if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
if (!myRefCountHolder.isReferenced(field) && !isImplicitUsage(field, progress)) {
if (HighlightUtil.isSerializationImplicitlyUsedField(field)) {
else if (isImplicitUsage(field, progress)) {
return null;
}
- else if (!myRefCountHolder.isReferenced(field) && weAreSureThereAreNoUsages(field, progress)) {
- if (field instanceof PsiEnumConstant && isEnumValuesMethodUsed(field, progress)) {
+ else if (!myRefCountHolder.isReferenced(field) && weAreSureThereAreNoUsages(field, progress, helper)) {
+ if (field instanceof PsiEnumConstant && isEnumValuesMethodUsed(field, progress, helper)) {
return null;
}
return formatUnusedSymbolHighlightInfo("field.is.not.used", field, "fields", myDeadCodeKey, myDeadCodeInfoType);
}
@Nullable
- private HighlightInfo processMethod(final PsiMethod method, ProgressIndicator progress) {
+ private HighlightInfo processMethod(final PsiMethod method, ProgressIndicator progress, GlobalUsageHelper helper) {
boolean isPrivate = method.hasModifierProperty(PsiModifier.PRIVATE);
PsiClass containingClass = method.getContainingClass();
- if (isMethodReferenced(method, progress, isPrivate, containingClass)) return null;
+ if (isMethodReferenced(method, progress, isPrivate, containingClass, helper)) return null;
HighlightInfoType highlightInfoType;
HighlightDisplayKey highlightDisplayKey;
String key;
return highlightInfo;
}
- private boolean isMethodReferenced(PsiMethod method, ProgressIndicator progress, boolean aPrivate, PsiClass containingClass) {
- if (myRefCountHolder.isReferenced(method)) return true;
+ private static boolean isMethodReferenced(PsiMethod method,
+ ProgressIndicator progress,
+ boolean aPrivate,
+ PsiClass containingClass,
+ GlobalUsageHelper helper) {
+ if (helper.isLocallyUsed(method)) return true;
if (HighlightMethodUtil.isSerializationRelatedMethod(method, containingClass)) return true;
if (aPrivate) {
//class maybe used in some weird way, e.g. from XML, therefore the only constructor is used too
if (containingClass != null && method.isConstructor()
&& containingClass.getConstructors().length == 1
- && isClassUnused(containingClass, progress) == USED) {
+ && isClassUsed(containingClass, progress, helper)) {
return true;
}
if (isImplicitUsage(method, progress)) return true;
if (method.findSuperMethods().length != 0) {
return true;
}
- if (!weAreSureThereAreNoUsages(method, progress)) {
+ if (!weAreSureThereAreNoUsages(method, progress, helper)) {
return true;
}
}
return false;
}
- private boolean weAreSureThereAreNoUsages(PsiMember member, ProgressIndicator progress) {
- if (myInLibrary) return false;
- if (!myDeadCodeEnabled) return false;
- if (myDeadCodeInspection.isEntryPoint(member)) return false;
-
- return isGloballyUnused(member, progress, myFile, member.getName());
- }
+ private static boolean weAreSureThereAreNoUsages(PsiMember member, ProgressIndicator progress, GlobalUsageHelper helper) {
+ if (!helper.shouldCheckUsages(member)) return false;
- public static boolean isGloballyUnused(PsiMember member, ProgressIndicator progress, @Nullable PsiFile fileToIgnoreOccurrencesIn, String name) {
+ String name = member.getName();
if (name == null) return false;
SearchScope useScope = member.getUseScope();
if (!(useScope instanceof GlobalSearchScope)) return false;
Project project = member.getProject();
if (member instanceof PsiClass) scope = GlobalSearchScope.projectScope(project).uniteWith(scope);
- PsiSearchHelper.SearchCostResult cheapEnough = PsiSearchHelper.SERVICE.getInstance(project).isCheapEnoughToSearch(name, scope, fileToIgnoreOccurrencesIn, progress);
+ 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
return !findUsagesManager.isUsed(member, findUsagesOptions);
}
- private boolean isEnumValuesMethodUsed(PsiMember member, ProgressIndicator progress) {
+ private static boolean isEnumValuesMethodUsed(PsiMember member, ProgressIndicator progress, GlobalUsageHelper helper) {
final PsiClassImpl containingClass = (PsiClassImpl)member.getContainingClass();
if (containingClass == null) return true;
final PsiMethod valuesMethod = containingClass.getValuesMethod();
if (valuesMethod == null) return true;
boolean isPrivate = valuesMethod.hasModifierProperty(PsiModifier.PRIVATE);
- return isMethodReferenced(valuesMethod, progress, isPrivate, containingClass);
+ return isMethodReferenced(valuesMethod, progress, isPrivate, containingClass, helper);
}
private static boolean canBeReferencedViaWeirdNames(PsiMember member) {
}
@Nullable
- private HighlightInfo processClass(PsiClass aClass, ProgressIndicator progress) {
- int usage = isClassUnused(aClass, progress);
- if (usage == USED) return null;
+ private HighlightInfo processClass(PsiClass aClass, ProgressIndicator progress, GlobalUsageHelper helper) {
+ if (isClassUsed(aClass, progress, helper)) return null;
String pattern;
HighlightDisplayKey highlightDisplayKey;
return formatUnusedSymbolHighlightInfo(pattern, aClass, "classes", highlightDisplayKey, highlightInfoType);
}
- private static final int USED = 1;
- private static final int UNUSED_LOCALLY = 2;
- private static final int UNUSED_GLOBALLY = 3;
- private final TObjectIntHashMap<PsiClass> unusedClassCache = new TObjectIntHashMap<PsiClass>();
- private int isClassUnused(PsiClass aClass, ProgressIndicator progress) {
- if (aClass == null) return USED;
- int result = unusedClassCache.get(aClass);
- if (result == 0) {
- result = isReallyUnused(aClass, progress);
- unusedClassCache.put(aClass, result);
+ public static boolean isClassUsed(PsiClass aClass, ProgressIndicator progress, GlobalUsageHelper helper) {
+ if (aClass == null) return true;
+ Boolean result = helper.unusedClassCache.get(aClass);
+ if (result == null) {
+ result = !isReallyUsed(aClass, progress, helper);
+ helper.unusedClassCache.put(aClass, result);
}
return result;
}
- private int isReallyUnused(PsiClass aClass, ProgressIndicator progress) {
- if (isImplicitUsage(aClass, progress) || myRefCountHolder.isReferenced(aClass)) return USED;
+ private static boolean isReallyUsed(PsiClass aClass, ProgressIndicator progress, GlobalUsageHelper helper) {
+ if (isImplicitUsage(aClass, progress) || helper.isLocallyUsed(aClass)) return true;
if (aClass.getContainingClass() != null && aClass.hasModifierProperty(PsiModifier.PRIVATE) ||
aClass.getParent() instanceof PsiDeclarationStatement ||
- aClass instanceof PsiTypeParameter) return UNUSED_LOCALLY;
- if (weAreSureThereAreNoUsages(aClass, progress)) return UNUSED_GLOBALLY;
- return USED;
+ aClass instanceof PsiTypeParameter) return false;
+ return !weAreSureThereAreNoUsages(aClass, progress, helper);
}
private static HighlightInfo formatUnusedSymbolHighlightInfo(@PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String pattern,
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.AnnotationSession;
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.util.Processor;
import org.jetbrains.annotations.NotNull;
}
public void doCollectInformation(final ProgressIndicator progress) {
- InspectionProfile profile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile();
+ 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 UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile);
+ final GlobalUsageHelper usageHelper = new GlobalUsageHelper() {
+ @Override
+ public boolean shouldCheckUsages(@NotNull PsiMember member) {
+ return deadCodeInspection == null || !deadCodeInspection.isEntryPoint(member);
+ }
+ };
final List<HighlightInfo> unusedDeclarations = new ArrayList<HighlightInfo>();
final Set<GrImportStatement> unusedImports = new HashSet<GrImportStatement>(GroovyImportOptimizer.getValidImportStatements(myFile));
if (deadCodeEnabled && element instanceof GrNamedElement && !PostHighlightingPass.isImplicitUsage((GrNamedElement)element, progress)) {
PsiElement nameId = ((GrNamedElement)element).getNameIdentifierGroovy();
String name = ((GrNamedElement)element).getName();
- if (element instanceof GrTypeDefinition && PostHighlightingPass.isGloballyUnused((GrTypeDefinition)element, progress, null, name)) {
+ if (element instanceof GrTypeDefinition && PostHighlightingPass.isClassUsed((GrTypeDefinition)element, progress, usageHelper)) {
unusedDeclarations.add(
PostHighlightingPass.createUnusedSymbolInfo(nameId, "Class " + name + " is unused", HighlightInfoType.UNUSED_SYMBOL));
}