[FIR] Resolve receiver in qualified expressions with no selector
In qualified expression like `foo().`, selector expression is null. Because of that the whole expression was marked as an error FIR expression, and `foo()` part was not resolved at all (including arguments and everything else). This commit fixes the problem by providing receiver's FIR expression as an underlying expression for error FIR expression. That way it will be seen by all resolve transformers and will be successfully resolved. ^KTIJ-21484 Fixed
This commit is contained in:
+18
@@ -1335,6 +1335,24 @@ public class FirSourceReferenceResolveTestGenerated extends AbstractReferenceRes
|
||||
runTest("analysis/analysis-api/testData/referenceResolve/withErrors/InvisibleMember.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("NoSelectorInDotQualifiedCall.kt")
|
||||
public void testNoSelectorInDotQualifiedCall() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/referenceResolve/withErrors/NoSelectorInDotQualifiedCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("NoSelectorInDotQualifiedCall_ResolveInsideLambda.kt")
|
||||
public void testNoSelectorInDotQualifiedCall_ResolveInsideLambda() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/referenceResolve/withErrors/NoSelectorInDotQualifiedCall_ResolveInsideLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("NoSelectorInSafeQualifiedCall.kt")
|
||||
public void testNoSelectorInSafeQualifiedCall() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/referenceResolve/withErrors/NoSelectorInSafeQualifiedCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("PropertyPlaceInClassObjectInObject.kt")
|
||||
public void testPropertyPlaceInClassObjectInObject() throws Exception {
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package testing
|
||||
|
||||
interface Foo
|
||||
|
||||
val otherFoo: Foo = makeFoo()
|
||||
|
||||
fun makeFoo(): Foo = Foo()
|
||||
|
||||
fun test() {
|
||||
<caret>makeFoo().
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
Resolved to:
|
||||
0: (in testing) fun makeFoo(): testing.Foo
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package testing
|
||||
|
||||
interface Foo
|
||||
|
||||
val otherFoo: Foo = makeFoo()
|
||||
|
||||
fun makeFoo(action: () -> Unit): Foo = Foo()
|
||||
|
||||
fun test() {}
|
||||
|
||||
fun test() {
|
||||
makeFoo {
|
||||
<caret>test()
|
||||
}.
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Resolved to:
|
||||
0: (in testing) fun test()
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package testing
|
||||
|
||||
interface Foo
|
||||
|
||||
val otherFoo: Foo = makeFoo()
|
||||
|
||||
fun makeFoo(): Foo = Foo()
|
||||
|
||||
fun test() {
|
||||
<caret>makeFoo()?.
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
Resolved to:
|
||||
0: (in testing) fun makeFoo(): testing.Foo
|
||||
+6
@@ -3225,6 +3225,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/doubleGenericDiamond.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptySelectorInQualifiedExpression.kt")
|
||||
public void testEmptySelectorInQualifiedExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
|
||||
+5
@@ -2844,6 +2844,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/doubleGenericDiamond.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("emptySelectorInQualifiedExpression.kt")
|
||||
public void testEmptySelectorInQualifiedExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/expectConstructor.kt");
|
||||
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
FILE: emptySelectorInQualifiedExpression.kt
|
||||
public final fun foo(action: R|() -> kotlin/Unit| = fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
|
||||
^ Unit
|
||||
}
|
||||
): R|kotlin/Int| {
|
||||
^foo Int(0)
|
||||
}
|
||||
public final fun usageResolved1(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
public final fun usageResolved2(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
public final fun usageResolved3(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
public final fun usageUnresolved1(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
public final fun usageUnresolved2(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
public final fun usageUnresolved3(): R|kotlin/Unit| {
|
||||
ERROR_EXPR(Qualified expression without selector)
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
fun foo(action: () -> Unit = {}): Int = 0
|
||||
|
||||
fun usageResolved1() {
|
||||
foo().<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
fun usageResolved2() {
|
||||
foo()?.<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
fun usageResolved3() {
|
||||
foo {
|
||||
foo()
|
||||
}.<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
fun usageUnresolved1() {
|
||||
<!UNRESOLVED_REFERENCE!>bar<!>().<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
fun usageUnresolved2() {
|
||||
<!UNRESOLVED_REFERENCE!>bar<!>()?.<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
fun usageUnresolved3() {
|
||||
foo {
|
||||
<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
}.<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
+6
@@ -3225,6 +3225,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/doubleGenericDiamond.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptySelectorInQualifiedExpression.kt")
|
||||
public void testEmptySelectorInQualifiedExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
|
||||
+6
@@ -3225,6 +3225,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/doubleGenericDiamond.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptySelectorInQualifiedExpression.kt")
|
||||
public void testEmptySelectorInQualifiedExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
|
||||
+7
-4
@@ -554,10 +554,13 @@ class ExpressionsConverter(
|
||||
result = convertFirSelector(it, dotQualifiedExpression.toFirSourceElement(), firReceiver!!) as? FirExpression
|
||||
}
|
||||
|
||||
return result ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax)
|
||||
)
|
||||
return result ?: buildErrorExpression {
|
||||
source = null
|
||||
diagnostic = ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax)
|
||||
|
||||
// if there is no selector, we still want to resolve the receiver
|
||||
expression = firReceiver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2389,14 +2389,19 @@ open class RawFirBuilder(
|
||||
}
|
||||
|
||||
override fun visitQualifiedExpression(expression: KtQualifiedExpression, data: Unit): FirElement {
|
||||
val receiver = expression.receiverExpression.toFirExpression("Incorrect receiver expression")
|
||||
|
||||
val selector = expression.selectorExpression
|
||||
?: return buildErrorExpression(
|
||||
expression.toFirSourceElement(), ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax),
|
||||
)
|
||||
?: return buildErrorExpression {
|
||||
source = expression.toFirSourceElement()
|
||||
diagnostic = ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax)
|
||||
|
||||
// if there is no selector, we still want to resolve the receiver
|
||||
this.expression = receiver
|
||||
}
|
||||
|
||||
val firSelector = selector.toFirExpression("Incorrect selector expression")
|
||||
if (firSelector is FirQualifiedAccess) {
|
||||
val receiver = expression.receiverExpression.toFirExpression("Incorrect receiver expression")
|
||||
|
||||
if (expression is KtSafeQualifiedExpression) {
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
firSelector.replaceSource(expression.toFirSourceElement(KtFakeSourceElementKind.DesugaredSafeCallExpression))
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
enum class E {
|
||||
A,
|
||||
B,
|
||||
C
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
val e = <!NO_COMPANION_OBJECT!>E<!>.<!SYNTAX!><!>
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
enum class E {
|
||||
A,
|
||||
B,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// ISSUE: KT-34440
|
||||
|
||||
class BufferUtil {
|
||||
fun isDirect(cond: Boolean): Boolean =
|
||||
when (cond) {
|
||||
else -> throw Exception("${buf.<!SYNTAX!><!>}")
|
||||
}
|
||||
private class BufferInfo(private val type: Class<*>)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-34440
|
||||
|
||||
class BufferUtil {
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// NI_EXPECTED_FILE
|
||||
|
||||
val unwrapped = some.<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>cabc<!><!SYNTAX!>$Wrapper<!><<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>out Any<!>>::<!UNRESOLVED_REFERENCE!>unwrap<!>
|
||||
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!>.<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>cabc<!><!SYNTAX!>$Wrapper<!><<!PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT!>out Any<!>>::<!UNRESOLVED_REFERENCE!>unwrap<!>
|
||||
|
||||
Reference in New Issue
Block a user