FIR IDE: create call target for super reference

This commit is contained in:
Jinseong Jeon
2021-07-20 22:49:26 -07:00
committed by Ilya Kirillov
parent c597ee0e34
commit 59ad7e0e04
13 changed files with 128 additions and 9 deletions
@@ -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(
@@ -0,0 +1,9 @@
class Base(
val p1: Int
)
class Sub(
override val p1: Int
) : Base(p1) {
constructor(i : Int, j : Int) : <expr>super(i + j)</expr>
}
@@ -0,0 +1,4 @@
KtDelegatedConstructorCall:
argumentMapping = { i + j -> (p1: kotlin.Int) }
targetFunction = <constructor>(p1: kotlin.Int): Base
kind = SUPER_CALL
@@ -0,0 +1,9 @@
class Base(
val p1: Int
)
class Sub(
p: Int
) : Base(p), Unresolved {
constructor(s: String) : <expr>super(s)</expr>
}
@@ -0,0 +1,4 @@
KtDelegatedConstructorCall:
argumentMapping = { s -> (p1: kotlin.Int) }
targetFunction = ERR<Argument type mismatch: actual type is kotlin/String but kotlin/Int was expected, [<constructor>(p1: kotlin.Int): Base]>
kind = SUPER_CALL
@@ -0,0 +1,9 @@
class Base(
val p1: Int
)
class Sub(
override val p1: Int
) : Base(p1) {
constructor(s: String) : <expr>this(s.length)</expr>
}
@@ -0,0 +1,4 @@
KtDelegatedConstructorCall:
argumentMapping = { s.length -> (p1: kotlin.Int) }
targetFunction = <constructor>(p1: kotlin.Int): Sub
kind = THIS_CALL
@@ -0,0 +1,9 @@
class Base(
val p1: Int
)
class Sub(
p: Int
) : Base(p), Unresolved {
constructor(i : Int, j : Int) : <expr>this(i, j, i * j)</expr>
}
@@ -0,0 +1,4 @@
KtDelegatedConstructorCall:
argumentMapping = { }
targetFunction = ERR<None of the following functions are applicable: [/Sub.Sub, /Sub.Sub], [<constructor>(p: kotlin.Int): Sub, <constructor>(i: kotlin.Int, j: kotlin.Int): Sub]>
kind = THIS_CALL
@@ -0,0 +1,5 @@
interface I
class A(
p : Int
) : I, <expr>Unresolved(p)</expr>
@@ -0,0 +1,4 @@
KtDelegatedConstructorCall:
argumentMapping = { }
targetFunction = ERR<Unresolved reference: Unresolved, []>
kind = SUPER_CALL
@@ -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}")
}
@@ -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 {