diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassesWithAnnotatedMembersSearch.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassesWithAnnotatedMembersSearch.java new file mode 100644 index 000000000000..b42149b2b36c --- /dev/null +++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassesWithAnnotatedMembersSearch.java @@ -0,0 +1,55 @@ +/* + * 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.psi.search.searches; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.*; +import com.intellij.psi.search.SearchScope; +import com.intellij.util.Query; +import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; + +/** + * Searcher that searches for classes which have members annotated with the specified annotation. + * + * @author yole + */ +public class ClassesWithAnnotatedMembersSearch extends ExtensibleQueryFactory { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.classesWithAnnotatedMembersSearch"); + public static final ClassesWithAnnotatedMembersSearch INSTANCE = new ClassesWithAnnotatedMembersSearch(); + + public static class Parameters { + private final PsiClass myAnnotationClass; + private final SearchScope myScope; + + public Parameters(final PsiClass annotationClass, final SearchScope scope) { + myAnnotationClass = annotationClass; + myScope = scope; + } + + public PsiClass getAnnotationClass() { + return myAnnotationClass; + } + + public SearchScope getScope() { + return myScope; + } + } + + public static Query search(@NotNull PsiClass annotationClass, @NotNull SearchScope scope) { + return INSTANCE.createQuery(new Parameters(annotationClass, scope)); + } +} diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/ScopedQueryExecutor.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/ScopedQueryExecutor.java new file mode 100644 index 000000000000..1aa3cf4496a6 --- /dev/null +++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/ScopedQueryExecutor.java @@ -0,0 +1,34 @@ +/* + * 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.psi.search.searches; + +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; + +/** + * A query executor that handles all searches within the specified scope, requesting the default query + * executor to not perform any searches in this scope. + * + * @author yole + */ +public interface ScopedQueryExecutor extends QueryExecutor { + /** + * Returns the scope handled by this executor. + */ + @NotNull + GlobalSearchScope getScope(); +} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/ClassesWithAnnotatedMembersSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ClassesWithAnnotatedMembersSearcher.java new file mode 100644 index 000000000000..99f82c227789 --- /dev/null +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ClassesWithAnnotatedMembersSearcher.java @@ -0,0 +1,69 @@ +/* + * 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.psi.impl.search; + +import com.intellij.openapi.application.*; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMember; +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.ClassesWithAnnotatedMembersSearch; +import com.intellij.psi.search.searches.ScopedQueryExecutor; +import com.intellij.util.Processor; +import com.intellij.util.QueryExecutor; +import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * @author yole + */ +public class ClassesWithAnnotatedMembersSearcher extends QueryExecutorBase { + @Override + public void processQuery(@NotNull ClassesWithAnnotatedMembersSearch.Parameters queryParameters, + @NotNull final Processor consumer) { + SearchScope scope = queryParameters.getScope(); + for (QueryExecutor executor : Extensions.getExtensions(ClassesWithAnnotatedMembersSearch.EP_NAME)) { + if (executor instanceof ScopedQueryExecutor) { + scope = scope.intersectWith(GlobalSearchScope.notScope(((ScopedQueryExecutor) executor).getScope())); + } + } + + final Set processed = new HashSet(); + AnnotatedElementsSearch.searchPsiMembers(queryParameters.getAnnotationClass(), scope).forEach(new Processor() { + @Override + public boolean process(PsiMember member) { + PsiClass psiClass; + AccessToken token = ReadAction.start(); + try { + psiClass = member instanceof PsiClass ? (PsiClass)member : member.getContainingClass(); + } + finally { + token.finish(); + } + + if (psiClass != null && processed.add(psiClass)) { + consumer.process(psiClass); + } + + return true; + } + }); + } +} diff --git a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java index 4c0630b644fb..11161e14e52e 100644 --- a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java +++ b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -27,9 +27,12 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.search.*; -import com.intellij.psi.search.searches.AnnotatedMembersSearch; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiElementProcessor; +import com.intellij.psi.search.PsiElementProcessorAdapter; +import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.ClassesWithAnnotatedMembersSearch; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -99,22 +102,16 @@ public class ConfigurationUtil { ); if (testAnnotation != null) { //allScope is used to find all abstract test cases which probably have inheritors in the current 'scope' - AnnotatedMembersSearch.search(testAnnotation, GlobalSearchScope.allScope(manager.getProject())).forEach(new Processor() { - public boolean process(final PsiMember annotated) { - final PsiClass containingClass; - + ClassesWithAnnotatedMembersSearch.search(testAnnotation, GlobalSearchScope.allScope(manager.getProject())).forEach(new Processor() { + public boolean process(final PsiClass annotated) { AccessToken token = ReadAction.start(); try { - containingClass = annotated instanceof PsiClass ? (PsiClass)annotated : annotated.getContainingClass(); - if (containingClass == null || annotated instanceof PsiMethod != isMethod) { + if (!processed.add(annotated)) { // don't process the same class twice regardless of it being in the scope return true; } - if (!processed.add(containingClass)) { // don't process the same class twice regardless of it being in the scope - return true; - } - final VirtualFile file = PsiUtilCore.getVirtualFile(containingClass); - if (file != null && scope.contains(file) && testClassFilter.isAccepted(containingClass)) { - if (!found.add(containingClass)) { + final VirtualFile file = PsiUtilCore.getVirtualFile(annotated); + if (file != null && scope.contains(file) && testClassFilter.isAccepted(annotated)) { + if (!found.add(annotated)) { return true; } isJUnit4.set(Boolean.TRUE); @@ -124,7 +121,7 @@ public class ConfigurationUtil { token.finish(); } - ClassInheritorsSearch.search(containingClass, scope, true, true, false).forEach(new ReadActionProcessor() { + ClassInheritorsSearch.search(annotated, scope, true, true, false).forEach(new ReadActionProcessor() { @Override public boolean processInReadAction(PsiClass aClass) { if (testClassFilter.isAccepted(aClass)) { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index e9f3a0c2fe14..ffb20528ed12 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -170,6 +170,7 @@ + +