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 2ea37a8a692..ec972dc8daf 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 @@ -209,4 +209,32 @@ public class KtFe10HLExpressionTypeTestGenerated extends AbstractKtFe10HLExpress public void testWhileExpression() throws Exception { runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/whileExpression.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment") + @TestDataPath("$PROJECT_ROOT") + public class Assignment { + @Test + public void testAllFilesPresentInAssignment() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("arrayAssignementTarget.kt") + public void testArrayAssignementTarget() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.kt"); + } + + @Test + @TestMetadata("arrayAssignmentTargetUnresovledSet.kt") + public void testArrayAssignmentTargetUnresovledSet() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt"); + } + + @Test + @TestMetadata("arrayCompoundAssignementTarget.kt") + public void testArrayCompoundAssignementTarget() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.kt"); + } + } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt index e873ba568aa..1a46c91b769 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt @@ -39,6 +39,10 @@ internal class KtFirExpressionTypeProvider( override fun getKtExpressionType(expression: KtExpression): KtType? = withValidityAssertion { when (val fir = expression.unwrap().getOrBuildFir(firResolveState)) { + is FirFunctionCall -> { + getReturnTypeForArrayStyleAssignmentTarget(expression, fir) + ?: fir.typeRef.coneType.asKtType() + } is FirPropertyAccessExpression -> { // For unresolved `super`, we manually create an intersection type so that IDE features like completion can work correctly. val containingClass = @@ -78,6 +82,18 @@ internal class KtFirExpressionTypeProvider( } } + private fun getReturnTypeForArrayStyleAssignmentTarget( + expression: KtExpression, + fir: FirFunctionCall + ): KtType? { + if (fir.calleeReference !is FirResolvedNamedReference) return null + if (expression !is KtArrayAccessExpression) return null + val assignment = expression.parent as? KtBinaryExpression ?: return null + if (assignment.operationToken !in KtTokens.ALL_ASSIGNMENTS) return null + val setTargetArgumentParameter = fir.argumentMapping?.entries?.last()?.value ?: return null + return setTargetArgumentParameter.returnTypeRef.coneType.asKtType() + } + override fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KtType = withValidityAssertion { val firDeclaration = declaration.getOrBuildFirOfType(firResolveState) firDeclaration.returnTypeRef.coneType.asKtType() 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 592a3ffbb44..06282a27320 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 @@ -209,4 +209,32 @@ public class FirHLExpressionTypeTestGenerated extends AbstractFirHLExpressionTyp public void testWhileExpression() throws Exception { runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/whileExpression.kt"); } + + @Nested + @TestMetadata("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment") + @TestDataPath("$PROJECT_ROOT") + public class Assignment { + @Test + public void testAllFilesPresentInAssignment() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("arrayAssignementTarget.kt") + public void testArrayAssignementTarget() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.kt"); + } + + @Test + @TestMetadata("arrayAssignmentTargetUnresovledSet.kt") + public void testArrayAssignmentTargetUnresovledSet() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt"); + } + + @Test + @TestMetadata("arrayCompoundAssignementTarget.kt") + public void testArrayCompoundAssignementTarget() throws Exception { + runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.kt"); + } + } } 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 b356e17fde2..0c5b3b5252a 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.components.expressionTypeProvider +import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest @@ -24,7 +25,7 @@ abstract class AbstractHLExpressionTypeTest(configurator: FrontendApiTestConfigu else -> null } ?: error("expect an expression but got ${selected.text}") val type = executeOnPooledThreadInReadAction { - analyseForTest(expression) { expression.getKtType()?.render() } + analyseForTest(expression) { expression.getKtType()?.render(TYPE_RENDERING_OPTIONS) } } val actual = buildString { appendLine("expression: ${expression.text}") @@ -32,4 +33,8 @@ abstract class AbstractHLExpressionTypeTest(configurator: FrontendApiTestConfigu } testServices.assertions.assertEqualsToTestDataFileSibling(actual) } + + companion object { + private val TYPE_RENDERING_OPTIONS = KtTypeRendererOptions.DEFAULT.copy(renderUnresolvedTypeAsResolved = false) + } } \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.descriptors.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.descriptors.txt new file mode 100644 index 00000000000..4d419a2be39 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.descriptors.txt @@ -0,0 +1,2 @@ +expression: arr[0] +type: kotlin.Unit diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.kt new file mode 100644 index 00000000000..618faa73ae2 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.kt @@ -0,0 +1,4 @@ +fun foo() { + val arr = arrayOfNulls>(10) + arr[0] = emptyList() +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.txt new file mode 100644 index 00000000000..7fdd6a520df --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignementTarget.txt @@ -0,0 +1,2 @@ +expression: arr[0] +type: kotlin.collections.List<*>? diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.descriptors.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.descriptors.txt new file mode 100644 index 00000000000..4d419a2be39 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.descriptors.txt @@ -0,0 +1,2 @@ +expression: arr[0] +type: kotlin.Unit diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt new file mode 100644 index 00000000000..13084d15c34 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt @@ -0,0 +1,4 @@ +fun foo() { + val arr = 1 + arr[0] = 1 +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.txt new file mode 100644 index 00000000000..d4ab42a78b4 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.txt @@ -0,0 +1,2 @@ +expression: arr[0] +type: ERROR_TYPE diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.kt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.kt new file mode 100644 index 00000000000..3c02514f721 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.kt @@ -0,0 +1,4 @@ +fun foo() { + val arr = intArrayOf() + arr[0] += 1 +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.txt b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.txt new file mode 100644 index 00000000000..0461e58b462 --- /dev/null +++ b/analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayCompoundAssignementTarget.txt @@ -0,0 +1,2 @@ +expression: arr[0] +type: kotlin.Int