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.psi.PsiDocumentManager
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.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.isInlined
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
public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
@@ -73,22 +76,27 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
if (resolvedCall.getCandidateDescriptor().getOriginal() != enclosingFunctionDescriptor) return false
val extensionReceiver = resolvedCall.getExtensionReceiver()
if (extensionReceiver is ExpressionReceiver) {
val thisTarget = (extensionReceiver.getExpression() as? JetThisExpression)?.getInstanceReference()?.getReference()?.resolve()
if (thisTarget != enclosingFunction) {
return false
}
}
val dispatchReceiver = resolvedCall.getDispatchReceiver()
if (dispatchReceiver is ExpressionReceiver) {
val thisTarget = (dispatchReceiver.getExpression() as? JetThisExpression)?.getInstanceReference()?.getReference()?.resolve()
if (thisTarget != enclosingFunction.getNonStrictParentOfType<JetClassOrObject>()) {
return false
fun isDifferentReceiver(receiver: ReceiverValue): Boolean {
val receiverOwner =
when (receiver) {
is ExpressionReceiver -> {
val thisRef = (receiver.getExpression() as? JetThisExpression)?.getInstanceReference() ?: return true
bindingContext[BindingContext.REFERENCE_TARGET, thisRef] ?: return true
}
is ThisReceiver -> receiver.getDeclarationDescriptor()
else -> 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
}
@@ -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);
}
@TestMetadata("differentImplicitReceiver.kt")
public void testDifferentImplicitReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/differentImplicitReceiver.kt");
doTest(fileName);
}
@TestMetadata("extension.kt")
public void testExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/recursiveCall/extension.kt");