KT-13426: store map from ImplicitReceiver into KotlinType for implicit receiver smart casts
This commit is contained in:
+12
-3
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.types.expressions.CaptureKind
|
||||
|
||||
internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext)
|
||||
@@ -79,9 +81,16 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon
|
||||
override fun visitExpression(expression: KtExpression) {
|
||||
val implicitSmartCast = bindingContext.get(IMPLICIT_RECEIVER_SMARTCAST, expression)
|
||||
if (implicitSmartCast != null) {
|
||||
holder.createInfoAnnotation(expression,
|
||||
"Implicit receiver smart cast to " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(implicitSmartCast))
|
||||
.textAttributes = SMART_CAST_RECEIVER
|
||||
for ((receiver, type) in implicitSmartCast.receiverTypes) {
|
||||
val receiverName = when (receiver) {
|
||||
is ExtensionReceiver -> "Extension implicit receiver"
|
||||
is ImplicitClassReceiver -> "Implicit receiver"
|
||||
else -> "Unknown receiver"
|
||||
}
|
||||
holder.createInfoAnnotation(expression,
|
||||
"$receiverName smart cast to " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type))
|
||||
.textAttributes = SMART_CAST_RECEIVER
|
||||
}
|
||||
}
|
||||
|
||||
val nullSmartCast = bindingContext.get(SMARTCAST_NULL, expression) == true
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@ private fun KtCodeFragment.markSmartCasts() {
|
||||
val factory = KtPsiFactory(project)
|
||||
|
||||
getContentElement()?.forEachDescendantOfType<KtExpression> { expression ->
|
||||
val smartCast = bindingContext.get(SMARTCAST, expression) ?: bindingContext.get(IMPLICIT_RECEIVER_SMARTCAST, expression)
|
||||
val smartCast = bindingContext.get(SMARTCAST, expression)
|
||||
if (smartCast != null) {
|
||||
val smartCastedExpression = factory.createExpressionByPattern(
|
||||
"($0 as ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast)})",
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
interface IA
|
||||
interface IB
|
||||
interface IC
|
||||
|
||||
object Host : IB
|
||||
|
||||
object Prop : IA {
|
||||
val Host.foo: Callee <info descr="null">get</info>() = Callee
|
||||
}
|
||||
|
||||
object Callee
|
||||
|
||||
object Invoke : IC {
|
||||
<info descr="null">operator</info> fun Callee.invoke() { }
|
||||
}
|
||||
|
||||
<info descr="null">public</info> <info descr="null">inline</info> fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
fun test(a: IA, b: IB, c: IC) {
|
||||
with(a) lambdaA@{
|
||||
with(b) lambdaB@{
|
||||
with(c) lambdaC@{
|
||||
if (this@lambdaA is Prop && this@lambdaB is Host && this@lambdaC is Invoke) {
|
||||
<info descr="Extension implicit receiver smart cast to Host"><info descr="Extension implicit receiver smart cast to Prop">foo</info></info>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
interface IA
|
||||
interface IB
|
||||
|
||||
object A : IA {
|
||||
fun B.foo() { }
|
||||
}
|
||||
|
||||
object B : IB
|
||||
|
||||
<info descr="null">public</info> <info descr="null">inline</info> fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
fun test(a: IA, b: IB) {
|
||||
with(a) lambda1@{
|
||||
with(b) lambda2@{
|
||||
if (this@lambda1 is A && this@lambda2 is B) {
|
||||
<info descr="Extension implicit receiver smart cast to A"><info descr="Extension implicit receiver smart cast to B">foo</info></info>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -928,6 +928,18 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
||||
doTestWithInfos(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("threeImplicitReceivers.kt")
|
||||
public void testThreeImplicitReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/threeImplicitReceivers.kt");
|
||||
doTestWithInfos(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("twoImplicitReceivers.kt")
|
||||
public void testTwoImplicitReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/twoImplicitReceivers.kt");
|
||||
doTestWithInfos(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Typos.kt")
|
||||
public void testTypos() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/Typos.kt");
|
||||
|
||||
Reference in New Issue
Block a user