Don't apply "object->lambda" if 'this' is used inside #KT-15250 Fixed
This commit is contained in:
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.TextRange
|
|||||||
import com.intellij.psi.PsiComment
|
import com.intellij.psi.PsiComment
|
||||||
import com.intellij.psi.search.LocalSearchScope
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
@@ -38,7 +39,10 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention::class)
|
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention::class)
|
||||||
@@ -61,22 +65,30 @@ class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiter
|
|||||||
if (singleFunction.valueParameters.any { it.name == null }) return null
|
if (singleFunction.valueParameters.any { it.name == null }) return null
|
||||||
|
|
||||||
val bodyExpression = singleFunction.bodyExpression!!
|
val bodyExpression = singleFunction.bodyExpression!!
|
||||||
|
val context = bodyExpression.analyze()
|
||||||
|
val containingDeclaration = functionDescriptor.containingDeclaration
|
||||||
|
|
||||||
// this-reference
|
// this-reference
|
||||||
val thisReferences = bodyExpression.collectDescendantsOfType<KtThisExpression> { it !is KtClassOrObject }
|
if (bodyExpression.anyDescendantOfType<KtThisExpression> { thisReference ->
|
||||||
for (thisReference in thisReferences) {
|
context[BindingContext.REFERENCE_TARGET, thisReference.instanceReference] == containingDeclaration
|
||||||
val context = thisReference.analyze(BodyResolveMode.PARTIAL)
|
}) return null
|
||||||
val thisDescriptor = context[BindingContext.REFERENCE_TARGET, thisReference.instanceReference]
|
|
||||||
if (thisDescriptor == functionDescriptor.containingDeclaration) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursive call, skip labels
|
// Recursive call, skip labels
|
||||||
if (ReferencesSearch.search(singleFunction, LocalSearchScope(bodyExpression)).any { it.element !is KtLabelReferenceExpression }) {
|
if (ReferencesSearch.search(singleFunction, LocalSearchScope(bodyExpression)).any { it.element !is KtLabelReferenceExpression }) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ReceiverValue?.isImplicitClassFor(descriptor: DeclarationDescriptor) =
|
||||||
|
this is ImplicitClassReceiver && classDescriptor == descriptor
|
||||||
|
|
||||||
|
if (bodyExpression.anyDescendantOfType<KtExpression> { expression ->
|
||||||
|
val resolvedCall = expression.getResolvedCall(context)
|
||||||
|
resolvedCall?.let {
|
||||||
|
it.dispatchReceiver.isImplicitClassFor(containingDeclaration) ||
|
||||||
|
it.extensionReceiver.isImplicitClassFor(containingDeclaration)
|
||||||
|
} ?: false
|
||||||
|
}) return null
|
||||||
|
|
||||||
return TextRange(element.objectDeclaration.getObjectKeyword()!!.startOffset, baseTypeRef.endOffset)
|
return TextRange(element.objectDeclaration.getObjectKeyword()!!.startOffset, baseTypeRef.endOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: false
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
<caret>object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
this.hashCode()
|
||||||
|
}
|
||||||
|
}.run()
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: false
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
<caret>object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
hashCode()
|
||||||
|
}
|
||||||
|
}.run()
|
||||||
|
}
|
||||||
@@ -11418,6 +11418,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExplicitThis.kt")
|
||||||
|
public void testExplicitThis() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ExplicitThis.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ExpressionBody.kt")
|
@TestMetadata("ExpressionBody.kt")
|
||||||
public void testExpressionBody() throws Exception {
|
public void testExpressionBody() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ExpressionBody.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ExpressionBody.kt");
|
||||||
@@ -11430,6 +11436,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ImplicitThis.kt")
|
||||||
|
public void testImplicitThis() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ImplicitThis.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("MultipleBases.kt")
|
@TestMetadata("MultipleBases.kt")
|
||||||
public void testMultipleBases() throws Exception {
|
public void testMultipleBases() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/MultipleBases.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/MultipleBases.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user