FIR IDE: Expand KtCall API to include annotation calls and delegated

constructor calls.
This commit is contained in:
Mark Punzalan
2021-07-13 06:42:44 +00:00
committed by teamcityserver
parent d30d8037cf
commit cb85fd26f5
3 changed files with 84 additions and 32 deletions
@@ -55,15 +55,50 @@ public class KtVariableWithInvokeFunctionCall(
override val targetFunction: KtCallTarget override val targetFunction: KtCallTarget
) : KtDeclaredFunctionCall() ) : KtDeclaredFunctionCall()
/**
* Represents a direct function call with arguments
*/
public sealed class KtCallWithArguments : KtDeclaredFunctionCall() {
public abstract val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>
}
/** /**
* Simple function call, e.g., * Simple function call, e.g.,
* *
* x.toString() // function call * x.toString() // function call
*/ */
public data class KtFunctionCall( public class KtFunctionCall(
public val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>, override val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>,
override val targetFunction: KtCallTarget override val targetFunction: KtCallTarget
) : KtDeclaredFunctionCall() ) : KtCallWithArguments()
/**
* Annotation call, e.g.,
*
* @Retention(AnnotationRetention.SOURCE) // annotation call
* annotation class Ann
*/
public class KtAnnotationCall(
override val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>,
override val targetFunction: KtCallTarget
) : KtCallWithArguments()
// TODO: Add other properties, e.g., useSiteTarget
/**
* Delegated constructor call, e.g.,
*
* open class A(a: Int)
* class B(b: Int) : A(b) { // delegated constructor call (kind = SUPER_CALL)
* constructor() : this(1) // delegated constructor call (kind = THIS_CALL)
* }
*/
public class KtDelegatedConstructorCall(
override val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>,
override val targetFunction: KtCallTarget,
public val kind: KtDelegatedConstructorCallKind
) : KtCallWithArguments()
public enum class KtDelegatedConstructorCallKind { SUPER_CALL, THIS_CALL }
/** /**
* Represents function(s) in which call was resolved, * Represents function(s) in which call was resolved,
@@ -7,17 +7,17 @@ package org.jetbrains.kotlin.idea.frontend.api.components
import org.jetbrains.kotlin.idea.frontend.api.calls.KtCall import org.jetbrains.kotlin.idea.frontend.api.calls.KtCall
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtUnaryExpression import org.jetbrains.kotlin.psi.KtUnaryExpression
public abstract class KtCallResolver : KtAnalysisSessionComponent() { public abstract class KtCallResolver : KtAnalysisSessionComponent() {
public abstract fun resolveCall(call: KtCallExpression): KtCall? public abstract fun resolveCall(call: KtCallElement): KtCall?
public abstract fun resolveCall(call: KtBinaryExpression): KtCall? public abstract fun resolveCall(call: KtBinaryExpression): KtCall?
public abstract fun resolveCall(call: KtUnaryExpression): KtCall? public abstract fun resolveCall(call: KtUnaryExpression): KtCall?
} }
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn { public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
public fun KtCallExpression.resolveCall(): KtCall? = public fun KtCallElement.resolveCall(): KtCall? =
analysisSession.callResolver.resolveCall(this) analysisSession.callResolver.resolveCall(this)
public fun KtBinaryExpression.resolveCall(): KtCall? = public fun KtBinaryExpression.resolveCall(): KtCall? =
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement
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.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference 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
@@ -30,11 +31,9 @@ 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
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtUnaryExpression
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class KtFirCallResolver( internal class KtFirCallResolver(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
@@ -64,13 +63,14 @@ internal class KtFirCallResolver(
} }
} }
override fun resolveCall(call: KtCallExpression): KtCall? = withValidityAssertion { override fun resolveCall(call: KtCallElement): KtCall? = withValidityAssertion {
val firCall = when (val fir = call.getOrBuildFir(firResolveState)) { return when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> fir is FirFunctionCall -> resolveCall(fir)
is FirSafeCallExpression -> fir.regularQualifiedAccess as? FirFunctionCall is FirAnnotationCall -> fir.asAnnotationCall()
is FirDelegatedConstructorCall -> fir.asDelegatedConstructorCall()
is FirSafeCallExpression -> fir.regularQualifiedAccess.safeAs<FirFunctionCall>()?.let { resolveCall(it) }
else -> null else -> null
} ?: return null }
return resolveCall(firCall)
} }
private fun resolveCall(firCall: FirFunctionCall): KtCall? { private fun resolveCall(firCall: FirFunctionCall): KtCall? {
@@ -114,23 +114,41 @@ internal class KtFirCallResolver(
} }
private fun FirFunctionCall.asSimpleFunctionCall(): KtFunctionCall? { private fun FirFunctionCall.asSimpleFunctionCall(): KtFunctionCall? {
val target = when (val calleeReference = calleeReference) { val target = calleeReference.createCallTarget() ?: return null
is FirResolvedNamedReference -> calleeReference.getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) } return KtFunctionCall(createArgumentMapping(), target)
is FirErrorNamedReference -> calleeReference.createErrorCallTarget(source) }
is FirErrorReferenceWithCandidate -> calleeReference.createErrorCallTarget(source)
private fun FirAnnotationCall.asAnnotationCall(): KtAnnotationCall? {
val target = calleeReference.createCallTarget() ?: return null
return KtAnnotationCall(createArgumentMapping(), target)
}
private fun FirDelegatedConstructorCall.asDelegatedConstructorCall(): KtDelegatedConstructorCall? {
val target = calleeReference.createCallTarget() ?: return null
val kind = if (isSuper) KtDelegatedConstructorCallKind.SUPER_CALL else KtDelegatedConstructorCallKind.THIS_CALL
return KtDelegatedConstructorCall(createArgumentMapping(), target, kind)
}
private fun FirReference.createCallTarget(): KtCallTarget? {
return when (this) {
is FirResolvedNamedReference -> getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
is FirErrorNamedReference -> createErrorCallTarget(source)
is FirErrorReferenceWithCandidate -> createErrorCallTarget(source)
is FirSimpleNamedReference -> is FirSimpleNamedReference ->
null null
/* error( /* error(
""" """
Looks like ${this::class.simpleName} && it calle reference ${calleeReference::class.simpleName} were not resolved to BODY_RESOLVE phase, Looks like ${this::class.simpleName} && it calle reference ${calleeReference::class.simpleName} were not resolved to BODY_RESOLVE phase,
consider resolving it containing declaration before starting resolve calls consider resolving it containing declaration before starting resolve calls
${this.render()} ${this.render()}
${(this.psi as? KtElement)?.getElementTextInContext()} ${(this.psi as? KtElement)?.getElementTextInContext()}
""".trimIndent() """.trimIndent()
)*/ )*/
else -> error("Unexpected call reference ${calleeReference::class.simpleName}") else -> error("Unexpected call reference ${this::class.simpleName}")
} ?: return null }
}
private fun FirCall.createArgumentMapping(): LinkedHashMap<KtValueArgument, KtValueParameterSymbol> {
val ktArgumentMapping = LinkedHashMap<KtValueArgument, KtValueParameterSymbol>() val ktArgumentMapping = LinkedHashMap<KtValueArgument, KtValueParameterSymbol>()
argumentMapping?.let { argumentMapping?.let {
fun FirExpression.findKtValueArgument(): KtValueArgument? { fun FirExpression.findKtValueArgument(): KtValueArgument? {
@@ -156,8 +174,7 @@ internal class KtFirCallResolver(
} }
} }
} }
return ktArgumentMapping
return KtFunctionCall(ktArgumentMapping, target)
} }
private fun FirErrorNamedReference.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget = private fun FirErrorNamedReference.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget =