introduce DumbAwareSearchParameters and delay reference search executors until smart mode by default

This commit is contained in:
peter
2015-03-12 17:36:47 +01:00
parent 128eb02c7e
commit b0d813f26d
6 changed files with 88 additions and 19 deletions
@@ -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<PsiReference,
public static final ExtensionPointName<QueryExecutor> 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;
@@ -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();
}
@@ -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}.
* <p/>
* 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<Result, Params> implements QueryExecutor<Result, Params> {
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<Result, Params> 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<Result, Params> 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<Result> consumer);
}
@@ -18,10 +18,17 @@ package com.intellij.util;
import org.jetbrains.annotations.NotNull;
/**
* A generic extension to enable plugging into various searches.<p/>
*
* Consider extending {@link com.intellij.openapi.application.QueryExecutorBase} instead unless you know what you're doing.
*
* @author max
*/
public interface QueryExecutor<Result, Param> {
/**
* 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<Result> consumer);
}
@@ -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<PsiReference, Refer
private ReferencesSearch() {
}
public static class SearchParameters {
public static class SearchParameters implements DumbAwareSearchParameters {
private final PsiElement myElementToSearch;
private final SearchScope myScope;
private final boolean myIgnoreAccessScope;
@@ -17,7 +17,6 @@ package com.theoryinpractice.testng;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.UsageSearchContext;
@@ -27,23 +26,21 @@ import org.jetbrains.annotations.NotNull;
import org.testng.annotations.DataProvider;
public class DataProviderSearcher extends QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters> {
public DataProviderSearcher() {
super(true);
}
@Override
public void processQuery(@NotNull final MethodReferencesSearch.SearchParameters queryParameters, @NotNull Processor<PsiReference> 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<PsiReference> 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);
}
}
}