From 56910b70a397cf26efdb4c6c133d857a99385de7 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 30 Aug 2023 23:47:19 +0200 Subject: [PATCH] [Analysis API] fix "KotlinIllegalStateExceptionWithAttachments: expected as maximum one `expect` for the actual" ^KT-61597 fixed --- .../KtFe10MultiplatformInfoProvider.kt | 21 ++++++------------- ...rceModuleExpectForActualTestGenerated.java | 6 ++++++ .../KtFirMultiplatformInfoProvider.kt | 17 ++++----------- ...rceModuleExpectForActualTestGenerated.java | 6 ++++++ ...rceModuleExpectForActualTestGenerated.java | 6 ++++++ .../AbstractExpectForActualTest.kt | 9 +++++--- ...rceModuleExpectForActualTestGenerated.java | 6 ++++++ .../components/KtMultiplatformInfoProvider.kt | 7 ++++--- .../actual_object.descriptors.txt | 3 ++- .../expectForActual/actual_object.txt | 3 ++- .../multipleExpects.descriptors.txt | 1 + .../expectForActual/multipleExpects.kt | 19 +++++++++++++++++ .../expectForActual/multipleExpects.txt | 3 +++ 13 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.descriptors.txt create mode 100644 analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt create mode 100644 analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.txt diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10MultiplatformInfoProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10MultiplatformInfoProvider.kt index e914317b739..bbb43c1b8d8 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10MultiplatformInfoProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10MultiplatformInfoProvider.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.bas import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol import org.jetbrains.kotlin.analysis.api.symbols.psiSafe -import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier @@ -20,25 +19,17 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver internal class KtFe10MultiplatformInfoProvider( - override val analysisSession: KtFe10AnalysisSession + override val analysisSession: KtFe10AnalysisSession, ) : KtMultiplatformInfoProvider(), Fe10KtAnalysisSessionComponent { - override fun getExpectForActual(actual: KtDeclarationSymbol): KtDeclarationSymbol? { - if (actual.psiSafe()?.hasActualModifier() != true) return null - val memberDescriptor = (getSymbolDescriptor(actual) as? MemberDescriptor)?.takeIf { it.isActual } ?: return null + override fun getExpectForActual(actual: KtDeclarationSymbol): List { + if (actual.psiSafe()?.hasActualModifier() != true) return emptyList() + val memberDescriptor = (getSymbolDescriptor(actual) as? MemberDescriptor)?.takeIf { it.isActual } ?: return emptyList() val expectedCompatibilityMap = - ExpectedActualResolver.findExpectedForActual(memberDescriptor) ?: return null + ExpectedActualResolver.findExpectedForActual(memberDescriptor) ?: return emptyList() val expectsForActual = (expectedCompatibilityMap[ExpectActualCompatibility.Compatible] ?: expectedCompatibilityMap.values.flatten()) - check(expectsForActual.size <= 1) { "expected as maximum one `expect` for the actual" } - checkWithAttachment(expectsForActual.size <= 1, message = { "expected as maximum one `expect` for the actual" }) { - withEntry("actual", memberDescriptor.toString()) - withEntry("expectsForActualSize", expectsForActual.size.toString()) - for ((index, expectForActual) in expectsForActual.withIndex()) { - withEntry("expectsForActual$index", expectForActual.toString()) - } - } - return expectsForActual.singleOrNull()?.toKtSymbol(analysisContext) as? KtDeclarationSymbol + return expectsForActual.map { it.toKtSymbol(analysisContext) as KtDeclarationSymbol } } } \ No newline at end of file diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/multiplatformInfoProvider/Fe10IdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/multiplatformInfoProvider/Fe10IdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java index 11c7a9ebb1d..b5a486ae7ba 100644 --- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/multiplatformInfoProvider/Fe10IdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/multiplatformInfoProvider/Fe10IdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java @@ -51,4 +51,10 @@ public class Fe10IdeNormalAnalysisSourceModuleExpectForActualTestGenerated exten public void testAllFilesPresentInExpectForActual() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual"), Pattern.compile("^(.+)\\.kt$"), null, true); } + + @Test + @TestMetadata("multipleExpects.kt") + public void testMultipleExpects() throws Exception { + runTest("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt"); + } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirMultiplatformInfoProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirMultiplatformInfoProvider.kt index d18c1c60ae8..67319870a90 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirMultiplatformInfoProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirMultiplatformInfoProvider.kt @@ -10,8 +10,6 @@ import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol -import org.jetbrains.kotlin.fir.utils.exceptions.withFirSymbolEntry -import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment import org.jetbrains.kotlin.fir.declarations.expectForActual import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol @@ -22,7 +20,7 @@ internal class KtFirMultiplatformInfoProvider( override val analysisSession: KtFirAnalysisSession, override val token: KtLifetimeToken, ) : KtMultiplatformInfoProvider(), KtFirAnalysisSessionComponent { - override fun getExpectForActual(actual: KtDeclarationSymbol): KtDeclarationSymbol? { + override fun getExpectForActual(actual: KtDeclarationSymbol): List { require(actual is KtFirSymbol<*>) val firSymbol = actual.firSymbol val status = when (firSymbol) { @@ -31,16 +29,9 @@ internal class KtFirMultiplatformInfoProvider( is FirTypeAliasSymbol -> firSymbol.rawStatus else -> null } - if (status?.isActual != true) return null + if (status?.isActual != true) return emptyList() - val expectsForActual = firSymbol.expectForActual?.get(ExpectActualCompatibility.Compatible) ?: return null - checkWithAttachment(expectsForActual.size <= 1, message = { "expected as maximum one `expect` for the actual" }) { - withFirSymbolEntry("actual", firSymbol) - withEntry("expectsForActualSize", expectsForActual.size.toString()) - for ((index, expectForActual) in expectsForActual.withIndex()) { - withFirSymbolEntry("expectsForActual$index", expectForActual) - } - } - return expectsForActual.singleOrNull()?.let { analysisSession.firSymbolBuilder.buildSymbol(it) as? KtDeclarationSymbol } + val expectsForActual = firSymbol.expectForActual?.get(ExpectActualCompatibility.Compatible) ?: return emptyList() + return expectsForActual.map { analysisSession.firSymbolBuilder.buildSymbol(it) as KtDeclarationSymbol } } } \ No newline at end of file diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeDependentAnalysisSourceModuleExpectForActualTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeDependentAnalysisSourceModuleExpectForActualTestGenerated.java index 7aaf0fe51b8..48ed3ab59b7 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeDependentAnalysisSourceModuleExpectForActualTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeDependentAnalysisSourceModuleExpectForActualTestGenerated.java @@ -51,4 +51,10 @@ public class FirIdeDependentAnalysisSourceModuleExpectForActualTestGenerated ext public void testAllFilesPresentInExpectForActual() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual"), Pattern.compile("^(.+)\\.kt$"), null, true); } + + @Test + @TestMetadata("multipleExpects.kt") + public void testMultipleExpects() throws Exception { + runTest("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt"); + } } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java index 3f688ac8ac6..a2db2fe93a2 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirIdeNormalAnalysisSourceModuleExpectForActualTestGenerated.java @@ -51,4 +51,10 @@ public class FirIdeNormalAnalysisSourceModuleExpectForActualTestGenerated extend public void testAllFilesPresentInExpectForActual() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual"), Pattern.compile("^(.+)\\.kt$"), null, true); } + + @Test + @TestMetadata("multipleExpects.kt") + public void testMultipleExpects() throws Exception { + runTest("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt"); + } } diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/multiplatformInfoProvider/AbstractExpectForActualTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/multiplatformInfoProvider/AbstractExpectForActualTest.kt index 457c456a0fc..73a39795590 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/multiplatformInfoProvider/AbstractExpectForActualTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/multiplatformInfoProvider/AbstractExpectForActualTest.kt @@ -24,13 +24,16 @@ abstract class AbstractExpectForActualTest : AbstractAnalysisApiBasedTest() { val expectedSymbolText: String? = executeOnPooledThreadInReadAction { analyseForTest(declaration) { - val expectedSymbol = declaration.getSymbol().getExpectForActual() ?: return@analyseForTest null - expectedSymbol.psi?.containingFile?.name + " : " + expectedSymbol.render() + val expectedSymbols = declaration.getSymbol().getExpectsForActual() + expectedSymbols.joinToString(separator = "\n") { expectedSymbol -> + expectedSymbol.psi?.containingFile?.name + " : " + expectedSymbol.render() + } } } val actual = buildString { - appendLine("expected symbol: $expectedSymbolText") + appendLine("expected symbols:") + appendLine(expectedSymbolText) } testServices.assertions.assertEqualsToTestDataFileSibling(actual) diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirStandaloneNormalAnalysisSourceModuleExpectForActualTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirStandaloneNormalAnalysisSourceModuleExpectForActualTestGenerated.java index f4c5a4959b4..da2193e1ea8 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirStandaloneNormalAnalysisSourceModuleExpectForActualTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/multiplatformInfoProvider/FirStandaloneNormalAnalysisSourceModuleExpectForActualTestGenerated.java @@ -51,4 +51,10 @@ public class FirStandaloneNormalAnalysisSourceModuleExpectForActualTestGenerated public void testAllFilesPresentInExpectForActual() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual"), Pattern.compile("^(.+)\\.kt$"), null, true); } + + @Test + @TestMetadata("multipleExpects.kt") + public void testMultipleExpects() throws Exception { + runTest("analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt"); + } } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtMultiplatformInfoProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtMultiplatformInfoProvider.kt index 65df5843e06..96d609fded7 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtMultiplatformInfoProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtMultiplatformInfoProvider.kt @@ -9,15 +9,16 @@ import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol public abstract class KtMultiplatformInfoProvider : KtAnalysisSessionComponent() { - public abstract fun getExpectForActual(actual: KtDeclarationSymbol): KtDeclarationSymbol? + public abstract fun getExpectForActual(actual: KtDeclarationSymbol): List } public interface KtMultiplatformInfoProviderMixin : KtAnalysisSessionMixIn { /** * Gives expect symbol for the actual one if it is available. + * + * @return a single expect declaration corresponds to the [KtDeclarationSymbol] on valid code or multiple expects in a case of erroneous code with multiple expects. **/ - public fun KtDeclarationSymbol.getExpectForActual(): KtDeclarationSymbol? = + public fun KtDeclarationSymbol.getExpectsForActual(): List = withValidityAssertion { analysisSession.multiplatformInfoProvider.getExpectForActual(this) } - } \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.descriptors.txt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.descriptors.txt index f96ab8e3557..34692129f6c 100644 --- a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.descriptors.txt +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.descriptors.txt @@ -1 +1,2 @@ -expected symbol: null +expected symbols: + diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.txt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.txt index 68bbd71edee..00d2a58929e 100644 --- a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.txt +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.txt @@ -1 +1,2 @@ -expected symbol: Common.kt : object Platform +expected symbols: +Common.kt : object Platform diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.descriptors.txt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.descriptors.txt new file mode 100644 index 00000000000..e755e4f5b33 --- /dev/null +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.descriptors.txt @@ -0,0 +1 @@ +expected symbols: diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt new file mode 100644 index 00000000000..8bb62fbb03d --- /dev/null +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt @@ -0,0 +1,19 @@ +// !LANGUAGE: +MultiPlatformProjects + +// MODULE: commonMain1 +// FILE: Common1.kt + +package sample +expect fun foo() + +// MODULE: commonMain2 +// FILE: Common2.kt + +package sample +expect fun foo() + +// MODULE: androidMain(commonMain1, commonMain2) +// FILE: JvmAndroid.kt + +package sample +actual fun foo() {} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.txt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.txt new file mode 100644 index 00000000000..bd7843e6cc8 --- /dev/null +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.txt @@ -0,0 +1,3 @@ +expected symbols: +Common1.kt : fun foo() +Common2.kt : fun foo()