Analysis API: Add API functions to get all the candidates (with argument
mapping and substitutor) for a function call.
This commit is contained in:
committed by
Ilya Kirillov
parent
322b10f1bb
commit
4a09abc418
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerGroup
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom
|
||||
@@ -159,11 +160,43 @@ class FirCallResolver(
|
||||
val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>,
|
||||
)
|
||||
|
||||
/** WARNING: This function is public for the analysis API and should only be used there. */
|
||||
fun <T : FirQualifiedAccess> collectAllCandidates(
|
||||
qualifiedAccess: T,
|
||||
name: Name,
|
||||
containingDeclarations: List<FirDeclaration> = transformer.components.containingDeclarations,
|
||||
resolutionContext: ResolutionContext = transformer.resolutionContext
|
||||
): List<OverloadCandidate> {
|
||||
class AllCandidatesCollector(
|
||||
components: BodyResolveComponents,
|
||||
resolutionStageRunner: ResolutionStageRunner
|
||||
) : CandidateCollector(components, resolutionStageRunner) {
|
||||
private val allCandidatesSet = mutableSetOf<Candidate>()
|
||||
|
||||
override fun consumeCandidate(group: TowerGroup, candidate: Candidate, context: ResolutionContext): CandidateApplicability {
|
||||
allCandidatesSet += candidate
|
||||
return super.consumeCandidate(group, candidate, context)
|
||||
}
|
||||
|
||||
val allCandidates: List<Candidate>
|
||||
get() = allCandidatesSet.toList()
|
||||
}
|
||||
|
||||
val collector = AllCandidatesCollector(components, components.resolutionStageRunner)
|
||||
val origin = (qualifiedAccess as? FirFunctionCall)?.origin ?: FirFunctionCallOrigin.Regular
|
||||
val result =
|
||||
collectCandidates(qualifiedAccess, name, forceCallKind = null, origin, containingDeclarations, resolutionContext, collector)
|
||||
return collector.allCandidates.map { OverloadCandidate(it, isInBestCandidates = it in result.candidates) }
|
||||
}
|
||||
|
||||
private fun <T : FirQualifiedAccess> collectCandidates(
|
||||
qualifiedAccess: T,
|
||||
name: Name,
|
||||
forceCallKind: CallKind? = null,
|
||||
origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular
|
||||
origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular,
|
||||
containingDeclarations: List<FirDeclaration> = transformer.components.containingDeclarations,
|
||||
resolutionContext: ResolutionContext = transformer.resolutionContext,
|
||||
collector: CandidateCollector? = null
|
||||
): ResolutionResult {
|
||||
val explicitReceiver = qualifiedAccess.explicitReceiver
|
||||
val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList
|
||||
@@ -179,11 +212,15 @@ class FirCallResolver(
|
||||
typeArguments,
|
||||
session,
|
||||
components.file,
|
||||
transformer.components.containingDeclarations,
|
||||
containingDeclarations,
|
||||
origin = origin
|
||||
)
|
||||
towerResolver.reset()
|
||||
val result = towerResolver.runResolver(info, transformer.resolutionContext)
|
||||
val result = if (collector != null) {
|
||||
towerResolver.runResolver(info, resolutionContext, collector)
|
||||
} else {
|
||||
towerResolver.runResolver(info, resolutionContext)
|
||||
}
|
||||
val bestCandidates = result.bestCandidates()
|
||||
|
||||
fun chooseMostSpecific(): Set<Candidate> {
|
||||
@@ -773,19 +810,6 @@ class FirCallResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConeDiagnosticForCandidateWithError(
|
||||
applicability: CandidateApplicability,
|
||||
candidate: Candidate
|
||||
): ConeDiagnostic {
|
||||
return when (applicability) {
|
||||
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
||||
CandidateApplicability.VISIBILITY_ERROR -> ConeVisibilityError(candidate.symbol)
|
||||
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
||||
CandidateApplicability.NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
||||
else -> ConeInapplicableCandidateError(applicability, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildErrorReference(
|
||||
callInfo: CallInfo,
|
||||
diagnostic: ConeDiagnostic,
|
||||
@@ -800,3 +824,6 @@ class FirCallResolver(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A candidate in the overload candidate set. */
|
||||
data class OverloadCandidate(val candidate: Candidate, val isInBestCandidates: Boolean)
|
||||
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
|
||||
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
@@ -509,3 +510,16 @@ fun FirExpression?.isIntegerLiteralOrOperatorCall(): Boolean {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun createConeDiagnosticForCandidateWithError(
|
||||
applicability: CandidateApplicability,
|
||||
candidate: Candidate
|
||||
): ConeDiagnostic {
|
||||
return when (applicability) {
|
||||
CandidateApplicability.HIDDEN -> ConeHiddenCandidateError(candidate)
|
||||
CandidateApplicability.VISIBILITY_ERROR -> ConeVisibilityError(candidate.symbol)
|
||||
CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ConeInapplicableWrongReceiver(listOf(candidate))
|
||||
CandidateApplicability.NO_COMPANION_OBJECT -> ConeNoCompanionObject(candidate)
|
||||
else -> ConeInapplicableCandidateError(applicability, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
+29
-13
@@ -133,20 +133,19 @@ private class FirCallArgumentsProcessor(
|
||||
}
|
||||
|
||||
fun processNonLambdaArguments(arguments: List<FirExpression>) {
|
||||
for (argument in arguments) {
|
||||
// process position argument
|
||||
if (argument !is FirNamedArgumentExpression) {
|
||||
if (processPositionArgument(argument, isLastArgument = argument === arguments.last())) {
|
||||
state = State.VARARG_POSITION
|
||||
for ((argumentIndex, argument) in arguments.withIndex()) {
|
||||
if (argument is FirVarargArgumentsExpression) {
|
||||
// If the argument list was already resolved, any arguments for a vararg parameter will be in a FirVarargArgumentsExpression.
|
||||
// This can happen when getting all the candidates for an already resolved function call.
|
||||
val varargArguments = argument.arguments
|
||||
for ((varargArgumentIndex, varargArgument) in varargArguments.withIndex()) {
|
||||
processNonLambdaArgument(
|
||||
varargArgument,
|
||||
isLastArgument = argumentIndex == arguments.lastIndex && varargArgumentIndex == varargArguments.lastIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
// process named argument
|
||||
else {
|
||||
if (state == State.VARARG_POSITION) {
|
||||
completeVarargPositionArguments()
|
||||
}
|
||||
|
||||
processNamedArgument(argument)
|
||||
} else {
|
||||
processNonLambdaArgument(argument, isLastArgument = argumentIndex == arguments.lastIndex)
|
||||
}
|
||||
}
|
||||
if (state == State.VARARG_POSITION) {
|
||||
@@ -154,6 +153,23 @@ private class FirCallArgumentsProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun processNonLambdaArgument(argument: FirExpression, isLastArgument: Boolean) {
|
||||
// process position argument
|
||||
if (argument !is FirNamedArgumentExpression) {
|
||||
if (processPositionArgument(argument, isLastArgument)) {
|
||||
state = State.VARARG_POSITION
|
||||
}
|
||||
}
|
||||
// process named argument
|
||||
else {
|
||||
if (state == State.VARARG_POSITION) {
|
||||
completeVarargPositionArguments()
|
||||
}
|
||||
|
||||
processNamedArgument(argument)
|
||||
}
|
||||
}
|
||||
|
||||
// return true, if it was mapped to vararg parameter
|
||||
private fun processPositionArgument(argument: FirExpression, isLastArgument: Boolean): Boolean {
|
||||
if (state == State.NAMED_ONLY_ARGUMENTS) {
|
||||
|
||||
+10
-2
@@ -27,8 +27,16 @@ class FirTowerResolver(
|
||||
fun runResolver(
|
||||
info: CallInfo,
|
||||
context: ResolutionContext,
|
||||
collector: CandidateCollector = this.collector,
|
||||
manager: TowerResolveManager = this.manager
|
||||
externalCollector: CandidateCollector? = null
|
||||
): CandidateCollector {
|
||||
return runResolver(info, context, externalCollector ?: collector, manager)
|
||||
}
|
||||
|
||||
fun runResolver(
|
||||
info: CallInfo,
|
||||
context: ResolutionContext,
|
||||
collector: CandidateCollector,
|
||||
manager: TowerResolveManager
|
||||
): CandidateCollector {
|
||||
val candidateFactoriesAndCollectors = buildCandidateFactoriesAndCollectors(info, collector, context)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user