diff --git a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java new file mode 100644 index 000000000000..dd34369321d4 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java @@ -0,0 +1,654 @@ +/* + * 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 com.intellij.find.FindBundle; +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.util.Comparing; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.NullableComputable; +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.impl.search.ThrowSearchUtil; +import com.intellij.psi.meta.PsiMetaData; +import com.intellij.psi.meta.PsiMetaOwner; +import com.intellij.psi.search.*; +import com.intellij.psi.search.searches.*; +import com.intellij.psi.targets.AliasingPsiTarget; +import com.intellij.psi.targets.AliasingPsiTargetMapper; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class JavaFindUsagesHelper { + private static final Logger LOG = Logger.getInstance("#com.intellij.find.findUsages.JavaFindUsagesHelper"); + + @NotNull + static Set getElementNames(@NotNull final PsiElement element) { + if (element instanceof PsiDirectory) { // normalize a directory to a corresponding package + PsiPackage aPackage = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiPackage compute() { + return JavaDirectoryService.getInstance().getPackage((PsiDirectory)element); + } + }); + return aPackage == null ? Collections.emptySet() : getElementNames(aPackage); + } + + final Set result = new HashSet(); + + 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; + } + + public static boolean processElementUsages(@NotNull final PsiElement element, + @NotNull final FindUsagesOptions options, @NotNull final Processor processor) { + if (options instanceof JavaVariableFindUsagesOptions) { + final JavaVariableFindUsagesOptions varOptions = (JavaVariableFindUsagesOptions) options; + if (varOptions.isReadAccess || varOptions.isWriteAccess){ + if (varOptions.isReadAccess && varOptions.isWriteAccess){ + if (!addElementUsages(element, options, processor)) return false; + } + else{ + if (!addElementUsages(element, varOptions, new Processor() { + @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; + } + })) return false; + } + } + } + else if (options.isUsages) { + if (!addElementUsages(element, options, processor)) return false; + } + + boolean success = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + if (ThrowSearchUtil.isSearchable(element) && options instanceof JavaThrowFindUsagesOptions && options.isUsages) { + ThrowSearchUtil.Root root = ((JavaThrowFindUsagesOptions)options).getRoot(); + 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, (JavaPackageFindUsagesOptions)options, processor)) return false; + } + + if (options instanceof JavaClassFindUsagesOptions) { + final JavaClassFindUsagesOptions classOptions = (JavaClassFindUsagesOptions)options; + final PsiClass psiClass = (PsiClass)element; + PsiManager manager = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiManager compute() { + return psiClass.getManager(); + } + }); + if (classOptions.isMethodsUsages){ + if (!addMethodsUsages(psiClass, manager, classOptions, processor)) return false; + } + if (classOptions.isFieldsUsages){ + if (!addFieldsUsages(psiClass, manager, classOptions, processor)) return false; + } + if (psiClass.isInterface()) { + if (classOptions.isDerivedInterfaces){ + if (classOptions.isImplementingClasses){ + if (!addInheritors(psiClass, classOptions, processor)) return false; + } + else{ + if (!addDerivedInterfaces(psiClass, classOptions, processor)) return false; + } + } + else if (classOptions.isImplementingClasses){ + if (!addImplementingClasses(psiClass, classOptions, processor)) return false; + } + + if (classOptions.isImplementingClasses) { + FunctionalExpressionSearch + .search(psiClass, classOptions.searchScope).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiFunctionalExpression expression) { + return addResult(expression, options, processor); + } + })); + } + } + else if (classOptions.isDerivedClasses) { + if (!addInheritors(psiClass, classOptions, processor)) return false; + } + } + + if (options instanceof JavaMethodFindUsagesOptions){ + final PsiMethod psiMethod = (PsiMethod)element; + boolean isAbstract = ApplicationManager.getApplication().runReadAction(new Computable() { + @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; + FunctionalExpressionSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiFunctionalExpression expression) { + return addResult(expression, options, processor); + } + })); + } + } + + if (element instanceof PomTarget) { + if (!addAliasingUsages((PomTarget)element, options, processor)) return false; + } + final Boolean isSearchable = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return ThrowSearchUtil.isSearchable(element); + } + }); + if (!isSearchable && options.isSearchForTextOccurrences && options.searchScope instanceof GlobalSearchScope) { + Collection stringsToSearch = ApplicationManager.getApplication().runReadAction(new NullableComputable>() { + @Override + public Collection compute() { + return getElementNames(element); + } + }); + // todo add to fastTrack + if (!FindUsagesHelper.processUsagesInText(element, stringsToSearch, (GlobalSearchScope)options.searchScope, processor)) return false; + } + return true; + } + + private static boolean addAliasingUsages(@NotNull PomTarget pomTarget, + @NotNull final FindUsagesOptions options, + @NotNull final Processor processor) { + 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() { + @Override + public boolean processInReadAction(final PsiReference reference) { + return addResult(reference, options, processor); + } + }); + if (!success) return false; + } + } + return true; + } + + private static boolean processOverridingMethods(@NotNull PsiMethod psiMethod, + @NotNull final Processor processor, + @NotNull final JavaMethodFindUsagesOptions options) { + return OverridingMethodsSearch.search(psiMethod, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiMethod element) { + return addResult(element.getNavigationElement(), options, processor); + } + })); + } + + private static boolean addClassesUsages(@NotNull PsiPackage aPackage, + @NotNull final JavaPackageFindUsagesOptions options, + @NotNull final Processor processor) { + ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); + if (progress != null){ + progress.pushState(); + } + + List classes = new ArrayList(); + addClassesInPackage(aPackage, options.isIncludeSubpackages, classes); + for (final PsiClass aClass : classes) { + if (progress != null) { + String name = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return aClass.getName(); + } + }); + progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", name)); + progress.checkCanceled(); + } + boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { + @Override + public boolean processInReadAction(final PsiReference psiReference) { + return addResult(psiReference, options, processor); + } + }); + if (!success) return false; + } + + if (progress != null){ + progress.popState(); + } + return true; + } + + private static void addClassesInPackage(@NotNull final PsiPackage aPackage, boolean includeSubpackages, @NotNull List array) { + PsiDirectory[] dirs = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiDirectory[] compute() { + return aPackage.getDirectories(); + } + }); + for (PsiDirectory dir : dirs) { + addClassesInDirectory(dir, includeSubpackages, array); + } + } + + private static void addClassesInDirectory(@NotNull final PsiDirectory dir, + final boolean includeSubdirs, + @NotNull final List 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 PsiManager manager, + @NotNull final JavaClassFindUsagesOptions options, + @NotNull final Processor processor) { + if (options.isIncludeInherited) { + final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiMethod[] compute() { + return aClass.getAllMethods(); + } + }); + for(int i = 0; i < methods.length; i++){ + final PsiMethod method = methods[i]; + // filter overridden methods + final int finalI = i; + final PsiClass methodClass = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiClass compute() { + MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); + for (int j = 0; j < finalI; j++) { + if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY))) return null; + } + return method.getContainingClass(); + } + }); + if (methodClass == null) continue; + boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return manager.areElementsEquivalent(methodClass, aClass); + } + }); + if (equivalent){ + if (!addElementUsages(method, options, processor)) return false; + } + else { + MethodReferencesSearch.SearchParameters parameters = + new MethodReferencesSearch.SearchParameters(method, options.searchScope, true, options.fastTrack); + boolean success = MethodReferencesSearch.search(parameters) + .forEach(new PsiReferenceProcessorAdapter(new PsiReferenceProcessor() { + @Override + public boolean execute(PsiReference reference) { + addResultFromReference(reference, methodClass, manager, aClass, options, processor); + return true; + } + })); + if (!success) return false; + } + } + } + else { + PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiMethod[] compute() { + return aClass.getMethods(); + } + }); + for (PsiMethod method : methods) { + if (!addElementUsages(method, options, processor)) return false; + } + } + return true; + } + + private static boolean addFieldsUsages(@NotNull final PsiClass aClass, + @NotNull final PsiManager manager, + @NotNull final JavaClassFindUsagesOptions options, + @NotNull final Processor processor) { + if (options.isIncludeInherited) { + final PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiField[] compute() { + return aClass.getAllFields(); + } + }); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + // filter hidden fields + final int finalI = i; + final PsiClass fieldClass = + ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiClass compute() { + for (int j = 0; j < finalI; j++) { + if (Comparing.strEqual(field.getName(), fields[j].getName())) return null; + } + return field.getContainingClass(); + } + }); + if (fieldClass == null) continue; + boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return manager.areElementsEquivalent(fieldClass, aClass); + } + }); + if (equivalent) { + if (!addElementUsages(fields[i], options, processor)) return false; + } + else { + boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(field, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { + @Override + public boolean processInReadAction(final PsiReference reference) { + return addResultFromReference(reference, fieldClass, manager, aClass, options, processor); + } + }); + if (!success) return false; + } + } + } + else { + PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiField[] compute() { + return aClass.getFields(); + } + }); + for (PsiField field : fields) { + if (!addElementUsages(field, options, processor)) return false; + } + } + return true; + } + + @Nullable + private static PsiClass getFieldOrMethodAccessedClass(@NotNull PsiReferenceExpression ref, @NotNull 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 JavaClassFindUsagesOptions options, + @NotNull final Processor processor) { + return ClassInheritorsSearch.search(aClass, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiClass element) { + return addResult(element, options, processor); + } + + })); + } + + private static boolean addDerivedInterfaces(@NotNull PsiClass anInterface, + @NotNull final JavaClassFindUsagesOptions options, + @NotNull final Processor processor) { + return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiClass inheritor) { + return !inheritor.isInterface() || addResult(inheritor, options, processor); + } + + })); + } + + private static boolean addImplementingClasses(@NotNull PsiClass anInterface, + @NotNull final JavaClassFindUsagesOptions options, + @NotNull final Processor processor) { + return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiClass inheritor) { + return inheritor.isInterface() || addResult(inheritor, options, processor); + } + })); + } + + private static boolean addResultFromReference(@NotNull PsiReference reference, + @NotNull PsiClass methodClass, + @NotNull PsiManager manager, + @NotNull PsiClass aClass, + @NotNull FindUsagesOptions options, + @NotNull Processor processor) { + 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(refElement, options, processor)) return false; + } + } + } + return true; + } + + private static boolean addElementUsages(@NotNull final PsiElement element, + @NotNull final FindUsagesOptions options, + @NotNull final Processor processor) { + final SearchScope searchScope = options.searchScope; + final PsiClass[] parentClass = new PsiClass[1]; + if (element instanceof PsiMethod && ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + PsiMethod method = (PsiMethod)element; + parentClass[0] = method.getContainingClass(); + return method.isConstructor(); + } + })) { + PsiMethod method = (PsiMethod)element; + + if (parentClass[0] != null) { + boolean strictSignatureSearch = + !(options instanceof JavaMethodFindUsagesOptions) || !((JavaMethodFindUsagesOptions)options).isIncludeOverloadUsages; + return MethodReferencesSearch + .search(new MethodReferencesSearch.SearchParameters(method, searchScope, strictSignatureSearch, options.fastTrack)) + .forEach(new ReadActionProcessor() { + @Override + public boolean processInReadAction(final PsiReference ref) { + return addResult(ref, options, processor); + } + }); + } + return true; + } + + final ReadActionProcessor consumer = new ReadActionProcessor() { + @Override + public boolean processInReadAction(final PsiReference ref) { + return addResult(ref, options, processor); + } + }; + + 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 PsiElement element, + @NotNull FindUsagesOptions options, + @NotNull Processor processor) { + return !filterUsage(element, options) || processor.process(new UsageInfo(element)); + } + + private static boolean addResult(@NotNull PsiReference ref, @NotNull FindUsagesOptions options, @NotNull Processor processor) { + 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, @NotNull 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; + } +} diff --git a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java index 4aff727524bf..9d2b9176f9c7 100644 --- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java +++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java @@ -20,33 +20,18 @@ 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.openapi.util.*; 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.*; import com.intellij.psi.search.searches.*; -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; @@ -221,598 +206,16 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{ @Override protected Set getStringsToSearch(@NotNull final PsiElement element) { - if (element instanceof PsiDirectory) { // normalize a directory to a corresponding package - PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)element); - return aPackage == null ? Collections.emptySet() : getStringsToSearch(aPackage); - } - - final Set result = new HashSet(); - - 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; + return JavaFindUsagesHelper.getElementNames(element); } @Override public boolean processElementUsages(@NotNull final PsiElement element, @NotNull final Processor 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, options, processor)) return false; - } - else{ - if (!addElementUsages(element, varOptions, new Processor() { - @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; - } - })) return false; - } - } - } - else if (options.isUsages) { - if (!addElementUsages(element, options, processor)) return false; - } - - boolean success = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - if (ThrowSearchUtil.isSearchable (element) && options instanceof JavaThrowFindUsagesOptions && options.isUsages) { - ThrowSearchUtil.Root root = ((JavaThrowFindUsagesOptions)options).getRoot(); - 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, (JavaPackageFindUsagesOptions)options, processor)) return false; - } - - if (options instanceof JavaClassFindUsagesOptions) { - final JavaClassFindUsagesOptions classOptions = (JavaClassFindUsagesOptions)options; - final PsiClass psiClass = (PsiClass)element; - PsiManager manager = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiManager compute() { - return psiClass.getManager(); - } - }); - if (classOptions.isMethodsUsages){ - if (!addMethodsUsages(psiClass, manager, classOptions, processor)) return false; - } - if (classOptions.isFieldsUsages){ - if (!addFieldsUsages(psiClass, manager, classOptions, processor)) return false; - } - if (psiClass.isInterface()) { - if (classOptions.isDerivedInterfaces){ - if (classOptions.isImplementingClasses){ - if (!addInheritors(psiClass, classOptions, processor)) return false; - } - else{ - if (!addDerivedInterfaces(psiClass, classOptions, processor)) return false; - } - } - else if (classOptions.isImplementingClasses){ - if (!addImplementingClasses(psiClass, classOptions, processor)) return false; - } - - if (classOptions.isImplementingClasses) { - FunctionalExpressionSearch.search(psiClass, classOptions.searchScope).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiFunctionalExpression expression) { - return addResult(expression, options, processor); - } - })); - } - } - else if (classOptions.isDerivedClasses) { - if (!addInheritors(psiClass, classOptions, processor)) return false; - } - } - - if (options instanceof JavaMethodFindUsagesOptions){ - final PsiMethod psiMethod = (PsiMethod)element; - boolean isAbstract = ApplicationManager.getApplication().runReadAction(new Computable() { - @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; - FunctionalExpressionSearch.search(psiMethod, methodOptions.searchScope).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiFunctionalExpression expression) { - return addResult(expression, options, processor); - } - })); - } - } - - if (element instanceof PomTarget) { - if (!addAliasingUsages((PomTarget)element, options, processor)) return false; - } - final Boolean isSearchable = ApplicationManager.getApplication().runReadAction(new Computable() { - @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; + return JavaFindUsagesHelper.processElementUsages(element, options, processor); } - private static boolean addAliasingUsages(@NotNull PomTarget pomTarget, - @NotNull final FindUsagesOptions options, - @NotNull final Processor processor) { - 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() { - @Override - public boolean processInReadAction(final PsiReference reference) { - return addResult(reference, options, processor); - } - }); - if (!success) return false; - } - } - return true; - } - - private static boolean processOverridingMethods(@NotNull PsiMethod psiMethod, - @NotNull final Processor processor, - @NotNull final JavaMethodFindUsagesOptions options) { - return OverridingMethodsSearch.search(psiMethod, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiMethod element) { - return addResult(element.getNavigationElement(), options, processor); - } - })); - } - - - private static boolean addClassesUsages(@NotNull PsiPackage aPackage, - @NotNull final JavaPackageFindUsagesOptions options, - @NotNull final Processor processor) { - ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null){ - progress.pushState(); - } - - List classes = new ArrayList(); - addClassesInPackage(aPackage, options.isIncludeSubpackages, classes); - for (final PsiClass aClass : classes) { - if (progress != null) { - String name = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return aClass.getName(); - } - }); - progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", name)); - progress.checkCanceled(); - } - boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { - @Override - public boolean processInReadAction(final PsiReference psiReference) { - return addResult(psiReference, options, processor); - } - }); - if (!success) return false; - } - - if (progress != null){ - progress.popState(); - } - return true; - } - - private static void addClassesInPackage(@NotNull final PsiPackage aPackage, boolean includeSubpackages, @NotNull List array) { - PsiDirectory[] dirs = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiDirectory[] compute() { - return aPackage.getDirectories(); - } - }); - for (PsiDirectory dir : dirs) { - addClassesInDirectory(dir, includeSubpackages, array); - } - } - - private static void addClassesInDirectory(@NotNull final PsiDirectory dir, - final boolean includeSubdirs, - @NotNull final List 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 PsiManager manager, - @NotNull final JavaClassFindUsagesOptions options, - @NotNull final Processor processor) { - if (options.isIncludeInherited) { - final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiMethod[] compute() { - return aClass.getAllMethods(); - } - }); - for(int i = 0; i < methods.length; i++){ - final PsiMethod method = methods[i]; - // filter overridden methods - final int finalI = i; - final PsiClass methodClass = - ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiClass compute() { - MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); - for (int j = 0; j < finalI; j++) { - if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY))) return null; - } - return method.getContainingClass(); - } - }); - if (methodClass == null) continue; - boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return manager.areElementsEquivalent(methodClass, aClass); - } - }); - if (equivalent){ - if (!addElementUsages(method, options, processor)) return false; - } - else { - MethodReferencesSearch.SearchParameters parameters = - new MethodReferencesSearch.SearchParameters(method, options.searchScope, true, options.fastTrack); - boolean success = MethodReferencesSearch.search(parameters) - .forEach(new PsiReferenceProcessorAdapter(new PsiReferenceProcessor() { - @Override - public boolean execute(PsiReference reference) { - addResultFromReference(reference, methodClass, manager, aClass, options, processor); - return true; - } - })); - if (!success) return false; - } - } - } - else { - PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiMethod[] compute() { - return aClass.getMethods(); - } - }); - for (PsiMethod method : methods) { - if (!addElementUsages(method, options, processor)) return false; - } - } - return true; - } - - private static boolean addFieldsUsages(@NotNull final PsiClass aClass, - @NotNull final PsiManager manager, - @NotNull final JavaClassFindUsagesOptions options, - @NotNull final Processor processor) { - if (options.isIncludeInherited) { - final PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiField[] compute() { - return aClass.getAllFields(); - } - }); - for (int i = 0; i < fields.length; i++) { - final PsiField field = fields[i]; - // filter hidden fields - final int finalI = i; - final PsiClass fieldClass = - ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiClass compute() { - for (int j = 0; j < finalI; j++) { - if (Comparing.strEqual(field.getName(), fields[j].getName())) return null; - } - return field.getContainingClass(); - } - }); - if (fieldClass == null) continue; - boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - return manager.areElementsEquivalent(fieldClass, aClass); - } - }); - if (equivalent) { - if (!addElementUsages(fields[i], options, processor)) return false; - } - else { - boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(field, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { - @Override - public boolean processInReadAction(final PsiReference reference) { - return addResultFromReference(reference, fieldClass, manager, aClass, options, processor); - } - }); - if (!success) return false; - } - } - } - else { - PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiField[] compute() { - return aClass.getFields(); - } - }); - for (PsiField field : fields) { - if (!addElementUsages(field, options, processor)) return false; - } - } - return true; - } - - @Nullable - private static PsiClass getFieldOrMethodAccessedClass(@NotNull PsiReferenceExpression ref, @NotNull 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 JavaClassFindUsagesOptions options, - @NotNull final Processor processor) { - return ClassInheritorsSearch.search(aClass, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiClass element) { - return addResult(element, options, processor); - } - - })); - } - - private static boolean addDerivedInterfaces(@NotNull PsiClass anInterface, - @NotNull final JavaClassFindUsagesOptions options, - @NotNull final Processor processor) { - return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiClass inheritor) { - return !inheritor.isInterface() || addResult(inheritor, options, processor); - } - - })); - } - - private static boolean addImplementingClasses(@NotNull PsiClass anInterface, - @NotNull final JavaClassFindUsagesOptions options, - @NotNull final Processor processor) { - return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter( - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiClass inheritor) { - return inheritor.isInterface() || addResult(inheritor, options, processor); - } - })); - } - - private static boolean addResultFromReference(@NotNull PsiReference reference, - @NotNull PsiClass methodClass, - @NotNull PsiManager manager, - @NotNull PsiClass aClass, - @NotNull FindUsagesOptions options, - @NotNull Processor processor) { - 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(refElement, options, processor)) return false; - } - } - } - return true; - } - - private static boolean addElementUsages(@NotNull final PsiElement element, - @NotNull final FindUsagesOptions options, - @NotNull final Processor processor) { - final SearchScope searchScope = options.searchScope; - final PsiClass[] parentClass = new PsiClass[1]; - if (element instanceof PsiMethod && ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - PsiMethod method = (PsiMethod)element; - parentClass[0] = method.getContainingClass(); - return method.isConstructor(); - } - })) { - PsiMethod method = (PsiMethod)element; - - if (parentClass[0] != null) { - boolean strictSignatureSearch = - !(options instanceof JavaMethodFindUsagesOptions) || !((JavaMethodFindUsagesOptions)options).isIncludeOverloadUsages; - return MethodReferencesSearch - .search(new MethodReferencesSearch.SearchParameters(method, searchScope, strictSignatureSearch, options.fastTrack)) - .forEach(new ReadActionProcessor() { - @Override - public boolean processInReadAction(final PsiReference ref) { - return addResult(ref, options, processor); - } - }); - } - return true; - } - - final ReadActionProcessor consumer = new ReadActionProcessor() { - @Override - public boolean processInReadAction(final PsiReference ref) { - return addResult(ref, options, processor); - } - }; - - 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 PsiElement element, - @NotNull FindUsagesOptions options, - @NotNull Processor processor) { - return !filterUsage(element, options) || processor.process(new UsageInfo(element)); - } - - private static boolean addResult(@NotNull PsiReference ref, @NotNull FindUsagesOptions options, @NotNull Processor processor) { - 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, @NotNull 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; diff --git a/platform/core-api/src/com/intellij/ide/util/PsiNavigationSupport.java b/platform/core-api/src/com/intellij/ide/util/PsiNavigationSupport.java index 56af9e0fa582..9ffcf9943b3e 100644 --- a/platform/core-api/src/com/intellij/ide/util/PsiNavigationSupport.java +++ b/platform/core-api/src/com/intellij/ide/util/PsiNavigationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -21,6 +21,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -34,7 +35,7 @@ public abstract class PsiNavigationSupport { @Nullable public abstract Navigatable getDescriptor(final PsiElement element); - @Nullable + @NotNull public abstract Navigatable createNavigatable(Project project, VirtualFile vFile, int offset); public abstract boolean canNavigate(final PsiElement element); diff --git a/platform/lang-api/src/com/intellij/pom/PsiDeclaredTarget.java b/platform/core-api/src/com/intellij/pom/PsiDeclaredTarget.java similarity index 96% rename from platform/lang-api/src/com/intellij/pom/PsiDeclaredTarget.java rename to platform/core-api/src/com/intellij/pom/PsiDeclaredTarget.java index 93a7ee09016a..9268ca472b76 100644 --- a/platform/lang-api/src/com/intellij/pom/PsiDeclaredTarget.java +++ b/platform/core-api/src/com/intellij/pom/PsiDeclaredTarget.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. diff --git a/platform/lang-api/src/com/intellij/psi/DelegatePsiTarget.java b/platform/core-api/src/com/intellij/psi/DelegatePsiTarget.java similarity index 82% rename from platform/lang-api/src/com/intellij/psi/DelegatePsiTarget.java rename to platform/core-api/src/com/intellij/psi/DelegatePsiTarget.java index 4f94492d93a2..c8e508dd1266 100644 --- a/platform/lang-api/src/com/intellij/psi/DelegatePsiTarget.java +++ b/platform/core-api/src/com/intellij/psi/DelegatePsiTarget.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -15,12 +15,11 @@ */ package com.intellij.psi; -import com.intellij.ide.util.EditSourceUtil; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.ide.util.PsiNavigationSupport; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.PsiDeclaredTarget; -import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; /** @@ -47,20 +46,20 @@ public class DelegatePsiTarget implements PsiTarget { @Override public void navigate(boolean requestFocus) { final int offset = getTextOffset(); - final VirtualFile virtualFile = PsiUtilBase.getVirtualFile(myElement); + final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(myElement); if (virtualFile != null && virtualFile.isValid()) { - new OpenFileDescriptor(myElement.getProject(), virtualFile, offset).navigate(requestFocus); + PsiNavigationSupport.getInstance().createNavigatable(myElement.getProject(), virtualFile, offset).navigate(requestFocus); } } @Override public boolean canNavigate() { - return EditSourceUtil.canNavigate(myElement); + return PsiNavigationSupport.getInstance().canNavigate(myElement); } @Override public boolean canNavigateToSource() { - return EditSourceUtil.canNavigate(myElement); + return PsiNavigationSupport.getInstance().canNavigate(myElement); } @Override diff --git a/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTarget.java b/platform/core-api/src/com/intellij/psi/targets/AliasingPsiTarget.java similarity index 75% rename from platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTarget.java rename to platform/core-api/src/com/intellij/psi/targets/AliasingPsiTarget.java index 7375c5ce8fb5..c73a72c9f0a3 100644 --- a/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTarget.java +++ b/platform/core-api/src/com/intellij/psi/targets/AliasingPsiTarget.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -19,8 +19,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.PomRenameableTarget; import com.intellij.psi.DelegatePsiTarget; import com.intellij.psi.PsiNamedElement; -import com.intellij.refactoring.RefactoringFactory; -import com.intellij.refactoring.RenameRefactoring; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,14 +52,4 @@ public class AliasingPsiTarget extends DelegatePsiTarget implements PomRenameabl public String getNameAlias(@Nullable String delegatePsiTargetName) { return delegatePsiTargetName; } - - protected void renameTargets(@NotNull String newDelegateName) { - final PsiNamedElement namedElement = (PsiNamedElement)getNavigationElement(); - if (!newDelegateName.equals(namedElement.getName())) { - final RenameRefactoring refactoring = - RefactoringFactory.getInstance(namedElement.getProject()).createRename(namedElement, newDelegateName); - refactoring.run(); - - } - } } diff --git a/platform/core-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java b/platform/core-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java new file mode 100644 index 000000000000..a06de84d5105 --- /dev/null +++ b/platform/core-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java @@ -0,0 +1,29 @@ +/* + * 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.psi.targets; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.pom.PomTarget; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +public interface AliasingPsiTargetMapper { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.aliasingPsiTargetMapper"); + + @NotNull + Set getTargets(@NotNull PomTarget target); +} diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessor.java b/platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessor.java similarity index 97% rename from platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessor.java rename to platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessor.java index 64b756bdaea2..ed4e6fcb2b15 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessor.java +++ b/platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java b/platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java similarity index 96% rename from platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java rename to platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java index 6c8bbd637711..783d82f06964 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java +++ b/platform/indexing-api/src/com/intellij/psi/search/PsiReferenceProcessorAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. diff --git a/platform/indexing-impl/src/com/intellij/find/findUsages/FindUsagesHelper.java b/platform/indexing-impl/src/com/intellij/find/findUsages/FindUsagesHelper.java new file mode 100644 index 000000000000..79ed77763966 --- /dev/null +++ b/platform/indexing-impl/src/com/intellij/find/findUsages/FindUsagesHelper.java @@ -0,0 +1,74 @@ +/* + * 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 com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceService; +import com.intellij.psi.impl.search.PsiSearchHelperImpl; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.usageView.UsageInfo; +import com.intellij.usageView.UsageInfoFactory; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public class FindUsagesHelper { + protected static boolean processUsagesInText(@NotNull final PsiElement element, + @NotNull Collection stringToSearch, + @NotNull GlobalSearchScope searchScope, + @NotNull Processor processor) { + final TextRange elementTextRange = ApplicationManager.getApplication().runReadAction(new NullableComputable() { + @Override + public TextRange compute() { + if (!element.isValid()) return null; + return element.getTextRange(); + } + }); + UsageInfoFactory factory = new UsageInfoFactory() { + @Override + public UsageInfo createUsageInfo(@NotNull PsiElement usage, int startOffset, int endOffset) { + if (elementTextRange != null + && usage.getContainingFile() == element.getContainingFile() + && elementTextRange.contains(startOffset) + && elementTextRange.contains(endOffset)) { + return null; + } + + PsiReference someReference = usage.findReferenceAt(startOffset); + if (someReference != null) { + PsiElement refElement = someReference.getElement(); + for (PsiReference ref : PsiReferenceService.getService().getReferences(refElement, new PsiReferenceService.Hints(element, null))) { + if (element.getManager().areElementsEquivalent(ref.resolve(), element)) { + TextRange range = ref.getRangeInElement().shiftRight(refElement.getTextRange().getStartOffset() - usage.getTextRange().getStartOffset()); + return new UsageInfo(usage, range.getStartOffset(), range.getEndOffset(), true); + } + } + } + + return new UsageInfo(usage, startOffset, endOffset, true); + } + }; + for (String s : stringToSearch) { + if (!PsiSearchHelperImpl.processTextOccurrences(element, s, searchScope, processor, factory)) return false; + } + return true; + } +} diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index ba8d9ce3500e..e0009c5b8bda 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -16,9 +16,12 @@ package com.intellij.psi.impl.search; -import com.intellij.concurrency.*; +import com.intellij.concurrency.AsyncFuture; +import com.intellij.concurrency.AsyncUtil; +import com.intellij.concurrency.JobLauncher; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationUtil; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -39,6 +42,8 @@ import com.intellij.psi.impl.cache.impl.id.IdIndex; import com.intellij.psi.impl.cache.impl.id.IdIndexEntry; import com.intellij.psi.search.*; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.usageView.UsageInfo; +import com.intellij.usageView.UsageInfoFactory; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import com.intellij.util.SmartList; @@ -59,6 +64,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; public class PsiSearchHelperImpl implements PsiSearchHelper { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.PsiSearchHelperImpl"); private final PsiManagerEx myManager; @Override @@ -979,4 +985,39 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { } return keys; } + + public static boolean processTextOccurrences(@NotNull final PsiElement element, + @NotNull String stringToSearch, + @NotNull GlobalSearchScope searchScope, + @NotNull final Processor processor, + @NotNull final UsageInfoFactory factory) { + PsiSearchHelper helper = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiSearchHelper compute() { + return SERVICE.getInstance(element.getProject()); + } + }); + + return helper.processUsagesInNonJavaFiles(element, stringToSearch, new PsiNonJavaFileReferenceProcessor() { + @Override + public boolean process(final PsiFile psiFile, final int startOffset, final int endOffset) { + try { + UsageInfo usageInfo = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public UsageInfo compute() { + return factory.createUsageInfo(psiFile, startOffset, endOffset); + } + }); + return usageInfo == null || processor.process(usageInfo); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Exception e) { + LOG.error(e); + return true; + } + } + }, searchScope); + } } diff --git a/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java b/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java deleted file mode 100644 index ed4c81f6d91c..000000000000 --- a/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetMapper.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.intellij.psi.targets; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.pom.PomTarget; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -public interface AliasingPsiTargetMapper { - ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.aliasingPsiTargetMapper"); - - @NotNull - Set getTargets(@NotNull PomTarget target); -} diff --git a/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetUtil.java b/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetUtil.java new file mode 100644 index 000000000000..c2271fce3f1d --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/targets/AliasingPsiTargetUtil.java @@ -0,0 +1,33 @@ +/* + * 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.psi.targets; + +import com.intellij.psi.PsiNamedElement; +import com.intellij.refactoring.RefactoringFactory; +import com.intellij.refactoring.RenameRefactoring; +import org.jetbrains.annotations.NotNull; + +public class AliasingPsiTargetUtil { + public static void renameTargets(AliasingPsiTarget target, @NotNull String newDelegateName) { + final PsiNamedElement namedElement = (PsiNamedElement)target.getNavigationElement(); + if (!newDelegateName.equals(namedElement.getName())) { + final RenameRefactoring refactoring = + RefactoringFactory.getInstance(namedElement.getProject()).createRename(namedElement, newDelegateName); + refactoring.run(); + + } + } +} diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesHandler.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesHandler.java index ac7770687027..cb449f9602b7 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesHandler.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesHandler.java @@ -25,13 +25,10 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.PsiReference; -import com.intellij.psi.PsiReferenceService; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtilCore; -import com.intellij.refactoring.util.TextOccurrencesUtil; -import com.intellij.usageView.UsageInfoFactory; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; @@ -156,48 +153,7 @@ public abstract class FindUsagesHandler { } }); if (stringToSearch == null) return true; - return processUsagesInText(element, stringToSearch, searchScope, processor); - } - - protected static boolean processUsagesInText(@NotNull final PsiElement element, - @NotNull Collection stringToSearch, - @NotNull GlobalSearchScope searchScope, - @NotNull Processor processor) { - final TextRange elementTextRange = ApplicationManager.getApplication().runReadAction(new NullableComputable() { - @Override - public TextRange compute() { - if (!element.isValid()) return null; - return element.getTextRange(); - } - }); - UsageInfoFactory factory = new UsageInfoFactory() { - @Override - public UsageInfo createUsageInfo(@NotNull PsiElement usage, int startOffset, int endOffset) { - if (elementTextRange != null - && usage.getContainingFile() == element.getContainingFile() - && elementTextRange.contains(startOffset) - && elementTextRange.contains(endOffset)) { - return null; - } - - PsiReference someReference = usage.findReferenceAt(startOffset); - if (someReference != null) { - PsiElement refElement = someReference.getElement(); - for (PsiReference ref : PsiReferenceService.getService().getReferences(refElement, new PsiReferenceService.Hints(element, null))) { - if (element.getManager().areElementsEquivalent(ref.resolve(), element)) { - TextRange range = ref.getRangeInElement().shiftRight(refElement.getTextRange().getStartOffset() - usage.getTextRange().getStartOffset()); - return new UsageInfo(usage, range.getStartOffset(), range.getEndOffset(), true); - } - } - } - - return new UsageInfo(usage, startOffset, endOffset, true); - } - }; - for (String s : stringToSearch) { - if (!TextOccurrencesUtil.processTextOccurences(element, s, searchScope, processor, factory)) return false; - } - return true; + return FindUsagesHelper.processUsagesInText(element, stringToSearch, searchScope, processor); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/ide/util/PsiNavigationSupportImpl.java b/platform/lang-impl/src/com/intellij/ide/util/PsiNavigationSupportImpl.java index 8533b0240882..f268be4892bc 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/PsiNavigationSupportImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/util/PsiNavigationSupportImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -35,7 +36,7 @@ public class PsiNavigationSupportImpl extends PsiNavigationSupport { return EditSourceUtil.getDescriptor(element); } - @Nullable + @NotNull @Override public Navigatable createNavigatable(Project project, VirtualFile vFile, int offset) { return new OpenFileDescriptor(project, vFile, offset); diff --git a/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java b/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java index e77206812f7d..f700ecfe6554 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java @@ -24,15 +24,11 @@ import com.intellij.find.impl.FindManagerImpl; import com.intellij.lang.ASTNode; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.search.PsiSearchHelperImpl; import com.intellij.psi.search.*; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageInfoFactory; @@ -43,7 +39,6 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; public class TextOccurrencesUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.TextOccurrencesUtil"); private TextOccurrencesUtil() { } @@ -52,7 +47,7 @@ public class TextOccurrencesUtil { @NotNull GlobalSearchScope searchScope, @NotNull final Collection results, @NotNull final UsageInfoFactory factory) { - processTextOccurences(element, stringToSearch, searchScope, new Processor() { + PsiSearchHelperImpl.processTextOccurrences(element, stringToSearch, searchScope, new Processor() { @Override public boolean process(UsageInfo t) { results.add(t); @@ -61,41 +56,6 @@ public class TextOccurrencesUtil { }, factory); } - public static boolean processTextOccurences(@NotNull final PsiElement element, - @NotNull String stringToSearch, - @NotNull GlobalSearchScope searchScope, - @NotNull final Processor processor, - @NotNull final UsageInfoFactory factory) { - PsiSearchHelper helper = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiSearchHelper compute() { - return PsiSearchHelper.SERVICE.getInstance(element.getProject()); - } - }); - - return helper.processUsagesInNonJavaFiles(element, stringToSearch, new PsiNonJavaFileReferenceProcessor() { - @Override - public boolean process(final PsiFile psiFile, final int startOffset, final int endOffset) { - try { - UsageInfo usageInfo = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public UsageInfo compute() { - return factory.createUsageInfo(psiFile, startOffset, endOffset); - } - }); - return usageInfo == null || processor.process(usageInfo); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception e) { - LOG.error(e); - return true; - } - } - }, searchScope); - } - private static boolean processStringLiteralsContainingIdentifier(@NotNull String identifier, @NotNull SearchScope searchScope, PsiSearchHelper helper, final Processor processor) { TextOccurenceProcessor occurenceProcessor = new TextOccurenceProcessor() { @Override