Down-shifting to plain search when operator usage search required
This commit is contained in:
+29
-2
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
|
||||
import org.jetbrains.kotlin.idea.util.toFuzzyType
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
@@ -59,7 +60,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import java.util.*
|
||||
|
||||
enum class DestructuringDeclarationUsageSearch {
|
||||
ALWAYS_SMART, ALWAYS_PLAIN, PLAIN_WHEN_NEEDED
|
||||
ALWAYS_SMART,
|
||||
ALWAYS_PLAIN,
|
||||
PLAIN_WHEN_NEEDED // use plain search for LocalSearchScope and when unknown type of reference encountered
|
||||
}
|
||||
|
||||
// for tests
|
||||
@@ -223,12 +226,18 @@ private class Processor(
|
||||
PROCESS_LAMBDAS
|
||||
}
|
||||
|
||||
//TODO: check if it's operator (too expensive)
|
||||
/**
|
||||
* Adds declaration whose type is our data class (or data class used anywhere inside that type)
|
||||
* or which has parameter of functional type with our data class used inside
|
||||
*/
|
||||
private fun addCallableDeclarationToProcess(declaration: PsiElement, kind: CallableToProcessKind) {
|
||||
if (declaration.isOperatorExpensiveToSearch()) { // cancel all tasks and use plain search
|
||||
tasks.clear()
|
||||
scopesToUsePlainSearch.clear()
|
||||
plainSearchHandler(searchScope)
|
||||
return
|
||||
}
|
||||
|
||||
data class ProcessCallableUsagesTask(val declaration: PsiElement, val kind: CallableToProcessKind) : Task {
|
||||
override fun perform() {
|
||||
// we don't need to search usages of declarations in Java because Java doesn't have implicitly typed declarations so such usages cannot affect Kotlin code
|
||||
@@ -621,6 +630,24 @@ private class Processor(
|
||||
return hasModifierProperty(PsiModifier.PRIVATE) || parents.any { it is PsiCodeBlock }
|
||||
}
|
||||
|
||||
private fun PsiElement.isOperatorExpensiveToSearch(): Boolean {
|
||||
when (this) {
|
||||
is KtFunction -> {
|
||||
if (name?.startsWith("component") == true) return false // component functions are not so expensive to search
|
||||
return hasModifier(KtTokens.OPERATOR_KEYWORD)
|
||||
|| hasModifier(KtTokens.OVERRIDE_KEYWORD) && (resolveToDescriptorIfAny() as? FunctionDescriptor)?.isOperator == true
|
||||
}
|
||||
|
||||
is KtLightMethod -> {
|
||||
return kotlinOrigin?.isOperatorExpensiveToSearch() == true
|
||||
}
|
||||
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean {
|
||||
return type.checkIsSuperTypeOf(this) != null || arguments.any { it.type.containsTypeOrDerivedInside(type) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtParameter
|
||||
// OPTIONS: usages
|
||||
|
||||
data class A(val <caret>x: Int, val y: Int) {
|
||||
fun f() {
|
||||
val (x, y) = this
|
||||
}
|
||||
}
|
||||
|
||||
class B
|
||||
|
||||
operator fun B.plus(other: B): A = TODO()
|
||||
|
||||
fun f(b1: B, b2: B) {
|
||||
val (x, y) = b1 + b2
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Searched inheritors of A
|
||||
Searched references to A
|
||||
Used plain search in LocalSearchScope:
|
||||
CLASS:A
|
||||
Used plain search in whole search scope
|
||||
@@ -0,0 +1,2 @@
|
||||
Value read 15 val (x, y) = b1 + b2
|
||||
Value read 6 val (x, y) = this
|
||||
@@ -254,6 +254,12 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("operators.0.kt")
|
||||
public void testOperators() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/operators.0.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("recursiveDataClass1.0.kt")
|
||||
public void testRecursiveDataClass1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/recursiveDataClass1.0.kt");
|
||||
|
||||
Reference in New Issue
Block a user