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 c2e176aa0cf..d8fb28ba63f 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 @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic +import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.references.* @@ -71,6 +72,7 @@ internal class KtFirCallResolver( is FirFunctionCall -> resolveCall(fir) is FirAnnotationCall -> fir.asAnnotationCall() is FirDelegatedConstructorCall -> fir.asDelegatedConstructorCall() + is FirConstructor -> fir.asDelegatedConstructorCall() is FirSafeCallExpression -> fir.regularQualifiedAccess.safeAs()?.let { resolveCall(it) } else -> null } @@ -132,6 +134,18 @@ internal class KtFirCallResolver( return KtDelegatedConstructorCall(createArgumentMapping(), target, kind) } + private fun FirConstructor.asDelegatedConstructorCall(): KtDelegatedConstructorCall? { + // A delegation call may not be present in the source code: + // + // class A { + // constructor(i: Int) // <--- implicit constructor delegation call (empty element after RPAR) + // } + // + // and FIR built/found from that implicit `KtConstructorDelegationCall` is `FirConstructor`, + // which may have a pointer to the delegated constructor. + return delegatedConstructor?.asDelegatedConstructorCall() + } + private fun FirReference.createCallTarget(): KtCallTarget? { return when (this) { is FirSuperReference -> createCallTarget(source) diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.kt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.kt new file mode 100644 index 00000000000..710cc0c7b79 --- /dev/null +++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.kt @@ -0,0 +1,9 @@ +class A { + constructor(i: Int) +} + +fun call() { + val a = A(42) +} + +// CALL: KtFunctionCall: targetFunction = (i: kotlin.Int): A diff --git a/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.txt b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.txt new file mode 100644 index 00000000000..19368281c34 --- /dev/null +++ b/idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.txt @@ -0,0 +1,3 @@ +KtFunctionCall: +argumentMapping = { 42 -> (i: kotlin.Int) } +targetFunction = (i: kotlin.Int): A diff --git a/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.kt b/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.kt new file mode 100644 index 00000000000..3ad609286fa --- /dev/null +++ b/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.kt @@ -0,0 +1,3 @@ +class A { + constructor(i: Int) +} diff --git a/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.txt b/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.txt new file mode 100644 index 00000000000..5d5fb0ad473 --- /dev/null +++ b/idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.txt @@ -0,0 +1,52 @@ +KtFirValueParameterSymbol: + annotatedType: [] kotlin/Int + annotationClassIds: [] + annotations: [] + callableIdIfNonLocal: null + hasDefaultValue: false + isExtension: false + isVararg: false + name: i + origin: SOURCE + receiverType: null + symbolKind: LOCAL + +KtFirConstructorSymbol: + annotatedType: [] A + annotationClassIds: [] + annotations: [] + callableIdIfNonLocal: null + containingClassIdIfNonLocal: A + dispatchType: null + hasStableParameterNames: true + isExtension: false + isPrimary: false + origin: SOURCE + receiverType: null + symbolKind: MEMBER + typeParameters: [] + valueParameters: [ + KtFirValueParameterSymbol(i) + ] + visibility: Public + +KtFirNamedClassOrObjectSymbol: + annotationClassIds: [] + annotations: [] + classIdIfNonLocal: A + classKind: CLASS + companionObject: null + isData: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: A + origin: SOURCE + superTypes: [ + [] kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public 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 b9d19cbe409..b7d5432e48d 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 @@ -66,6 +66,12 @@ public class ResolveCallTestGenerated extends AbstractResolveCallTest { runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/functionWithReceiverSafeCall.kt"); } + @Test + @TestMetadata("implicitConstructorDelegationCall.kt") + public void testImplicitConstructorDelegationCall() throws Exception { + runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/implicitConstructorDelegationCall.kt"); + } + @Test @TestMetadata("implicitConstuctorCall.kt") public void testImplicitConstuctorCall() throws Exception { diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/symbols/SymbolByPsiTestGenerated.java b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/symbols/SymbolByPsiTestGenerated.java index af9d5e56371..2aa5db49528 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/symbols/SymbolByPsiTestGenerated.java +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/symbols/SymbolByPsiTestGenerated.java @@ -96,6 +96,12 @@ public class SymbolByPsiTestGenerated extends AbstractSymbolByPsiTest { runTest("idea/idea-frontend-fir/testData/symbols/symbolByPsi/functionWithTypeParams.kt"); } + @Test + @TestMetadata("implicitConstructorDelegationCall.kt") + public void testImplicitConstructorDelegationCall() throws Exception { + runTest("idea/idea-frontend-fir/testData/symbols/symbolByPsi/implicitConstructorDelegationCall.kt"); + } + @Test @TestMetadata("implicitReturn.kt") public void testImplicitReturn() throws Exception {