diff --git a/annotations/com/intellij/util/annotations.xml b/annotations/com/intellij/util/annotations.xml new file mode 100644 index 00000000000..01e6a7e5584 --- /dev/null +++ b/annotations/com/intellij/util/annotations.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index 718bcf67c9a..79c3f297294 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -35,6 +35,8 @@ import org.jetbrains.jet.lang.psi.JetBlockExpression import org.jetbrains.jet.lang.psi.JetPsiUtil import org.jetbrains.jet.lang.psi.JetPsiFactory import kotlin.test.assertTrue +import com.intellij.psi.search.SearchScope +import com.intellij.psi.search.PsiSearchScopeUtil fun PsiElement.getParentByTypeAndPredicate( parentClass : Class, strict : Boolean = false, predicate: (T) -> Boolean @@ -147,4 +149,6 @@ fun StubBasedPsiElementBase } return result -} \ No newline at end of file +} + +fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element) \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/search/declarationsSearch/declarationSearchUtil.kt b/idea/src/org/jetbrains/jet/plugin/search/declarationsSearch/declarationSearchUtil.kt new file mode 100644 index 00000000000..8cb4bf56d90 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/search/declarationsSearch/declarationSearchUtil.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2010-2013 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.jet.plugin.search.declarationsSearch + +import com.intellij.psi.search.SearchScope +import com.intellij.util.Query +import com.intellij.util.QueryFactory +import com.intellij.util.Processor +import com.intellij.openapi.application.QueryExecutorBase +import com.intellij.openapi.progress.ProgressIndicatorProvider +import com.intellij.psi.PsiElement +import com.intellij.openapi.project.Project +import com.intellij.util.EmptyQuery +import java.util.Stack +import java.util.HashSet +import com.intellij.openapi.progress.ProgressIndicatorProvider +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.jet.lang.psi.psiUtil.contains + +trait DeclarationSearchRequest { + val project: Project + val searchScope: SearchScope +} + +public trait SearchRequestWithElement : DeclarationSearchRequest { + val originalElement: T + override val project: Project get() = originalElement.getProject() +} + +abstract class DeclarationsSearch>: QueryFactory() { + { + registerExecutor( + object : QueryExecutorBase(true) { + override fun processQuery(queryParameters: R, consumer: Processor) { + doSearch(queryParameters, consumer) + } + } + ) + } + + protected abstract fun doSearch(request: R, consumer: Processor) + protected open fun isApplicable(request: R): Boolean = true + + fun search(request: R): Query = if (isApplicable(request)) createUniqueResultsQuery(request) else EmptyQuery.getEmptyQuery() +} + +public class HierarchySearchRequest ( + override val originalElement: T, + override val searchScope: SearchScope, + val searchDeeply: Boolean = true +) : SearchRequestWithElement + +abstract class HierarchyTraverser { + protected abstract fun nextElements(current: T): Iterable + protected abstract fun shouldDescend(element: T): Boolean + + fun forEach(initialElement: T, body: (T) -> Unit) { + val stack = Stack() + val processed = HashSet() + + stack.push(initialElement) + while (!stack.empty) { + ProgressIndicatorProvider.checkCanceled() + + val current = stack.pop()!! + if (!processed.add(current)) continue + + for (next in nextElements(current)) { + ProgressIndicatorProvider.checkCanceled() + + body(next) + + if (shouldDescend(next)) { + stack.push(next) + } + } + } + } +} + +fun Processor.consumeHierarchy(request: SearchRequestWithElement, traverser: HierarchyTraverser) { + traverser.forEach(request.originalElement) { element -> + if (element in request.searchScope) { + process(element) + } + } +}