Checking for different receiver in implicit calls. They are considered not recursive.

This commit is contained in:
Evgeny Gerashchenko
2015-04-08 16:37:41 +03:00
parent 01b8718ac7
commit 4c5bfaeb8b
3 changed files with 42 additions and 14 deletions
@@ -24,13 +24,16 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
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.caches.resolve.analyze
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
import java.util.HashSet import java.util.HashSet
public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider { public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
@@ -73,22 +76,27 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
if (resolvedCall.getCandidateDescriptor().getOriginal() != enclosingFunctionDescriptor) return false if (resolvedCall.getCandidateDescriptor().getOriginal() != enclosingFunctionDescriptor) return false
val extensionReceiver = resolvedCall.getExtensionReceiver() fun isDifferentReceiver(receiver: ReceiverValue): Boolean {
if (extensionReceiver is ExpressionReceiver) { val receiverOwner =
val thisTarget = (extensionReceiver.getExpression() as? JetThisExpression)?.getInstanceReference()?.getReference()?.resolve() when (receiver) {
if (thisTarget != enclosingFunction) { is ExpressionReceiver -> {
return false val thisRef = (receiver.getExpression() as? JetThisExpression)?.getInstanceReference() ?: return true
} bindingContext[BindingContext.REFERENCE_TARGET, thisRef] ?: return true
} }
val dispatchReceiver = resolvedCall.getDispatchReceiver() is ThisReceiver -> receiver.getDeclarationDescriptor()
if (dispatchReceiver is ExpressionReceiver) { else -> return false
val thisTarget = (dispatchReceiver.getExpression() as? JetThisExpression)?.getInstanceReference()?.getReference()?.resolve() }
if (thisTarget != enclosingFunction.getNonStrictParentOfType<JetClassOrObject>()) {
return false return when (receiverOwner) {
is SimpleFunctionDescriptor -> receiverOwner != enclosingFunctionDescriptor
is ClassDescriptor -> receiverOwner != enclosingFunctionDescriptor.getContainingDeclaration()
else -> throw IllegalStateException("Unexpected receiver owner: $receiverOwner")
} }
} }
if (isDifferentReceiver(resolvedCall.getExtensionReceiver())) return false
if (isDifferentReceiver(resolvedCall.getDispatchReceiver())) return false
return true return true
} }
@@ -0,0 +1,14 @@
private fun Any.foo() {
with("different extension receiver") {
foo()
}
}
class Klass(p: String) {
private fun bar() {
with(Klass("different dispatch receiver")) {
bar()
}
}
}
@@ -195,6 +195,12 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("differentImplicitReceiver.kt")
public void testDifferentImplicitReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/differentImplicitReceiver.kt");
doTest(fileName);
}
@TestMetadata("extension.kt") @TestMetadata("extension.kt")
public void testExtension() throws Exception { public void testExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/extension.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/extension.kt");