Fixed infinite recursion

This commit is contained in:
Valentin Kipyatkov
2016-08-29 19:31:13 +03:00
parent 9022c71949
commit 5682c917f9
8 changed files with 96 additions and 24 deletions
@@ -66,6 +66,10 @@ enum class DestructuringDeclarationUsageSearch {
var destructuringDeclarationUsageSearchMode = if (ApplicationManager.getApplication().isUnitTestMode) ALWAYS_SMART else PLAIN_WHEN_NEEDED
var destructuringDeclarationUsageSearchLog: MutableList<String>? = null
private object DestructuringDeclarationSearchesInProgress : ThreadLocal<HashSet<KtDeclaration>>() {
override fun initialValue() = HashSet<KtDeclaration>()
}
//TODO: check if it's too expensive
fun findDestructuringDeclarationUsages(
@@ -85,35 +89,43 @@ fun findDestructuringDeclarationUsages(
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector
) {
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
}
val inProgress = DestructuringDeclarationSearchesInProgress.get()
try {
if (!inProgress.add(ktDeclaration)) 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) {
descriptor.fuzzyExtensionReceiverType()!!
if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return
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 {
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
finally {
inProgress.remove(ktDeclaration)
}
Processor(dataType,
ktDeclaration,
scope,
consumer,
plainSearchHandler = { searchScope -> doPlainSearch(ktDeclaration, searchScope, optimizer) },
testLog = destructuringDeclarationUsageSearchLog
).run()
}
private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, optimizer: SearchRequestCollector) {
@@ -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
}
@@ -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
@@ -0,0 +1,3 @@
Value read 7 val (a1, n1) = a
Value read 8 val (a2, n2) =
Value read 9 a?.a ?: return
@@ -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
}
@@ -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
@@ -0,0 +1 @@
Value read 8 val (b, n) = a
@@ -254,6 +254,18 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
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")
public void testSAM() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/components/SAM.0.kt");