Fixed infinite recursion
This commit is contained in:
+36
-24
@@ -66,6 +66,10 @@ enum class DestructuringDeclarationUsageSearch {
|
|||||||
var destructuringDeclarationUsageSearchMode = if (ApplicationManager.getApplication().isUnitTestMode) ALWAYS_SMART else PLAIN_WHEN_NEEDED
|
var destructuringDeclarationUsageSearchMode = if (ApplicationManager.getApplication().isUnitTestMode) ALWAYS_SMART else PLAIN_WHEN_NEEDED
|
||||||
var destructuringDeclarationUsageSearchLog: MutableList<String>? = null
|
var destructuringDeclarationUsageSearchLog: MutableList<String>? = null
|
||||||
|
|
||||||
|
private object DestructuringDeclarationSearchesInProgress : ThreadLocal<HashSet<KtDeclaration>>() {
|
||||||
|
override fun initialValue() = HashSet<KtDeclaration>()
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: check if it's too expensive
|
//TODO: check if it's too expensive
|
||||||
|
|
||||||
fun findDestructuringDeclarationUsages(
|
fun findDestructuringDeclarationUsages(
|
||||||
@@ -85,35 +89,43 @@ fun findDestructuringDeclarationUsages(
|
|||||||
consumer: Processor<PsiReference>,
|
consumer: Processor<PsiReference>,
|
||||||
optimizer: SearchRequestCollector
|
optimizer: SearchRequestCollector
|
||||||
) {
|
) {
|
||||||
val usePlainSearch = when (destructuringDeclarationUsageSearchMode) {
|
val inProgress = DestructuringDeclarationSearchesInProgress.get()
|
||||||
ALWAYS_SMART -> false
|
try {
|
||||||
ALWAYS_PLAIN -> true
|
if (!inProgress.add(ktDeclaration)) return
|
||||||
PLAIN_WHEN_NEEDED -> scope is LocalSearchScope // for local scope it's faster to use plain search
|
|
||||||
}
|
|
||||||
if (usePlainSearch) {
|
|
||||||
doPlainSearch(ktDeclaration, scope, optimizer)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val descriptor = ktDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return
|
val usePlainSearch = when (destructuringDeclarationUsageSearchMode) {
|
||||||
|
ALWAYS_SMART -> false
|
||||||
|
ALWAYS_PLAIN -> true
|
||||||
|
PLAIN_WHEN_NEEDED -> scope is LocalSearchScope // for local scope it's faster to use plain search
|
||||||
|
}
|
||||||
|
if (usePlainSearch) {
|
||||||
|
doPlainSearch(ktDeclaration, scope, optimizer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return
|
val descriptor = ktDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return
|
||||||
|
|
||||||
val dataType = if (descriptor.isExtension) {
|
if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return
|
||||||
descriptor.fuzzyExtensionReceiverType()!!
|
|
||||||
|
val dataType = if (descriptor.isExtension) {
|
||||||
|
descriptor.fuzzyExtensionReceiverType()!!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return
|
||||||
|
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor(dataType,
|
||||||
|
ktDeclaration,
|
||||||
|
scope,
|
||||||
|
consumer,
|
||||||
|
plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) },
|
||||||
|
testLog = destructuringDeclarationUsageSearchLog
|
||||||
|
).run()
|
||||||
}
|
}
|
||||||
else {
|
finally {
|
||||||
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return
|
inProgress.remove(ktDeclaration)
|
||||||
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Processor(dataType,
|
|
||||||
ktDeclaration,
|
|
||||||
scope,
|
|
||||||
consumer,
|
|
||||||
plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) },
|
|
||||||
testLog = destructuringDeclarationUsageSearchLog
|
|
||||||
).run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, optimizer: SearchRequestCollector) {
|
private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, optimizer: SearchRequestCollector) {
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtParameter
|
||||||
|
// OPTIONS: usages
|
||||||
|
|
||||||
|
data class A(val <caret>a: A?, val n: Int)
|
||||||
|
|
||||||
|
fun f(a: A) {
|
||||||
|
val (a1, n1) = a
|
||||||
|
val (a2, n2) =
|
||||||
|
a?.a ?: return
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
Checked type of (a1, n1)
|
||||||
|
Checked type of (a2, n2)
|
||||||
|
Checked type of (a2, n2)
|
||||||
|
Searched inheritors of A
|
||||||
|
Searched references to A
|
||||||
|
Searched references to parameter a in A() in Kotlin files
|
||||||
|
Searched references to parameter a in f() in Kotlin files
|
||||||
|
Used plain search in LocalSearchScope:
|
||||||
|
CLASS:A
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
Value read 7 val (a1, n1) = a
|
||||||
|
Value read 8 val (a2, n2) =
|
||||||
|
Value read 9 a?.a ?: return
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtParameter
|
||||||
|
// OPTIONS: usages
|
||||||
|
|
||||||
|
data class A(val <caret>b: B, val n: Int)
|
||||||
|
data class B(val a: A?, val s: String)
|
||||||
|
|
||||||
|
fun f(a: A) {
|
||||||
|
val (b, n) = a
|
||||||
|
val (a1, s) = b
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
Checked type of (a1, s)
|
||||||
|
Checked type of (b, n)
|
||||||
|
Searched inheritors of A
|
||||||
|
Searched inheritors of B
|
||||||
|
Searched references to A
|
||||||
|
Searched references to B
|
||||||
|
Searched references to a1 in Kotlin files
|
||||||
|
Searched references to b in Kotlin files
|
||||||
|
Searched references to parameter a in B() in Kotlin files
|
||||||
|
Searched references to parameter a in f() in Kotlin files
|
||||||
|
Searched references to parameter b in A() in Kotlin files
|
||||||
|
Used plain search in LocalSearchScope:
|
||||||
|
CLASS:A
|
||||||
|
Used plain search in LocalSearchScope:
|
||||||
|
CLASS:B
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
Value read 8 val (b, n) = a
|
||||||
@@ -254,6 +254,18 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recursiveDataClass1.0.kt")
|
||||||
|
public void testRecursiveDataClass1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/recursiveDataClass1.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recursiveDataClass2.0.kt")
|
||||||
|
public void testRecursiveDataClass2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/recursiveDataClass2.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("SAM.0.kt")
|
@TestMetadata("SAM.0.kt")
|
||||||
public void testSAM() throws Exception {
|
public void testSAM() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/SAM.0.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/SAM.0.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user