From ec43f49ab4a86171d6a51f2c3de81eef30a334c9 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Tue, 18 Aug 2015 15:52:08 +0300 Subject: [PATCH] Fixed completion for extension function after removing members for implicit receiver from scope. --- .../codeInsight/ReferenceVariantsHelper.kt | 153 +++++++++--------- .../kotlin/idea/util/extensionsUtils.kt | 13 +- .../boldOrGrayed/NonPredictableSmartCast.kt | 4 +- ...PredictableSmartCastWithWrongReturnType.kt | 15 ++ .../MemberExtensionWithoutExplicitReceiver.kt | 20 +++ .../MemberExtensionAfterThisSmartCast.kt | 12 ++ .../common/smartCast/MembersAfterSmartCast.kt | 21 +++ .../test/JSBasicCompletionTestGenerated.java | 24 +++ .../test/JvmBasicCompletionTestGenerated.java | 24 +++ 9 files changed, 209 insertions(+), 77 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt create mode 100644 idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt create mode 100644 idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt create mode 100644 idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 6b3a6b66a4e..cc81ed18654 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -29,12 +29,9 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.JetScope -import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.resolve.scopes.* import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor @@ -110,6 +107,10 @@ public class ReferenceVariantsHelper( val dataFlowInfo = context.getDataFlowInfo(expression) + val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap { + SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo) + }.toSet() + val pair = getExplicitReceiverData(expression) if (pair != null) { val (receiverExpression, callType) = pair @@ -126,29 +127,22 @@ public class ReferenceVariantsHelper( context.getType(receiverExpression) if (expressionType != null && !expressionType.isError()) { val receiverValue = ExpressionReceiver(receiverExpression, expressionType) - descriptors.addMembersFromReceiverAndSyntheticExtensions(receiverValue, callType, kindFilter, nameFilter, resolutionScope, dataFlowInfo) + val explicitReceiverTypes = SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo) - descriptors.addCallableExtensions(resolutionScope, receiverValue, dataFlowInfo, callType, kindFilter, nameFilter) + descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter) } } else { - // process instance members that can be called via implicit receiver's instances - val receivers = resolutionScope.getImplicitReceiversWithInstance() - val receiverValues = receivers.map { it.getValue() } - for (receiverValue in receiverValues) { - descriptors.addMembersFromReceiverAndSyntheticExtensions(receiverValue, CallType.NORMAL, kindFilter, nameFilter, resolutionScope, dataFlowInfo) - } + descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, CallType.NORMAL, kindFilter, nameFilter) - // process extensions and non-instance members + // process non-instance members for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) { - if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) { - val dispatchReceiver = descriptor.getDispatchReceiverParameter() - if (dispatchReceiver == null || dispatchReceiver in receivers) { - descriptors.addAll(descriptor.substituteExtensionIfCallable(receiverValues, context, dataFlowInfo, CallType.NORMAL, containingDeclaration)) + if (descriptor is CallableDescriptor) { + assert(descriptor.dispatchReceiverParameter == null) { + "Resolution scope with member descriptor: $descriptor. Scope structure: ${JetScopeUtils.printStructure(resolutionScope)}" } } - else { - if (descriptor is CallableDescriptor && descriptor.getDispatchReceiverParameter() != null) continue // should already be processed via implicit receivers + if (!descriptor.isExtension) { descriptors.add(descriptor) } } @@ -157,25 +151,47 @@ public class ReferenceVariantsHelper( return descriptors } - private fun MutableSet.addMembersFromReceiverAndSyntheticExtensions( - receiverValue: ReceiverValue, + private fun MutableSet.processAll( + implicitReceiverTypes: Collection, + receiverTypes: Collection, + resolutionScope: JetScope, callType: CallType, kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean, - resolutionScope: JetScope, - dataFlowInfo: DataFlowInfo + nameFilter: (Name) -> Boolean + ) { + addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter) + addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter) + addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter) + } + + private fun MutableSet.addMemberExtensions( + dispatchReceiverTypes: Collection, + extensionReceiverTypes: Collection, + callType: CallType, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean + ) { + val memberFilter = kindFilter exclude DescriptorKindExclude.NonExtensions + for (dispatchReceiverType in dispatchReceiverTypes) { + for (member in dispatchReceiverType.memberScope.getDescriptorsFiltered(memberFilter, nameFilter)) { + addAll((member as CallableDescriptor).substituteExtensionIfCallable(extensionReceiverTypes, callType)) + } + } + } + + private fun MutableSet.addNonExtensionMembers( + receiverTypes: Collection, + callType: CallType, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean ) { val memberFilter = kindFilter exclude DescriptorKindExclude.Extensions - val containingDeclaration = resolutionScope.getContainingDeclaration() - - val receiverTypes = SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo) - for (receiverType in receiverTypes) { - val members = receiverType.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors + val members = receiverType.memberScope.getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors for (member in members) { if (member is ClassDescriptor) { - if (member.isInner()) { - member.getConstructors().filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) } + if (member.isInner) { + member.constructors.filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) } } } else if (callType.canCall(member) && memberFilter.accepts(member)) { @@ -183,24 +199,42 @@ public class ReferenceVariantsHelper( } } } + } - if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) { - fun processExtension(extension: CallableDescriptor) { - if (nameFilter(extension.name) && kindFilter.accepts(extension)) { - addAll(extension.substituteExtensionIfCallable(receiverValue, callType, context, dataFlowInfo, containingDeclaration)) - } + private fun MutableSet.addScopeAndSyntheticExtensions( + resolutionScope: JetScope, + receiverTypes: Collection, + callType: CallType, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean + ) { + if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return + + + fun process(extension: CallableDescriptor) { + if (nameFilter(extension.name) && kindFilter.accepts(extension)) { + addAll(extension.substituteExtensionIfCallable(receiverTypes, callType)) } + } - if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) { - for (extension in resolutionScope.getSyntheticExtensionProperties(receiverTypes)) { - processExtension(extension) - } + for (descriptor in resolutionScope.getDescriptors(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) { + assert(descriptor !is CallableDescriptor || descriptor.dispatchReceiverParameter == null) { + "Resolution scope with member descriptor: $descriptor. Scope structure: ${JetScopeUtils.printStructure(resolutionScope)}" } + if (descriptor.isExtension) { + process(descriptor as CallableDescriptor) + } + } - if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) { - for (extension in resolutionScope.getSyntheticExtensionFunctions(receiverTypes)) { - processExtension(extension) - } + if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) { + for (extension in resolutionScope.getSyntheticExtensionProperties(receiverTypes)) { + process(extension) + } + } + + if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) { + for (extension in resolutionScope.getSyntheticExtensionFunctions(receiverTypes)) { + process(extension) } } } @@ -227,35 +261,6 @@ public class ReferenceVariantsHelper( return type } - private fun MutableCollection.addCallableExtensions( - resolutionScope: JetScope, - receiver: ReceiverValue, - dataFlowInfo: DataFlowInfo, - callType: CallType, - kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean - ) { - if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return - val extensionsFilter = kindFilter.exclude(DescriptorKindExclude.NonExtensions) - - fun processExtension(descriptor: DeclarationDescriptor) { - addAll((descriptor as CallableDescriptor).substituteExtensionIfCallable(receiver, callType, context, dataFlowInfo, resolutionScope.getContainingDeclaration())) - } - - // process member extensions from implicit receivers separately to filter out ones from implicit receivers with no instance - for (implicitReceiver in resolutionScope.getImplicitReceiversWithInstance()) { - for (extension in implicitReceiver.getType().getMemberScope().getDescriptorsFiltered(extensionsFilter, nameFilter)) { - processExtension(extension) - } - } - - for (extension in resolutionScope.getDescriptorsFiltered(extensionsFilter, nameFilter)) { - if ((extension as CallableDescriptor).getDispatchReceiverParameter() == null) { // otherwise it should already be processed via implicit receivers - processExtension(extension) - } - } - } - public fun getPackageReferenceVariants( expression: JetSimpleNameExpression, nameFilter: (Name) -> Boolean diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt index bdabaa0ee08..6fb045d3397 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/extensionsUtils.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver +import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.nullability @@ -82,10 +83,18 @@ public fun CallableDescriptor.substituteExtensionIfCallable( containingDeclarationOrModule: DeclarationDescriptor ): Collection { if (!receiver.exists()) return listOf() + + var types = SmartCastUtils.getSmartCastVariants(receiver, bindingContext, containingDeclarationOrModule, dataFlowInfo) + return substituteExtensionIfCallable(types, callType) +} + +public fun CallableDescriptor.substituteExtensionIfCallable( + receiverTypes: Collection, + callType: CallType +): Collection { if (!callType.canCall(this)) return listOf() - var types = SmartCastUtils.getSmartCastVariants(receiver, bindingContext, containingDeclarationOrModule, dataFlowInfo).asSequence() - + var types = receiverTypes.asSequence() if (callType == CallType.SAFE) { types = types.map { it.makeNotNullable() } } diff --git a/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCast.kt b/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCast.kt index 5c9a3f2400e..cf9d9cd82c5 100644 --- a/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCast.kt +++ b/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCast.kt @@ -12,4 +12,6 @@ fun f(pair: Pair) { // EXIST: { lookupString: "hashCode", attributes: "bold" } // EXIST: { lookupString: "forString", attributes: "grayed" } // EXIST: { lookupString: "forAny", attributes: "bold" } -// EXIST: { lookupString: "forT", attributes: "" } + +/*TODO: { lookupString: "forT", attributes: "" }*/ +// EXIST: { lookupString: "forT", attributes: "grayed" } diff --git a/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt b/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt new file mode 100644 index 00000000000..a54ea50b419 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt @@ -0,0 +1,15 @@ +interface A { + fun foo(): Any + fun bar() +} +interface B: A { + override fun foo(): String +} + +fun f(pair: Pair) { + if (pair.first !is B) return + pair.first. +} +/*TODO: { lookupString: "foo", "typeText":"Any", attributes: "bold" } */ +// EXIST: { lookupString: "foo", "typeText":"String", attributes: "bold" } +// EXIST: { lookupString: "bar", attributes: "bold" } diff --git a/idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt b/idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt new file mode 100644 index 00000000000..8d8c68934ba --- /dev/null +++ b/idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt @@ -0,0 +1,20 @@ +class B { + fun A.extFunInBForA() {} + fun B.extFunInBForB() {} + +} +class A { + fun B.extFunInAForB() {} + fun A.extFunInAForA() {} +} + +fun A.test() { + with(B()) { + + } +} + +// EXIST: extFunInAForA +// EXIST: extFunInBForA +// EXIST: extFunInAForB +// EXIST: extFunInBForB diff --git a/idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt b/idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt new file mode 100644 index 00000000000..f96976b5240 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt @@ -0,0 +1,12 @@ +class A { + fun String.foo() {} +} + +fun Any.test() { // see KT-8865 Member extension after this smart cast not working + if (this is A) { + "". + } +} + + +// EXIST: foo \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt b/idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt new file mode 100644 index 00000000000..da744675c32 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt @@ -0,0 +1,21 @@ +interface A { + fun memberA() +} + +interface B { + fun memberB() +} + +interface C { + fun memberC() +} + +fun C.test(a: Any) { + if (a is A && a is B) { + a. + } +} + +// EXIST: memberA +// EXIST: memberB +// ABSENT: memberC diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index cf2e40f8010..bad4275b530 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1110,6 +1110,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("NonPredictableSmartCastWithWrongReturnType.kt") + public void testNonPredictableSmartCastWithWrongReturnType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt"); + doTest(fileName); + } + @TestMetadata("SafeCallAfterNullable.kt") public void testSafeCallAfterNullable() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/SafeCallAfterNullable.kt"); @@ -1215,6 +1221,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("MemberExtensionWithoutExplicitReceiver.kt") + public void testMemberExtensionWithoutExplicitReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt"); + doTest(fileName); + } + @TestMetadata("MemberExtensionsFromMemberExtension.kt") public void testMemberExtensionsFromMemberExtension() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/MemberExtensionsFromMemberExtension.kt"); @@ -1800,6 +1812,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/smartCast"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("MemberExtensionAfterThisSmartCast.kt") + public void testMemberExtensionAfterThisSmartCast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt"); + doTest(fileName); + } + + @TestMetadata("MembersAfterSmartCast.kt") + public void testMembersAfterSmartCast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt"); + doTest(fileName); + } + @TestMetadata("SmartCastAfterIf.kt") public void testSmartCastAfterIf() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/SmartCastAfterIf.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index bdab2b9e541..8931abc5efe 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1110,6 +1110,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("NonPredictableSmartCastWithWrongReturnType.kt") + public void testNonPredictableSmartCastWithWrongReturnType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/NonPredictableSmartCastWithWrongReturnType.kt"); + doTest(fileName); + } + @TestMetadata("SafeCallAfterNullable.kt") public void testSafeCallAfterNullable() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/boldOrGrayed/SafeCallAfterNullable.kt"); @@ -1215,6 +1221,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("MemberExtensionWithoutExplicitReceiver.kt") + public void testMemberExtensionWithoutExplicitReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/MemberExtensionWithoutExplicitReceiver.kt"); + doTest(fileName); + } + @TestMetadata("MemberExtensionsFromMemberExtension.kt") public void testMemberExtensionsFromMemberExtension() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/MemberExtensionsFromMemberExtension.kt"); @@ -1800,6 +1812,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/smartCast"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("MemberExtensionAfterThisSmartCast.kt") + public void testMemberExtensionAfterThisSmartCast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/MemberExtensionAfterThisSmartCast.kt"); + doTest(fileName); + } + + @TestMetadata("MembersAfterSmartCast.kt") + public void testMembersAfterSmartCast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/MembersAfterSmartCast.kt"); + doTest(fileName); + } + @TestMetadata("SmartCastAfterIf.kt") public void testSmartCastAfterIf() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/smartCast/SmartCastAfterIf.kt");