diff --git a/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java b/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java index 65ddc53296f1..93d6c61933b7 100644 --- a/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java +++ b/platform/lang-api/src/com/intellij/psi/search/PsiSearchRequest.java @@ -1,5 +1,6 @@ package com.intellij.psi.search; +import com.intellij.openapi.util.Computable; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -21,7 +22,7 @@ public class PsiSearchRequest { return new ComplexRequest(); } - public static CustomRequest custom(Runnable searchAction) { + public static CustomRequest custom(Computable searchAction) { return new CustomRequest(searchAction); } @@ -66,9 +67,9 @@ public class PsiSearchRequest { } public static class CustomRequest extends PsiSearchRequest { - public final Runnable searchAction; + public final Computable searchAction; - private CustomRequest(Runnable searchAction) { + private CustomRequest(Computable searchAction) { this.searchAction = searchAction; } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 70309af9ec53..6b9cd4ff52b6 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -484,17 +484,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return processSingleRequest((PsiSearchRequest.SingleRequest)request); } else if (request instanceof PsiSearchRequest.CustomRequest) { - ((PsiSearchRequest.CustomRequest)request).searchAction.run(); - return true; + return ((PsiSearchRequest.CustomRequest)request).searchAction.compute(); } else if (request instanceof PsiSearchRequest.ComplexRequest) { - final MultiMap singles = new MultiMap(); + final MultiMap, PsiSearchRequest.SingleRequest> singles = new MultiMap, PsiSearchRequest.SingleRequest>(); final List customs = new ArrayList(); distributePrimitives((PsiSearchRequest.ComplexRequest)request, singles, customs); if (processRequestsOptimized(singles)) { for (PsiSearchRequest.CustomRequest custom : customs) { - custom.searchAction.run(); + if (!custom.searchAction.compute()) { + return false; + } } return true; } @@ -506,7 +507,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { } } - private boolean processRequestsOptimized(MultiMap singles) { + private boolean processRequestsOptimized(MultiMap, PsiSearchRequest.SingleRequest> singles) { if (singles.isEmpty()) { return true; } @@ -551,39 +552,68 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { }); } - private MultiMap collectFiles(MultiMap singles) { + private MultiMap collectFiles(MultiMap, PsiSearchRequest.SingleRequest> singles) { final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex(); - final MultiMap candidateFiles = new MultiMap(); - for (IdIndexEntry key : singles.keySet()) { + final MultiMap result = new MultiMap(); + for (Set key : singles.keySet()) { final Collection data = singles.get(key); - GlobalSearchScope commonScope = null; - for (PsiSearchRequest.SingleRequest r : data) { - final GlobalSearchScope scope = (GlobalSearchScope)r.searchScope; - commonScope = commonScope == null ? scope : commonScope.uniteWith(scope); - } - assert commonScope != null; + GlobalSearchScope commonScope = uniteScopes(data); + MultiMap intersection = null; - FileBasedIndex.getInstance().processValues(IdIndex.NAME, key, null, new FileBasedIndex.ValueProcessor() { - public boolean process(VirtualFile file, Integer value) { - if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { - return true; - } - int mask = value.intValue(); - for (PsiSearchRequest.SingleRequest single : data) { - if ((mask & single.searchContext) != 0) { - candidateFiles.putValue(file, single); + boolean first = true; + for (IdIndexEntry entry : key) { + final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope); + if (first) { + intersection = local; + first = false; + } else { + for (VirtualFile file : local.keySet()) { + if (intersection.containsKey(file)) { + intersection.putValues(file, local.get(file)); } } + } + } + result.putAllValues(intersection); + } + return result; + } + + private static GlobalSearchScope uniteScopes(Collection requests) { + GlobalSearchScope commonScope = null; + for (PsiSearchRequest.SingleRequest r : requests) { + final GlobalSearchScope scope = (GlobalSearchScope)r.searchScope; + commonScope = commonScope == null ? scope : commonScope.uniteWith(scope); + } + assert commonScope != null; + return commonScope; + } + + private static MultiMap findFilesWithIndexEntry(IdIndexEntry entry, + final ProjectFileIndex index, + final Collection data, + GlobalSearchScope commonScope) { + final MultiMap local = new MultiMap(); + FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor() { + public boolean process(VirtualFile file, Integer value) { + if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { return true; } - }, commonScope); - } - return candidateFiles; + int mask = value.intValue(); + for (PsiSearchRequest.SingleRequest single : data) { + if ((mask & single.searchContext) != 0) { + local.putValue(file, single); + } + } + return true; + } + }, commonScope); + return local; } private void distributePrimitives(PsiSearchRequest.ComplexRequest request, - MultiMap singles, + MultiMap, PsiSearchRequest.SingleRequest> singles, List customs) { for (PsiSearchRequest primitive : request.getConstituents()) { if (primitive instanceof PsiSearchRequest.CustomRequest) { @@ -592,13 +622,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { final PsiSearchRequest.SingleRequest single = (PsiSearchRequest.SingleRequest) primitive; final SearchScope scope = single.searchScope; if (scope instanceof LocalSearchScope) { - customs.add(PsiSearchRequest.custom(new Runnable() { - public void run() { - processSingleRequest(single); + customs.add(PsiSearchRequest.custom(new Computable() { + public Boolean compute() { + return processSingleRequest(single); } })); } else { - singles.putValue(new IdIndexEntry(single.word, single.caseSensitive), single); + final List words = StringUtil.getWordsIn(single.word); + final Set key = new HashSet(words.size()); + for (String word : words) { + key.add(new IdIndexEntry(word, single.caseSensitive)); + } + singles.putValue(key, single); } }