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.analysis.diagnostics.FirDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.realPsi
|
import org.jetbrains.kotlin.fir.realPsi
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirReference
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirErrorReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirErrorReferenceWithCandidate
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
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.getCandidateSymbols
|
||||||
import org.jetbrains.kotlin.idea.fir.isImplicitFunctionCall
|
import org.jetbrains.kotlin.idea.fir.isImplicitFunctionCall
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir
|
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.calls.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtCallResolver
|
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.diagnostics.KtNonBoundToPsiErrorDiagnostic
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
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.fir.buildSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers
|
||||||
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.tokens.ValidityToken
|
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
||||||
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
|
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
|
||||||
@@ -133,6 +134,7 @@ internal class KtFirCallResolver(
|
|||||||
|
|
||||||
private fun FirReference.createCallTarget(): KtCallTarget? {
|
private fun FirReference.createCallTarget(): KtCallTarget? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
|
is FirSuperReference -> createCallTarget(source)
|
||||||
is FirResolvedNamedReference -> getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
|
is FirResolvedNamedReference -> getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
|
||||||
is FirErrorNamedReference -> createErrorCallTarget(source)
|
is FirErrorNamedReference -> createErrorCallTarget(source)
|
||||||
is FirErrorReferenceWithCandidate -> createErrorCallTarget(source)
|
is FirErrorReferenceWithCandidate -> createErrorCallTarget(source)
|
||||||
@@ -196,6 +198,29 @@ internal class KtFirCallResolver(
|
|||||||
private fun FirResolvedNamedReference.getKtFunctionOrConstructorSymbol(): KtFunctionLikeSymbol? =
|
private fun FirResolvedNamedReference.getKtFunctionOrConstructorSymbol(): KtFunctionLikeSymbol? =
|
||||||
resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as? 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 {
|
companion object {
|
||||||
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
|
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
|
||||||
listOf(
|
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.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.analyse
|
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.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.KtErrorCallTarget
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.calls.KtSuccessCallTarget
|
import org.jetbrains.kotlin.idea.frontend.api.calls.KtSuccessCallTarget
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
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) {
|
private fun KtAnalysisSession.resolveCall(element: PsiElement): KtCall? = when (element) {
|
||||||
is KtCallExpression -> element.resolveCall()
|
is KtCallElement -> element.resolveCall()
|
||||||
is KtBinaryExpression -> element.resolveCall()
|
is KtBinaryExpression -> element.resolveCall()
|
||||||
|
is KtUnaryExpression -> element.resolveCall()
|
||||||
is KtValueArgument -> resolveCall(element.getArgumentExpression()!!)
|
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 Boolean -> toString()
|
||||||
is Map<*, *> -> entries.joinToString(prefix = "{ ", postfix = " }") { (k, v) -> "${k?.stringValue()} -> (${v?.stringValue()})" }
|
is Map<*, *> -> entries.joinToString(prefix = "{ ", postfix = " }") { (k, v) -> "${k?.stringValue()} -> (${v?.stringValue()})" }
|
||||||
is KtValueArgument -> this.text
|
is KtValueArgument -> this.text
|
||||||
|
is KtDelegatedConstructorCallKind -> toString()
|
||||||
else -> error("unexpected parameter type ${this::class}")
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("functionCallInTheSameFile.kt")
|
@TestMetadata("functionCallInTheSameFile.kt")
|
||||||
public void testFunctionCallInTheSameFile() throws Exception {
|
public void testFunctionCallInTheSameFile() throws Exception {
|
||||||
@@ -72,6 +96,12 @@ public class ResolveCallTestGenerated extends AbstractResolveCallTest {
|
|||||||
runTest("idea/idea-frontend-fir/testData/analysisSession/resolveCall/simpleCallWithNonMatchingArgs.kt");
|
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
|
@Test
|
||||||
@TestMetadata("variableAsFunction.kt")
|
@TestMetadata("variableAsFunction.kt")
|
||||||
public void testVariableAsFunction() throws Exception {
|
public void testVariableAsFunction() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user