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)
+ }
+ }
+}