Java tutorial
/* * Copyright 2000-2014 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 com.intellij.find.findUsages; import gnu.trove.THashSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.consulo.psi.PsiPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.CommonBundle; import com.intellij.find.FindBundle; import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.pom.PomTarget; import com.intellij.pom.references.PomService; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.impl.search.ThrowSearchUtil; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.PsiReferenceProcessor; import com.intellij.psi.search.PsiReferenceProcessorAdapter; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.targets.AliasingPsiTarget; import com.intellij.psi.targets.AliasingPsiTargetMapper; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.refactoring.util.JavaNonCodeSearchElementDescriptionProvider; import com.intellij.refactoring.util.NonCodeSearchDescriptionLocation; import com.intellij.usageView.UsageInfo; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; /** * @author peter */ public class JavaFindUsagesHandler extends FindUsagesHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.find.findUsages.JavaFindUsagesHandler"); public static final String ACTION_STRING = FindBundle.message("find.super.method.warning.action.verb"); private final PsiElement[] myElementsToSearch; private final JavaFindUsagesHandlerFactory myFactory; public JavaFindUsagesHandler(@NotNull PsiElement psiElement, @NotNull JavaFindUsagesHandlerFactory factory) { this(psiElement, PsiElement.EMPTY_ARRAY, factory); } public JavaFindUsagesHandler(@NotNull PsiElement psiElement, @NotNull PsiElement[] elementsToSearch, @NotNull JavaFindUsagesHandlerFactory factory) { super(psiElement); myElementsToSearch = elementsToSearch; myFactory = factory; } @Override @NotNull public AbstractFindUsagesDialog getFindUsagesDialog(boolean isSingleFile, boolean toShowInNewTab, boolean mustOpenInNewTab) { PsiElement element = getPsiElement(); if (element instanceof PsiPackage) { return new FindPackageUsagesDialog(element, getProject(), myFactory.getFindPackageOptions(), toShowInNewTab, mustOpenInNewTab, isSingleFile, this); } if (element instanceof PsiClass) { return new FindClassUsagesDialog(element, getProject(), myFactory.getFindClassOptions(), toShowInNewTab, mustOpenInNewTab, isSingleFile, this); } if (element instanceof PsiMethod) { return new FindMethodUsagesDialog(element, getProject(), myFactory.getFindMethodOptions(), toShowInNewTab, mustOpenInNewTab, isSingleFile, this); } if (element instanceof PsiVariable) { return new FindVariableUsagesDialog(element, getProject(), myFactory.getFindVariableOptions(), toShowInNewTab, mustOpenInNewTab, isSingleFile, this); } if (ThrowSearchUtil.isSearchable(element)) { return new FindThrowUsagesDialog(element, getProject(), myFactory.getFindThrowOptions(), toShowInNewTab, mustOpenInNewTab, isSingleFile, this); } return super.getFindUsagesDialog(isSingleFile, toShowInNewTab, mustOpenInNewTab); } private static boolean askWhetherShouldSearchForParameterInOverridingMethods(final PsiElement psiElement, final PsiParameter parameter) { return Messages.showOkCancelDialog(psiElement.getProject(), FindBundle.message("find.parameter.usages.in.overriding.methods.prompt", parameter.getName()), FindBundle.message("find.parameter.usages.in.overriding.methods.title"), CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText(), Messages.getQuestionIcon()) == Messages.OK; } @NotNull private static PsiElement[] getParameterElementsToSearch(@NotNull PsiParameter parameter) { final PsiMethod method = (PsiMethod) parameter.getDeclarationScope(); PsiMethod[] overrides = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); for (int i = 0; i < overrides.length; i++) { overrides[i] = (PsiMethod) overrides[i].getNavigationElement(); } List<PsiElement> elementsToSearch = new ArrayList<PsiElement>(overrides.length + 1); elementsToSearch.add(parameter); int idx = method.getParameterList().getParameterIndex(parameter); for (PsiMethod override : overrides) { final PsiParameter[] parameters = override.getParameterList().getParameters(); if (idx < parameters.length) { elementsToSearch.add(parameters[idx]); } } return PsiUtilCore.toPsiElementArray(elementsToSearch); } @Override @NotNull public PsiElement[] getPrimaryElements() { final PsiElement element = getPsiElement(); if (element instanceof PsiParameter) { final PsiParameter parameter = (PsiParameter) element; final PsiElement scope = parameter.getDeclarationScope(); if (scope instanceof PsiMethod) { final PsiMethod method = (PsiMethod) scope; if (PsiUtil.canBeOverriden(method)) { final PsiClass aClass = method.getContainingClass(); LOG.assertTrue(aClass != null); //Otherwise can not be overriden boolean hasOverridden = OverridingMethodsSearch.search(method).findFirst() != null; if (hasOverridden && askWhetherShouldSearchForParameterInOverridingMethods(element, parameter)) { return getParameterElementsToSearch(parameter); } } } } return myElementsToSearch.length == 0 ? new PsiElement[] { element } : myElementsToSearch; } @Override @NotNull public PsiElement[] getSecondaryElements() { PsiElement element = getPsiElement(); if (ApplicationManager.getApplication().isUnitTestMode()) { return PsiElement.EMPTY_ARRAY; } if (element instanceof PsiField) { final PsiField field = (PsiField) element; PsiClass containingClass = field.getContainingClass(); if (containingClass != null) { String fieldName = field.getName(); final String propertyName = JavaCodeStyleManager.getInstance(getProject()) .variableNameToPropertyName(fieldName, VariableKind.FIELD); Set<PsiMethod> accessors = new THashSet<PsiMethod>(); boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); PsiMethod getter = PropertyUtil.findPropertyGetterWithType(propertyName, isStatic, field.getType(), ContainerUtil.iterate(containingClass.getMethods())); if (getter != null) { accessors.add(getter); } PsiMethod setter = PropertyUtil.findPropertySetterWithType(propertyName, isStatic, field.getType(), ContainerUtil.iterate(containingClass.getMethods())); if (setter != null) { accessors.add(setter); } accessors.addAll(PropertyUtil.getAccessors(containingClass, fieldName)); if (!accessors.isEmpty()) { boolean containsPhysical = ContainerUtil.find(accessors, new Condition<PsiMethod>() { @Override public boolean value(PsiMethod psiMethod) { return psiMethod.isPhysical(); } }) != null; final boolean doSearch = !containsPhysical || Messages.showOkCancelDialog( FindBundle.message("find.field.accessors.prompt", fieldName), FindBundle.message("find.field.accessors.title"), CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText(), Messages.getQuestionIcon()) == Messages.OK; if (doSearch) { final Set<PsiElement> elements = new THashSet<PsiElement>(); for (PsiMethod accessor : accessors) { ContainerUtil.addAll(elements, SuperMethodWarningUtil.checkSuperMethods(accessor, ACTION_STRING)); } return PsiUtilCore.toPsiElementArray(elements); } } } } return super.getSecondaryElements(); } @Override @NotNull public FindUsagesOptions getFindUsagesOptions(@Nullable final DataContext dataContext) { PsiElement element = getPsiElement(); if (element instanceof PsiPackage) { return myFactory.getFindPackageOptions(); } if (element instanceof PsiClass) { return myFactory.getFindClassOptions(); } if (element instanceof PsiMethod) { return myFactory.getFindMethodOptions(); } if (element instanceof PsiVariable) { return myFactory.getFindVariableOptions(); } if (ThrowSearchUtil.isSearchable(element)) { return myFactory.getFindThrowOptions(); } return super.getFindUsagesOptions(dataContext); } @Override protected Set<String> getStringsToSearch(final PsiElement element) { if (element instanceof PsiDirectory) { // normalize a directory to a corresponding package return getStringsToSearch(JavaDirectoryService.getInstance().getPackage((PsiDirectory) element)); } final Set<String> result = new HashSet<String>(); ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { if (element instanceof PsiPackage) { ContainerUtil.addIfNotNull(result, ((PsiPackage) element).getQualifiedName()); } else if (element instanceof PsiClass) { final String qname = ((PsiClass) element).getQualifiedName(); if (qname != null) { result.add(qname); PsiClass topLevelClass = PsiUtil.getTopLevelClass(element); if (topLevelClass != null) { String topName = topLevelClass.getQualifiedName(); assert topName != null; if (qname.length() > topName.length()) { result.add(topName + qname.substring(topName.length()).replace('.', '$')); } } } } else if (element instanceof PsiMethod) { ContainerUtil.addIfNotNull(result, ((PsiMethod) element).getName()); } else if (element instanceof PsiVariable) { ContainerUtil.addIfNotNull(result, ((PsiVariable) element).getName()); } else if (element instanceof PsiMetaOwner) { final PsiMetaData metaData = ((PsiMetaOwner) element).getMetaData(); if (metaData != null) { ContainerUtil.addIfNotNull(result, metaData.getName()); } } else if (element instanceof PsiNamedElement) { ContainerUtil.addIfNotNull(result, ((PsiNamedElement) element).getName()); } else if (element instanceof XmlAttributeValue) { ContainerUtil.addIfNotNull(result, ((XmlAttributeValue) element).getValue()); } else { LOG.error("Unknown element type: " + element); } } }); return result; } @Override public boolean processElementUsages(@NotNull final PsiElement element, @NotNull final Processor<UsageInfo> processor, @NotNull final FindUsagesOptions options) { if (options instanceof JavaVariableFindUsagesOptions) { final JavaVariableFindUsagesOptions varOptions = (JavaVariableFindUsagesOptions) options; if (varOptions.isReadAccess || varOptions.isWriteAccess) { if (varOptions.isReadAccess && varOptions.isWriteAccess) { if (!addElementUsages(element, processor, options)) { return false; } } else { if (!addElementUsages(element, new Processor<UsageInfo>() { @Override public boolean process(UsageInfo info) { final PsiElement element = info.getElement(); boolean isWrite = element instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression) element); if (isWrite == varOptions.isWriteAccess) { if (!processor.process(info)) { return false; } } return true; } }, varOptions)) { return false; } } } } else if (options.isUsages) { if (!addElementUsages(element, processor, options)) { return false; } } boolean success = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { if (ThrowSearchUtil.isSearchable(element) && options instanceof JavaThrowFindUsagesOptions && options.isUsages) { ThrowSearchUtil.Root root = options.getUserData(ThrowSearchUtil.THROW_SEARCH_ROOT_KEY); if (root == null) { final ThrowSearchUtil.Root[] roots = ThrowSearchUtil.getSearchRoots(element); if (roots != null && roots.length > 0) { root = roots[0]; } } if (root != null) { return ThrowSearchUtil.addThrowUsages(processor, root, options); } } return true; } }); if (!success) { return false; } if (options instanceof JavaPackageFindUsagesOptions && ((JavaPackageFindUsagesOptions) options).isClassesUsages) { if (!addClassesUsages((PsiPackage) element, processor, (JavaPackageFindUsagesOptions) options)) { return false; } } if (options instanceof JavaClassFindUsagesOptions) { final JavaClassFindUsagesOptions classOptions = (JavaClassFindUsagesOptions) options; final PsiClass psiClass = (PsiClass) element; if (classOptions.isMethodsUsages) { if (!addMethodsUsages(psiClass, processor, classOptions)) { return false; } } if (classOptions.isFieldsUsages) { if (!addFieldsUsages(psiClass, processor, classOptions)) { return false; } } if (psiClass.isInterface()) { if (classOptions.isDerivedInterfaces) { if (classOptions.isImplementingClasses) { if (!addInheritors(psiClass, processor, classOptions)) { return false; } } else { if (!addDerivedInterfaces(psiClass, processor, classOptions)) { return false; } } } else if (classOptions.isImplementingClasses) { if (!addImplementingClasses(psiClass, processor, classOptions)) { return false; } } } else if (classOptions.isDerivedClasses) { if (!addInheritors(psiClass, processor, classOptions)) { return false; } } } if (options instanceof JavaMethodFindUsagesOptions) { final PsiMethod psiMethod = (PsiMethod) element; boolean isAbstract = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { return psiMethod.hasModifierProperty(PsiModifier.ABSTRACT); } }); final JavaMethodFindUsagesOptions methodOptions = (JavaMethodFindUsagesOptions) options; if (isAbstract && methodOptions.isImplementingMethods || methodOptions.isOverridingMethods) { if (!processOverridingMethods(psiMethod, processor, methodOptions)) { return false; } } } if (element instanceof PomTarget) { if (!addAliasingUsages((PomTarget) element, processor, options)) { return false; } } final Boolean isSearchable = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { return ThrowSearchUtil.isSearchable(element); } }); if (!isSearchable && options.isSearchForTextOccurrences && options.searchScope instanceof GlobalSearchScope) { // todo add to fastTrack if (!processUsagesInText(element, processor, (GlobalSearchScope) options.searchScope)) { return false; } } return true; } private static boolean addAliasingUsages(@NotNull PomTarget pomTarget, @NotNull final Processor<UsageInfo> processor, @NotNull final FindUsagesOptions options) { for (AliasingPsiTargetMapper aliasingPsiTargetMapper : Extensions .getExtensions(AliasingPsiTargetMapper.EP_NAME)) { for (AliasingPsiTarget psiTarget : aliasingPsiTargetMapper.getTargets(pomTarget)) { boolean success = ReferencesSearch .search(new ReferencesSearch.SearchParameters(PomService.convertToPsi(psiTarget), options.searchScope, false, options.fastTrack)) .forEach(new ReadActionProcessor<PsiReference>() { @Override public boolean processInReadAction(final PsiReference reference) { return addResult(processor, reference, options); } }); if (!success) { return false; } } } return true; } private static boolean processOverridingMethods(@NotNull PsiMethod psiMethod, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaMethodFindUsagesOptions options) { return OverridingMethodsSearch.search(psiMethod, options.searchScope, options.isCheckDeepInheritance) .forEach(new PsiElementProcessorAdapter<PsiMethod>(new PsiElementProcessor<PsiMethod>() { @Override public boolean execute(@NotNull PsiMethod element) { return addResult(processor, element.getNavigationElement(), options); } })); } private static boolean addClassesUsages(@NotNull PsiPackage aPackage, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaPackageFindUsagesOptions options) { ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); if (progress != null) { progress.pushState(); } List<PsiClass> classes = new ArrayList<PsiClass>(); addClassesInPackage(aPackage, options.isIncludeSubpackages, classes); for (final PsiClass aClass : classes) { if (progress != null) { progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", ApplicationManager.getApplication().runReadAction(new Computable<String>() { @Override public String compute() { return aClass.getName(); } }))); progress.checkCanceled(); } boolean success = ReferencesSearch.search( new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)) .forEach(new ReadActionProcessor<PsiReference>() { @Override public boolean processInReadAction(final PsiReference psiReference) { return addResult(processor, psiReference, options); } }); if (!success) { return false; } } if (progress != null) { progress.popState(); } return true; } private static void addClassesInPackage(@NotNull PsiPackage aPackage, boolean includeSubpackages, @NotNull List<PsiClass> array) { PsiDirectory[] dirs = aPackage.getDirectories(); for (PsiDirectory dir : dirs) { addClassesInDirectory(dir, includeSubpackages, array); } } private static void addClassesInDirectory(@NotNull final PsiDirectory dir, final boolean includeSubdirs, @NotNull final List<PsiClass> array) { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { PsiClass[] classes = JavaDirectoryService.getInstance().getClasses(dir); ContainerUtil.addAll(array, classes); if (includeSubdirs) { PsiDirectory[] dirs = dir.getSubdirectories(); for (PsiDirectory directory : dirs) { addClassesInDirectory(directory, includeSubdirs, array); } } } }); } private static boolean addMethodsUsages(@NotNull final PsiClass aClass, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaClassFindUsagesOptions options) { if (options.isIncludeInherited) { final PsiManager manager = aClass.getManager(); PsiMethod[] methods = aClass.getAllMethods(); MethodsLoop: for (int i = 0; i < methods.length; i++) { final PsiMethod method = methods[i]; // filter overriden methods MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); for (int j = 0; j < i; j++) { if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY))) { continue MethodsLoop; } } final PsiClass methodClass = method.getContainingClass(); if (methodClass != null && manager.areElementsEquivalent(methodClass, aClass)) { if (!addElementUsages(methods[i], processor, options)) { return false; } } else { boolean success = MethodReferencesSearch .search(new MethodReferencesSearch.SearchParameters(method, options.searchScope, true, options.fastTrack)) .forEach(new PsiReferenceProcessorAdapter(new PsiReferenceProcessor() { @Override public boolean execute(PsiReference reference) { addResultFromReference(reference, methodClass, manager, aClass, processor, options); return true; } })); if (!success) { return false; } } } } else { for (PsiMethod method : aClass.getMethods()) { if (!addElementUsages(method, processor, options)) { return false; } } } return true; } private static boolean addFieldsUsages(@NotNull final PsiClass aClass, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaClassFindUsagesOptions options) { if (options.isIncludeInherited) { final PsiManager manager = aClass.getManager(); PsiField[] fields = aClass.getAllFields(); FieldsLoop: for (int i = 0; i < fields.length; i++) { final PsiField field = fields[i]; // filter hidden fields for (int j = 0; j < i; j++) { if (Comparing.strEqual(field.getName(), fields[j].getName())) { continue FieldsLoop; } } final PsiClass fieldClass = field.getContainingClass(); if (manager.areElementsEquivalent(fieldClass, aClass)) { if (!addElementUsages(fields[i], processor, options)) { return false; } } else { boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(field, options.searchScope, false, options.fastTrack)) .forEach(new ReadActionProcessor<PsiReference>() { @Override public boolean processInReadAction(final PsiReference reference) { return addResultFromReference(reference, fieldClass, manager, aClass, processor, options); } }); if (!success) { return false; } } } } else { PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable<PsiField[]>() { @Override public PsiField[] compute() { return aClass.getFields(); } }); for (PsiField field : fields) { if (!addElementUsages(field, processor, options)) { return false; } } } return true; } @Nullable private static PsiClass getFieldOrMethodAccessedClass(@NotNull PsiReferenceExpression ref, PsiClass fieldOrMethodClass) { PsiElement[] children = ref.getChildren(); if (children.length > 1 && children[0] instanceof PsiExpression) { PsiExpression expr = (PsiExpression) children[0]; PsiType type = expr.getType(); if (type != null) { if (!(type instanceof PsiClassType)) { return null; } return PsiUtil.resolveClassInType(type); } else { if (expr instanceof PsiReferenceExpression) { PsiElement refElement = ((PsiReferenceExpression) expr).resolve(); if (refElement instanceof PsiClass) { return (PsiClass) refElement; } } return null; } } PsiManager manager = ref.getManager(); for (PsiElement parent = ref; parent != null; parent = parent.getParent()) { if (parent instanceof PsiClass && (manager.areElementsEquivalent(parent, fieldOrMethodClass) || ((PsiClass) parent).isInheritor(fieldOrMethodClass, true))) { return (PsiClass) parent; } } return null; } private static boolean addInheritors(@NotNull PsiClass aClass, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaClassFindUsagesOptions options) { return ClassInheritorsSearch.search(aClass, options.searchScope, options.isCheckDeepInheritance) .forEach(new PsiElementProcessorAdapter<PsiClass>(new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass element) { return addResult(processor, element, options); } })); } private static boolean addDerivedInterfaces(@NotNull PsiClass anInterface, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaClassFindUsagesOptions options) { return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance) .forEach(new PsiElementProcessorAdapter<PsiClass>(new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass inheritor) { return !inheritor.isInterface() || addResult(processor, inheritor, options); } })); } private static boolean addImplementingClasses(@NotNull PsiClass anInterface, @NotNull final Processor<UsageInfo> processor, @NotNull final JavaClassFindUsagesOptions options) { return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance) .forEach(new PsiElementProcessorAdapter<PsiClass>(new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass inheritor) { return inheritor.isInterface() || addResult(processor, inheritor, options); } })); } private static boolean addResultFromReference(@NotNull PsiReference reference, @NotNull PsiClass methodClass, @NotNull PsiManager manager, @NotNull PsiClass aClass, @NotNull Processor<UsageInfo> processor, @NotNull FindUsagesOptions options) { PsiElement refElement = reference.getElement(); if (refElement instanceof PsiReferenceExpression) { PsiClass usedClass = getFieldOrMethodAccessedClass((PsiReferenceExpression) refElement, methodClass); if (usedClass != null) { if (manager.areElementsEquivalent(usedClass, aClass) || usedClass.isInheritor(aClass, true)) { if (!addResult(processor, refElement, options)) { return false; } } } } return true; } private static boolean addElementUsages(@NotNull final PsiElement element, @NotNull final Processor<UsageInfo> processor, @NotNull final FindUsagesOptions options) { final SearchScope searchScope = options.searchScope; if (element instanceof PsiMethod && ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { return ((PsiMethod) element).isConstructor(); } })) { PsiMethod method = (PsiMethod) element; final PsiClass parentClass = method.getContainingClass(); if (parentClass != null) { boolean strictSignatureSearch = !(options instanceof JavaMethodFindUsagesOptions) || !((JavaMethodFindUsagesOptions) options).isIncludeOverloadUsages; return MethodReferencesSearch .search(new MethodReferencesSearch.SearchParameters(method, searchScope, strictSignatureSearch, options.fastTrack)) .forEach(new ReadActionProcessor<PsiReference>() { @Override public boolean processInReadAction(final PsiReference ref) { return addResult(processor, ref, options); } }); } return true; } final ReadActionProcessor<PsiReference> consumer = new ReadActionProcessor<PsiReference>() { @Override public boolean processInReadAction(final PsiReference ref) { return addResult(processor, ref, options); } }; if (element instanceof PsiMethod) { final boolean strictSignatureSearch = !(options instanceof JavaMethodFindUsagesOptions) || // field with getter !((JavaMethodFindUsagesOptions) options).isIncludeOverloadUsages; return MethodReferencesSearch.search(new MethodReferencesSearch.SearchParameters((PsiMethod) element, searchScope, strictSignatureSearch, options.fastTrack)).forEach(consumer); } return ReferencesSearch .search(new ReferencesSearch.SearchParameters(element, searchScope, false, options.fastTrack)) .forEach(consumer); } private static boolean addResult(@NotNull Processor<UsageInfo> processor, @NotNull PsiElement element, @NotNull FindUsagesOptions options) { return !filterUsage(element, options) || processor.process(new UsageInfo(element)); } private static boolean addResult(Processor<UsageInfo> processor, PsiReference ref, FindUsagesOptions options) { if (filterUsage(ref.getElement(), options)) { TextRange rangeInElement = ref.getRangeInElement(); return processor.process(new UsageInfo(ref.getElement(), rangeInElement.getStartOffset(), rangeInElement.getEndOffset(), false)); } return true; } private static boolean filterUsage(PsiElement usage, FindUsagesOptions options) { if (!(usage instanceof PsiJavaCodeReferenceElement)) { return true; } if (options instanceof JavaPackageFindUsagesOptions && !((JavaPackageFindUsagesOptions) options).isIncludeSubpackages && ((PsiReference) usage).resolve() instanceof PsiPackage) { PsiElement parent = usage.getParent(); if (parent instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement) parent).resolve() instanceof PsiPackage) { return false; } } if (!(usage instanceof PsiReferenceExpression)) { if (options instanceof JavaFindUsagesOptions && ((JavaFindUsagesOptions) options).isSkipImportStatements) { PsiElement parent = usage.getParent(); while (parent instanceof PsiJavaCodeReferenceElement) { parent = parent.getParent(); } if (parent instanceof PsiImportStatement) { return false; } } if (options instanceof JavaPackageFindUsagesOptions && ((JavaPackageFindUsagesOptions) options).isSkipPackageStatements) { PsiElement parent = usage.getParent(); while (parent instanceof PsiJavaCodeReferenceElement) { parent = parent.getParent(); } if (parent instanceof PsiPackageStatement) { return false; } } } return true; } @Override protected boolean isSearchForTextOccurencesAvailable(@NotNull PsiElement psiElement, boolean isSingleFile) { if (isSingleFile) { return false; } return new JavaNonCodeSearchElementDescriptionProvider().getElementDescription(psiElement, NonCodeSearchDescriptionLocation.NON_JAVA) != null; } @Override public Collection<PsiReference> findReferencesToHighlight(@NotNull final PsiElement target, @NotNull final SearchScope searchScope) { if (target instanceof PsiMethod) { final PsiMethod[] superMethods = ((PsiMethod) target).findDeepestSuperMethods(); if (superMethods.length == 0) { return MethodReferencesSearch.search((PsiMethod) target, searchScope, true).findAll(); } final Collection<PsiReference> result = new ArrayList<PsiReference>(); for (PsiMethod superMethod : superMethods) { result.addAll(MethodReferencesSearch.search(superMethod, searchScope, true).findAll()); } return result; } return super.findReferencesToHighlight(target, searchScope); } }