From 59ad7e0e04aeec87391e0e9779d0e2c913345ab3 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 20 Jul 2021 22:49:26 -0700 Subject: [PATCH] FIR IDE: create call target for super reference --- .../api/fir/components/KtFirCallResolver.kt | 39 +++++++++++++++---- .../delegatedConstructorCall_super.kt | 9 +++++ .../delegatedConstructorCall_super.txt | 4 ++ ...legatedConstructorCall_super_unresolved.kt | 9 +++++ ...egatedConstructorCall_super_unresolved.txt | 4 ++ .../delegatedConstructorCall_this.kt | 9 +++++ .../delegatedConstructorCall_this.txt | 4 ++ ...elegatedConstructorCall_this_unresolved.kt | 9 +++++ ...legatedConstructorCall_this_unresolved.txt | 4 ++ .../resolveCall/unresolvedSuperReference.kt | 5 +++ .../resolveCall/unresolvedSuperReference.txt | 4 ++ .../api/fir/AbstractResolveCallTest.kt | 7 +++- .../api/fir/ResolveCallTestGenerated.java | 30 ++++++++++++++ 13 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.kt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super.txt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.kt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_super_unresolved.txt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.kt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this.txt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.kt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/delegatedConstructorCall_this_unresolved.txt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.kt create mode 100644 idea/idea-frontend-fir/testData/analysisSession/resolveCall/unresolvedSuperReference.txt 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 {