Minor: reformat and cleanup org.jetbrains.kotlin.idea.search package
This commit is contained in:
+5
-4
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.search
|
||||
|
||||
import com.intellij.lexer.Lexer
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.search.IndexPatternBuilder
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
|
||||
@@ -26,8 +25,10 @@ import org.jetbrains.kotlin.lexer.KotlinLexer
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class KotlinIndexPatternBuilder: IndexPatternBuilderAdapter() {
|
||||
private val TODO_COMMENT_TOKENS = TokenSet.orSet(KtTokens.COMMENTS, TokenSet.create(KDocTokens.KDOC))
|
||||
class KotlinIndexPatternBuilder : IndexPatternBuilderAdapter() {
|
||||
private companion object {
|
||||
private val TODO_COMMENT_TOKENS = TokenSet.orSet(KtTokens.COMMENTS, TokenSet.create(KDocTokens.KDOC))
|
||||
}
|
||||
|
||||
override fun getCommentTokenSet(file: PsiFile): TokenSet? {
|
||||
return if (file is KtFile) TODO_COMMENT_TOKENS else null
|
||||
@@ -39,7 +40,7 @@ class KotlinIndexPatternBuilder: IndexPatternBuilderAdapter() {
|
||||
|
||||
override fun getCommentStartDelta(tokenType: IElementType?): Int = 0
|
||||
|
||||
override fun getCommentEndDelta(tokenType: IElementType?): Int = when(tokenType) {
|
||||
override fun getCommentEndDelta(tokenType: IElementType?): Int = when (tokenType) {
|
||||
KtTokens.BLOCK_COMMENT -> "*/".length
|
||||
else -> 0
|
||||
}
|
||||
|
||||
@@ -34,30 +34,33 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
|
||||
val KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT: Short = 0x20
|
||||
const val KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT: Short = 0x20
|
||||
|
||||
private val ALL_SEARCHABLE_OPERATIONS: ImmutableSet<KtToken> = ImmutableSet
|
||||
.builder<KtToken>()
|
||||
.addAll(OperatorConventions.UNARY_OPERATION_NAMES.keys)
|
||||
.addAll(OperatorConventions.BINARY_OPERATION_NAMES.keys)
|
||||
.addAll(OperatorConventions.ASSIGNMENT_OPERATIONS.keys)
|
||||
.addAll(OperatorConventions.COMPARISON_OPERATIONS)
|
||||
.addAll(OperatorConventions.EQUALS_OPERATIONS)
|
||||
.addAll(OperatorConventions.IN_OPERATIONS)
|
||||
.add(KtTokens.LBRACKET)
|
||||
.add(KtTokens.BY_KEYWORD)
|
||||
.build()
|
||||
.builder<KtToken>()
|
||||
.addAll(OperatorConventions.UNARY_OPERATION_NAMES.keys)
|
||||
.addAll(OperatorConventions.BINARY_OPERATION_NAMES.keys)
|
||||
.addAll(OperatorConventions.ASSIGNMENT_OPERATIONS.keys)
|
||||
.addAll(OperatorConventions.COMPARISON_OPERATIONS)
|
||||
.addAll(OperatorConventions.EQUALS_OPERATIONS)
|
||||
.addAll(OperatorConventions.IN_OPERATIONS)
|
||||
.add(KtTokens.LBRACKET)
|
||||
.add(KtTokens.BY_KEYWORD)
|
||||
.build()
|
||||
|
||||
class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): BaseFilterLexer(KotlinLexer(), occurrenceConsumer) {
|
||||
private val codeTokens = TokenSet.orSet(
|
||||
class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer) : BaseFilterLexer(KotlinLexer(), occurrenceConsumer) {
|
||||
private companion object {
|
||||
private val codeTokens = TokenSet.orSet(
|
||||
TokenSet.create(*ALL_SEARCHABLE_OPERATIONS.toTypedArray()),
|
||||
TokenSet.create(KtTokens.IDENTIFIER)
|
||||
)
|
||||
)
|
||||
|
||||
private val commentTokens = TokenSet.orSet(KtTokens.COMMENTS, TokenSet.create(KDocTokens.KDOC))
|
||||
private val commentTokens = TokenSet.orSet(KtTokens.COMMENTS, TokenSet.create(KDocTokens.KDOC))
|
||||
|
||||
private const val MAX_PREV_TOKENS = 2
|
||||
private val prevTokens = ArrayDeque<IElementType>(MAX_PREV_TOKENS)
|
||||
}
|
||||
|
||||
private val MAX_PREV_TOKENS = 2
|
||||
private val prevTokens = ArrayDeque<IElementType>(MAX_PREV_TOKENS)
|
||||
private var prevTokenStart = -1
|
||||
private var prevTokenEnd = -1
|
||||
|
||||
@@ -69,7 +72,13 @@ class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): Bas
|
||||
if (prevTokens.peekFirst() == KtTokens.IDENTIFIER) {
|
||||
val prevPrev = prevTokens.elementAtOrNull(1)
|
||||
if (prevPrev == KtTokens.COMMA || prevPrev == KtTokens.LPAR) {
|
||||
occurrenceConsumer.addOccurrence(bufferSequence, null, prevTokenStart, prevTokenEnd, KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT.toInt())
|
||||
occurrenceConsumer.addOccurrence(
|
||||
bufferSequence,
|
||||
null,
|
||||
prevTokenStart,
|
||||
prevTokenEnd,
|
||||
KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,22 +90,21 @@ class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): Bas
|
||||
}
|
||||
|
||||
KtTokens.IDENTIFIER -> {
|
||||
if (myDelegate.tokenText.startsWith("`")) {
|
||||
scanWordsInToken(UsageSearchContext.IN_CODE.toInt(), false, false)
|
||||
}
|
||||
else {
|
||||
addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
|
||||
if (myDelegate.tokenText == "TODO" ) {
|
||||
// Heuristics to reduce mismatches between indexer and searcher. The searcher returns only occurrences of TO_DO
|
||||
// as the callee of a call expression, but we can't tell calls and other usages apart based on limited lexer context,
|
||||
// so we just exclude occurrences in declaration names (and even that doesn't work precisely because it doesn't handle
|
||||
// declarations with type parameters)
|
||||
val prevToken = prevTokens.peekFirst()
|
||||
if (prevToken != KtTokens.FUN_KEYWORD && prevToken != KtTokens.VAR_KEYWORD && prevToken != KtTokens.VAL_KEYWORD && prevToken != KtTokens.CLASS_KEYWORD) {
|
||||
advanceTodoItemCountsInToken()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (myDelegate.tokenText.startsWith("`")) {
|
||||
scanWordsInToken(UsageSearchContext.IN_CODE.toInt(), false, false)
|
||||
} else {
|
||||
addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
|
||||
if (myDelegate.tokenText == "TODO") {
|
||||
// Heuristics to reduce mismatches between indexer and searcher. The searcher returns only occurrences of TO_DO
|
||||
// as the callee of a call expression, but we can't tell calls and other usages apart based on limited lexer context,
|
||||
// so we just exclude occurrences in declaration names (and even that doesn't work precisely because it doesn't handle
|
||||
// declarations with type parameters)
|
||||
val prevToken = prevTokens.peekFirst()
|
||||
if (prevToken != KtTokens.FUN_KEYWORD && prevToken != KtTokens.VAR_KEYWORD && prevToken != KtTokens.VAL_KEYWORD && prevToken != KtTokens.CLASS_KEYWORD) {
|
||||
advanceTodoItemCountsInToken()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in codeTokens -> addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
|
||||
@@ -128,13 +136,13 @@ class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): Bas
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinIdIndexer: LexerBasedIdIndexer() {
|
||||
class KotlinIdIndexer : LexerBasedIdIndexer() {
|
||||
override fun createLexer(consumer: OccurrenceConsumer): Lexer = KotlinFilterLexer(consumer)
|
||||
|
||||
override fun getVersion() = 3
|
||||
}
|
||||
|
||||
class KotlinTodoIndexer: LexerBasedTodoIndexer(), IdAndToDoScannerBasedOnFilterLexer {
|
||||
class KotlinTodoIndexer : LexerBasedTodoIndexer(), IdAndToDoScannerBasedOnFilterLexer {
|
||||
override fun getVersion() = 2
|
||||
|
||||
override fun createLexer(consumer: OccurrenceConsumer) = KotlinFilterLexer(consumer)
|
||||
|
||||
@@ -62,9 +62,12 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
private var forceAmbiguityForNonAnnotations: Boolean = false
|
||||
|
||||
companion object {
|
||||
@TestOnly val attempts = AtomicInteger()
|
||||
@TestOnly val trueHits = AtomicInteger()
|
||||
@TestOnly val falseHits = AtomicInteger()
|
||||
@TestOnly
|
||||
val attempts = AtomicInteger()
|
||||
@TestOnly
|
||||
val trueHits = AtomicInteger()
|
||||
@TestOnly
|
||||
val falseHits = AtomicInteger()
|
||||
|
||||
private val PSI_BASED_CLASS_RESOLVER_KEY = Key<CachedValue<PsiBasedClassResolver>>("PsiBasedClassResolver")
|
||||
|
||||
@@ -86,7 +89,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(target: PsiClass): this(target.qualifiedName ?: "") {
|
||||
private constructor(target: PsiClass) : this(target.qualifiedName ?: "") {
|
||||
if (target.qualifiedName == null || target.containingClass != null || targetPackage.isEmpty()) {
|
||||
forceAmbiguity = true
|
||||
return
|
||||
@@ -105,8 +108,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
if (candidate.containingClass != null && !candidate.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
if (candidate.isAnnotationType) {
|
||||
forceAmbiguity = true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
forceAmbiguityForNonAnnotations = true
|
||||
}
|
||||
break
|
||||
@@ -118,8 +120,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
forceAmbiguity = true
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
candidate.qualifiedName?.substringBeforeLast('.', "")?.let { candidatePackage ->
|
||||
if (candidatePackage == "")
|
||||
forceAmbiguity = true
|
||||
@@ -137,7 +138,8 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly fun addConflict(fqName: String) {
|
||||
@TestOnly
|
||||
fun addConflict(fqName: String) {
|
||||
conflictingPackages.add(fqName.substringBeforeLast('.'))
|
||||
}
|
||||
|
||||
@@ -192,8 +194,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
|
||||
if (result.returnValue == MATCH) {
|
||||
trueHits.incrementAndGet()
|
||||
}
|
||||
else if (result.returnValue == NO_MATCH) {
|
||||
} else if (result.returnValue == NO_MATCH) {
|
||||
falseHits.incrementAndGet()
|
||||
}
|
||||
return result.returnValue
|
||||
@@ -202,24 +203,23 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
|
||||
private fun analyzeSingleImport(result: Result, importedFqName: FqName?, isAllUnder: Boolean, aliasName: String?): Result {
|
||||
if (!isAllUnder) {
|
||||
if (importedFqName?.asString() == targetClassFqName &&
|
||||
(aliasName == null || aliasName == targetShortName)) {
|
||||
(aliasName == null || aliasName == targetShortName)
|
||||
) {
|
||||
return result.changeTo(Result.Found)
|
||||
}
|
||||
else if (importedFqName?.shortName()?.asString() == targetShortName &&
|
||||
importedFqName.parent().asString() in conflictingPackages &&
|
||||
aliasName == null) {
|
||||
} else if (importedFqName?.shortName()?.asString() == targetShortName &&
|
||||
importedFqName.parent().asString() in conflictingPackages &&
|
||||
aliasName == null
|
||||
) {
|
||||
return result.changeTo(Result.FoundOther)
|
||||
}
|
||||
else if (importedFqName?.shortName()?.asString() == targetShortName &&
|
||||
importedFqName.parent().asString() in packagesWithTypeAliases &&
|
||||
aliasName == null) {
|
||||
} else if (importedFqName?.shortName()?.asString() == targetShortName &&
|
||||
importedFqName.parent().asString() in packagesWithTypeAliases &&
|
||||
aliasName == null
|
||||
) {
|
||||
return Result.Ambiguity
|
||||
}
|
||||
else if (aliasName == targetShortName) {
|
||||
} else if (aliasName == targetShortName) {
|
||||
return result.changeTo(Result.FoundOther)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
when {
|
||||
importedFqName?.asString() == targetPackage -> return result.changeTo(Result.Found)
|
||||
importedFqName?.asString() in conflictingPackages -> return result.changeTo(Result.FoundOther)
|
||||
|
||||
+9
-9
@@ -29,17 +29,17 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
|
||||
val psiClass: PsiClass = when (originalElement) {
|
||||
is KtClassOrObject -> runReadAction { originalElement.toLightClassWithBuiltinMapping() ?: KtFakeLightClass(originalElement) }
|
||||
is PsiClass -> originalElement
|
||||
else -> null
|
||||
} ?: return EmptyQuery.getEmptyQuery()
|
||||
is KtClassOrObject -> runReadAction { originalElement.toLightClassWithBuiltinMapping() ?: KtFakeLightClass(originalElement) }
|
||||
is PsiClass -> originalElement
|
||||
else -> null
|
||||
} ?: return EmptyQuery.getEmptyQuery()
|
||||
|
||||
return ClassInheritorsSearch.search(
|
||||
psiClass,
|
||||
searchScope,
|
||||
searchDeeply,
|
||||
/* checkInheritance = */ true,
|
||||
/* includeAnonymous = */ true
|
||||
psiClass,
|
||||
searchScope,
|
||||
searchDeeply,
|
||||
/* checkInheritance = */ true,
|
||||
/* includeAnonymous = */ true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+17
-18
@@ -39,18 +39,18 @@ interface SearchRequestWithElement<T : PsiElement> : DeclarationSearchRequest<T>
|
||||
override val project: Project get() = originalElement.project
|
||||
}
|
||||
|
||||
abstract class DeclarationsSearch<T: PsiElement, R: DeclarationSearchRequest<T>>: QueryFactory<T, R>() {
|
||||
abstract class DeclarationsSearch<T : PsiElement, R : DeclarationSearchRequest<T>> : QueryFactory<T, R>() {
|
||||
init {
|
||||
registerExecutor(
|
||||
object : QueryExecutorBase<T, R>(true) {
|
||||
override fun processQuery(queryParameters: R, consumer: ExecutorProcessor<T>) {
|
||||
doSearch(queryParameters, consumer)
|
||||
}
|
||||
object : QueryExecutorBase<T, R>(true) {
|
||||
override fun processQuery(queryParameters: R, consumer: ExecutorProcessor<T>) {
|
||||
doSearch(queryParameters, consumer)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override final fun registerExecutor(executor: QueryExecutor<T, R>) {
|
||||
final override fun registerExecutor(executor: QueryExecutor<T, R>) {
|
||||
super.registerExecutor(executor)
|
||||
}
|
||||
|
||||
@@ -60,13 +60,13 @@ abstract class DeclarationsSearch<T: PsiElement, R: DeclarationSearchRequest<T>>
|
||||
fun search(request: R): Query<T> = if (isApplicable(request)) createUniqueResultsQuery(request) else EmptyQuery.getEmptyQuery<T>()
|
||||
}
|
||||
|
||||
class HierarchySearchRequest<T: PsiElement> (
|
||||
override val originalElement: T,
|
||||
override val searchScope: SearchScope,
|
||||
val searchDeeply: Boolean = true
|
||||
class HierarchySearchRequest<T : PsiElement>(
|
||||
override val originalElement: T,
|
||||
override val searchScope: SearchScope,
|
||||
val searchDeeply: Boolean = true
|
||||
) : SearchRequestWithElement<T> {
|
||||
fun <U: PsiElement> copy(newOriginalElement: U): HierarchySearchRequest<U> =
|
||||
HierarchySearchRequest(newOriginalElement, searchScope, searchDeeply)
|
||||
fun <U : PsiElement> copy(newOriginalElement: U): HierarchySearchRequest<U> =
|
||||
HierarchySearchRequest(newOriginalElement, searchScope, searchDeeply)
|
||||
}
|
||||
|
||||
interface HierarchyTraverser<T> {
|
||||
@@ -97,7 +97,7 @@ interface HierarchyTraverser<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T: PsiElement> ExecutorProcessor<T>.consumeHierarchy(request: SearchRequestWithElement<T>, traverser: HierarchyTraverser<T>) {
|
||||
fun <T : PsiElement> ExecutorProcessor<T>.consumeHierarchy(request: SearchRequestWithElement<T>, traverser: HierarchyTraverser<T>) {
|
||||
traverser.forEach(request.originalElement) { element ->
|
||||
if (element in request.searchScope) {
|
||||
process(element)
|
||||
@@ -105,9 +105,9 @@ fun <T: PsiElement> ExecutorProcessor<T>.consumeHierarchy(request: SearchRequest
|
||||
}
|
||||
}
|
||||
|
||||
abstract class HierarchySearch<T: PsiElement>(
|
||||
protected val traverser: HierarchyTraverser<T>
|
||||
): DeclarationsSearch<T, HierarchySearchRequest<T>>() {
|
||||
abstract class HierarchySearch<T : PsiElement>(
|
||||
private val traverser: HierarchyTraverser<T>
|
||||
) : DeclarationsSearch<T, HierarchySearchRequest<T>>() {
|
||||
protected open fun doSearchAll(request: HierarchySearchRequest<T>, consumer: ExecutorProcessor<T>) {
|
||||
consumer.consumeHierarchy(request, traverser)
|
||||
}
|
||||
@@ -117,8 +117,7 @@ abstract class HierarchySearch<T: PsiElement>(
|
||||
override fun doSearch(request: HierarchySearchRequest<T>, consumer: ExecutorProcessor<T>) {
|
||||
if (request.searchDeeply) {
|
||||
doSearchAll(request, consumer)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
doSearchDirect(request, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
+38
-36
@@ -52,34 +52,33 @@ fun HierarchySearchRequest<*>.searchOverriders(): Query<PsiMethod> {
|
||||
if (psiMethods.isEmpty()) return EmptyQuery.getEmptyQuery()
|
||||
|
||||
return psiMethods
|
||||
.map { psiMethod -> KotlinPsiMethodOverridersSearch.search(copy(psiMethod)) }
|
||||
.reduce { query1, query2 -> MergeQuery(query1, query2)}
|
||||
.map { psiMethod -> KotlinPsiMethodOverridersSearch.search(copy(psiMethod)) }
|
||||
.reduce { query1, query2 -> MergeQuery(query1, query2) }
|
||||
}
|
||||
|
||||
object KotlinPsiMethodOverridersSearch : HierarchySearch<PsiMethod>(PsiMethodOverridingHierarchyTraverser) {
|
||||
fun searchDirectOverriders(psiMethod: PsiMethod): Iterable<PsiMethod> {
|
||||
fun PsiMethod.isAcceptable(inheritor: PsiClass, baseMethod: PsiMethod, baseClass: PsiClass): Boolean =
|
||||
when {
|
||||
hasModifierProperty(PsiModifier.STATIC) -> false
|
||||
baseMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ->
|
||||
JavaPsiFacade.getInstance(project).arePackagesTheSame(baseClass, inheritor)
|
||||
else -> true
|
||||
}
|
||||
when {
|
||||
hasModifierProperty(PsiModifier.STATIC) -> false
|
||||
baseMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ->
|
||||
JavaPsiFacade.getInstance(project).arePackagesTheSame(baseClass, inheritor)
|
||||
else -> true
|
||||
}
|
||||
|
||||
val psiClass = psiMethod.containingClass
|
||||
if (psiClass == null) return Collections.emptyList()
|
||||
val psiClass = psiMethod.containingClass ?: return Collections.emptyList()
|
||||
|
||||
val classToMethod = LinkedHashMap<PsiClass, PsiMethod>()
|
||||
val classTraverser = object : HierarchyTraverser<PsiClass> {
|
||||
override fun nextElements(current: PsiClass): Iterable<PsiClass> =
|
||||
DirectClassInheritorsSearch.search(
|
||||
current,
|
||||
current.project.allScope(),
|
||||
/* includeAnonymous = */ true
|
||||
)
|
||||
DirectClassInheritorsSearch.search(
|
||||
current,
|
||||
current.project.allScope(),
|
||||
/* includeAnonymous = */ true
|
||||
)
|
||||
|
||||
override fun shouldDescend(element: PsiClass): Boolean =
|
||||
element.isInheritable() && !classToMethod.containsKey(element)
|
||||
element.isInheritable() && !classToMethod.containsKey(element)
|
||||
}
|
||||
|
||||
classTraverser.forEach(psiClass) { inheritor ->
|
||||
@@ -87,7 +86,7 @@ object KotlinPsiMethodOverridersSearch : HierarchySearch<PsiMethod>(PsiMethodOve
|
||||
val signature = psiMethod.getSignature(substitutor)
|
||||
val candidate = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false)
|
||||
if (candidate != null && candidate.isAcceptable(inheritor, psiMethod, psiClass)) {
|
||||
classToMethod.put(inheritor, candidate)
|
||||
classToMethod[inheritor] = candidate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,14 +94,14 @@ object KotlinPsiMethodOverridersSearch : HierarchySearch<PsiMethod>(PsiMethodOve
|
||||
}
|
||||
|
||||
override fun isApplicable(request: HierarchySearchRequest<PsiMethod>): Boolean =
|
||||
runReadAction { request.originalElement.isOverridableElement() }
|
||||
runReadAction { request.originalElement.isOverridableElement() }
|
||||
|
||||
override fun doSearchDirect(request: HierarchySearchRequest<PsiMethod>, consumer: ExecutorProcessor<PsiMethod>) {
|
||||
searchDirectOverriders(request.originalElement).forEach { method -> consumer.process(method) }
|
||||
}
|
||||
}
|
||||
|
||||
object PsiMethodOverridingHierarchyTraverser: HierarchyTraverser<PsiMethod> {
|
||||
object PsiMethodOverridingHierarchyTraverser : HierarchyTraverser<PsiMethod> {
|
||||
override fun nextElements(current: PsiMethod): Iterable<PsiMethod> = KotlinPsiMethodOverridersSearch.searchDirectOverriders(current)
|
||||
override fun shouldDescend(element: PsiMethod): Boolean = PsiUtil.canBeOverridden(element)
|
||||
}
|
||||
@@ -119,23 +118,26 @@ fun PsiElement.toPossiblyFakeLightMethods(): List<PsiMethod> {
|
||||
}
|
||||
|
||||
private fun forEachKotlinOverride(
|
||||
ktClass: KtClass,
|
||||
members: List<KtNamedDeclaration>,
|
||||
scope: SearchScope,
|
||||
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
|
||||
ktClass: KtClass,
|
||||
members: List<KtNamedDeclaration>,
|
||||
scope: SearchScope,
|
||||
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
|
||||
): Boolean {
|
||||
val baseClassDescriptor = runReadAction { ktClass.unsafeResolveToDescriptor() as ClassDescriptor }
|
||||
val baseDescriptors = runReadAction { members.mapNotNull { it.unsafeResolveToDescriptor() as? CallableMemberDescriptor }.filter { it.isOverridable } }
|
||||
val baseDescriptors =
|
||||
runReadAction { members.mapNotNull { it.unsafeResolveToDescriptor() as? CallableMemberDescriptor }.filter { it.isOverridable } }
|
||||
if (baseDescriptors.isEmpty()) return true
|
||||
|
||||
HierarchySearchRequest(ktClass, scope, true).searchInheritors().forEach(Processor {
|
||||
val inheritor = it.unwrapped as? KtClassOrObject ?: return@Processor true
|
||||
HierarchySearchRequest(ktClass, scope, true).searchInheritors().forEach(Processor { psiClass ->
|
||||
val inheritor = psiClass.unwrapped as? KtClassOrObject ?: return@Processor true
|
||||
runReadAction {
|
||||
val inheritorDescriptor = inheritor.unsafeResolveToDescriptor() as ClassDescriptor
|
||||
val substitutor = getTypeSubstitutor(baseClassDescriptor.defaultType, inheritorDescriptor.defaultType) ?: return@runReadAction true
|
||||
val substitutor =
|
||||
getTypeSubstitutor(baseClassDescriptor.defaultType, inheritorDescriptor.defaultType) ?: return@runReadAction true
|
||||
baseDescriptors.forEach {
|
||||
val superMember = it.source.getPsi()!!
|
||||
val overridingDescriptor = inheritorDescriptor.findCallableMemberBySignature(it.substitute(substitutor) as CallableMemberDescriptor)
|
||||
val overridingDescriptor =
|
||||
inheritorDescriptor.findCallableMemberBySignature(it.substitute(substitutor) as CallableMemberDescriptor)
|
||||
val overridingMember = overridingDescriptor?.source?.getPsi()
|
||||
if (overridingMember != null) {
|
||||
if (!processor(superMember, overridingMember)) return@runReadAction false
|
||||
@@ -149,8 +151,8 @@ private fun forEachKotlinOverride(
|
||||
}
|
||||
|
||||
fun KtNamedDeclaration.forEachOverridingElement(
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiElement, PsiElement) -> Boolean
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiElement, PsiElement) -> Boolean
|
||||
): Boolean {
|
||||
val ktClass = runReadAction { containingClassOrObject as? KtClass } ?: return true
|
||||
|
||||
@@ -162,8 +164,8 @@ fun KtNamedDeclaration.forEachOverridingElement(
|
||||
}
|
||||
|
||||
fun PsiMethod.forEachOverridingMethod(
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiMethod) -> Boolean
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiMethod) -> Boolean
|
||||
): Boolean {
|
||||
if (this !is KtFakeLightMethod) {
|
||||
if (!OverridingMethodsSearch.search(this, scope.excludeKotlinSources(), true).forEach(processor)) return false
|
||||
@@ -178,11 +180,11 @@ fun PsiMethod.forEachOverridingMethod(
|
||||
}
|
||||
|
||||
fun PsiMethod.forEachImplementation(
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiElement) -> Boolean
|
||||
scope: SearchScope = runReadAction { useScope },
|
||||
processor: (PsiElement) -> Boolean
|
||||
): Boolean {
|
||||
return forEachOverridingMethod(scope, processor)
|
||||
&& FunctionalExpressionSearch.search(this, scope.excludeKotlinSources()).forEach(processor)
|
||||
&& FunctionalExpressionSearch.search(this, scope.excludeKotlinSources()).forEach(processor)
|
||||
}
|
||||
|
||||
fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean) {
|
||||
@@ -194,7 +196,7 @@ fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement,
|
||||
|
||||
val ktClass = unwrapped as? KtClass ?: return
|
||||
val members = ktClass.declarations.filterIsInstance<KtNamedDeclaration>() +
|
||||
ktClass.primaryConstructorParameters.filter { it.hasValOrVar() }
|
||||
ktClass.primaryConstructorParameters.filter { it.hasValOrVar() }
|
||||
forEachKotlinOverride(ktClass, members, scope, processor)
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -31,10 +31,10 @@ import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
class KotlinRequestResultProcessor(
|
||||
private val unwrappedElement: PsiElement,
|
||||
private val originalElement: PsiElement = unwrappedElement,
|
||||
private val filter: (PsiReference) -> Boolean = { true },
|
||||
private val options: KotlinReferencesSearchOptions = KotlinReferencesSearchOptions.Empty
|
||||
private val unwrappedElement: PsiElement,
|
||||
private val originalElement: PsiElement = unwrappedElement,
|
||||
private val filter: (PsiReference) -> Boolean = { true },
|
||||
private val options: KotlinReferencesSearchOptions = KotlinReferencesSearchOptions.Empty
|
||||
) : RequestResultProcessor(unwrappedElement, originalElement, filter, options) {
|
||||
private val referenceService = PsiReferenceService.getService()
|
||||
|
||||
@@ -48,8 +48,7 @@ class KotlinRequestResultProcessor(
|
||||
|
||||
if (filter(ref) && ref.containsOffsetInElement(offsetInElement) && ref.isReferenceToTarget(unwrappedElement)) {
|
||||
consumer.process(ref)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ fun PsiFile.fileScope(): GlobalSearchScope = GlobalSearchScope.fileScope(this)
|
||||
|
||||
fun GlobalSearchScope.restrictByFileType(fileType: FileType) = GlobalSearchScope.getScopeRestrictedByFileTypes(this, fileType)
|
||||
|
||||
fun SearchScope.restrictByFileType(fileType: FileType) = when (this) {
|
||||
fun SearchScope.restrictByFileType(fileType: FileType): SearchScope = when (this) {
|
||||
is GlobalSearchScope -> restrictByFileType(fileType)
|
||||
is LocalSearchScope -> {
|
||||
val elements = scope.filter { it.containingFile.fileType == fileType }
|
||||
@@ -79,8 +79,7 @@ fun SearchScope.excludeFileTypes(vararg fileTypes: FileType): SearchScope {
|
||||
return if (this is GlobalSearchScope) {
|
||||
val includedFileTypes = FileTypeRegistry.getInstance().registeredFileTypes.filter { it !in fileTypes }.toTypedArray()
|
||||
GlobalSearchScope.getScopeRestrictedByFileTypes(this, *includedFileTypes)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this as LocalSearchScope
|
||||
val filteredElements = scope.filter { it.containingFile.fileType !in fileTypes }
|
||||
if (filteredElements.isNotEmpty())
|
||||
@@ -94,7 +93,8 @@ fun SearchScope.excludeFileTypes(vararg fileTypes: FileType): SearchScope {
|
||||
fun ReferencesSearch.SearchParameters.effectiveSearchScope(element: PsiElement): SearchScope {
|
||||
if (element == elementToSearch) return effectiveSearchScope
|
||||
if (isIgnoreAccessScope) return scopeDeterminedByUser
|
||||
val accessScope = PsiSearchHelper.SERVICE.getInstance(element.project).getUseScope(element)
|
||||
// BUNCH: 181
|
||||
@Suppress("DEPRECATION") val accessScope = PsiSearchHelper.SERVICE.getInstance(element.project).getUseScope(element)
|
||||
return scopeDeterminedByUser.intersectWith(accessScope)
|
||||
}
|
||||
|
||||
|
||||
+59
-46
@@ -64,12 +64,12 @@ import java.util.*
|
||||
//TODO: check if smart search is too expensive
|
||||
|
||||
class ExpressionsOfTypeProcessor(
|
||||
private val typeToSearch: FuzzyType,
|
||||
private val classToSearch: PsiClass?,
|
||||
private val searchScope: SearchScope,
|
||||
private val project: Project,
|
||||
private val possibleMatchHandler: (KtExpression) -> Unit,
|
||||
private val possibleMatchesInScopeHandler: (SearchScope) -> Unit
|
||||
private val typeToSearch: FuzzyType,
|
||||
private val classToSearch: PsiClass?,
|
||||
private val searchScope: SearchScope,
|
||||
private val project: Project,
|
||||
private val possibleMatchHandler: (KtExpression) -> Unit,
|
||||
private val possibleMatchesInScopeHandler: (SearchScope) -> Unit
|
||||
) {
|
||||
@TestOnly
|
||||
enum class Mode {
|
||||
@@ -94,7 +94,7 @@ class ExpressionsOfTypeProcessor(
|
||||
return runReadAction {
|
||||
if (element !is KtDeclaration && element !is PsiMember) return@runReadAction element.text
|
||||
val fqName = element.getKotlinFqName()?.asString()
|
||||
?: (element as? KtNamedDeclaration)?.name
|
||||
?: (element as? KtNamedDeclaration)?.name
|
||||
when (element) {
|
||||
is PsiMethod -> fqName + element.parameterList.text
|
||||
is KtFunction -> fqName + element.valueParameterList!!.text
|
||||
@@ -135,7 +135,12 @@ class ExpressionsOfTypeProcessor(
|
||||
}
|
||||
|
||||
// optimization
|
||||
if (runReadAction { searchScope is GlobalSearchScope && !FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, searchScope) }) return
|
||||
if (runReadAction {
|
||||
searchScope is GlobalSearchScope && !FileTypeIndex.containsFileOfType(
|
||||
KotlinFileType.INSTANCE,
|
||||
searchScope
|
||||
)
|
||||
}) return
|
||||
|
||||
// for class from library always use plain search because we cannot search usages in compiled code (we could though)
|
||||
if (!runReadAction { classToSearch.isValid && ProjectRootsUtil.isInProjectSource(classToSearch) }) {
|
||||
@@ -149,9 +154,9 @@ class ExpressionsOfTypeProcessor(
|
||||
|
||||
runReadAction {
|
||||
val scopeElements = scopesToUsePlainSearch.values
|
||||
.flatten()
|
||||
.filter { it.isValid }
|
||||
.toTypedArray()
|
||||
.flatten()
|
||||
.filter { it.isValid }
|
||||
.toTypedArray()
|
||||
if (scopeElements.isNotEmpty()) {
|
||||
possibleMatchesInScopeHandler(LocalSearchScope(scopeElements))
|
||||
}
|
||||
@@ -173,7 +178,7 @@ class ExpressionsOfTypeProcessor(
|
||||
|
||||
private fun downShiftToPlainSearch(reference: PsiReference) {
|
||||
val message = getFallbackDiagnosticsMessage(reference)
|
||||
LOG.info("ExpressionsOfTypeProcessor: " + message)
|
||||
LOG.info("ExpressionsOfTypeProcessor: $message")
|
||||
testLog { "Downgrade to plain text search: $message" }
|
||||
|
||||
tasks.clear()
|
||||
@@ -207,7 +212,8 @@ class ExpressionsOfTypeProcessor(
|
||||
data class ProcessClassUsagesTask(val classToSearch: PsiClass) : Task {
|
||||
override fun perform() {
|
||||
testLog { "Searched references to ${logPresentation(classToSearch)}" }
|
||||
val scope = GlobalSearchScope.allScope(project).excludeFileTypes(XmlFileType.INSTANCE) // ignore usages in XML - they don't affect us
|
||||
val scope = GlobalSearchScope.allScope(project)
|
||||
.excludeFileTypes(XmlFileType.INSTANCE) // ignore usages in XML - they don't affect us
|
||||
searchReferences(classToSearch, scope) { reference ->
|
||||
val element = reference.element
|
||||
val wasProcessed = when (element.language) {
|
||||
@@ -262,7 +268,8 @@ class ExpressionsOfTypeProcessor(
|
||||
})
|
||||
}
|
||||
|
||||
private class StaticMemberRequestResultProcessor(val psiMember: PsiMember, classes: List<PsiClass>) : RequestResultProcessor(psiMember) {
|
||||
private class StaticMemberRequestResultProcessor(val psiMember: PsiMember, classes: List<PsiClass>) :
|
||||
RequestResultProcessor(psiMember) {
|
||||
val possibleClassesNames: Set<String> = runReadAction { classes.map { it.qualifiedName }.filterNotNullTo(HashSet()) }
|
||||
|
||||
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: ExecutorProcessor<PsiReference>): Boolean {
|
||||
@@ -290,9 +297,9 @@ class ExpressionsOfTypeProcessor(
|
||||
val fqName = element.importedFqName?.asString()
|
||||
if (fqName != null && fqName in possibleClassesNames) {
|
||||
val ref = element.importedReference
|
||||
?.getQualifiedElementSelector()
|
||||
?.references
|
||||
?.firstOrNull()
|
||||
?.getQualifiedElementSelector()
|
||||
?.references
|
||||
?.firstOrNull()
|
||||
if (ref != null) {
|
||||
consumer.process(ref)
|
||||
}
|
||||
@@ -319,13 +326,18 @@ class ExpressionsOfTypeProcessor(
|
||||
val declarationName = runReadAction { psiMember.name } ?: return
|
||||
if (declarationName.isEmpty()) return
|
||||
|
||||
data class ProcessStaticCallableUsagesTask(val member: PsiMember, val memberScope: SearchScope, val taskProcessor: ReferenceProcessor) : Task {
|
||||
data class ProcessStaticCallableUsagesTask(
|
||||
val member: PsiMember,
|
||||
val memberScope: SearchScope,
|
||||
val taskProcessor: ReferenceProcessor
|
||||
) : Task {
|
||||
override fun perform() {
|
||||
// This class will look through the whole hierarchy anyway, so shouldn't be a big overhead here
|
||||
val inheritanceClasses = ClassInheritorsSearch.search(
|
||||
declarationClass,
|
||||
classUseScope(declarationClass),
|
||||
true, true, false).findAll()
|
||||
declarationClass,
|
||||
classUseScope(declarationClass),
|
||||
true, true, false
|
||||
).findAll()
|
||||
|
||||
val classes = (inheritanceClasses + declarationClass).filter {
|
||||
it !is KtLightClass
|
||||
@@ -340,20 +352,24 @@ class ExpressionsOfTypeProcessor(
|
||||
|
||||
testLog { "Searched references to static $memberName in non-Java files by request $request" }
|
||||
searchRequestCollector.searchWord(
|
||||
request,
|
||||
classUseScope(klass).intersectWith(memberScope), UsageSearchContext.IN_CODE, true, member, resultProcessor)
|
||||
request,
|
||||
classUseScope(klass).intersectWith(memberScope), UsageSearchContext.IN_CODE, true, member, resultProcessor
|
||||
)
|
||||
|
||||
val qualifiedName = runReadAction { klass.qualifiedName }
|
||||
if (qualifiedName != null) {
|
||||
val importAllUnderRequest = qualifiedName + ".*"
|
||||
val importAllUnderRequest = "$qualifiedName.*"
|
||||
|
||||
testLog { "Searched references to static $memberName in non-Java files by request $importAllUnderRequest" }
|
||||
searchRequestCollector.searchWord(
|
||||
importAllUnderRequest,
|
||||
classUseScope(klass).intersectWith(memberScope), UsageSearchContext.IN_CODE, true, member, resultProcessor)
|
||||
importAllUnderRequest,
|
||||
classUseScope(klass).intersectWith(memberScope), UsageSearchContext.IN_CODE, true, member, resultProcessor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// BUNCH: 181
|
||||
@Suppress("DEPRECATION")
|
||||
PsiSearchHelper.SERVICE.getInstance(project).processRequests(searchRequestCollector) { reference ->
|
||||
if (reference.element.parents.any { it is KtImportDirective }) {
|
||||
// Found declaration in import - process all file with an ordinal reference search
|
||||
@@ -361,8 +377,7 @@ class ExpressionsOfTypeProcessor(
|
||||
addCallableDeclarationToProcess(member, LocalSearchScope(containingFile), taskProcessor)
|
||||
|
||||
true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val processed = taskProcessor.handler(this@ExpressionsOfTypeProcessor, reference)
|
||||
if (!processed) { // we don't know how to handle this reference and down-shift to plain search
|
||||
downShiftToPlainSearch(reference)
|
||||
@@ -379,26 +394,29 @@ class ExpressionsOfTypeProcessor(
|
||||
}
|
||||
|
||||
private fun addCallableDeclarationToProcess(declaration: PsiElement, scope: SearchScope, processor: ReferenceProcessor) {
|
||||
if (scope !is LocalSearchScope && declaration is PsiMember && (declaration.modifierList?.hasModifierProperty(PsiModifier.STATIC) ?: false)) {
|
||||
if (scope !is LocalSearchScope && declaration is PsiMember &&
|
||||
(declaration.modifierList?.hasModifierProperty(PsiModifier.STATIC) == true)
|
||||
) {
|
||||
addStaticMemberToProcess(declaration, scope, processor)
|
||||
return
|
||||
}
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
data class ProcessCallableUsagesTask(
|
||||
val declaration: PsiElement,
|
||||
val processor: ReferenceProcessor,
|
||||
val scope: SearchScope) : Task {
|
||||
val declaration: PsiElement,
|
||||
val processor: ReferenceProcessor,
|
||||
val scope: SearchScope
|
||||
) : Task {
|
||||
override fun perform() {
|
||||
if (scope is LocalSearchScope) {
|
||||
testLog { "Searched imported static member $declaration in ${scope.scope.toList()}" }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
testLog { "Searched references to ${logPresentation(declaration)} in non-Java files" }
|
||||
}
|
||||
|
||||
val searchParameters = KotlinReferencesSearchParameters(
|
||||
declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false))
|
||||
declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false)
|
||||
)
|
||||
searchReferences(searchParameters) { reference ->
|
||||
val processed = processor.handler(this@ExpressionsOfTypeProcessor, reference)
|
||||
if (!processed) { // we don't know how to handle this reference and down-shift to plain search
|
||||
@@ -438,8 +456,7 @@ class ExpressionsOfTypeProcessor(
|
||||
if (reference is KtDestructuringDeclarationReference) {
|
||||
// declaration usage in form of destructuring declaration entry
|
||||
addCallableDeclarationOfOurType(reference.element)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
(reference.element as? KtReferenceExpression)?.let { processSuspiciousExpression(it) }
|
||||
}
|
||||
true
|
||||
@@ -613,8 +630,7 @@ class ExpressionsOfTypeProcessor(
|
||||
val whenExpression = whenEntry.parent as KtWhenExpression
|
||||
val entriesAfter = whenExpression.entries.dropWhile { it != whenEntry }.drop(1)
|
||||
entriesAfter.forEach { usePlainSearch(it) }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
usePlainSearch(whenEntry)
|
||||
}
|
||||
return true
|
||||
@@ -662,7 +678,7 @@ class ExpressionsOfTypeProcessor(
|
||||
break@ParentsLoop
|
||||
}
|
||||
|
||||
//TODO: if Java parameter has Kotlin functional type then we should process method usages
|
||||
//TODO: if Java parameter has Kotlin functional type then we should process method usages
|
||||
is PsiParameter -> {
|
||||
if (prev == parent.typeElement) { // usage in parameter type - check if the method is in SAM interface
|
||||
processParameterInSamClass(parent)
|
||||
@@ -831,8 +847,7 @@ class ExpressionsOfTypeProcessor(
|
||||
private fun processSuspiciousDeclaration(declaration: KtDeclaration) {
|
||||
if (declaration is KtDestructuringDeclaration) {
|
||||
declaration.entries.forEach { processSuspiciousDeclaration(it) }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!isImplicitlyTyped(declaration)) return
|
||||
|
||||
testLog { "Checked type of ${logPresentation(declaration)}" }
|
||||
@@ -873,8 +888,7 @@ class ExpressionsOfTypeProcessor(
|
||||
}
|
||||
prevElements.add(element)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(restricted == GlobalSearchScope.EMPTY_SCOPE)
|
||||
}
|
||||
|
||||
@@ -931,8 +945,7 @@ class ExpressionsOfTypeProcessor(
|
||||
runReadAction {
|
||||
if (ref.element.isValid) {
|
||||
processor(ref)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
+13
-7
@@ -30,13 +30,19 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class BinaryOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
private val operationTokens: List<KtSingleValueToken>,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtBinaryExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = operationTokens.map { it.value }) {
|
||||
targetFunction: PsiElement,
|
||||
private val operationTokens: List<KtSingleValueToken>,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtBinaryExpression>(
|
||||
targetFunction,
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options,
|
||||
wordsToSearch = operationTokens.map { it.value }) {
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
val binaryExpression = expression.parent as? KtBinaryExpression ?: return
|
||||
|
||||
+16
-8
@@ -28,14 +28,22 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class ContainsOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtOperationReferenceExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = listOf("in")) {
|
||||
|
||||
private val OPERATION_TOKENS = setOf(KtTokens.IN_KEYWORD, KtTokens.NOT_IN)
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtOperationReferenceExpression>(
|
||||
targetFunction,
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options,
|
||||
wordsToSearch = listOf("in")
|
||||
) {
|
||||
private companion object {
|
||||
private val OPERATION_TOKENS = setOf(KtTokens.IN_KEYWORD, KtTokens.NOT_IN)
|
||||
}
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
val parent = expression.parent
|
||||
|
||||
+16
-11
@@ -30,19 +30,25 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class DestructuringDeclarationReferenceSearcher(
|
||||
targetDeclaration: PsiElement,
|
||||
private val componentIndex: Int,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, options, wordsToSearch = listOf("(")) {
|
||||
targetDeclaration: PsiElement,
|
||||
private val componentIndex: Int,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtDestructuringDeclaration>(
|
||||
targetDeclaration,
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options,
|
||||
wordsToSearch = listOf("(")
|
||||
) {
|
||||
|
||||
override fun resolveTargetToDescriptor(): FunctionDescriptor? {
|
||||
return if (targetDeclaration is KtParameter) {
|
||||
targetDeclaration.dataClassComponentFunction()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
super.resolveTargetToDescriptor()
|
||||
}
|
||||
}
|
||||
@@ -64,8 +70,7 @@ class DestructuringDeclarationReferenceSearcher(
|
||||
is KtContainerNode -> {
|
||||
if (parent.node.elementType == KtNodeTypes.LOOP_RANGE) {
|
||||
(parent.parent as KtForExpression).destructuringDeclaration
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
+16
-8
@@ -30,13 +30,20 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class IndexingOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions,
|
||||
private val isSet: Boolean
|
||||
) : OperatorReferenceSearcher<KtArrayAccessExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = listOf("[")) {
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions,
|
||||
private val isSet: Boolean
|
||||
) : OperatorReferenceSearcher<KtArrayAccessExpression>(
|
||||
targetFunction,
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options,
|
||||
wordsToSearch = listOf("[")
|
||||
) {
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
val accessExpression = expression.parent as? KtArrayAccessExpression ?: return
|
||||
@@ -45,7 +52,8 @@ class IndexingOperatorReferenceSearcher(
|
||||
processReferenceElement(accessExpression)
|
||||
}
|
||||
|
||||
override fun isReferenceToCheck(ref: PsiReference) = ref is KtArrayAccessReference && checkAccessExpression(ref.element as KtArrayAccessExpression)
|
||||
override fun isReferenceToCheck(ref: PsiReference) =
|
||||
ref is KtArrayAccessReference && checkAccessExpression(ref.element)
|
||||
|
||||
override fun extractReference(element: KtElement): PsiReference? {
|
||||
val accessExpression = element as? KtArrayAccessExpression ?: return null
|
||||
|
||||
+21
-12
@@ -34,11 +34,11 @@ import org.jetbrains.uast.UastContext
|
||||
import org.jetbrains.uast.convertOpt
|
||||
|
||||
class InvokeOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtCallExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = emptyList()) {
|
||||
private val callArgumentsSize: Int?
|
||||
|
||||
@@ -49,15 +49,24 @@ class InvokeOperatorReferenceSearcher(
|
||||
val uMethod = uastContext.convertOpt<UMethod>(targetDeclaration, null)
|
||||
val uastParameters = uMethod?.uastParameters
|
||||
|
||||
val isStableNumberOfArguments = uastParameters != null && uastParameters.none { it.uastInitializer != null || it.isVarArgs }
|
||||
if (isStableNumberOfArguments) {
|
||||
val numberOfArguments = uastParameters!!.size
|
||||
when {
|
||||
targetFunction.isExtensionDeclaration() -> numberOfArguments - 1
|
||||
else -> numberOfArguments
|
||||
if (uastParameters != null) {
|
||||
val isStableNumberOfArguments = uastParameters.none { uParameter ->
|
||||
@Suppress("UElementAsPsi")
|
||||
uParameter.uastInitializer != null || uParameter.isVarArgs
|
||||
}
|
||||
|
||||
if (isStableNumberOfArguments) {
|
||||
val numberOfArguments = uastParameters.size
|
||||
when {
|
||||
targetFunction.isExtensionDeclaration() -> numberOfArguments - 1
|
||||
else -> numberOfArguments
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
else -> null
|
||||
|
||||
+5
-5
@@ -30,11 +30,11 @@ import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class IteratorOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtForExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = listOf("in")) {
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
|
||||
+90
-71
@@ -54,12 +54,12 @@ import org.jetbrains.kotlin.util.isValidOperator
|
||||
import java.util.*
|
||||
|
||||
abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
protected val targetDeclaration: PsiElement,
|
||||
private val searchScope: SearchScope,
|
||||
private val consumer: ExecutorProcessor<PsiReference>,
|
||||
private val optimizer: SearchRequestCollector,
|
||||
private val options: KotlinReferencesSearchOptions,
|
||||
private val wordsToSearch: List<String>
|
||||
protected val targetDeclaration: PsiElement,
|
||||
private val searchScope: SearchScope,
|
||||
private val consumer: ExecutorProcessor<PsiReference>,
|
||||
private val optimizer: SearchRequestCollector,
|
||||
private val options: KotlinReferencesSearchOptions,
|
||||
private val wordsToSearch: List<String>
|
||||
) {
|
||||
private val project = targetDeclaration.project
|
||||
|
||||
@@ -83,19 +83,18 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
testLog { "Resolved ${logPresentation(element)}" }
|
||||
return if (reference.isReferenceTo(targetDeclaration)) {
|
||||
consumer.process(reference)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
declaration: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
declaration: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
): OperatorReferenceSearcher<*>? {
|
||||
return runReadAction {
|
||||
if (declaration.isValid)
|
||||
@@ -106,13 +105,13 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
}
|
||||
|
||||
private fun createInReadAction(
|
||||
declaration: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
declaration: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
): OperatorReferenceSearcher<*>? {
|
||||
val functionName = when (declaration) {
|
||||
val functionName = when (declaration) {
|
||||
is KtNamedFunction -> declaration.name
|
||||
is PsiMethod -> declaration.name
|
||||
else -> null
|
||||
@@ -123,8 +122,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
|
||||
val declarationToUse = if (declaration is KtLightMethod) {
|
||||
declaration.kotlinOrigin ?: return null
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
declaration
|
||||
}
|
||||
|
||||
@@ -132,12 +130,12 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
}
|
||||
|
||||
private fun createInReadAction(
|
||||
declaration: PsiElement,
|
||||
name: Name,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions,
|
||||
searchScope: SearchScope
|
||||
declaration: PsiElement,
|
||||
name: Name,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions,
|
||||
searchScope: SearchScope
|
||||
): OperatorReferenceSearcher<*>? {
|
||||
if (DataClassDescriptorResolver.isComponentLike(name)) {
|
||||
if (!options.searchForComponentConventions) return null
|
||||
@@ -154,7 +152,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
when {
|
||||
binaryOp != null -> {
|
||||
val counterpartAssignmentOp = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp]
|
||||
val operationTokens = listOf(binaryOp, counterpartAssignmentOp).filterNotNull()
|
||||
val operationTokens = listOfNotNull(binaryOp, counterpartAssignmentOp)
|
||||
return BinaryOperatorReferenceSearcher(declaration, operationTokens, searchScope, consumer, optimizer, options)
|
||||
}
|
||||
|
||||
@@ -177,10 +175,24 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
return ContainsOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options)
|
||||
|
||||
name == OperatorNameConventions.EQUALS ->
|
||||
return BinaryOperatorReferenceSearcher(declaration, listOf(KtTokens.EQEQ, KtTokens.EXCLEQ), searchScope, consumer, optimizer, options)
|
||||
return BinaryOperatorReferenceSearcher(
|
||||
declaration,
|
||||
listOf(KtTokens.EQEQ, KtTokens.EXCLEQ),
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options
|
||||
)
|
||||
|
||||
name == OperatorNameConventions.COMPARE_TO ->
|
||||
return BinaryOperatorReferenceSearcher(declaration, listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ), searchScope, consumer, optimizer, options)
|
||||
return BinaryOperatorReferenceSearcher(
|
||||
declaration,
|
||||
listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ),
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options
|
||||
)
|
||||
|
||||
name == OperatorNameConventions.ITERATOR ->
|
||||
return IteratorOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options)
|
||||
@@ -214,11 +226,14 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
val inProgress = SearchesInProgress.get()
|
||||
if (psiClass != null) {
|
||||
if (!inProgress.add(psiClass)) {
|
||||
testLog { "ExpressionOfTypeProcessor is already started for ${runReadAction { psiClass.qualifiedName }}. Exit for operator ${logPresentation(targetDeclaration)}." }
|
||||
testLog {
|
||||
"ExpressionOfTypeProcessor is already started for ${runReadAction { psiClass.qualifiedName }}. Exit for operator ${logPresentation(
|
||||
targetDeclaration
|
||||
)}."
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!inProgress.add(targetDeclaration)) {
|
||||
testLog { "ExpressionOfTypeProcessor is already started for operator ${logPresentation(targetDeclaration)}. Exit." }
|
||||
return //TODO: it's not quite correct
|
||||
@@ -227,16 +242,15 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
|
||||
try {
|
||||
ExpressionsOfTypeProcessor(
|
||||
receiverType,
|
||||
psiClass,
|
||||
searchScope,
|
||||
project,
|
||||
possibleMatchHandler = { expression -> processPossibleReceiverExpression(expression) },
|
||||
possibleMatchesInScopeHandler = { searchScope -> doPlainSearch(searchScope) }
|
||||
receiverType,
|
||||
psiClass,
|
||||
searchScope,
|
||||
project,
|
||||
possibleMatchHandler = { expression -> processPossibleReceiverExpression(expression) },
|
||||
possibleMatchesInScopeHandler = { searchScope -> doPlainSearch(searchScope) }
|
||||
).run()
|
||||
}
|
||||
finally {
|
||||
inProgress.remove(if (psiClass != null) psiClass else targetDeclaration)
|
||||
} finally {
|
||||
inProgress.remove(psiClass ?: targetDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +269,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
|
||||
return if (descriptor.isExtension) {
|
||||
descriptor.fuzzyExtensionReceiverType()!!
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null
|
||||
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
|
||||
}
|
||||
@@ -281,25 +294,32 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
(element.containingFile as KtFile).getResolutionFacade().analyze(elements, BodyResolveMode.PARTIAL)
|
||||
|
||||
refs
|
||||
.filter { it.isReferenceTo(targetDeclaration) }
|
||||
.forEach { consumer.process(it) }
|
||||
.filter { it.isReferenceTo(targetDeclaration) }
|
||||
.forEach { consumer.process(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
scope as GlobalSearchScope
|
||||
if (wordsToSearch.isNotEmpty()) {
|
||||
val unwrappedElement = targetDeclaration.namedUnwrappedElement ?: return
|
||||
val resultProcessor = KotlinRequestResultProcessor(unwrappedElement,
|
||||
filter = { ref -> isReferenceToCheck(ref) },
|
||||
options = options)
|
||||
val resultProcessor = KotlinRequestResultProcessor(
|
||||
unwrappedElement,
|
||||
filter = { ref -> isReferenceToCheck(ref) },
|
||||
options = options
|
||||
)
|
||||
wordsToSearch.forEach {
|
||||
optimizer.searchWord(it, scope.restrictToKotlinSources(), UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor)
|
||||
optimizer.searchWord(
|
||||
it,
|
||||
scope.restrictToKotlinSources(),
|
||||
UsageSearchContext.IN_CODE,
|
||||
true,
|
||||
unwrappedElement,
|
||||
resultProcessor
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
// we must unwrap progress indicator because ProgressWrapper does not do anything on changing text and fraction
|
||||
val progress = ProgressWrapper.unwrap(ProgressIndicatorProvider.getGlobalProgressIndicator())
|
||||
@@ -321,8 +341,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
progress?.popState()
|
||||
}
|
||||
}
|
||||
@@ -335,24 +354,24 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
|
||||
is LocalSearchScope -> {
|
||||
scope
|
||||
.map { element ->
|
||||
" " + runReadAction {
|
||||
when (element) {
|
||||
is KtFunctionLiteral -> element.text
|
||||
is KtWhenEntry -> {
|
||||
if (element.isElse)
|
||||
"KtWhenEntry \"else\""
|
||||
else
|
||||
"KtWhenEntry \"" + element.conditions.joinToString(", ") { it.text } + "\""
|
||||
}
|
||||
is KtNamedDeclaration -> element.node.elementType.toString() + ":" + element.name
|
||||
else -> element.toString()
|
||||
.map { element ->
|
||||
" " + runReadAction {
|
||||
when (element) {
|
||||
is KtFunctionLiteral -> element.text
|
||||
is KtWhenEntry -> {
|
||||
if (element.isElse)
|
||||
"KtWhenEntry \"else\""
|
||||
else
|
||||
"KtWhenEntry \"" + element.conditions.joinToString(", ") { it.text } + "\""
|
||||
}
|
||||
is KtNamedDeclaration -> element.node.elementType.toString() + ":" + element.name
|
||||
else -> element.toString()
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
.sorted()
|
||||
.joinToString("\n", "LocalSearchScope:\n")
|
||||
}
|
||||
.toList()
|
||||
.sorted()
|
||||
.joinToString("\n", "LocalSearchScope:\n")
|
||||
}
|
||||
|
||||
else -> this.displayName
|
||||
|
||||
+5
-5
@@ -29,11 +29,11 @@ import org.jetbrains.kotlin.psi.KtPropertyDelegate
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class PropertyDelegationOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
targetFunction: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtPropertyDelegate>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = listOf("by")) {
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
|
||||
+14
-7
@@ -30,13 +30,20 @@ import org.jetbrains.kotlin.psi.KtUnaryExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class UnaryOperatorReferenceSearcher(
|
||||
targetFunction: PsiElement,
|
||||
private val operationToken: KtSingleValueToken,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtUnaryExpression>(targetFunction, searchScope, consumer, optimizer, options, wordsToSearch = listOf(operationToken.value)) {
|
||||
targetFunction: PsiElement,
|
||||
private val operationToken: KtSingleValueToken,
|
||||
searchScope: SearchScope,
|
||||
consumer: ExecutorProcessor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
) : OperatorReferenceSearcher<KtUnaryExpression>(
|
||||
targetFunction,
|
||||
searchScope,
|
||||
consumer,
|
||||
optimizer,
|
||||
options,
|
||||
wordsToSearch = listOf(operationToken.value)
|
||||
) {
|
||||
|
||||
override fun processPossibleReceiverExpression(expression: KtExpression) {
|
||||
val unaryExpression = expression.parent as? KtUnaryExpression ?: return
|
||||
|
||||
@@ -81,9 +81,9 @@ fun PsiReference.checkUsageVsOriginalDescriptor(
|
||||
}
|
||||
|
||||
fun PsiReference.isImportUsage(): Boolean =
|
||||
element!!.getNonStrictParentOfType<KtImportDirective>() != null
|
||||
element.getNonStrictParentOfType<KtImportDirective>() != null
|
||||
|
||||
fun PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean = with(element!!) {
|
||||
fun PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean = with(element) {
|
||||
fun checkJavaUsage(): Boolean {
|
||||
val call = getNonStrictParentOfType<PsiConstructorCall>()
|
||||
return call == parent && call?.resolveConstructor()?.containingClass?.navigationElement == ktClassOrObject
|
||||
@@ -92,8 +92,7 @@ fun PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean =
|
||||
fun checkKotlinUsage(): Boolean {
|
||||
if (this !is KtElement) return false
|
||||
|
||||
val descriptor = getConstructorCallDescriptor()
|
||||
if (descriptor !is ConstructorDescriptor) return false
|
||||
val descriptor = getConstructorCallDescriptor() as? ConstructorDescriptor ?: return false
|
||||
|
||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor.containingDeclaration)
|
||||
return declaration == ktClassOrObject || (declaration is KtConstructor<*> && declaration.getContainingClassOrObject() == ktClassOrObject)
|
||||
@@ -223,9 +222,9 @@ private fun processClassDelegationCallsToSpecifiedConstructor(
|
||||
fun PsiReference.isExtensionOfDeclarationClassUsage(declaration: KtNamedDeclaration): Boolean {
|
||||
val descriptor = declaration.descriptor ?: return false
|
||||
return checkUsageVsOriginalDescriptor(descriptor) { usageDescriptor, targetDescriptor ->
|
||||
when {
|
||||
usageDescriptor == targetDescriptor -> false
|
||||
usageDescriptor !is FunctionDescriptor -> false
|
||||
when (usageDescriptor) {
|
||||
targetDescriptor -> false
|
||||
!is FunctionDescriptor -> false
|
||||
else -> {
|
||||
val receiverDescriptor =
|
||||
usageDescriptor.extensionReceiverParameter?.type?.constructor?.declarationDescriptor
|
||||
@@ -251,12 +250,12 @@ fun PsiReference.isUsageInContainingDeclaration(declaration: KtNamedDeclaration)
|
||||
}
|
||||
|
||||
fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boolean {
|
||||
val toDescriptor: (KtDeclaration) -> CallableDescriptor? = { declaration ->
|
||||
if (declaration is KtParameter) {
|
||||
val toDescriptor: (KtDeclaration) -> CallableDescriptor? = { sourceDeclaration ->
|
||||
if (sourceDeclaration is KtParameter) {
|
||||
// we don't treat parameters in overriding method as "override" here (overriding parameters usages are searched optionally and via searching of overriding methods first)
|
||||
if (declaration.hasValOrVar()) declaration.propertyDescriptor else null
|
||||
if (sourceDeclaration.hasValOrVar()) sourceDeclaration.propertyDescriptor else null
|
||||
} else {
|
||||
declaration.descriptor as? CallableDescriptor
|
||||
sourceDeclaration.descriptor as? CallableDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user