diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt
index bd0a8944ba6..c2e176aa0cf 100644
--- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt
+++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt
@@ -10,24 +10,25 @@ import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.realPsi
-import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
-import org.jetbrains.kotlin.fir.references.FirReference
-import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
+import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.FirErrorReferenceWithCandidate
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
+import org.jetbrains.kotlin.fir.types.ConeClassLikeType
+import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
+import org.jetbrains.kotlin.fir.types.classId
+import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.idea.fir.getCandidateSymbols
import org.jetbrains.kotlin.idea.fir.isImplicitFunctionCall
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir
+import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.calls.*
import org.jetbrains.kotlin.idea.frontend.api.components.KtCallResolver
import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.buildSymbol
-import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
-import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
-import org.jetbrains.kotlin.idea.frontend.api.symbols.KtValueParameterSymbol
-import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol
+import org.jetbrains.kotlin.idea.frontend.api.symbols.*
+import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
@@ -133,6 +134,7 @@ internal class KtFirCallResolver(
private fun FirReference.createCallTarget(): KtCallTarget? {
return when (this) {
+ is FirSuperReference -> createCallTarget(source)
is FirResolvedNamedReference -> getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
is FirErrorNamedReference -> createErrorCallTarget(source)
is FirErrorReferenceWithCandidate -> createErrorCallTarget(source)
@@ -196,6 +198,29 @@ internal class KtFirCallResolver(
private fun FirResolvedNamedReference.getKtFunctionOrConstructorSymbol(): KtFunctionLikeSymbol? =
resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol
+ private fun FirSuperReference.createCallTarget(qualifiedAccessSource: FirSourceElement?): KtCallTarget? =
+ when (val type = superTypeRef.coneType) {
+ is ConeKotlinErrorType ->
+ KtErrorCallTarget(
+ (firSymbolBuilder.classifierBuilder.buildClassLikeSymbolByLookupTag(type.lookupTag) as? KtSymbolWithMembers)?.let {
+ analysisSession.getPrimaryConstructor(it)?.let { ctor -> listOf(ctor) }
+ } ?: emptyList(),
+ source?.let { type.diagnostic.asKtDiagnostic(it, qualifiedAccessSource, diagnosticCache) }
+ ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, type.diagnostic.reason, token)
+ )
+ is ConeClassLikeType ->
+ type.classId?.let { classId ->
+ (firSymbolBuilder.classifierBuilder.buildClassLikeSymbolByClassId(classId) as? KtSymbolWithMembers)?.let {
+ analysisSession.getPrimaryConstructor(it)?.let { ctor -> KtSuccessCallTarget(ctor) }
+ }
+ }
+ else ->
+ error("Unexpected type in super reference: ${type::class}")
+ }
+
+ private fun KtAnalysisSession.getPrimaryConstructor(symbolWithMembers: KtSymbolWithMembers): KtConstructorSymbol? =
+ symbolWithMembers.getDeclaredMemberScope().getConstructors().firstOrNull { it.isPrimary }
+
companion object {
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
listOf(
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.kt
new file mode 100644
index 00000000000..656eba4d4c5
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.kt
@@ -0,0 +1,9 @@
+class Base(
+ val p1: Int
+)
+
+class Sub(
+ override val p1: Int
+) : Base(p1) {
+ constructor(i : Int, j : Int) : super(i + j)
+}
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.txt
new file mode 100644
index 00000000000..0f012e4b3de
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.txt
@@ -0,0 +1,4 @@
+KtDelegatedConstructorCall:
+argumentMapping = { i + j -> (p1: kotlin.Int) }
+targetFunction = (p1: kotlin.Int): Base
+kind = SUPER_CALL
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.kt
new file mode 100644
index 00000000000..83597ec4e61
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.kt
@@ -0,0 +1,9 @@
+class Base(
+ val p1: Int
+)
+
+class Sub(
+ p: Int
+) : Base(p), Unresolved {
+ constructor(s: String) : super(s)
+}
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.txt
new file mode 100644
index 00000000000..7e2d3d7bf9a
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.txt
@@ -0,0 +1,4 @@
+KtDelegatedConstructorCall:
+argumentMapping = { s -> (p1: kotlin.Int) }
+targetFunction = ERR(p1: kotlin.Int): Base]>
+kind = SUPER_CALL
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.kt
new file mode 100644
index 00000000000..4961de22556
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.kt
@@ -0,0 +1,9 @@
+class Base(
+ val p1: Int
+)
+
+class Sub(
+ override val p1: Int
+) : Base(p1) {
+ constructor(s: String) : this(s.length)
+}
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.txt
new file mode 100644
index 00000000000..9a84bfff4b7
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.txt
@@ -0,0 +1,4 @@
+KtDelegatedConstructorCall:
+argumentMapping = { s.length -> (p1: kotlin.Int) }
+targetFunction = (p1: kotlin.Int): Sub
+kind = THIS_CALL
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.kt
new file mode 100644
index 00000000000..4ac202cb254
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.kt
@@ -0,0 +1,9 @@
+class Base(
+ val p1: Int
+)
+
+class Sub(
+ p: Int
+) : Base(p), Unresolved {
+ constructor(i : Int, j : Int) : this(i, j, i * j)
+}
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.txt
new file mode 100644
index 00000000000..381157388a3
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.txt
@@ -0,0 +1,4 @@
+KtDelegatedConstructorCall:
+argumentMapping = { }
+targetFunction = ERR(p: kotlin.Int): Sub, (i: kotlin.Int, j: kotlin.Int): Sub]>
+kind = THIS_CALL
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.kt
new file mode 100644
index 00000000000..4f3d07e5c1b
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.kt
@@ -0,0 +1,5 @@
+interface I
+
+class A(
+ p : Int
+) : I, Unresolved(p)
diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.txt
new file mode 100644
index 00000000000..5596e333b8d
--- /dev/null
+++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.txt
@@ -0,0 +1,4 @@
+KtDelegatedConstructorCall:
+argumentMapping = { }
+targetFunction = ERR
+kind = SUPER_CALL
diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/AbstractResolveCallTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/AbstractResolveCallTest.kt
index c4f1620191b..bc85ae628e1 100644
--- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/AbstractResolveCallTest.kt
+++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/AbstractResolveCallTest.kt
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.test.base.expressionMarkerPro
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.analyse
import org.jetbrains.kotlin.idea.frontend.api.calls.KtCall
+import org.jetbrains.kotlin.idea.frontend.api.calls.KtDelegatedConstructorCallKind
import org.jetbrains.kotlin.idea.frontend.api.calls.KtErrorCallTarget
import org.jetbrains.kotlin.idea.frontend.api.calls.KtSuccessCallTarget
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
@@ -41,10 +42,11 @@ abstract class AbstractResolveCallTest : AbstractHLApiSingleModuleTest() {
}
private fun KtAnalysisSession.resolveCall(element: PsiElement): KtCall? = when (element) {
- is KtCallExpression -> element.resolveCall()
+ is KtCallElement -> element.resolveCall()
is KtBinaryExpression -> element.resolveCall()
+ is KtUnaryExpression -> element.resolveCall()
is KtValueArgument -> resolveCall(element.getArgumentExpression()!!)
- else -> error("Selected should be either KtCallExpression or KtBinaryExpression but was $element")
+ else -> error("Selected should be either KtCallElement, KtBinaryExpression, or KtUnaryExpression, but was $element")
}
}
@@ -71,6 +73,7 @@ private fun KtCall.stringRepresentation(): String {
is Boolean -> toString()
is Map<*, *> -> entries.joinToString(prefix = "{ ", postfix = " }") { (k, v) -> "${k?.stringValue()} -> (${v?.stringValue()})" }
is KtValueArgument -> this.text
+ is KtDelegatedConstructorCallKind -> toString()
else -> error("unexpected parameter type ${this::class}")
}
diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/ResolveCallTestGenerated.java b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/ResolveCallTestGenerated.java
index c08444aca87..b9d19cbe409 100644
--- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/ResolveCallTestGenerated.java
+++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/fir/ResolveCallTestGenerated.java
@@ -24,6 +24,30 @@ public class ResolveCallTestGenerated extends AbstractResolveCallTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/testData/analysisSession/resolveCall"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
+ @Test
+ @TestMetadata("delegatedConstructorCall_super.kt")
+ public void testDelegatedConstructorCall_super() throws Exception {
+ runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.kt");
+ }
+
+ @Test
+ @TestMetadata("delegatedConstructorCall_super_unresolved.kt")
+ public void testDelegatedConstructorCall_super_unresolved() throws Exception {
+ runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.kt");
+ }
+
+ @Test
+ @TestMetadata("delegatedConstructorCall_this.kt")
+ public void testDelegatedConstructorCall_this() throws Exception {
+ runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.kt");
+ }
+
+ @Test
+ @TestMetadata("delegatedConstructorCall_this_unresolved.kt")
+ public void testDelegatedConstructorCall_this_unresolved() throws Exception {
+ runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.kt");
+ }
+
@Test
@TestMetadata("functionCallInTheSameFile.kt")
public void testFunctionCallInTheSameFile() throws Exception {
@@ -72,6 +96,12 @@ public class ResolveCallTestGenerated extends AbstractResolveCallTest {
runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/simpleCallWithNonMatchingArgs.kt");
}
+ @Test
+ @TestMetadata("unresolvedSuperReference.kt")
+ public void testUnresolvedSuperReference() throws Exception {
+ runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.kt");
+ }
+
@Test
@TestMetadata("variableAsFunction.kt")
public void testVariableAsFunction() throws Exception {