FIR IDE: create call target for super reference
This commit is contained in:
committed by
Ilya Kirillov
parent
c597ee0e34
commit
59ad7e0e04
+32
-7
@@ -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(
|
||||
|
||||
Vendored
+9
@@ -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>
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
KtDelegatedConstructorCall:
|
||||
argumentMapping = { i + j -> (p1: kotlin.Int) }
|
||||
targetFunction = <constructor>(p1: kotlin.Int): Base
|
||||
kind = SUPER_CALL
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class Base(
|
||||
val p1: Int
|
||||
)
|
||||
|
||||
class Sub(
|
||||
p: Int
|
||||
) : Base(p), Unresolved {
|
||||
constructor(s: String) : <expr>super(s)</expr>
|
||||
}
|
||||
+4
@@ -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
|
||||
Vendored
+9
@@ -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>
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
KtDelegatedConstructorCall:
|
||||
argumentMapping = { s.length -> (p1: kotlin.Int) }
|
||||
targetFunction = <constructor>(p1: kotlin.Int): Sub
|
||||
kind = THIS_CALL
|
||||
+9
@@ -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>
|
||||
}
|
||||
+4
@@ -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
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
interface I
|
||||
|
||||
class A(
|
||||
p : Int
|
||||
) : I, <expr>Unresolved(p)</expr>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
KtDelegatedConstructorCall:
|
||||
argumentMapping = { }
|
||||
targetFunction = ERR<Unresolved reference: Unresolved, []>
|
||||
kind = SUPER_CALL
|
||||
+5
-2
@@ -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}")
|
||||
}
|
||||
|
||||
|
||||
+30
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user