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
) : 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.,
*
* x.toString() // function call
*/
public data class KtFunctionCall(
public val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>,
public class KtFunctionCall(
override val argumentMapping: LinkedHashMap<KtValueArgument, KtValueParameterSymbol>,
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,
@@ -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.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtUnaryExpression
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: KtUnaryExpression): KtCall?
}
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
public fun KtCallExpression.resolveCall(): KtCall? =
public fun KtCallElement.resolveCall(): KtCall? =
analysisSession.callResolver.resolveCall(this)
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.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.impl.FirSimpleNamedReference
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.references.FirReferenceResolveHelper
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtUnaryExpression
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class KtFirCallResolver(
override val analysisSession: KtFirAnalysisSession,
@@ -64,13 +63,14 @@ internal class KtFirCallResolver(
}
}
override fun resolveCall(call: KtCallExpression): KtCall? = withValidityAssertion {
val firCall = when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> fir
is FirSafeCallExpression -> fir.regularQualifiedAccess as? FirFunctionCall
override fun resolveCall(call: KtCallElement): KtCall? = withValidityAssertion {
return when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> resolveCall(fir)
is FirAnnotationCall -> fir.asAnnotationCall()
is FirDelegatedConstructorCall -> fir.asDelegatedConstructorCall()
is FirSafeCallExpression -> fir.regularQualifiedAccess.safeAs<FirFunctionCall>()?.let { resolveCall(it) }
else -> null
} ?: return null
return resolveCall(firCall)
}
}
private fun resolveCall(firCall: FirFunctionCall): KtCall? {
@@ -114,23 +114,41 @@ internal class KtFirCallResolver(
}
private fun FirFunctionCall.asSimpleFunctionCall(): KtFunctionCall? {
val target = when (val calleeReference = calleeReference) {
is FirResolvedNamedReference -> calleeReference.getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
is FirErrorNamedReference -> calleeReference.createErrorCallTarget(source)
is FirErrorReferenceWithCandidate -> calleeReference.createErrorCallTarget(source)
val target = calleeReference.createCallTarget() ?: return null
return KtFunctionCall(createArgumentMapping(), target)
}
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 ->
null
/* error(
"""
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
${this.render()}
${(this.psi as? KtElement)?.getElementTextInContext()}
""".trimIndent()
)*/
else -> error("Unexpected call reference ${calleeReference::class.simpleName}")
} ?: return null
/* error(
"""
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
${this.render()}
${(this.psi as? KtElement)?.getElementTextInContext()}
""".trimIndent()
)*/
else -> error("Unexpected call reference ${this::class.simpleName}")
}
}
private fun FirCall.createArgumentMapping(): LinkedHashMap<KtValueArgument, KtValueParameterSymbol> {
val ktArgumentMapping = LinkedHashMap<KtValueArgument, KtValueParameterSymbol>()
argumentMapping?.let {
fun FirExpression.findKtValueArgument(): KtValueArgument? {
@@ -156,8 +174,7 @@ internal class KtFirCallResolver(
}
}
}
return KtFunctionCall(ktArgumentMapping, target)
return ktArgumentMapping
}
private fun FirErrorNamedReference.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget =