Store map (Call to KotlinType) for SMARTCAST slice #KT-13426 Fixed
Also EA-86848 Fixed
This commit is contained in:
@@ -297,7 +297,7 @@ object WhenChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
|
private fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
|
||||||
expression.subjectExpression?.let { context.get(SMARTCAST, it) ?: context.getType(it) } ?: null
|
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) } ?: null
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getEnumMissingCases(
|
fun getEnumMissingCases(
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.ExplicitSmartCasts;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts;
|
||||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
|
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
|
||||||
@@ -143,7 +144,7 @@ public interface BindingContext {
|
|||||||
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> INDEXED_LVALUE_GET = Slices.createSimpleSlice();
|
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> INDEXED_LVALUE_GET = Slices.createSimpleSlice();
|
||||||
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> INDEXED_LVALUE_SET = Slices.createSimpleSlice();
|
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> INDEXED_LVALUE_SET = Slices.createSimpleSlice();
|
||||||
|
|
||||||
WritableSlice<KtExpression, KotlinType> SMARTCAST = Slices.createSimpleSlice();
|
WritableSlice<KtExpression, ExplicitSmartCasts> SMARTCAST = new BasicWritableSlice<KtExpression, ExplicitSmartCasts>(DO_NOTHING);
|
||||||
WritableSlice<KtExpression, Boolean> SMARTCAST_NULL = Slices.createSimpleSlice();
|
WritableSlice<KtExpression, Boolean> SMARTCAST_NULL = Slices.createSimpleSlice();
|
||||||
WritableSlice<KtExpression, ImplicitSmartCasts> IMPLICIT_RECEIVER_SMARTCAST = new BasicWritableSlice<KtExpression, ImplicitSmartCasts>(DO_NOTHING);
|
WritableSlice<KtExpression, ImplicitSmartCasts> IMPLICIT_RECEIVER_SMARTCAST = new BasicWritableSlice<KtExpression, ImplicitSmartCasts>(DO_NOTHING);
|
||||||
|
|
||||||
|
|||||||
@@ -377,7 +377,8 @@ class CandidateResolver(
|
|||||||
val spreadElement = argument.getSpreadElement()
|
val spreadElement = argument.getSpreadElement()
|
||||||
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
||||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context, calleeExpression = null, recordExpressionType = false)
|
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context,
|
||||||
|
call = null, recordExpressionType = false)
|
||||||
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
||||||
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
||||||
}
|
}
|
||||||
@@ -531,7 +532,7 @@ class CandidateResolver(
|
|||||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
||||||
dataFlowValue, expectedReceiverParameterType,
|
dataFlowValue, expectedReceiverParameterType,
|
||||||
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
||||||
expression, this, candidateCall.call.calleeExpression, recordExpressionType = true
|
expression, this, candidateCall.call, recordExpressionType = true
|
||||||
)
|
)
|
||||||
|
|
||||||
if (smartCastResult == null) {
|
if (smartCastResult == null) {
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.smartcasts
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.psi.Call
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
interface ExplicitSmartCasts {
|
||||||
|
fun type(call: Call?): KotlinType?
|
||||||
|
|
||||||
|
val defaultType: KotlinType?
|
||||||
|
|
||||||
|
operator fun plus(smartCast: SingleSmartCast): ExplicitSmartCasts
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SingleSmartCast(val call: Call?, val type: KotlinType) : ExplicitSmartCasts {
|
||||||
|
override fun type(call: Call?) = if (call == this.call) type else null
|
||||||
|
|
||||||
|
override val defaultType: KotlinType get() = type
|
||||||
|
|
||||||
|
override fun plus(smartCast: SingleSmartCast) =
|
||||||
|
if (this == smartCast) this
|
||||||
|
else MultipleSmartCasts(mapOf(call to type, smartCast.call to smartCast.type))
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MultipleSmartCasts internal constructor(val map: Map<Call?, KotlinType>) : ExplicitSmartCasts {
|
||||||
|
override fun type(call: Call?) = map[call]
|
||||||
|
|
||||||
|
override val defaultType: KotlinType? get() = null
|
||||||
|
|
||||||
|
override fun plus(smartCast: SingleSmartCast) = MultipleSmartCasts(map + mapOf(smartCast.call to smartCast.type))
|
||||||
|
}
|
||||||
+12
-7
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE
|
import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE
|
||||||
|
import org.jetbrains.kotlin.psi.Call
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -114,11 +115,14 @@ class SmartCastManager {
|
|||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
dataFlowValue: DataFlowValue,
|
dataFlowValue: DataFlowValue,
|
||||||
|
call: Call?,
|
||||||
recordExpressionType: Boolean
|
recordExpressionType: Boolean
|
||||||
) {
|
) {
|
||||||
if (KotlinBuiltIns.isNullableNothing(type)) return
|
if (KotlinBuiltIns.isNullableNothing(type)) return
|
||||||
if (dataFlowValue.isStable) {
|
if (dataFlowValue.isStable) {
|
||||||
trace.record(SMARTCAST, expression, type)
|
val oldSmartCasts = trace[SMARTCAST, expression]
|
||||||
|
val newSmartCast = SingleSmartCast(call, type)
|
||||||
|
trace.record(SMARTCAST, expression, oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast)
|
||||||
if (recordExpressionType) {
|
if (recordExpressionType) {
|
||||||
//TODO
|
//TODO
|
||||||
//Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
|
//Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
|
||||||
@@ -135,10 +139,10 @@ class SmartCastManager {
|
|||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
expression: KtExpression?,
|
expression: KtExpression?,
|
||||||
c: ResolutionContext<*>,
|
c: ResolutionContext<*>,
|
||||||
calleeExpression: KtExpression?,
|
call: Call?,
|
||||||
recordExpressionType: Boolean
|
recordExpressionType: Boolean
|
||||||
): SmartCastResult? {
|
): SmartCastResult? {
|
||||||
return checkAndRecordPossibleCast(dataFlowValue, expectedType, null, expression, c, calleeExpression, recordExpressionType)
|
return checkAndRecordPossibleCast(dataFlowValue, expectedType, null, expression, c, call, recordExpressionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkAndRecordPossibleCast(
|
fun checkAndRecordPossibleCast(
|
||||||
@@ -147,13 +151,14 @@ class SmartCastManager {
|
|||||||
additionalPredicate: ((KotlinType) -> Boolean)?,
|
additionalPredicate: ((KotlinType) -> Boolean)?,
|
||||||
expression: KtExpression?,
|
expression: KtExpression?,
|
||||||
c: ResolutionContext<*>,
|
c: ResolutionContext<*>,
|
||||||
calleeExpression: KtExpression?,
|
call: Call?,
|
||||||
recordExpressionType: Boolean
|
recordExpressionType: Boolean
|
||||||
): SmartCastResult? {
|
): SmartCastResult? {
|
||||||
|
val calleeExpression = call?.calleeExpression
|
||||||
for (possibleType in c.dataFlowInfo.getCollectedTypes(dataFlowValue)) {
|
for (possibleType in c.dataFlowInfo.getCollectedTypes(dataFlowValue)) {
|
||||||
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType) && (additionalPredicate == null || additionalPredicate(possibleType))) {
|
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType) && (additionalPredicate == null || additionalPredicate(possibleType))) {
|
||||||
if (expression != null) {
|
if (expression != null) {
|
||||||
recordCastOrError(expression, possibleType, c.trace, dataFlowValue, recordExpressionType)
|
recordCastOrError(expression, possibleType, c.trace, dataFlowValue, call, recordExpressionType)
|
||||||
}
|
}
|
||||||
else if (calleeExpression != null && dataFlowValue.isStable) {
|
else if (calleeExpression != null && dataFlowValue.isStable) {
|
||||||
val receiver = (dataFlowValue.identifierInfo as? IdentifierInfo.Receiver)?.value
|
val receiver = (dataFlowValue.identifierInfo as? IdentifierInfo.Receiver)?.value
|
||||||
@@ -188,12 +193,12 @@ class SmartCastManager {
|
|||||||
|
|
||||||
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.type, nullableExpectedType) && (additionalPredicate == null || additionalPredicate(dataFlowValue.type))) {
|
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.type, nullableExpectedType) && (additionalPredicate == null || additionalPredicate(dataFlowValue.type))) {
|
||||||
if (!immanentlyNotNull && expression != null) {
|
if (!immanentlyNotNull && expression != null) {
|
||||||
recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, recordExpressionType)
|
recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, call, recordExpressionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
|
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
|
||||||
}
|
}
|
||||||
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, calleeExpression, recordExpressionType)
|
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, call, recordExpressionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
interface I1
|
||||||
|
interface I2
|
||||||
|
interface I3
|
||||||
|
interface I4
|
||||||
|
interface I5
|
||||||
|
|
||||||
|
operator fun I1.component1() = 1
|
||||||
|
operator fun I2.component2() = 2
|
||||||
|
operator fun I3.component3() = 3
|
||||||
|
operator fun I4.component4() = 4
|
||||||
|
operator fun I5.component5() = 5
|
||||||
|
|
||||||
|
fun test(x: Any): Int {
|
||||||
|
if (x is I1 && x is I2 && x is I3 && x is I4 && x is I5) {
|
||||||
|
val (t1, t2, t3, t4, t5) = <!DEBUG_INFO_SMARTCAST!>x<!>
|
||||||
|
return t1 + t2 + t3 + t4 + t5
|
||||||
|
}
|
||||||
|
else return 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test(/*0*/ x: kotlin.Any): kotlin.Int
|
||||||
|
public operator fun I1.component1(): kotlin.Int
|
||||||
|
public operator fun I2.component2(): kotlin.Int
|
||||||
|
public operator fun I3.component3(): kotlin.Int
|
||||||
|
public operator fun I4.component4(): kotlin.Int
|
||||||
|
public operator fun I5.component5(): kotlin.Int
|
||||||
|
|
||||||
|
public interface I1 {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface I2 {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface I3 {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface I4 {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface I5 {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -17577,6 +17577,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleResolvedCalls.kt")
|
||||||
|
public void testMultipleResolvedCalls() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/multipleResolvedCalls.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("noErrorCheckForPackageLevelVal.kt")
|
@TestMetadata("noErrorCheckForPackageLevelVal.kt")
|
||||||
public void testNoErrorCheckForPackageLevelVal() throws Exception {
|
public void testNoErrorCheckForPackageLevelVal() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/noErrorCheckForPackageLevelVal.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/noErrorCheckForPackageLevelVal.kt");
|
||||||
|
|||||||
+14
-3
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.MultipleSmartCasts
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||||
@@ -101,9 +102,19 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon
|
|||||||
|
|
||||||
val smartCast = bindingContext.get(SMARTCAST, expression)
|
val smartCast = bindingContext.get(SMARTCAST, expression)
|
||||||
if (smartCast != null) {
|
if (smartCast != null) {
|
||||||
holder.createInfoAnnotation(getSmartCastTarget(expression),
|
val defaultType = smartCast.defaultType
|
||||||
"Smart cast to " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast))
|
if (defaultType != null) {
|
||||||
.textAttributes = SMART_CAST_VALUE
|
holder.createInfoAnnotation(getSmartCastTarget(expression),
|
||||||
|
"Smart cast to " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(defaultType))
|
||||||
|
.textAttributes = SMART_CAST_VALUE
|
||||||
|
}
|
||||||
|
else if (smartCast is MultipleSmartCasts) {
|
||||||
|
for ((call, type) in smartCast.map) {
|
||||||
|
holder.createInfoAnnotation(getSmartCastTarget(expression),
|
||||||
|
"Smart cast to ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type)} (for $call call)")
|
||||||
|
.textAttributes = SMART_CAST_VALUE
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitExpression(expression)
|
super.visitExpression(expression)
|
||||||
|
|||||||
+1
-1
@@ -160,7 +160,7 @@ private fun KtCodeFragment.markSmartCasts() {
|
|||||||
val factory = KtPsiFactory(project)
|
val factory = KtPsiFactory(project)
|
||||||
|
|
||||||
getContentElement()?.forEachDescendantOfType<KtExpression> { expression ->
|
getContentElement()?.forEachDescendantOfType<KtExpression> { expression ->
|
||||||
val smartCast = bindingContext.get(SMARTCAST, expression)
|
val smartCast = bindingContext.get(SMARTCAST, expression)?.defaultType
|
||||||
if (smartCast != null) {
|
if (smartCast != null) {
|
||||||
val smartCastedExpression = factory.createExpressionByPattern(
|
val smartCastedExpression = factory.createExpressionByPattern(
|
||||||
"($0 as ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast)})",
|
"($0 as ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast)})",
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class AddFunctionParametersFix(
|
|||||||
validator.addName(parameters[i].name.asString())
|
validator.addName(parameters[i].name.asString())
|
||||||
val argumentType = expression?.let {
|
val argumentType = expression?.let {
|
||||||
val bindingContext = it.analyze()
|
val bindingContext = it.analyze()
|
||||||
bindingContext[BindingContext.SMARTCAST, it] ?: bindingContext.getType(it)
|
bindingContext[BindingContext.SMARTCAST, it]?.defaultType ?: bindingContext.getType(it)
|
||||||
}
|
}
|
||||||
val parameterType = parameters[i].type
|
val parameterType = parameters[i].type
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -210,7 +210,7 @@ data class ExtractionData(
|
|||||||
val qualifiedExpression = newRef.getQualifiedExpressionForSelector()
|
val qualifiedExpression = newRef.getQualifiedExpressionForSelector()
|
||||||
if (qualifiedExpression != null) {
|
if (qualifiedExpression != null) {
|
||||||
val smartCastTarget = originalResolveResult.originalRefExpr.parent as KtExpression
|
val smartCastTarget = originalResolveResult.originalRefExpr.parent as KtExpression
|
||||||
smartCast = originalContext[BindingContext.SMARTCAST, smartCastTarget]
|
smartCast = originalContext[BindingContext.SMARTCAST, smartCastTarget]?.defaultType
|
||||||
possibleTypes = getPossibleTypes(smartCastTarget, originalResolveResult.resolvedCall, originalContext)
|
possibleTypes = getPossibleTypes(smartCastTarget, originalResolveResult.resolvedCall, originalContext)
|
||||||
val receiverDescriptor =
|
val receiverDescriptor =
|
||||||
(originalResolveResult.resolvedCall?.dispatchReceiver as? ImplicitReceiver)?.declarationDescriptor
|
(originalResolveResult.resolvedCall?.dispatchReceiver as? ImplicitReceiver)?.declarationDescriptor
|
||||||
@@ -221,7 +221,7 @@ data class ExtractionData(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (newRef.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null) continue
|
if (newRef.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null) continue
|
||||||
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]
|
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]?.defaultType
|
||||||
possibleTypes = getPossibleTypes(originalResolveResult.originalRefExpr, originalResolveResult.resolvedCall, originalContext)
|
possibleTypes = getPossibleTypes(originalResolveResult.originalRefExpr, originalResolveResult.resolvedCall, originalContext)
|
||||||
shouldSkipPrimaryReceiver = false
|
shouldSkipPrimaryReceiver = false
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -308,7 +308,7 @@ private fun suggestParameterType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameterExpression != null ->
|
parameterExpression != null ->
|
||||||
(if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression] else null)
|
(if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression]?.defaultType else null)
|
||||||
?: bindingContext.getType(parameterExpression)
|
?: bindingContext.getType(parameterExpression)
|
||||||
?: (parameterExpression as? KtReferenceExpression)?.let {
|
?: (parameterExpression as? KtReferenceExpression)?.let {
|
||||||
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.returnType
|
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.returnType
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
interface I1
|
||||||
|
interface I2
|
||||||
|
interface I3
|
||||||
|
interface I4
|
||||||
|
interface I5
|
||||||
|
|
||||||
|
<info descr="null">operator</info> fun I1.component1() = 1
|
||||||
|
<info descr="null">operator</info> fun I2.component2() = 2
|
||||||
|
<info descr="null">operator</info> fun I3.component3() = 3
|
||||||
|
<info descr="null">operator</info> fun I4.component4() = 4
|
||||||
|
<info descr="null">operator</info> fun I5.component5() = 5
|
||||||
|
|
||||||
|
fun test(x: Any): Int {
|
||||||
|
if (x is I1 && x is I2 && x is I3 && x is I4 && x is I5) {
|
||||||
|
val (t1, t2, t3, t4, t5) = <info descr="Smart cast to I1 (for t1 call)"><info descr="Smart cast to I2 (for t2 call)"><info descr="Smart cast to I3 (for t3 call)"><info descr="Smart cast to I4 (for t4 call)"><info descr="Smart cast to I5 (for t5 call)">x</info></info></info></info></info>
|
||||||
|
return t1 + t2 + t3 + t4 + t5
|
||||||
|
}
|
||||||
|
else return 0
|
||||||
|
}
|
||||||
@@ -886,6 +886,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
|||||||
doTestWithInfos(fileName);
|
doTestWithInfos(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleResolvedCalls.kt")
|
||||||
|
public void testMultipleResolvedCalls() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/multipleResolvedCalls.kt");
|
||||||
|
doTestWithInfos(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("PropertiesWithBackingFields.kt")
|
@TestMetadata("PropertiesWithBackingFields.kt")
|
||||||
public void testPropertiesWithBackingFields() throws Exception {
|
public void testPropertiesWithBackingFields() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user