[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.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`.
*/
@@ -340,19 +340,13 @@ internal object FirReferenceResolveHelper {
if (expression is KtLabelReferenceExpression && fir is FirPropertyAccessExpression && fir.calleeReference is FirSuperReference) {
return listOfNotNull((fir.dispatchReceiver.typeRef as? FirResolvedTypeRef)?.toTargetSymbol(session, symbolBuilder))
}
val calleeReference =
if (fir is FirFunctionCall &&
fir.isImplicitFunctionCall() &&
expression is KtNameReferenceExpression
) {
// we are resolving implicit invoke call, like
// fun foo(a: () -> Unit) {
// <expression>a</expression>()
// }
val receiver =
fir.dispatchReceiver as? FirQualifiedAccessExpression ?: fir.extensionReceiver as FirQualifiedAccessExpression
receiver.calleeReference
} else fir.calleeReference
val implicitInvokeReceiver = if (fir is FirImplicitInvokeCall) {
fir.explicitReceiver as? FirQualifiedAccessExpression
} else {
null
}
val calleeReference = implicitInvokeReceiver?.calleeReference ?: fir.calleeReference
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");
}
@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
@TestMetadata("ExternalCompanionObject.kt")
public void testExternalCompanionObject() throws Exception {
@@ -508,6 +520,12 @@ public class FirLibrarySourceReferenceResolveTestGenerated extends AbstractRefer
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
@TestMetadata("TopLevelObjectVsLocalClassQualifier.kt")
public void testTopLevelObjectVsLocalClassQualifier() throws Exception {
@@ -142,6 +142,18 @@ public class FirSourceReferenceResolveTestGenerated extends AbstractReferenceRes
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
@TestMetadata("ExternalCompanionObject.kt")
public void testExternalCompanionObject() throws Exception {
@@ -508,6 +520,12 @@ public class FirSourceReferenceResolveTestGenerated extends AbstractReferenceRes
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
@TestMetadata("TopLevelObjectVsLocalClassQualifier.kt")
public void testTopLevelObjectVsLocalClassQualifier() throws Exception {
@@ -1,5 +1,3 @@
// IGNORE_FIR
package test
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()