Line Markers: Detect recursive calls of companion invoke() member
#KT-21076 Fixed
This commit is contained in:
@@ -21,6 +21,7 @@ package org.jetbrains.kotlin.idea.util
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtThisExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
@@ -113,3 +114,21 @@ fun ReceiverValue?.getThisReceiverOwner(bindingContext: BindingContext): Declara
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun ReceiverValue?.getReceiverTargetDescriptor(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||
return when (this) {
|
||||
is ExpressionReceiver -> {
|
||||
val expression = KtPsiUtil.deparenthesize(this.expression)
|
||||
val refExpression = when (expression) {
|
||||
is KtThisExpression -> expression.instanceReference
|
||||
is KtReferenceExpression -> expression
|
||||
else -> null
|
||||
} ?: return null
|
||||
bindingContext[BindingContext.REFERENCE_TARGET, refExpression]
|
||||
}
|
||||
|
||||
is ImplicitReceiver -> this.declarationDescriptor
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.inspections.RecursivePropertyAccessorInspection
|
||||
import org.jetbrains.kotlin.idea.util.getThisReceiverOwner
|
||||
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -82,7 +82,9 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
val resolveName = getCallNameFromPsi(element) ?: return false
|
||||
val enclosingFunction = getEnclosingFunction(element, false) ?: return false
|
||||
|
||||
if (enclosingFunction.name != resolveName.asString()) return false
|
||||
val enclosingFunctionName = enclosingFunction.name
|
||||
if (enclosingFunctionName != OperatorNameConventions.INVOKE.asString()
|
||||
&& enclosingFunctionName != resolveName.asString()) return false
|
||||
|
||||
// Check that there were no not-inlined lambdas on the way to enclosing function
|
||||
if (enclosingFunction != getEnclosingFunction(element, true)) return false
|
||||
@@ -98,12 +100,12 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
fun isDifferentReceiver(receiver: Receiver?): Boolean {
|
||||
if (receiver !is ReceiverValue) return false
|
||||
|
||||
val receiverOwner = receiver.getThisReceiverOwner(bindingContext) ?: return true
|
||||
val receiverOwner = receiver.getReceiverTargetDescriptor(bindingContext) ?: return true
|
||||
|
||||
return when (receiverOwner) {
|
||||
is SimpleFunctionDescriptor -> receiverOwner != enclosingFunctionDescriptor
|
||||
is ClassDescriptor -> receiverOwner != enclosingFunctionDescriptor.containingDeclaration
|
||||
else -> throw IllegalStateException("Unexpected receiver owner: $receiverOwner")
|
||||
else -> return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Example(val dummy: Any?) {
|
||||
companion object {
|
||||
operator fun invoke() = <lineMarker>Example</lineMarker>()
|
||||
}
|
||||
}
|
||||
@@ -209,6 +209,12 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/lineMarker/recursiveCall"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("companionInvoke.kt")
|
||||
public void testCompanionInvoke() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/companionInvoke.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("conventionCall.kt")
|
||||
public void testConventionCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/conventionCall.kt");
|
||||
|
||||
Reference in New Issue
Block a user