mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'usages'
This commit is contained in:
+21
-47
@@ -3,17 +3,15 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMemberReference;
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil;
|
||||
import com.intellij.psi.search.SearchRequestCollector;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
/**
|
||||
@@ -30,38 +28,29 @@ public class ConstructorReferencesSearchHelper {
|
||||
final PsiMethod constructor,
|
||||
final SearchScope searchScope,
|
||||
boolean ignoreAccessScope,
|
||||
final boolean isStrictSignatureSearch) {
|
||||
final Ref<Boolean> result = new Ref<Boolean>();
|
||||
PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
public PsiClass compute() {
|
||||
PsiClass aClass = constructor.getContainingClass();
|
||||
if (aClass == null) {
|
||||
result.set(true);
|
||||
return null;
|
||||
}
|
||||
final boolean isStrictSignatureSearch, SearchRequestCollector collector) {
|
||||
PsiClass aClass = constructor.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aClass.isEnum()) {
|
||||
PsiField[] fields = aClass.getFields();
|
||||
for (PsiField field : fields) {
|
||||
if (field instanceof PsiEnumConstant) {
|
||||
PsiReference reference = field.getReference();
|
||||
if (reference != null && reference.isReferenceTo(constructor)) {
|
||||
if (!processor.process(reference)) {
|
||||
result.set(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (aClass.isEnum()) {
|
||||
for (PsiField field : aClass.getFields()) {
|
||||
if (field instanceof PsiEnumConstant) {
|
||||
PsiReference reference = field.getReference();
|
||||
if (reference != null && reference.isReferenceTo(constructor)) {
|
||||
if (!processor.process(reference)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return aClass;
|
||||
}
|
||||
});
|
||||
if (!result.isNull()) return result.get();
|
||||
}
|
||||
|
||||
// search usages like "new XXX(..)"
|
||||
Processor<PsiReference> processor1 = new ReadActionProcessor<PsiReference>() {
|
||||
public boolean processInReadAction(final PsiReference reference) {
|
||||
PairProcessor<PsiReference, SearchRequestCollector> processor1 = new PairProcessor<PsiReference, SearchRequestCollector>() {
|
||||
@Override
|
||||
public boolean process(PsiReference reference, SearchRequestCollector collector) {
|
||||
PsiElement parent = reference.getElement().getParent();
|
||||
if (parent instanceof PsiAnonymousClass) {
|
||||
parent = parent.getParent();
|
||||
@@ -85,12 +74,12 @@ public class ConstructorReferencesSearchHelper {
|
||||
}
|
||||
};
|
||||
|
||||
if (!ReferencesSearch.search(aClass, searchScope, ignoreAccessScope).forEach(processor1)) return false;
|
||||
ReferencesSearch.searchOptimized(aClass, searchScope, ignoreAccessScope, collector, true, processor1);
|
||||
|
||||
final boolean constructorCanBeCalledImplicitly = constructor.getParameterList().getParametersCount() == 0;
|
||||
// search usages like "this(..)"
|
||||
if (!processSuperOrThis(processor, aClass, constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch,
|
||||
PsiKeyword.THIS)) {
|
||||
PsiKeyword.THIS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,7 +87,7 @@ public class ConstructorReferencesSearchHelper {
|
||||
Processor<PsiClass> processor2 = new Processor<PsiClass>() {
|
||||
public boolean process(PsiClass inheritor) {
|
||||
return processSuperOrThis(processor, (PsiClass)inheritor.getNavigationElement(), constructor, constructorCanBeCalledImplicitly, searchScope, isStrictSignatureSearch,
|
||||
PsiKeyword.SUPER);
|
||||
PsiKeyword.SUPER);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,21 +99,6 @@ public class ConstructorReferencesSearchHelper {
|
||||
final PsiMethod constructor, final boolean constructorCanBeCalledImplicitly, final SearchScope searchScope,
|
||||
final boolean isStrictSignatureSearch,
|
||||
final String superOrThisKeyword) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
return processSuperOrThisInReadAction(inheritor, searchScope, superOrThisKeyword, isStrictSignatureSearch, constructor,
|
||||
constructorCanBeCalledImplicitly, processor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean processSuperOrThisInReadAction(final PsiClass inheritor,
|
||||
final SearchScope searchScope,
|
||||
final String superOrThisKeyword,
|
||||
final boolean isStrictSignatureSearch,
|
||||
final PsiMethod constructor,
|
||||
final boolean constructorCanBeCalledImplicitly,
|
||||
final Processor<PsiReference> processor) {
|
||||
PsiMethod[] constructors = inheritor.getConstructors();
|
||||
if (constructors.length == 0 && constructorCanBeCalledImplicitly) {
|
||||
processImplicitConstructorCall(inheritor, processor, constructor, inheritor);
|
||||
|
||||
@@ -3,24 +3,28 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ConstructorReferencesSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
|
||||
public boolean execute(final ReferencesSearch.SearchParameters p, final Processor<PsiReference> consumer) {
|
||||
public class ConstructorReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
|
||||
protected ConstructorReferencesSearcher() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQuery(ReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
|
||||
final PsiElement element = p.getElementToSearch();
|
||||
if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
|
||||
return new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject()))
|
||||
.processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true);
|
||||
new ConstructorReferencesSearchHelper(PsiManager.getInstance(element.getProject()))
|
||||
.processConstructorReferences(consumer, (PsiMethod)p.getElementToSearch(), p.getScope(), p.isIgnoreAccessScope(), true, p.getOptimizer());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.SearchRequestCollector;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
@@ -18,6 +16,9 @@ import com.intellij.util.Processor;
|
||||
* @author max
|
||||
*/
|
||||
public class MethodUsagesSearcher extends QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters> {
|
||||
protected MethodUsagesSearcher() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQuery(MethodReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
|
||||
@@ -28,60 +29,42 @@ public class MethodUsagesSearcher extends QueryExecutorBase<PsiReference, Method
|
||||
|
||||
final PsiManager psiManager = PsiManager.getInstance(method.getProject());
|
||||
|
||||
final PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
|
||||
public PsiClass compute() {
|
||||
return method.isValid() ? method.getContainingClass() : null;
|
||||
}
|
||||
});
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null) return;
|
||||
|
||||
final boolean strictSignatureSearch = p.isStrictSignatureSearch();
|
||||
|
||||
if (method.isConstructor()) {
|
||||
collector.searchCustom(new Processor<Processor<PsiReference>>() {
|
||||
public boolean process(Processor<PsiReference> consumer) {
|
||||
return new ConstructorReferencesSearchHelper(psiManager).
|
||||
processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch);
|
||||
}
|
||||
});
|
||||
new ConstructorReferencesSearchHelper(psiManager).
|
||||
processConstructorReferences(consumer, method, searchScope, !strictSignatureSearch, strictSignatureSearch, collector);
|
||||
}
|
||||
|
||||
boolean needStrictSignatureSearch = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
return method.isValid() && strictSignatureSearch && (aClass instanceof PsiAnonymousClass
|
||||
boolean needStrictSignatureSearch = strictSignatureSearch && (aClass instanceof PsiAnonymousClass
|
||||
|| aClass.hasModifierProperty(PsiModifier.FINAL)
|
||||
|| method.hasModifierProperty(PsiModifier.STATIC)
|
||||
|| method.hasModifierProperty(PsiModifier.FINAL)
|
||||
|| method.hasModifierProperty(PsiModifier.PRIVATE));
|
||||
}
|
||||
});
|
||||
if (needStrictSignatureSearch) {
|
||||
ReferencesSearch.search(new ReferencesSearch.SearchParameters(method, searchScope, false, collector)).forEach(consumer);
|
||||
ReferencesSearch.searchOptimized(method, searchScope, false, collector, consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
if (!method.isValid()) return;
|
||||
final String textToSearch = method.getName();
|
||||
final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false);
|
||||
|
||||
final String textToSearch = method.getName();
|
||||
final PsiMethod[] methods = strictSignatureSearch ? new PsiMethod[]{method} : aClass.findMethodsByName(textToSearch, false);
|
||||
SearchScope accessScope = methods[0].getUseScope();
|
||||
for (int i = 1; i < methods.length; i++) {
|
||||
PsiMethod method1 = methods[i];
|
||||
accessScope = accessScope.union(method1.getUseScope());
|
||||
}
|
||||
|
||||
SearchScope accessScope = methods[0].getUseScope();
|
||||
for (int i = 1; i < methods.length; i++) {
|
||||
PsiMethod method1 = methods[i];
|
||||
accessScope = accessScope.union(method1.getUseScope());
|
||||
}
|
||||
final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope);
|
||||
|
||||
final SearchScope restrictedByAccess = searchScope.intersectWith(accessScope);
|
||||
short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES;
|
||||
collector.searchWord(textToSearch, restrictedByAccess, searchContext, true,
|
||||
new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods));
|
||||
|
||||
short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_COMMENTS | UsageSearchContext.IN_FOREIGN_LANGUAGES;
|
||||
collector.searchWord(textToSearch, restrictedByAccess, searchContext, true,
|
||||
new MethodTextOccurrenceProcessor(aClass, strictSignatureSearch, methods));
|
||||
|
||||
SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector);
|
||||
}
|
||||
});
|
||||
SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccess, collector);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,10 @@ package com.intellij.psi.search.searches;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchRequestCollector;
|
||||
import com.intellij.psi.search.SearchRequestQuery;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.util.MergeQuery;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.UniqueResultsQuery;
|
||||
import com.intellij.psi.search.*;
|
||||
import com.intellij.util.*;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -75,6 +71,21 @@ public class MethodReferencesSearch extends ExtensibleQueryFactory<PsiReference,
|
||||
return search(new SearchParameters(method, scope, strictSignatureSearch));
|
||||
}
|
||||
|
||||
public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch,
|
||||
@NotNull SearchRequestCollector collector, final Processor<PsiReference> processor) {
|
||||
searchOptimized(method, scope, strictSignatureSearch, collector, false, new PairProcessor<PsiReference, SearchRequestCollector>() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference, SearchRequestCollector collector) {
|
||||
return processor.process(psiReference);
|
||||
}
|
||||
});
|
||||
}
|
||||
public static void searchOptimized(final PsiMethod method, SearchScope scope, final boolean strictSignatureSearch, SearchRequestCollector collector, final boolean inReadAction, PairProcessor<PsiReference, SearchRequestCollector> processor) {
|
||||
final SearchRequestCollector nested = new SearchRequestCollector();
|
||||
collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(method, scope, strictSignatureSearch, nested)), nested,
|
||||
inReadAction, processor));
|
||||
}
|
||||
|
||||
public static Query<PsiReference> search(final SearchParameters parameters) {
|
||||
final Query<PsiReference> result = INSTANCE.createQuery(parameters);
|
||||
if (parameters.isSharedOptimizer) {
|
||||
|
||||
@@ -25,4 +25,8 @@ public class PsiSearchRequest {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiSearchRequest: " + word + "; " + processor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.intellij.psi.search;
|
||||
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.Query;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class QuerySearchRequest {
|
||||
public final Query<PsiReference> query;
|
||||
public final SearchRequestCollector collector;
|
||||
public final Processor<PsiReference> processor;
|
||||
|
||||
public QuerySearchRequest(Query<PsiReference> query,
|
||||
final SearchRequestCollector collector,
|
||||
boolean inReadAction, final PairProcessor<PsiReference, SearchRequestCollector> processor) {
|
||||
this.query = query;
|
||||
this.collector = collector;
|
||||
if (inReadAction) {
|
||||
this.processor = new ReadActionProcessor<PsiReference>() {
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference psiReference) {
|
||||
return processor.process(psiReference, collector);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this.processor = new Processor<PsiReference>() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
return processor.process(psiReference, collector);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void runQuery() {
|
||||
query.forEach(processor);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.intellij.psi.search;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -12,8 +13,10 @@ import java.util.List;
|
||||
* @author peter
|
||||
*/
|
||||
public class SearchRequestCollector {
|
||||
private final List<PsiSearchRequest> myRequests = new ArrayList<PsiSearchRequest>();
|
||||
private final List<Processor<Processor<PsiReference>>> myCustomSearchActions = new ArrayList<Processor<Processor<PsiReference>>>();
|
||||
private final Object lock = new Object();
|
||||
private final List<PsiSearchRequest> myWordRequests = CollectionFactory.arrayList();
|
||||
private final List<QuerySearchRequest> myQueryRequests = CollectionFactory.arrayList();
|
||||
private final List<Processor<Processor<PsiReference>>> myCustomSearchActions = CollectionFactory.arrayList();
|
||||
|
||||
public void searchWord(@NotNull String word, @NotNull SearchScope searchScope, boolean caseSensitive, @NotNull PsiElement searchTarget) {
|
||||
final short searchContext = UsageSearchContext.IN_CODE | UsageSearchContext.IN_FOREIGN_LANGUAGES | UsageSearchContext.IN_COMMENTS;
|
||||
@@ -29,18 +32,48 @@ public class SearchRequestCollector {
|
||||
return;
|
||||
}
|
||||
|
||||
myRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor));
|
||||
synchronized (lock) {
|
||||
myWordRequests.add(new PsiSearchRequest(searchScope, word, searchContext, caseSensitive, processor));
|
||||
}
|
||||
}
|
||||
|
||||
public void searchQuery(QuerySearchRequest request) {
|
||||
assert request.collector != this;
|
||||
synchronized (lock) {
|
||||
myQueryRequests.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
public void searchCustom(Processor<Processor<PsiReference>> searchAction) {
|
||||
myCustomSearchActions.add(searchAction);
|
||||
synchronized (lock) {
|
||||
myCustomSearchActions.add(searchAction);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PsiSearchRequest> getSearchRequests() {
|
||||
return myRequests;
|
||||
public boolean hasRequests() {
|
||||
synchronized (lock) {
|
||||
return !myWordRequests.isEmpty() || !myCustomSearchActions.isEmpty() || !myQueryRequests.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Processor<Processor<PsiReference>>> getCustomSearchActions() {
|
||||
return myCustomSearchActions;
|
||||
public List<QuerySearchRequest> takeQueryRequests() {
|
||||
return takeRequests(myQueryRequests);
|
||||
}
|
||||
|
||||
private <T> List<T> takeRequests(List<T> list) {
|
||||
synchronized (lock) {
|
||||
final List<T> requests = new ArrayList<T>(list);
|
||||
requests.addAll(list);
|
||||
list.clear();
|
||||
return requests;
|
||||
}
|
||||
}
|
||||
|
||||
public List<PsiSearchRequest> takeSearchRequests() {
|
||||
return takeRequests(myWordRequests);
|
||||
}
|
||||
|
||||
public List<Processor<Processor<PsiReference>>> takeCustomSearchActions() {
|
||||
return takeRequests(myCustomSearchActions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@ package com.intellij.psi.search.searches;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchRequestCollector;
|
||||
import com.intellij.psi.search.SearchRequestQuery;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.*;
|
||||
import com.intellij.util.*;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -111,4 +108,21 @@ public class ReferencesSearch extends ExtensibleQueryFactory<PsiReference, Refer
|
||||
return new UniqueResultsQuery(composite, TObjectHashingStrategy.CANONICAL, ReferenceDescriptor.MAPPER);
|
||||
}
|
||||
|
||||
public static void searchOptimized(@NotNull PsiElement element, @NotNull SearchScope searchScope, boolean ignoreAccessScope,
|
||||
@NotNull SearchRequestCollector collector, final Processor<PsiReference> processor) {
|
||||
searchOptimized(element, searchScope, ignoreAccessScope, collector, false, new PairProcessor<PsiReference, SearchRequestCollector>() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference, SearchRequestCollector collector) {
|
||||
return processor.process(psiReference);
|
||||
}
|
||||
});
|
||||
}
|
||||
public static void searchOptimized(@NotNull PsiElement element, @NotNull SearchScope searchScope, boolean ignoreAccessScope,
|
||||
@NotNull SearchRequestCollector collector, final boolean inReadAction, PairProcessor<PsiReference, SearchRequestCollector> processor) {
|
||||
final SearchRequestCollector nested = new SearchRequestCollector();
|
||||
collector.searchQuery(new QuerySearchRequest(search(new SearchParameters(element, searchScope, ignoreAccessScope, nested)), nested,
|
||||
inReadAction, processor));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -487,34 +488,62 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
myManager.getCacheManager().processFilesWithWord(processor, word, UsageSearchContext.IN_STRINGS, scope, true);
|
||||
}
|
||||
|
||||
public boolean processRequests(@NotNull SearchRequestCollector request, Processor<PsiReference> processor) {
|
||||
final MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles = new MultiMap<Set<IdIndexEntry>, PsiSearchRequest>();
|
||||
final List<Processor<Processor<PsiReference>>> customs = new ArrayList<Processor<Processor<PsiReference>>>();
|
||||
distributePrimitives(request, singles, customs);
|
||||
|
||||
if (!processRequestsOptimized(singles, processor)) {
|
||||
return false;
|
||||
private static class RequestWithProcessor extends Pair<PsiSearchRequest, Processor<PsiReference>> {
|
||||
private RequestWithProcessor(PsiSearchRequest first, Processor<PsiReference> second) {
|
||||
super(first, second);
|
||||
}
|
||||
|
||||
for (Processor<Processor<PsiReference>> custom : customs) {
|
||||
if (!custom.process(processor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private boolean processRequestsOptimized(MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles, final Processor<PsiReference> consumer) {
|
||||
public boolean processRequests(@NotNull SearchRequestCollector collector, Processor<PsiReference> processor) {
|
||||
Map<SearchRequestCollector, Processor<PsiReference>> collectors = new HashMap<SearchRequestCollector, Processor<PsiReference>>();
|
||||
collectors.put(collector, processor);
|
||||
|
||||
appendCollectorsFromQueryRequests(collectors);
|
||||
|
||||
do {
|
||||
final MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
|
||||
final List<Computable<Boolean>> customs = new ArrayList<Computable<Boolean>>();
|
||||
distributePrimitives(collectors, singles, customs);
|
||||
|
||||
if (!processRequestsOptimized(singles)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Computable<Boolean> custom : customs) {
|
||||
if (!custom.compute()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (appendCollectorsFromQueryRequests(collectors));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean appendCollectorsFromQueryRequests(Map<SearchRequestCollector, Processor<PsiReference>> collectors) {
|
||||
boolean changed = false;
|
||||
LinkedList<SearchRequestCollector> queue = new LinkedList<SearchRequestCollector>(collectors.keySet());
|
||||
while (!queue.isEmpty()) {
|
||||
final SearchRequestCollector each = queue.removeFirst();
|
||||
for (QuerySearchRequest request : each.takeQueryRequests()) {
|
||||
request.runQuery();
|
||||
collectors.put(request.collector, request.processor);
|
||||
queue.addLast(request.collector);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private boolean processRequestsOptimized(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles) {
|
||||
if (singles.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (singles.size() == 1) {
|
||||
final Collection<PsiSearchRequest> requests = singles.get(singles.keySet().iterator().next());
|
||||
final Collection<RequestWithProcessor> requests = singles.get(singles.keySet().iterator().next());
|
||||
if (requests.size() == 1) {
|
||||
return processSingleRequest(requests.iterator().next(), consumer);
|
||||
final RequestWithProcessor theOnly = requests.iterator().next();
|
||||
return processSingleRequest(theOnly.first, theOnly.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,13 +553,17 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
progress.setText(PsiBundle.message("psi.scanning.files.progress"));
|
||||
}
|
||||
|
||||
final MultiMap<VirtualFile, PsiSearchRequest> candidateFiles = collectFiles(singles);
|
||||
final MultiMap<VirtualFile, RequestWithProcessor> candidateFiles = collectFiles(singles);
|
||||
|
||||
final Map<PsiSearchRequest, StringSearcher> searchers = new HashMap<PsiSearchRequest, StringSearcher>();
|
||||
if (candidateFiles.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Map<RequestWithProcessor, StringSearcher> searchers = new HashMap<RequestWithProcessor, StringSearcher>();
|
||||
final Set<String> allWords = new TreeSet<String>();
|
||||
for (PsiSearchRequest singleRequest : candidateFiles.values()) {
|
||||
searchers.put(singleRequest, new StringSearcher(singleRequest.word, singleRequest.caseSensitive, true));
|
||||
allWords.add(singleRequest.word);
|
||||
for (RequestWithProcessor singleRequest : candidateFiles.values()) {
|
||||
searchers.put(singleRequest, new StringSearcher(singleRequest.first.word, singleRequest.first.caseSensitive, true));
|
||||
allWords.add(singleRequest.first.word);
|
||||
}
|
||||
|
||||
if (progress != null) {
|
||||
@@ -540,9 +573,9 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
return processPsiFileRoots(progress, new ArrayList<VirtualFile>(candidateFiles.keySet()), new Processor<PsiElement>() {
|
||||
public boolean process(PsiElement psiRoot) {
|
||||
final VirtualFile vfile = psiRoot.getContainingFile().getVirtualFile();
|
||||
for (final PsiSearchRequest singleRequest : candidateFiles.get(vfile)) {
|
||||
for (final RequestWithProcessor singleRequest : candidateFiles.get(vfile)) {
|
||||
StringSearcher searcher = searchers.get(singleRequest);
|
||||
if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest, consumer), psiRoot, searcher, false, progress)) {
|
||||
if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest.first, singleRequest.second), psiRoot, searcher, false, progress)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -565,18 +598,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
};
|
||||
}
|
||||
|
||||
private MultiMap<VirtualFile, PsiSearchRequest> collectFiles(MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles) {
|
||||
private MultiMap<VirtualFile, RequestWithProcessor> collectFiles(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles) {
|
||||
final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex();
|
||||
final MultiMap<VirtualFile, PsiSearchRequest> result = new MultiMap<VirtualFile, PsiSearchRequest>();
|
||||
final MultiMap<VirtualFile, RequestWithProcessor> result = new MultiMap<VirtualFile, RequestWithProcessor>();
|
||||
for (Set<IdIndexEntry> key : singles.keySet()) {
|
||||
final Collection<PsiSearchRequest> data = singles.get(key);
|
||||
final Collection<RequestWithProcessor> data = singles.get(key);
|
||||
GlobalSearchScope commonScope = uniteScopes(data);
|
||||
|
||||
MultiMap<VirtualFile, PsiSearchRequest> intersection = null;
|
||||
MultiMap<VirtualFile, RequestWithProcessor> intersection = null;
|
||||
|
||||
boolean first = true;
|
||||
for (IdIndexEntry entry : key) {
|
||||
final MultiMap<VirtualFile, PsiSearchRequest> local = findFilesWithIndexEntry(entry, index, data, commonScope);
|
||||
final MultiMap<VirtualFile, RequestWithProcessor> local = findFilesWithIndexEntry(entry, index, data, commonScope);
|
||||
if (first) {
|
||||
intersection = local;
|
||||
first = false;
|
||||
@@ -593,31 +626,34 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static GlobalSearchScope uniteScopes(Collection<PsiSearchRequest> requests) {
|
||||
private static GlobalSearchScope uniteScopes(Collection<RequestWithProcessor> requests) {
|
||||
GlobalSearchScope commonScope = null;
|
||||
for (PsiSearchRequest r : requests) {
|
||||
final GlobalSearchScope scope = (GlobalSearchScope)r.searchScope;
|
||||
for (RequestWithProcessor r : requests) {
|
||||
final GlobalSearchScope scope = (GlobalSearchScope)r.first.searchScope;
|
||||
commonScope = commonScope == null ? scope : commonScope.uniteWith(scope);
|
||||
}
|
||||
assert commonScope != null;
|
||||
return commonScope;
|
||||
}
|
||||
|
||||
private static MultiMap<VirtualFile, PsiSearchRequest> findFilesWithIndexEntry(final IdIndexEntry entry,
|
||||
private static MultiMap<VirtualFile, RequestWithProcessor> findFilesWithIndexEntry(final IdIndexEntry entry,
|
||||
final ProjectFileIndex index,
|
||||
final Collection<PsiSearchRequest> data,
|
||||
final Collection<RequestWithProcessor> data,
|
||||
final GlobalSearchScope commonScope) {
|
||||
final MultiMap<VirtualFile, PsiSearchRequest> local = new MultiMap<VirtualFile, PsiSearchRequest>();
|
||||
final MultiMap<VirtualFile, RequestWithProcessor> local = new MultiMap<VirtualFile, RequestWithProcessor>();
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
ProgressManager.checkCanceled();
|
||||
FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor<Integer>() {
|
||||
public boolean process(VirtualFile file, Integer value) {
|
||||
ProgressManager.checkCanceled();
|
||||
if (!IndexCacheManagerImpl.shouldBeFound(file, index)) {
|
||||
return true;
|
||||
}
|
||||
int mask = value.intValue();
|
||||
for (PsiSearchRequest single : data) {
|
||||
if ((mask & single.searchContext) != 0 && ((GlobalSearchScope)single.searchScope).contains(file)) {
|
||||
for (RequestWithProcessor single : data) {
|
||||
final PsiSearchRequest request = single.first;
|
||||
if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) {
|
||||
local.putValue(file, single);
|
||||
}
|
||||
}
|
||||
@@ -630,27 +666,38 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
|
||||
return local;
|
||||
}
|
||||
|
||||
private void distributePrimitives(SearchRequestCollector request,
|
||||
MultiMap<Set<IdIndexEntry>, PsiSearchRequest> singles,
|
||||
List<Processor<Processor<PsiReference>>> customs) {
|
||||
for (final PsiSearchRequest primitive : request.getSearchRequests()) {
|
||||
final SearchScope scope = primitive.searchScope;
|
||||
if (scope instanceof LocalSearchScope) {
|
||||
customs.add(new Processor<Processor<PsiReference>>() {
|
||||
public boolean process(Processor<PsiReference> processor) {
|
||||
return processSingleRequest(primitive, processor);
|
||||
private void distributePrimitives(final Map<SearchRequestCollector, Processor<PsiReference>> collectors,
|
||||
MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
|
||||
List<Computable<Boolean>> customs) {
|
||||
for (final SearchRequestCollector collector : collectors.keySet()) {
|
||||
final Processor<PsiReference> processor = collectors.get(collector);
|
||||
for (final PsiSearchRequest primitive : collector.takeSearchRequests()) {
|
||||
final SearchScope scope = primitive.searchScope;
|
||||
if (scope instanceof LocalSearchScope) {
|
||||
customs.add(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return processSingleRequest(primitive, processor);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final List<String> words = StringUtil.getWordsIn(primitive.word);
|
||||
final Set<IdIndexEntry> key = new HashSet<IdIndexEntry>(words.size() * 2);
|
||||
for (String word : words) {
|
||||
key.add(new IdIndexEntry(word, primitive.caseSensitive));
|
||||
}
|
||||
singles.putValue(key, new RequestWithProcessor(primitive, processor));
|
||||
}
|
||||
}
|
||||
for (final Processor<Processor<PsiReference>> customAction : collector.takeCustomSearchActions()) {
|
||||
customs.add(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return customAction.process(processor);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final List<String> words = StringUtil.getWordsIn(primitive.word);
|
||||
final Set<IdIndexEntry> key = new HashSet<IdIndexEntry>(words.size() * 2);
|
||||
for (String word : words) {
|
||||
key.add(new IdIndexEntry(word, primitive.caseSensitive));
|
||||
}
|
||||
singles.putValue(key, primitive);
|
||||
}
|
||||
}
|
||||
customs.addAll(request.getCustomSearchActions());
|
||||
}
|
||||
|
||||
private boolean processSingleRequest(PsiSearchRequest single, Processor<PsiReference> consumer) {
|
||||
|
||||
+9
-5
@@ -15,26 +15,30 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.findUsages;
|
||||
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class ConstructorReferencesSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
|
||||
public boolean execute(ReferencesSearch.SearchParameters queryParameters, final Processor<PsiReference> consumer) {
|
||||
public class ConstructorReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
|
||||
protected ConstructorReferencesSearcher() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQuery(ReferencesSearch.SearchParameters queryParameters, Processor<PsiReference> consumer) {
|
||||
final PsiElement element = queryParameters.getElementToSearch();
|
||||
if (element instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)element;
|
||||
if (method.isConstructor()) {
|
||||
return GroovyConstructorUsagesSearchHelper.execute(method, queryParameters.getScope(), consumer);
|
||||
GroovyConstructorUsagesSearcher.processConstructorUsages(method, queryParameters.getScope(), consumer, queryParameters.getOptimizer(), true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-424
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.groovy.findUsages;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.NullableComputable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMemberReference;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ConcurrentHashSet;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Maxim.Medvedev
|
||||
* Date: May 2, 2009 3:48:53 PM
|
||||
*/
|
||||
public class GroovyConstructorUsagesSearchHelper {
|
||||
private GroovyConstructorUsagesSearchHelper() {
|
||||
}
|
||||
|
||||
public static boolean execute(final PsiMethod constructor, final SearchScope searchScope, final Processor<PsiReference> consumer) {
|
||||
if (!constructor.isConstructor()) return true;
|
||||
|
||||
SearchScope onlyGroovy = searchScope;
|
||||
if (onlyGroovy instanceof GlobalSearchScope) {
|
||||
onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE);
|
||||
}
|
||||
|
||||
final PsiClass clazz = ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiClass>() {
|
||||
public PsiClass compute() {
|
||||
return constructor.getContainingClass();
|
||||
}
|
||||
});
|
||||
if (clazz == null) return true;
|
||||
|
||||
|
||||
//enum constants
|
||||
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
if (!clazz.isEnum()) return true;
|
||||
if (!(clazz instanceof GroovyPsiElement)) return true;
|
||||
final PsiField[] fields = clazz.getFields();
|
||||
for (PsiField field : fields) {
|
||||
if (field instanceof GrEnumConstant) {
|
||||
final PsiReference ref = field.getReference();
|
||||
if (ref.isReferenceTo(constructor)) {
|
||||
if (!consumer.process(ref)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
final Set<PsiMethod> processedMethods = new ConcurrentHashSet<PsiMethod>();
|
||||
ReferencesSearch.search(clazz, searchScope, true).forEach(new Processor<PsiReference>() {
|
||||
@Override
|
||||
public boolean process(PsiReference ref) {
|
||||
return processClassReference(ref, clazz, constructor, consumer, processedMethods, searchScope);
|
||||
}
|
||||
});
|
||||
|
||||
//this()
|
||||
if (clazz instanceof GrTypeDefinition) {
|
||||
if (!processConstructors(constructor, consumer, clazz, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//super : does not work now, need to invent a way for it to work without repository
|
||||
if (!DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor<PsiClass>() {
|
||||
public boolean process(PsiClass inheritor) {
|
||||
if (inheritor instanceof GrTypeDefinition) {
|
||||
if (!processConstructors(constructor, consumer, inheritor, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass clazz, Set<PsiMethod> processedMethods) {
|
||||
final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
|
||||
if (parameter != null) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class);
|
||||
if (method != null && processedMethods.add(method) && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) {
|
||||
final PsiType parameterType = parameter.getType();
|
||||
if (parameterType instanceof PsiClassType) {
|
||||
if (method.getManager().areElementsEquivalent(clazz, ((PsiClassType)parameterType).resolve())) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean processClassReference(final PsiReference ref,
|
||||
final PsiClass clazz,
|
||||
final PsiMethod constructor,
|
||||
final Processor<PsiReference> consumer,
|
||||
final Set<PsiMethod> processedMethods, SearchScope scope) {
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof GrCodeReferenceElement) {
|
||||
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref);
|
||||
}
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final PsiMethod method = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod>() {
|
||||
public PsiMethod compute() {
|
||||
return getMethodToSearchForCallsWithLiteralArguments(element, clazz, processedMethods);
|
||||
}
|
||||
});
|
||||
if (method != null) {
|
||||
return MethodReferencesSearch.search(method, getGppScope(clazz.getProject()).intersectWith(scope), true).forEach(new ReadActionProcessor<PsiReference>() {
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference psiReference) {
|
||||
if (psiReference instanceof GrReferenceElement) {
|
||||
final PsiElement parent = ((GrReferenceElement)psiReference).getParent();
|
||||
if (parent instanceof GrCall) {
|
||||
final GrArgumentList argList = ((GrCall)parent).getArgumentList();
|
||||
if (argList != null) {
|
||||
boolean checkedTypedContext = false;
|
||||
|
||||
for (GrExpression argument : argList.getExpressionArguments()) {
|
||||
if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) {
|
||||
if (!checkedTypedContext) {
|
||||
if (!GppTypeConverter.hasTypedContext(parent)) {
|
||||
return true;
|
||||
}
|
||||
checkedTypedContext = true;
|
||||
}
|
||||
|
||||
for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) {
|
||||
if (psiType instanceof PsiClassType &&
|
||||
clazz.getManager().areElementsEquivalent(clazz,((PsiClassType)psiType).resolve()) &&
|
||||
!checkListInstantiation(constructor, consumer, (GrListOrMap)argument, (PsiClassType)psiType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static GlobalSearchScope getGppScope(final Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<GlobalSearchScope>() {
|
||||
@Override
|
||||
public Result<GlobalSearchScope> compute() {
|
||||
return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean processGroovyConstructorUsages(GrCodeReferenceElement element,
|
||||
final PsiMethod constructor,
|
||||
final Processor<PsiReference> consumer,
|
||||
PsiReference ref) {
|
||||
PsiElement parent = element.getParent();
|
||||
|
||||
if (parent instanceof GrAnonymousClassDefinition) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (parent instanceof GrNewExpression) {
|
||||
final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor();
|
||||
if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (parent instanceof GrTypeElement) {
|
||||
final GrTypeElement typeElement = (GrTypeElement)parent;
|
||||
|
||||
final PsiElement grandpa = typeElement.getParent();
|
||||
if (grandpa instanceof GrVariableDeclaration) {
|
||||
final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables();
|
||||
if (vars.length == 1) {
|
||||
final GrVariable variable = vars[0];
|
||||
if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrMethod) {
|
||||
final GrMethod method = (GrMethod)grandpa;
|
||||
if (typeElement == method.getReturnTypeElementGroovy()) {
|
||||
ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() {
|
||||
@Override
|
||||
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
|
||||
if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrTypeCastExpression) {
|
||||
final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa;
|
||||
if (cast.getCastTypeElement() == typeElement &&
|
||||
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrSafeCastExpression) {
|
||||
final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa;
|
||||
if (cast.getCastTypeElement() == typeElement &&
|
||||
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static GlobalSearchScope calcGppScope(Project project) {
|
||||
final GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
|
||||
final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE);
|
||||
GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) {
|
||||
@Override
|
||||
public boolean contains(VirtualFile file) {
|
||||
return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension());
|
||||
}
|
||||
};
|
||||
final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope);
|
||||
if (typed != null) {
|
||||
final Set<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor<PsiModifierListOwner>() {
|
||||
@Override
|
||||
public boolean process(PsiModifierListOwner occurrence) {
|
||||
ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files);
|
||||
return withTypedAnno.union(gppExtensions);
|
||||
}
|
||||
|
||||
return gppExtensions;
|
||||
}
|
||||
|
||||
private static boolean checkListInstantiation(PsiMethod constructor,
|
||||
Processor<PsiReference> consumer,
|
||||
GrExpression expression, final GrTypeElement typeElement) {
|
||||
if (expression instanceof GrListOrMap) {
|
||||
final GrListOrMap list = (GrListOrMap)expression;
|
||||
if (!list.isMap()) {
|
||||
final PsiType expectedType = typeElement.getType();
|
||||
if (expectedType instanceof PsiClassType) {
|
||||
return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkListInstantiation(PsiMethod constructor,
|
||||
Processor<PsiReference> consumer,
|
||||
GrListOrMap list,
|
||||
PsiClassType expectedType) {
|
||||
final PsiType listType = list.getType();
|
||||
if (listType instanceof GrTupleType) {
|
||||
for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) {
|
||||
if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) {
|
||||
if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processConstructors(final PsiMethod constructor, final Processor<PsiReference> consumer, final PsiClass clazz,
|
||||
final boolean processThisRefs) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
return processClassConstructors(clazz, constructor, consumer, processThisRefs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean processClassConstructors(PsiClass clazz,
|
||||
PsiMethod searchedConstructor,
|
||||
Processor<PsiReference> consumer,
|
||||
boolean processThisRefs) {
|
||||
final PsiMethod[] constructors = clazz.getConstructors();
|
||||
if (constructors.length == 0) {
|
||||
processImplicitConstructorCall(clazz, consumer, searchedConstructor);
|
||||
}
|
||||
for (PsiMethod constructor : constructors) {
|
||||
final GrOpenBlock block = ((GrMethod)constructor).getBlock();
|
||||
if (block != null) {
|
||||
final GrStatement[] statements = block.getStatements();
|
||||
if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
|
||||
final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0];
|
||||
if (invocation.isThisCall() == processThisRefs &&
|
||||
invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) &&
|
||||
!consumer.process(invocation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
processImplicitConstructorCall(constructor, consumer, searchedConstructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void processImplicitConstructorCall(final PsiMember usage,
|
||||
final Processor<PsiReference> processor,
|
||||
final PsiMethod constructor) {
|
||||
if (constructor instanceof GrMethod) {
|
||||
GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters();
|
||||
if (grParameters.length > 0 && !grParameters[0].isOptional()) return;
|
||||
}
|
||||
else if (constructor.getParameterList().getParameters().length > 0) return;
|
||||
|
||||
|
||||
PsiManager manager = constructor.getManager();
|
||||
if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return;
|
||||
processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) {
|
||||
public PsiElement getElement() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
public TextRange getRangeInElement() {
|
||||
if (usage instanceof PsiClass) {
|
||||
PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier();
|
||||
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
|
||||
}
|
||||
else if (usage instanceof PsiMethod) {
|
||||
PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier();
|
||||
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
|
||||
}
|
||||
return super.getRangeInElement();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
+387
-8
@@ -16,20 +16,399 @@
|
||||
|
||||
package org.jetbrains.plugins.groovy.findUsages;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMemberReference;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchRequestCollector;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
import com.intellij.util.containers.ConcurrentHashSet;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Maxim.Medvedev
|
||||
*/
|
||||
public class GroovyConstructorUsagesSearcher implements QueryExecutor<PsiReference, MethodReferencesSearch.SearchParameters> {
|
||||
public boolean execute(MethodReferencesSearch.SearchParameters p, final Processor<PsiReference> consumer) {
|
||||
final PsiMethod method = p.getMethod();
|
||||
final SearchScope searchScope = p.getScope();
|
||||
return GroovyConstructorUsagesSearchHelper.execute(method, searchScope, consumer);
|
||||
public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters> {
|
||||
public GroovyConstructorUsagesSearcher() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQuery(MethodReferencesSearch.SearchParameters p, Processor<PsiReference> consumer) {
|
||||
processConstructorUsages(p.getMethod(), p.getScope(), consumer, p.getOptimizer(), true);
|
||||
}
|
||||
|
||||
static void processConstructorUsages(final PsiMethod constructor, final SearchScope searchScope, final Processor<PsiReference> consumer, final SearchRequestCollector collector, final boolean searchGppCalls) {
|
||||
if (!constructor.isConstructor()) return;
|
||||
|
||||
SearchScope onlyGroovy = searchScope;
|
||||
if (onlyGroovy instanceof GlobalSearchScope) {
|
||||
onlyGroovy = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)onlyGroovy, GroovyFileType.GROOVY_FILE_TYPE);
|
||||
}
|
||||
|
||||
final PsiClass clazz = constructor.getContainingClass();
|
||||
if (clazz == null) return;
|
||||
|
||||
|
||||
if (clazz.isEnum() && clazz instanceof GroovyPsiElement) {
|
||||
for (PsiField field : clazz.getFields()) {
|
||||
if (field instanceof GrEnumConstant) {
|
||||
final PsiReference ref = field.getReference();
|
||||
if (ref != null && ref.isReferenceTo(constructor)) {
|
||||
if (!consumer.process(ref)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Set<PsiMethod> processedMethods = new ConcurrentHashSet<PsiMethod>();
|
||||
|
||||
ReferencesSearch.searchOptimized(clazz, searchScope, true, collector, true, new PairProcessor<PsiReference, SearchRequestCollector>() {
|
||||
@Override
|
||||
public boolean process(PsiReference ref, SearchRequestCollector collector) {
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof GrCodeReferenceElement) {
|
||||
if (!processGroovyConstructorUsages((GrCodeReferenceElement)element, constructor, consumer, ref, !searchGppCalls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchGppCalls) {
|
||||
final PsiMethod method = getMethodToSearchForCallsWithLiteralArguments(element, clazz);
|
||||
if (method != null && processedMethods.add(method)) {
|
||||
processGppMethodCalls(clazz, constructor, consumer, searchScope, collector, method);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//this()
|
||||
if (clazz instanceof GrTypeDefinition) {
|
||||
if (!processConstructors(constructor, consumer, clazz, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
//super()
|
||||
DirectClassInheritorsSearch.search(clazz, onlyGroovy).forEach(new Processor<PsiClass>() {
|
||||
public boolean process(PsiClass inheritor) {
|
||||
if (inheritor instanceof GrTypeDefinition) {
|
||||
if (!processConstructors(constructor, consumer, inheritor, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiMethod getMethodToSearchForCallsWithLiteralArguments(PsiElement element, PsiClass targetClass) {
|
||||
final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
|
||||
if (parameter != null) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class);
|
||||
if (method != null && Arrays.asList(method.getParameterList().getParameters()).contains(parameter)) {
|
||||
final PsiType parameterType = parameter.getType();
|
||||
if (parameterType instanceof PsiClassType) {
|
||||
if (method.getManager().areElementsEquivalent(targetClass, ((PsiClassType)parameterType).resolve())) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void processGppMethodCalls(final PsiClass targetClass,
|
||||
final PsiMethod originalTarget,
|
||||
final Processor<PsiReference> originalProcessor,
|
||||
SearchScope scope,
|
||||
SearchRequestCollector originalCollector, @NotNull PsiMethod currentTarget) {
|
||||
final SearchScope gppScope = getGppScope(targetClass.getProject()).intersectWith(scope);
|
||||
final ReadActionProcessor<PsiReference> gppCallProcessor = new ReadActionProcessor<PsiReference>() {
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference psiReference) {
|
||||
if (psiReference instanceof GrReferenceElement) {
|
||||
final PsiElement parent = ((GrReferenceElement)psiReference).getParent();
|
||||
if (parent instanceof GrCall) {
|
||||
final GrArgumentList argList = ((GrCall)parent).getArgumentList();
|
||||
if (argList != null) {
|
||||
boolean checkedTypedContext = false;
|
||||
|
||||
for (GrExpression argument : argList.getExpressionArguments()) {
|
||||
if (argument instanceof GrListOrMap && !((GrListOrMap)argument).isMap()) {
|
||||
if (!checkedTypedContext) {
|
||||
if (!GppTypeConverter.hasTypedContext(parent)) {
|
||||
return true;
|
||||
}
|
||||
checkedTypedContext = true;
|
||||
}
|
||||
|
||||
for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) {
|
||||
if (psiType instanceof PsiClassType &&
|
||||
targetClass.getManager().areElementsEquivalent(targetClass, ((PsiClassType)psiType).resolve()) &&
|
||||
!checkListInstantiation(originalTarget, originalProcessor, (GrListOrMap)argument, (PsiClassType)psiType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (currentTarget.isConstructor()) {
|
||||
processConstructorUsages(currentTarget, gppScope, gppCallProcessor, originalCollector, false);
|
||||
}
|
||||
else {
|
||||
MethodReferencesSearch.searchOptimized(currentTarget, gppScope, true, originalCollector, gppCallProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
static GlobalSearchScope getGppScope(final Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<GlobalSearchScope>() {
|
||||
@Override
|
||||
public Result<GlobalSearchScope> compute() {
|
||||
return Result.create(calcGppScope(project), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static boolean processGroovyConstructorUsages(GrCodeReferenceElement element,
|
||||
final PsiMethod constructor,
|
||||
final Processor<PsiReference> consumer,
|
||||
PsiReference ref, boolean usualCallsOnly) {
|
||||
PsiElement parent = element.getParent();
|
||||
|
||||
if (parent instanceof GrAnonymousClassDefinition) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (parent instanceof GrNewExpression) {
|
||||
final PsiMethod resolvedConstructor = ((GrNewExpression)parent).resolveConstructor();
|
||||
if (constructor.getManager().areElementsEquivalent(resolvedConstructor, constructor) && !consumer.process(ref)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!usualCallsOnly && parent instanceof GrTypeElement) {
|
||||
final GrTypeElement typeElement = (GrTypeElement)parent;
|
||||
|
||||
final PsiElement grandpa = typeElement.getParent();
|
||||
if (grandpa instanceof GrVariableDeclaration) {
|
||||
final GrVariable[] vars = ((GrVariableDeclaration)grandpa).getVariables();
|
||||
if (vars.length == 1) {
|
||||
final GrVariable variable = vars[0];
|
||||
if (!checkListInstantiation(constructor, consumer, variable.getInitializerGroovy(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrMethod) {
|
||||
final GrMethod method = (GrMethod)grandpa;
|
||||
if (typeElement == method.getReturnTypeElementGroovy()) {
|
||||
ControlFlowUtils.visitAllExitPoints(method.getBlock(), new ControlFlowUtils.ExitPointVisitor() {
|
||||
@Override
|
||||
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
|
||||
if (!checkListInstantiation(constructor, consumer, returnValue, typeElement)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrTypeCastExpression) {
|
||||
final GrTypeCastExpression cast = (GrTypeCastExpression)grandpa;
|
||||
if (cast.getCastTypeElement() == typeElement &&
|
||||
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (grandpa instanceof GrSafeCastExpression) {
|
||||
final GrSafeCastExpression cast = (GrSafeCastExpression)grandpa;
|
||||
if (cast.getCastTypeElement() == typeElement &&
|
||||
!checkListInstantiation(constructor, consumer, cast.getOperand(), typeElement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static GlobalSearchScope calcGppScope(Project project) {
|
||||
final GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
|
||||
final GlobalSearchScope maximal = GlobalSearchScope.getScopeRestrictedByFileTypes(allScope, GroovyFileType.GROOVY_FILE_TYPE);
|
||||
GlobalSearchScope gppExtensions = new DelegatingGlobalSearchScope(maximal) {
|
||||
@Override
|
||||
public boolean contains(VirtualFile file) {
|
||||
return super.contains(file) && GppTypeConverter.isGppExtension(file.getExtension());
|
||||
}
|
||||
};
|
||||
final PsiClass typed = JavaPsiFacade.getInstance(project).findClass(GppTypeConverter.GROOVY_LANG_TYPED, allScope);
|
||||
if (typed != null) {
|
||||
final Set<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
AnnotatedElementsSearch.searchElements(typed, maximal, PsiModifierListOwner.class).forEach(new Processor<PsiModifierListOwner>() {
|
||||
@Override
|
||||
public boolean process(PsiModifierListOwner occurrence) {
|
||||
ContainerUtil.addIfNotNull(occurrence.getContainingFile().getVirtualFile(), files);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
GlobalSearchScope withTypedAnno = GlobalSearchScope.filesScope(project, files);
|
||||
return withTypedAnno.union(gppExtensions);
|
||||
}
|
||||
|
||||
return gppExtensions;
|
||||
}
|
||||
|
||||
static boolean checkListInstantiation(PsiMethod constructor,
|
||||
Processor<PsiReference> consumer,
|
||||
GrExpression expression, final GrTypeElement typeElement) {
|
||||
if (expression instanceof GrListOrMap) {
|
||||
final GrListOrMap list = (GrListOrMap)expression;
|
||||
if (!list.isMap()) {
|
||||
final PsiType expectedType = typeElement.getType();
|
||||
if (expectedType instanceof PsiClassType) {
|
||||
return checkListInstantiation(constructor, consumer, list, (PsiClassType)expectedType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean checkListInstantiation(PsiMethod constructor,
|
||||
Processor<PsiReference> consumer,
|
||||
GrListOrMap list,
|
||||
PsiClassType expectedType) {
|
||||
final PsiType listType = list.getType();
|
||||
if (listType instanceof GrTupleType) {
|
||||
for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, ((GrTupleType)listType).getComponentTypes(), list)) {
|
||||
if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) {
|
||||
if (!consumer.process(PsiReferenceBase.createSelfReference(list, TextRange.from(0, list.getTextLength()), constructor))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean processConstructors(final PsiMethod constructor, final Processor<PsiReference> consumer, final PsiClass clazz,
|
||||
final boolean processThisRefs) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
return processClassConstructors(clazz, constructor, consumer, processThisRefs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static boolean processClassConstructors(PsiClass clazz,
|
||||
PsiMethod searchedConstructor,
|
||||
Processor<PsiReference> consumer,
|
||||
boolean processThisRefs) {
|
||||
final PsiMethod[] constructors = clazz.getConstructors();
|
||||
if (constructors.length == 0) {
|
||||
processImplicitConstructorCall(clazz, consumer, searchedConstructor);
|
||||
}
|
||||
for (PsiMethod constructor : constructors) {
|
||||
final GrOpenBlock block = ((GrMethod)constructor).getBlock();
|
||||
if (block != null) {
|
||||
final GrStatement[] statements = block.getStatements();
|
||||
if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
|
||||
final GrConstructorInvocation invocation = (GrConstructorInvocation)statements[0];
|
||||
if (invocation.isThisCall() == processThisRefs &&
|
||||
invocation.getManager().areElementsEquivalent(invocation.resolveConstructor(), searchedConstructor) &&
|
||||
!consumer.process(invocation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
processImplicitConstructorCall(constructor, consumer, searchedConstructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void processImplicitConstructorCall(final PsiMember usage,
|
||||
final Processor<PsiReference> processor,
|
||||
final PsiMethod constructor) {
|
||||
if (constructor instanceof GrMethod) {
|
||||
GrParameter[] grParameters = (GrParameter[])constructor.getParameterList().getParameters();
|
||||
if (grParameters.length > 0 && !grParameters[0].isOptional()) return;
|
||||
}
|
||||
else if (constructor.getParameterList().getParameters().length > 0) return;
|
||||
|
||||
|
||||
PsiManager manager = constructor.getManager();
|
||||
if (manager.areElementsEquivalent(usage, constructor) || manager.areElementsEquivalent(constructor.getContainingClass(), usage.getContainingClass())) return;
|
||||
processor.process(new LightMemberReference(manager, usage, PsiSubstitutor.EMPTY) {
|
||||
public PsiElement getElement() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
public TextRange getRangeInElement() {
|
||||
if (usage instanceof PsiClass) {
|
||||
PsiIdentifier identifier = ((PsiClass)usage).getNameIdentifier();
|
||||
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
|
||||
}
|
||||
else if (usage instanceof PsiMethod) {
|
||||
PsiIdentifier identifier = ((PsiMethod)usage).getNameIdentifier();
|
||||
if (identifier != null) return TextRange.from(identifier.getStartOffsetInParent(), identifier.getTextLength());
|
||||
}
|
||||
return super.getRangeInElement();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user