Object to lambda intention is inapplicable when reference to this is used

#KT-10202 In Progress
This commit is contained in:
Natalia Ukhorskaya
2016-01-11 16:31:40 +03:00
parent 41e7c3d70b
commit 2b1d60397d
5 changed files with 98 additions and 1 deletions
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.util.ShortenReferences
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.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.contentRange
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -60,8 +61,20 @@ class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiter
if (!singleFunction.hasBody()) return null
if (singleFunction.valueParameters.any { it.name == null }) return null
val bodyExpression = singleFunction.bodyExpression!!
// this-reference
val thisReferences = bodyExpression.collectDescendantsOfType<KtThisExpression> { it !is KtClassOrObject }
for (thisReference in thisReferences) {
val context = thisReference.analyze(BodyResolveMode.PARTIAL)
val thisDescriptor = context[BindingContext.REFERENCE_TARGET, thisReference.instanceReference]
if (thisDescriptor == functionDescriptor.containingDeclaration) {
return null
}
}
// Recursive call, skip labels
if (ReferencesSearch.search(singleFunction, LocalSearchScope(singleFunction.bodyExpression!!)).any { it.element !is KtLabelReferenceExpression }) {
if (ReferencesSearch.search(singleFunction, LocalSearchScope(bodyExpression)).any { it.element !is KtLabelReferenceExpression }) {
return null
}
@@ -0,0 +1,33 @@
// WITH_RUNTIME
class Test {
fun foo() {
bar(object : Runnable {
override fun run() {
println(this)
}
})
// Applicable
bar(<caret>object : Runnable {
override fun run() {
println(this@Test)
}
})
// Applicable
bar(object : Runnable {
override fun run() {
bar(object : Runnable {
override fun run() {
println(this)
}
})
}
})
}
private fun bar(b: Runnable) {
}
}
@@ -0,0 +1,29 @@
// WITH_RUNTIME
class Test {
fun foo() {
bar(object : Runnable {
override fun run() {
println(this)
}
})
// Applicable
bar(Runnable { println(this@Test) })
// Applicable
bar(object : Runnable {
override fun run() {
bar(object : Runnable {
override fun run() {
println(this)
}
})
}
})
}
private fun bar(b: Runnable) {
}
}
@@ -150,4 +150,20 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
<description>Convert to lambda</description>
</problem>
<problem>
<file>ThisReference.kt</file>
<line>12</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="ThisReference.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
<description>Convert to lambda</description>
</problem>
<problem>
<file>ThisReference.kt</file>
<line>19</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="ThisReference.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
<description>Convert to lambda</description>
</problem>
</problems>
@@ -6600,6 +6600,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("ThisReference.kt")
public void testThisReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ThisReference.kt");
doTest(fileName);
}
@TestMetadata("TwoFunctions.kt")
public void testTwoFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/TwoFunctions.kt");