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