diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/MethodReferencesSearch.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/MethodReferencesSearch.java index 75f3b38f16ff..341123eeae0e 100644 --- a/java/java-indexing-api/src/com/intellij/psi/search/searches/MethodReferencesSearch.java +++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/MethodReferencesSearch.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.search.searches; +import com.intellij.openapi.application.DumbAwareSearchParameters; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiMethod; @@ -33,7 +34,7 @@ public class MethodReferencesSearch extends ExtensibleQueryFactory EP_NAME = ExtensionPointName.create("com.intellij.methodReferencesSearch"); public static final MethodReferencesSearch INSTANCE = new MethodReferencesSearch(); - public static class SearchParameters { + public static class SearchParameters implements DumbAwareSearchParameters { private final PsiMethod myMethod; private final Project myProject; private final SearchScope myScope; diff --git a/platform/core-api/src/com/intellij/openapi/application/DumbAwareSearchParameters.java b/platform/core-api/src/com/intellij/openapi/application/DumbAwareSearchParameters.java new file mode 100644 index 000000000000..aab37a64f059 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/application/DumbAwareSearchParameters.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2015 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.openapi.application; + +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * A marker interface for {@link QueryExecutorBase} parameters which indicates that searches should only be executed when indexing is complete. + * The query executors that are not {@link com.intellij.openapi.project.DumbAware} are delayed in processing until index is ready. + * + * @author peter + */ +public interface DumbAwareSearchParameters { + @NotNull + Project getProject(); +} diff --git a/platform/core-api/src/com/intellij/openapi/application/QueryExecutorBase.java b/platform/core-api/src/com/intellij/openapi/application/QueryExecutorBase.java index 8b0899eac165..591063c4de0a 100644 --- a/platform/core-api/src/com/intellij/openapi/application/QueryExecutorBase.java +++ b/platform/core-api/src/com/intellij/openapi/application/QueryExecutorBase.java @@ -1,5 +1,8 @@ package com.intellij.openapi.application; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; import org.jetbrains.annotations.NotNull; @@ -7,15 +10,31 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.atomic.AtomicBoolean; /** + * An adapter for {@link QueryExecutor} interface which makes it easier to write implementations. It provides a possibility to + * automatically wrap the implementation code into a read action. During indexing, query executors that don't implement {@link com.intellij.openapi.project.DumbAware} + * (but need to be run in a read action), are delayed until indexing is complete, given that search parameters implement {@link DumbAwareSearchParameters}. + *

+ * Besides, {@link #processQuery(Object, Processor)} doesn't require to return a boolean value and thus it's harder to cancel the whole search + * by accidentally returning false. + * + * @see Application#runReadAction(Computable) + * @see DumbService + * * @author peter */ public abstract class QueryExecutorBase implements QueryExecutor { private final boolean myRequireReadAction; + /** + * @param requireReadAction whether {@link #processQuery(Object, Processor)} should be wrapped into a read action. + */ protected QueryExecutorBase(boolean requireReadAction) { myRequireReadAction = requireReadAction; } + /** + * Construct an instance that executes {@link #processQuery(Object, Processor)} as is, without wrapping into a read action. + */ protected QueryExecutorBase() { this(false); } @@ -39,11 +58,22 @@ public abstract class QueryExecutorBase implements QueryExecutor }; if (myRequireReadAction) { - ApplicationManager.getApplication().runReadAction(new Runnable() { + Runnable runnable = new Runnable() { public void run() { processQuery(queryParameters, wrapper); } - }); + }; + + if (!DumbService.isDumbAware(this)) { + Project project = queryParameters instanceof DumbAwareSearchParameters ? ((DumbAwareSearchParameters)queryParameters).getProject() + : null; + if (project != null) { + DumbService.getInstance(project).runReadActionInSmartMode(runnable); + return toContinue.get(); + } + } + + ApplicationManager.getApplication().runReadAction(runnable); } else { processQuery(queryParameters, wrapper); @@ -52,5 +82,8 @@ public abstract class QueryExecutorBase implements QueryExecutor return toContinue.get(); } + /** + * Find some results according to queryParameters and feed them to consumer. If consumer returns false, stop. + */ public abstract void processQuery(@NotNull Params queryParameters, @NotNull Processor consumer); } diff --git a/platform/core-api/src/com/intellij/util/QueryExecutor.java b/platform/core-api/src/com/intellij/util/QueryExecutor.java index 4feb460dfe75..63eec6c45d2a 100644 --- a/platform/core-api/src/com/intellij/util/QueryExecutor.java +++ b/platform/core-api/src/com/intellij/util/QueryExecutor.java @@ -18,10 +18,17 @@ package com.intellij.util; import org.jetbrains.annotations.NotNull; /** + * A generic extension to enable plugging into various searches.

+ * * Consider extending {@link com.intellij.openapi.application.QueryExecutorBase} instead unless you know what you're doing. * * @author max */ public interface QueryExecutor { + + /** + * Find some results according to queryParameters and feed them to consumer. If consumer returns false, stop. + * @return false if the searching should be stopped immediately. This should happen only when consumer has returned false. + */ boolean execute(@NotNull Param queryParameters, @NotNull Processor consumer); } diff --git a/platform/indexing-api/src/com/intellij/psi/search/searches/ReferencesSearch.java b/platform/indexing-api/src/com/intellij/psi/search/searches/ReferencesSearch.java index 88ed856c92c9..3cc940611f26 100644 --- a/platform/indexing-api/src/com/intellij/psi/search/searches/ReferencesSearch.java +++ b/platform/indexing-api/src/com/intellij/psi/search/searches/ReferencesSearch.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.search.searches; +import com.intellij.openapi.application.DumbAwareSearchParameters; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; @@ -39,7 +40,7 @@ public class ReferencesSearch extends ExtensibleQueryFactory { + public DataProviderSearcher() { + super(true); + } @Override - public void processQuery(@NotNull final MethodReferencesSearch.SearchParameters queryParameters, @NotNull Processor consumer) { - DumbService.getInstance(queryParameters.getProject()).runReadActionInSmartMode(new Runnable() { - @Override - public void run() { - final PsiMethod method = queryParameters.getMethod(); + public void processQuery(@NotNull MethodReferencesSearch.SearchParameters queryParameters, @NotNull Processor consumer) { + final PsiMethod method = queryParameters.getMethod(); - final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, DataProvider.class.getName()); - if (annotation == null) return; - final PsiAnnotationMemberValue dataProviderMethodName = annotation.findDeclaredAttributeValue("name"); - if (dataProviderMethodName != null) { - final String providerName = StringUtil.unquoteString(dataProviderMethodName.getText()); - queryParameters.getOptimizer().searchWord(providerName, queryParameters.getEffectiveSearchScope(), UsageSearchContext.IN_STRINGS, true, method); - } - } - }); + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, DataProvider.class.getName()); + if (annotation == null) return; + final PsiAnnotationMemberValue dataProviderMethodName = annotation.findDeclaredAttributeValue("name"); + if (dataProviderMethodName != null) { + final String providerName = StringUtil.unquoteString(dataProviderMethodName.getText()); + queryParameters.getOptimizer().searchWord(providerName, queryParameters.getEffectiveSearchScope(), UsageSearchContext.IN_STRINGS, true, method); + } } }