[FIR IDE] Resolve explicit invoke calls more correctly

Also, enable some muted tests

^KTIJ-21343 Fixed
This commit is contained in:
Roman Golyshev
2022-03-15 11:36:54 +04:00
committed by teamcity
parent 0c4f2711d6
commit 7bcd67068c
11 changed files with 77 additions and 30 deletions
@@ -28,21 +28,6 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
/**
* Checks if the function call is an implicit invoke call with a simple qualified receiver, or looks like it.
*
* For example, `foo()` and `foo.bar()` have simple qualified receivers, while `foo!!()`, `{}()` and `(foo ?: bar)()` - don't.
*
* @return `true` if the function call has a simple qualified receiver and is an implicit invoke call,
* or looks like it and resolves to the `invoke` function.
*/
fun FirFunctionCall.isImplicitFunctionCall(): Boolean {
if (extensionReceiver !is FirQualifiedAccessExpression && dispatchReceiver !is FirQualifiedAccessExpression) return false
return this is FirImplicitInvokeCall ||
calleeReference.getCandidateSymbols().any(FirBasedSymbol<*>::isInvokeFunction)
}
/** /**
* Returns `true` if the symbol is for a function named `invoke`. * Returns `true` if the symbol is for a function named `invoke`.
*/ */
@@ -340,19 +340,13 @@ internal object FirReferenceResolveHelper {
if (expression is KtLabelReferenceExpression && fir is FirPropertyAccessExpression && fir.calleeReference is FirSuperReference) { if (expression is KtLabelReferenceExpression && fir is FirPropertyAccessExpression && fir.calleeReference is FirSuperReference) {
return listOfNotNull((fir.dispatchReceiver.typeRef as? FirResolvedTypeRef)?.toTargetSymbol(session, symbolBuilder)) return listOfNotNull((fir.dispatchReceiver.typeRef as? FirResolvedTypeRef)?.toTargetSymbol(session, symbolBuilder))
} }
val calleeReference = val implicitInvokeReceiver = if (fir is FirImplicitInvokeCall) {
if (fir is FirFunctionCall && fir.explicitReceiver as? FirQualifiedAccessExpression
fir.isImplicitFunctionCall() && } else {
expression is KtNameReferenceExpression null
) { }
// we are resolving implicit invoke call, like val calleeReference = implicitInvokeReceiver?.calleeReference ?: fir.calleeReference
// fun foo(a: () -> Unit) {
// <expression>a</expression>()
// }
val receiver =
fir.dispatchReceiver as? FirQualifiedAccessExpression ?: fir.extensionReceiver as FirQualifiedAccessExpression
receiver.calleeReference
} else fir.calleeReference
return calleeReference.toTargetSymbol(session, symbolBuilder, isInLabelReference = expression is KtLabelReferenceExpression) return calleeReference.toTargetSymbol(session, symbolBuilder, isInLabelReference = expression is KtLabelReferenceExpression)
} }
@@ -142,6 +142,18 @@ public class FirLibrarySourceReferenceResolveTestGenerated extends AbstractRefer
runTest("analysis/analysis-api/testData/referenceResolve/EnumValues.kt"); runTest("analysis/analysis-api/testData/referenceResolve/EnumValues.kt");
} }
@Test
@TestMetadata("explicitFunctionalInterfaceInvoke_globalVal.kt")
public void testExplicitFunctionalInterfaceInvoke_globalVal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/explicitFunctionalInterfaceInvoke_globalVal.kt");
}
@Test
@TestMetadata("explicitFunctionalInterfaceInvoke_parameter.kt")
public void testExplicitFunctionalInterfaceInvoke_parameter() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/explicitFunctionalInterfaceInvoke_parameter.kt");
}
@Test @Test
@TestMetadata("ExternalCompanionObject.kt") @TestMetadata("ExternalCompanionObject.kt")
public void testExternalCompanionObject() throws Exception { public void testExternalCompanionObject() throws Exception {
@@ -508,6 +520,12 @@ public class FirLibrarySourceReferenceResolveTestGenerated extends AbstractRefer
runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor3.kt"); runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor3.kt");
} }
@Test
@TestMetadata("TopLevelObjectVsLocalClassConstructor4.kt")
public void testTopLevelObjectVsLocalClassConstructor4() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor4.kt");
}
@Test @Test
@TestMetadata("TopLevelObjectVsLocalClassQualifier.kt") @TestMetadata("TopLevelObjectVsLocalClassQualifier.kt")
public void testTopLevelObjectVsLocalClassQualifier() throws Exception { public void testTopLevelObjectVsLocalClassQualifier() throws Exception {
@@ -142,6 +142,18 @@ public class FirSourceReferenceResolveTestGenerated extends AbstractReferenceRes
runTest("analysis/analysis-api/testData/referenceResolve/EnumValues.kt"); runTest("analysis/analysis-api/testData/referenceResolve/EnumValues.kt");
} }
@Test
@TestMetadata("explicitFunctionalInterfaceInvoke_globalVal.kt")
public void testExplicitFunctionalInterfaceInvoke_globalVal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/explicitFunctionalInterfaceInvoke_globalVal.kt");
}
@Test
@TestMetadata("explicitFunctionalInterfaceInvoke_parameter.kt")
public void testExplicitFunctionalInterfaceInvoke_parameter() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/explicitFunctionalInterfaceInvoke_parameter.kt");
}
@Test @Test
@TestMetadata("ExternalCompanionObject.kt") @TestMetadata("ExternalCompanionObject.kt")
public void testExternalCompanionObject() throws Exception { public void testExternalCompanionObject() throws Exception {
@@ -508,6 +520,12 @@ public class FirSourceReferenceResolveTestGenerated extends AbstractReferenceRes
runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor3.kt"); runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor3.kt");
} }
@Test
@TestMetadata("TopLevelObjectVsLocalClassConstructor4.kt")
public void testTopLevelObjectVsLocalClassConstructor4() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/TopLevelObjectVsLocalClassConstructor4.kt");
}
@Test @Test
@TestMetadata("TopLevelObjectVsLocalClassQualifier.kt") @TestMetadata("TopLevelObjectVsLocalClassQualifier.kt")
public void testTopLevelObjectVsLocalClassQualifier() throws Exception { public void testTopLevelObjectVsLocalClassQualifier() throws Exception {
@@ -1,5 +1,3 @@
// IGNORE_FIR
package test package test
object Conflict { object Conflict {
@@ -0,0 +1,12 @@
package test
object Conflict
operator fun Conflict.invoke() {}
fun test() {
class Conflict(i: Int)
<caret>Conflict()
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in test) operator fun test.Conflict.invoke()
@@ -0,0 +1,9 @@
fun interface A {
operator fun invoke()
}
val globalA: A = A {}
fun foo() {
globalA.invo<caret>ke()
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in A) operator fun invoke()
@@ -0,0 +1,7 @@
fun interface A {
operator fun invoke()
}
fun foo(param: A) {
param.invo<caret>ke()
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in A) operator fun invoke()