[NI] Move irrelevant code from KotlinCallCompleter
Extract code about smart cast diagnostic to new component AdditionalDiagnosticReporter
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
3450340d7f
commit
9378bff65c
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
|
// very initial state of component
|
||||||
|
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
|
||||||
|
class AdditionalDiagnosticReporter {
|
||||||
|
|
||||||
|
fun createAdditionalDiagnostics(
|
||||||
|
candidate: SimpleKotlinResolutionCandidate,
|
||||||
|
resultingDescriptor: CallableDescriptor
|
||||||
|
): List<KotlinCallDiagnostic> = reportSmartCasts(candidate, resultingDescriptor)
|
||||||
|
|
||||||
|
private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? {
|
||||||
|
if (argument !is ExpressionKotlinCallArgument) return null
|
||||||
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) {
|
||||||
|
return SmartCastDiagnostic(argument, expectedResultType.unwrap())
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportSmartCastOnReceiver(
|
||||||
|
candidate: KotlinResolutionCandidate,
|
||||||
|
receiver: SimpleKotlinCallArgument?,
|
||||||
|
parameter: ReceiverParameterDescriptor?
|
||||||
|
): SmartCastDiagnostic? {
|
||||||
|
if (receiver == null || parameter == null) return null
|
||||||
|
val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it }
|
||||||
|
|
||||||
|
val smartCastDiagnostic = createSmartCastDiagnostic(receiver, expectedType) ?: return null
|
||||||
|
|
||||||
|
// todo may be we have smart cast to Int?
|
||||||
|
return smartCastDiagnostic.takeIf {
|
||||||
|
candidate.status.diagnostics.filterIsInstance<UnsafeCallError>().none {
|
||||||
|
it.receiver == receiver
|
||||||
|
}
|
||||||
|
&&
|
||||||
|
candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().none {
|
||||||
|
it.expressionArgument == receiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor) =
|
||||||
|
SmartList<KotlinCallDiagnostic>().apply {
|
||||||
|
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter))
|
||||||
|
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter))
|
||||||
|
|
||||||
|
for (parameter in resultingDescriptor.valueParameters) {
|
||||||
|
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
||||||
|
val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue
|
||||||
|
|
||||||
|
val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
||||||
|
it.expressionArgument == argument
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thereIsUnstableSmartCastError) {
|
||||||
|
add(smartCastDiagnostic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-61
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.resolve.calls.components
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
|
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
|
||||||
@@ -38,16 +37,14 @@ import org.jetbrains.kotlin.types.TypeApproximator
|
|||||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
|
|
||||||
class KotlinCallCompleter(
|
class KotlinCallCompleter(
|
||||||
val resultTypeResolver: ResultTypeResolver,
|
private val resultTypeResolver: ResultTypeResolver,
|
||||||
val fixationOrderCalculator: FixationOrderCalculator
|
private val fixationOrderCalculator: FixationOrderCalculator,
|
||||||
|
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter
|
||||||
) {
|
) {
|
||||||
interface Context {
|
interface Context {
|
||||||
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
||||||
@@ -165,60 +162,11 @@ class KotlinCallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun computeStatus(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): ResolutionCandidateStatus {
|
private fun computeStatus(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): ResolutionCandidateStatus {
|
||||||
val smartCasts = reportSmartCasts(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?: return candidate.status
|
val smartCasts = additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?:
|
||||||
|
return candidate.status
|
||||||
return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts)
|
return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? {
|
|
||||||
if (argument !is ExpressionKotlinCallArgument) return null
|
|
||||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) {
|
|
||||||
return SmartCastDiagnostic(argument, expectedResultType.unwrap())
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reportSmartCastOnReceiver(
|
|
||||||
candidate: KotlinResolutionCandidate,
|
|
||||||
receiver: SimpleKotlinCallArgument?,
|
|
||||||
parameter: ReceiverParameterDescriptor?
|
|
||||||
): SmartCastDiagnostic? {
|
|
||||||
if (receiver == null || parameter == null) return null
|
|
||||||
val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it }
|
|
||||||
|
|
||||||
val smartCastDiagnostic = createSmartCastDiagnostic(receiver, expectedType) ?: return null
|
|
||||||
|
|
||||||
// todo may be we have smart cast to Int?
|
|
||||||
return smartCastDiagnostic.takeIf {
|
|
||||||
candidate.status.diagnostics.filterIsInstance<UnsafeCallError>().none {
|
|
||||||
it.receiver == receiver
|
|
||||||
}
|
|
||||||
&&
|
|
||||||
candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().none {
|
|
||||||
it.expressionArgument == receiver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): List<KotlinCallDiagnostic> = SmartList<KotlinCallDiagnostic>().apply {
|
|
||||||
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter))
|
|
||||||
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter))
|
|
||||||
|
|
||||||
for (parameter in resultingDescriptor.valueParameters) {
|
|
||||||
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
|
||||||
val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue
|
|
||||||
|
|
||||||
val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
|
||||||
it.expressionArgument == argument
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!thereIsUnstableSmartCastError) {
|
|
||||||
add(smartCastDiagnostic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// true if we should complete this call
|
// true if we should complete this call
|
||||||
private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): Boolean {
|
private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): Boolean {
|
||||||
val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return false
|
val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return false
|
||||||
@@ -290,7 +238,3 @@ class KotlinCallCompleter(
|
|||||||
return lambda.parameters.all { c.canBeProper(it) }
|
return lambda.parameters.all { c.canBeProper(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SmartCastDiagnostic(val expressionArgument: ExpressionKotlinCallArgument, val smartCastType: UnwrappedType): KotlinCallDiagnostic(ResolutionCandidateApplicability.RESOLVED) {
|
|
||||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
|
||||||
}
|
|
||||||
+4
@@ -256,6 +256,10 @@ object InstantiationOfAbstractClass : KotlinCallDiagnostic(RUNTIME_ERROR) {
|
|||||||
override fun report(reporter: DiagnosticReporter) = reporter.onCall(this)
|
override fun report(reporter: DiagnosticReporter) = reporter.onCall(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SmartCastDiagnostic(val expressionArgument: ExpressionKotlinCallArgument, val smartCastType: UnwrappedType): KotlinCallDiagnostic(ResolutionCandidateApplicability.RESOLVED) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
||||||
|
}
|
||||||
|
|
||||||
class UnstableSmartCast(val expressionArgument: ExpressionKotlinCallArgument, val targetType: UnwrappedType) :
|
class UnstableSmartCast(val expressionArgument: ExpressionKotlinCallArgument, val targetType: UnwrappedType) :
|
||||||
KotlinCallDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) {
|
KotlinCallDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) {
|
||||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
||||||
|
|||||||
Reference in New Issue
Block a user