[NI] Support AllCandidates mode for features in IDE

This commit is contained in:
Mikhail Zarechenskiy
2017-08-21 14:57:21 +03:00
parent 3f8a685ace
commit e666b87545
5 changed files with 65 additions and 12 deletions
@@ -98,6 +98,7 @@ class KotlinToResolvedCallTransformer(
return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall<D> return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall<D>
} }
CallResolutionResult.Type.ALL_CANDIDATES -> error("Cannot transform result for ALL_CANDIDATES mode")
} }
} }
@@ -41,9 +41,9 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.* import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.resolve.calls.results.ManyCandidates
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
@@ -93,7 +93,8 @@ class PSICallResolver(
val factoryProviderForInvoke = FactoryProviderForInvoke(context, scopeTower, kotlinCall) val factoryProviderForInvoke = FactoryProviderForInvoke(context, scopeTower, kotlinCall)
val expectedType = calculateExpectedType(context) val expectedType = calculateExpectedType(context)
var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke) var result = kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates)
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) { if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
@@ -125,7 +126,8 @@ class PSICallResolver(
it.knownTypeParametersResultingSubstitutor) it.knownTypeParametersResultingSubstitutor)
} }
val result = kotlinCallResolver.resolveGivenCandidates(scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates) val result = kotlinCallResolver.resolveGivenCandidates(
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates)
return convertToOverloadResolutionResults(context, result, tracingStrategy) return convertToOverloadResolutionResults(context, result, tracingStrategy)
} }
@@ -142,7 +144,8 @@ class PSICallResolver(
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName) val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, refinedProviderForInvokeFactory) return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
refinedProviderForInvokeFactory, context.collectAllCandidates)
} }
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name { private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
@@ -173,6 +176,15 @@ class PSICallResolver(
result: CallResolutionResult, result: CallResolutionResult,
tracingStrategy: TracingStrategy tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> { ): OverloadResolutionResults<D> {
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
val resolvedCalls = result.allCandidates?.map {
val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor()
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, false, resultingSubstitutor)
}
return AllCandidates(resolvedCalls ?: emptyList())
}
val trace = context.trace val trace = context.trace
result.diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>()?.let { result.diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>()?.let {
@@ -559,8 +571,10 @@ class PSICallResolver(
ktExpression, argumentName, lhsNewResult, name) ktExpression, argumentName, lhsNewResult, name)
} }
// valueArgument.getArgumentExpression()!! instead of ktExpression is hack -- type info should be stored also for parenthesized expression val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument
val typeInfo = expressionTypingServices.getTypeInfo(valueArgument.getArgumentExpression()!!, context)
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context)
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
} }
@@ -38,7 +38,8 @@ class KotlinCallResolver(
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>,
collectAllCandidates: Boolean
): CallResolutionResult { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
@@ -53,6 +54,11 @@ class KotlinCallResolver(
KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException() KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException()
} }
if (collectAllCandidates) {
val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor)
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
}
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED) val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED)
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
@@ -63,12 +69,21 @@ class KotlinCallResolver(
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
givenCandidates: Collection<GivenCandidate> givenCandidates: Collection<GivenCandidate>,
collectAllCandidates: Boolean
): CallResolutionResult { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() } val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
if (collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
TowerResolver.AllCandidatesCollector(),
useOrder = false)
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
}
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
TowerResolver.SuccessfulResultCollector(), TowerResolver.SuccessfulResultCollector(),
useOrder = true) useOrder = true)
@@ -68,7 +68,25 @@ class KotlinCallCompleter(
else { else {
CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage())
} }
}
fun createAllCandidatesResult(
candidates: Collection<KotlinResolutionCandidate>,
expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks
): CallResolutionResult {
val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder()
for (candidate in candidates) {
candidate.prepareForCompletion(expectedType)
runCompletion(
candidate.resolvedCall,
ConstraintSystemCompletionMode.FULL,
diagnosticsHolder,
candidate.getSystem(),
resolutionCallbacks,
skipPostponedArguments = true)
}
return CallResolutionResult(CallResolutionResult.Type.ALL_CANDIDATES, null, emptyList(), ConstraintStorage.Empty, candidates)
} }
private fun runCompletion( private fun runCompletion(
@@ -76,11 +94,14 @@ class KotlinCallCompleter(
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
constraintSystem: NewConstraintSystem, constraintSystem: NewConstraintSystem,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks,
skipPostponedArguments: Boolean = false
) { ) {
val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType
kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) { kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) {
postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) if (!skipPostponedArguments) {
postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it)
}
} }
constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic) constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic)
@@ -150,14 +150,16 @@ class CallResolutionResult(
val type: Type, val type: Type,
val resultCallAtom: ResolvedCallAtom?, val resultCallAtom: ResolvedCallAtom?,
diagnostics: List<KotlinCallDiagnostic>, diagnostics: List<KotlinCallDiagnostic>,
val constraintSystem: ConstraintStorage val constraintSystem: ConstraintStorage,
val allCandidates: Collection<KotlinResolutionCandidate>? = null
) : ResolvedAtom() { ) : ResolvedAtom() {
override val atom: ResolutionAtom? get() = null override val atom: ResolutionAtom? get() = null
enum class Type { enum class Type {
COMPLETED, // resultSubstitutor possible create use constraintSystem COMPLETED, // resultSubstitutor possible create use constraintSystem
PARTIAL, PARTIAL,
ERROR // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates ERROR, // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates
ALL_CANDIDATES // allCandidates != null
} }
init { init {