diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ExpressionTypeProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ExpressionTypeProvider.kt
index da5a3d12af4..86e935516a1 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ExpressionTypeProvider.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ExpressionTypeProvider.kt
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
import org.jetbrains.kotlin.resolve.calls.smartcasts.MultipleSmartCasts
+import org.jetbrains.kotlin.resolve.calls.smartcasts.SingleSmartCast
import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getType
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.resolve.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.resolve.sam.getFunctionTypeForAbstractMethod
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeUtils
+import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
import org.jetbrains.kotlin.types.typeUtil.makeNullable
class KtFe10ExpressionTypeProvider(
@@ -54,7 +56,12 @@ class KtFe10ExpressionTypeProvider(
}
val bindingContext = analysisContext.analyze(unwrapped, AnalysisMode.PARTIAL)
- val kotlinType = expression.getType(bindingContext) ?: analysisContext.builtIns.unitType
+ val smartCastType = when (val smartCastType = bindingContext[BindingContext.SMARTCAST, expression]) {
+ is SingleSmartCast -> smartCastType.type
+ is MultipleSmartCasts -> intersectWrappedTypes(smartCastType.map.values)
+ else -> null
+ }
+ val kotlinType = smartCastType ?: expression.getType(bindingContext) ?: analysisContext.builtIns.unitType
return kotlinType.toKtType(analysisContext)
}
diff --git a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/expressionTypeProvider/KtFe10HLExpressionTypeTestGenerated.java b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/expressionTypeProvider/KtFe10HLExpressionTypeTestGenerated.java
index ab2da09d056..2ea37a8a692 100644
--- a/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/expressionTypeProvider/KtFe10HLExpressionTypeTestGenerated.java
+++ b/analysis/analysis-api-fe10/tests/org/jetbrains/kotlin/analysis/api/descriptors/test/components/expressionTypeProvider/KtFe10HLExpressionTypeTestGenerated.java
@@ -156,6 +156,30 @@ public class KtFe10HLExpressionTypeTestGenerated extends AbstractKtFe10HLExpress
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/returnExpression.kt");
}
+ @Test
+ @TestMetadata("smartcast_asCallArg.kt")
+ public void testSmartcast_asCallArg() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_asReceiver.kt")
+ public void testSmartcast_asReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_multi.kt")
+ public void testSmartcast_multi() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_unused.kt")
+ public void testSmartcast_unused() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt");
+ }
+
@Test
@TestMetadata("stringLiteral.kt")
public void testStringLiteral() throws Exception {
diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/expressionTypeProvider/FirHLExpressionTypeTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/expressionTypeProvider/FirHLExpressionTypeTestGenerated.java
index a319b3d5e9d..592a3ffbb44 100644
--- a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/expressionTypeProvider/FirHLExpressionTypeTestGenerated.java
+++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/expressionTypeProvider/FirHLExpressionTypeTestGenerated.java
@@ -156,6 +156,30 @@ public class FirHLExpressionTypeTestGenerated extends AbstractFirHLExpressionTyp
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/returnExpression.kt");
}
+ @Test
+ @TestMetadata("smartcast_asCallArg.kt")
+ public void testSmartcast_asCallArg() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_asReceiver.kt")
+ public void testSmartcast_asReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_multi.kt")
+ public void testSmartcast_multi() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt");
+ }
+
+ @Test
+ @TestMetadata("smartcast_unused.kt")
+ public void testSmartcast_unused() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt");
+ }
+
@Test
@TestMetadata("stringLiteral.kt")
public void testStringLiteral() throws Exception {
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/expressionTypeProvider/AbstractHLExpressionTypeTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/expressionTypeProvider/AbstractHLExpressionTypeTest.kt
index c1beefbb810..b356e17fde2 100644
--- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/expressionTypeProvider/AbstractHLExpressionTypeTest.kt
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/expressionTypeProvider/AbstractHLExpressionTypeTest.kt
@@ -10,13 +10,19 @@ import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProv
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractHLExpressionTypeTest(configurator: FrontendApiTestConfiguratorService) : AbstractHLApiSingleFileTest(configurator) {
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
- val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression
+ val selected = testServices.expressionMarkerProvider.getSelectedElement(ktFile)
+ val expression = when (selected) {
+ is KtExpression -> selected
+ is KtValueArgument -> selected.getArgumentExpression()
+ else -> null
+ } ?: error("expect an expression but got ${selected.text}")
val type = executeOnPooledThreadInReadAction {
analyseForTest(expression) { expression.getKtType()?.render() }
}
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt
new file mode 100644
index 00000000000..17b7b9b760d
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt
@@ -0,0 +1,7 @@
+fun test(a: Any) {
+ if (a is String) {
+ takeString(a)
+ }
+}
+
+fun takeString(s: String) {}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.txt
new file mode 100644
index 00000000000..693c21a0e31
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.txt
@@ -0,0 +1,2 @@
+expression: a
+type: kotlin.String
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt
new file mode 100644
index 00000000000..6a07e02836d
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt
@@ -0,0 +1,5 @@
+fun test(a: Any) {
+ if (a is String) {
+ a.length
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.txt
new file mode 100644
index 00000000000..693c21a0e31
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.txt
@@ -0,0 +1,2 @@
+expression: a
+type: kotlin.String
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.descriptors.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.descriptors.txt
new file mode 100644
index 00000000000..044cafcec08
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.descriptors.txt
@@ -0,0 +1,2 @@
+expression: a
+type: kotlin.Any
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt
new file mode 100644
index 00000000000..b9244d81b19
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt
@@ -0,0 +1,10 @@
+interface A
+interface B
+
+fun T.take() where T: A, T: B {}
+
+fun test(a: Any) {
+ if (a is A && a is B) {
+ a.take()
+ }
+}
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.txt
new file mode 100644
index 00000000000..e3a20081819
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.txt
@@ -0,0 +1,2 @@
+expression: a
+type: (A&B)
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.descriptors.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.descriptors.txt
new file mode 100644
index 00000000000..044cafcec08
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.descriptors.txt
@@ -0,0 +1,2 @@
+expression: a
+type: kotlin.Any
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt
new file mode 100644
index 00000000000..83b06340d2f
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt
@@ -0,0 +1,5 @@
+fun test(a: Any) {
+ if (a is String) {
+ a
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.txt
new file mode 100644
index 00000000000..693c21a0e31
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.txt
@@ -0,0 +1,2 @@
+expression: a
+type: kotlin.String