Implement UsagesSearch
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
<root>
|
||||||
|
<item
|
||||||
|
name='com.intellij.psi.PsiReferenceService java.util.List<com.intellij.psi.PsiReference> getReferences(com.intellij.psi.PsiElement, com.intellij.psi.PsiReferenceService.Hints)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.usagesSearch
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
|
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.*
|
||||||
|
|
||||||
|
class OrFilter(val filter1: UsagesSearchFilter, val filter2: UsagesSearchFilter): UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean =
|
||||||
|
filter1.accepts(ref, item) || filter2.accepts(ref, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
class AndFilter(val filter1: UsagesSearchFilter, val filter2: UsagesSearchFilter): UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean =
|
||||||
|
filter1.accepts(ref, item) && filter2.accepts(ref, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotFilter(val filter: UsagesSearchFilter): UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean =
|
||||||
|
!filter.accepts(ref, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.or(that: UsagesSearchFilter): UsagesSearchFilter = when {
|
||||||
|
this == False -> that
|
||||||
|
that == False -> this
|
||||||
|
this == True, that == True -> True
|
||||||
|
else -> OrFilter(this, that)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.and(that: UsagesSearchFilter): UsagesSearchFilter = when {
|
||||||
|
this == True -> that
|
||||||
|
that == True -> this
|
||||||
|
this == False, that == False -> False
|
||||||
|
else -> AndFilter(this, that)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.not(): UsagesSearchFilter = when {
|
||||||
|
this == False -> True
|
||||||
|
this == True -> False
|
||||||
|
else -> NotFilter(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.ifElse(condition: Boolean, elseFilter: UsagesSearchFilter): UsagesSearchFilter =
|
||||||
|
if (condition) this else elseFilter
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.ifOrFalse(condition: Boolean): UsagesSearchFilter = ifElse(condition, False)
|
||||||
|
|
||||||
|
fun UsagesSearchFilter.ifOrTrue(condition: Boolean): UsagesSearchFilter = ifElse(condition, True)
|
||||||
|
|
||||||
|
val (PsiReference.() -> Boolean).searchFilter: UsagesSearchFilter
|
||||||
|
get() = object: UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean = ref.this@searchFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
val <T: PsiNamedElement> (PsiReference.(T) -> Boolean).searchFilter: UsagesSearchFilter
|
||||||
|
get() = object: UsagesSearchFilter {
|
||||||
|
[suppress("UNCHECKED_CAST")]
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean = ref.this@searchFilter(item.target.element as T)
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* 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.usagesSearch
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.util.QueryFactory
|
||||||
|
import com.intellij.psi.search.SearchScope
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.search.SearchRequestCollector
|
||||||
|
import com.intellij.psi.search.SearchSession
|
||||||
|
import com.intellij.psi.search.PsiSearchHelper
|
||||||
|
import com.intellij.util.Query
|
||||||
|
import com.intellij.util.MergeQuery
|
||||||
|
import com.intellij.psi.search.SearchRequestQuery
|
||||||
|
import com.intellij.util.UniqueResultsQuery
|
||||||
|
import com.intellij.psi.search.searches.ReferenceDescriptor
|
||||||
|
import com.intellij.util.containers.ContainerUtil
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.psi.search.UsageSearchContext
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.search.RequestResultProcessor
|
||||||
|
import com.intellij.util.Processor
|
||||||
|
import com.intellij.openapi.application.QueryExecutorBase
|
||||||
|
import com.intellij.psi.PsiReferenceService
|
||||||
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.psi.ReferenceRange
|
||||||
|
import java.util.Collections
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.extensions.Extensions
|
||||||
|
import java.util.ArrayList
|
||||||
|
import com.intellij.util.EmptyQuery
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import java.util.ArrayDeque
|
||||||
|
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.*
|
||||||
|
|
||||||
|
public data class UsagesSearchLocation(
|
||||||
|
val inCode: Boolean = true,
|
||||||
|
val inComments: Boolean = false,
|
||||||
|
val inStrings: Boolean = false,
|
||||||
|
val inPlainText: Boolean = false
|
||||||
|
) {
|
||||||
|
class object {
|
||||||
|
public val DEFAULT: UsagesSearchLocation = UsagesSearchLocation()
|
||||||
|
public val EVERYWHERE: UsagesSearchLocation = UsagesSearchLocation(true, true, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchContext: Short
|
||||||
|
get() {
|
||||||
|
var res = 0
|
||||||
|
|
||||||
|
if (inCode) res += UsageSearchContext.IN_CODE + UsageSearchContext.IN_FOREIGN_LANGUAGES
|
||||||
|
if (inComments) res += UsageSearchContext.IN_COMMENTS
|
||||||
|
if (inStrings) res += UsageSearchContext.IN_STRINGS
|
||||||
|
if (inPlainText) res += UsageSearchContext.IN_PLAIN_TEXT
|
||||||
|
|
||||||
|
return res.toShort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public data class UsagesSearchTarget<out T : PsiElement>(
|
||||||
|
val element: T,
|
||||||
|
val scope: SearchScope,
|
||||||
|
val location: UsagesSearchLocation = UsagesSearchLocation.DEFAULT,
|
||||||
|
val restrictByTargetScope: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
public trait UsagesSearchFilter {
|
||||||
|
class object {
|
||||||
|
object False: UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
object True: UsagesSearchFilter {
|
||||||
|
override fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun accepts(ref: PsiReference, item: UsagesSearchRequestItem): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
public data class UsagesSearchRequestItem(
|
||||||
|
val target: UsagesSearchTarget<PsiElement>,
|
||||||
|
val words: List<String>,
|
||||||
|
val filter: UsagesSearchFilter
|
||||||
|
)
|
||||||
|
|
||||||
|
public data class UsagesSearchRequest(val project: Project, val items: List<UsagesSearchRequestItem>) {
|
||||||
|
val collector: SearchRequestCollector = SearchRequestCollector(SearchSession())
|
||||||
|
}
|
||||||
|
|
||||||
|
public object UsagesSearch: QueryFactory<PsiReference, UsagesSearchRequest>() {
|
||||||
|
{
|
||||||
|
class ResultProcessorImpl(private val node: UsagesSearchRequestItem) : RequestResultProcessor() {
|
||||||
|
private val referenceService = PsiReferenceService.getService()!!
|
||||||
|
|
||||||
|
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
|
||||||
|
referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
|
||||||
|
ProgressManager.checkCanceled()
|
||||||
|
|
||||||
|
when {
|
||||||
|
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
|
||||||
|
!node.filter.accepts(ref, node) -> true
|
||||||
|
else -> consumer.process(ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ExecutorImpl: QueryExecutorBase<PsiReference, UsagesSearchRequest>() {
|
||||||
|
override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) {
|
||||||
|
for (item in request.items) {
|
||||||
|
with (item) {
|
||||||
|
if (filter != False) {
|
||||||
|
ApplicationManager.getApplication()?.runReadAction {
|
||||||
|
for (word in words) {
|
||||||
|
request.collector.searchWord(
|
||||||
|
word, target.scope, target.location.searchContext, true, ResultProcessorImpl(item)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerExecutor(ExecutorImpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun search(request: UsagesSearchRequest): Query<PsiReference> = with(request) {
|
||||||
|
createQuery(this) merge SearchRequestQuery(project, collector).unique
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UsagesSearchRequest.search(): Query<PsiReference> = UsagesSearch.search(this)
|
||||||
|
|
||||||
|
fun <A: PsiElement, B: PsiElement> UsagesSearchTarget<A>.retarget(element: B) =
|
||||||
|
UsagesSearchTarget<B>(element, scope, location, restrictByTargetScope)
|
||||||
|
|
||||||
|
val <T: PsiElement> UsagesSearchTarget<T>.effectiveScope: SearchScope
|
||||||
|
get() = if (restrictByTargetScope) scope.intersectWith(element.effectiveScope) else scope
|
||||||
|
|
||||||
|
val PsiElement.effectiveScope: SearchScope
|
||||||
|
get() = PsiSearchHelper.SERVICE.getInstance(getProject())!!.getUseScope(this)
|
||||||
|
|
||||||
|
fun <T> Query<T>.merge(that: Query<T>): Query<T> = MergeQuery(this, that)
|
||||||
|
|
||||||
|
val Query<PsiReference>.unique: Query<PsiReference>
|
||||||
|
get() = UniqueResultsQuery(this, ContainerUtil.canonicalStrategy(), ReferenceDescriptor.MAPPER)
|
||||||
Reference in New Issue
Block a user