diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeDependentAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeDependentAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java new file mode 100644 index 00000000000..a3892c60752 --- /dev/null +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeDependentAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.fir.test.cases.generated.cases.types; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode; +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/substitutors/typeSubstitution") +@TestDataPath("$PROJECT_ROOT") +public class FirIdeDependentAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated extends AbstractAnalysisApiSubstitutorsTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fir, + TestModuleKind.Source, + AnalysisSessionMode.Dependent, + AnalysisApiMode.Ide + ) + ); + } + + @Test + public void testAllFilesPresentInTypeSubstitution() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/substitutors/typeSubstitution"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("directSubstitution.kt") + public void testDirectSubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt"); + } + + @Test + @TestMetadata("emptySubstitution.kt") + public void testEmptySubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt"); + } + + @Test + @TestMetadata("notApplicableSubstitutor.kt") + public void testNotApplicableSubstitutor() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt"); + } + + @Test + @TestMetadata("substitutionWithTypeParams.kt") + public void testSubstitutionWithTypeParams() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt"); + } +} diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java new file mode 100644 index 00000000000..bdb44e2e7b0 --- /dev/null +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/types/FirIdeNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.fir.test.cases.generated.cases.types; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode; +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/substitutors/typeSubstitution") +@TestDataPath("$PROJECT_ROOT") +public class FirIdeNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated extends AbstractAnalysisApiSubstitutorsTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fir, + TestModuleKind.Source, + AnalysisSessionMode.Normal, + AnalysisApiMode.Ide + ) + ); + } + + @Test + public void testAllFilesPresentInTypeSubstitution() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/substitutors/typeSubstitution"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("directSubstitution.kt") + public void testDirectSubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt"); + } + + @Test + @TestMetadata("emptySubstitution.kt") + public void testEmptySubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt"); + } + + @Test + @TestMetadata("notApplicableSubstitutor.kt") + public void testNotApplicableSubstitutor() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt"); + } + + @Test + @TestMetadata("substitutionWithTypeParams.kt") + public void testSubstitutionWithTypeParams() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt"); + } +} diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSignatureSubstitutionTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSignatureSubstitutionTest.kt index c921cebd9df..27ebe141300 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSignatureSubstitutionTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSignatureSubstitutionTest.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSing import org.jetbrains.kotlin.analysis.test.framework.services.SubstitutionParser import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.model.TestModule @@ -20,11 +21,11 @@ import org.jetbrains.kotlin.test.services.assertions abstract class AbstractAnalysisApiSignatureSubstitutionTest : AbstractAnalysisApiSingleFileTest() { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { - val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) + val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) val actual = analyseForTest(declaration) { val symbol = declaration.getSymbolOfType() - val substitutor = with(SubstitutionParser) { parseSubstitutors(module, ktFile) }.single() + val substitutor = SubstitutionParser.parseSubstitutor(ktFile, declaration) val signatureBeforeSubstitution = symbol.asSignature() val signatureAfterSubstitution = signatureBeforeSubstitution.substitute(substitutor) diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSymbolSubstitutionTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSymbolSubstitutionTest.kt index 898898e4e19..f5e5855662b 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSymbolSubstitutionTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/signatureSubstitution/AbstractAnalysisApiSymbolSubstitutionTest.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSing import org.jetbrains.kotlin.analysis.test.framework.services.SubstitutionParser import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.model.TestModule @@ -20,11 +21,11 @@ import org.jetbrains.kotlin.test.services.assertions abstract class AbstractAnalysisApiSymbolSubstitutionTest : AbstractAnalysisApiSingleFileTest() { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { - val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) + val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) val actual = analyseForTest(declaration) { val symbol = declaration.getSymbolOfType() - val substitutor = with(SubstitutionParser) { parseSubstitutors(module, ktFile) }.single() + val substitutor = SubstitutionParser.parseSubstitutor(ktFile, declaration) val signature = symbol.substitute(substitutor) prettyPrint { diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt index 1a5b7925468..c004f51f7c6 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.calls.KtCall import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall @@ -20,6 +21,7 @@ import kotlin.reflect.KProperty1 import kotlin.reflect.KVisibility import kotlin.reflect.full.memberProperties +@OptIn(KtAnalysisApiInternals::class) internal fun KtAnalysisSession.stringRepresentation(any: Any): String = with(any) { fun KtType.render() = asStringForDebugging().replace('/', '.') fun String.indented() = replace("\n", "\n ") diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/types/AbstractAnalysisApiSubstitutorsTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/types/AbstractAnalysisApiSubstitutorsTest.kt new file mode 100644 index 00000000000..dcdb528c312 --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/types/AbstractAnalysisApiSubstitutorsTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types + +import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.analysis.api.symbols.getSymbolOfType +import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest +import org.jetbrains.kotlin.analysis.test.framework.services.SubstitutionParser +import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider +import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions + +abstract class AbstractAnalysisApiSubstitutorsTest : AbstractAnalysisApiSingleFileTest() { + override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { + val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) + val actual = analyseForTest(declaration) { + val substitutor = SubstitutionParser.parseSubstitutor(ktFile, declaration) + val symbol = declaration.getSymbolOfType() + val type = symbol.returnType + val substituted = substitutor.substitute(type) + val substitutedOrNull = substitutor.substituteOrNull(type) + + prettyPrint { + appendLine("PSI type: ${declaration.typeReference?.text}") + appendLine("KtType: ${type.render()}") + appendLine("substitutor.substitute: ${substituted.render()}") + appendLine("substitutor.substituteOrNull: ${substitutedOrNull?.render()}") + } + } + testServices.assertions.assertEqualsToTestDataFileSibling(actual) + } +} diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/types/FirStandaloneNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/types/FirStandaloneNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java new file mode 100644 index 00000000000..af08827ab5f --- /dev/null +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/types/FirStandaloneNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.standalone.fir.test.cases.generated.cases.types; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.standalone.fir.test.AnalysisApiFirStandaloneModeTestConfiguratorFactory; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode; +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode; +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/substitutors/typeSubstitution") +@TestDataPath("$PROJECT_ROOT") +public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiSubstitutorsTestGenerated extends AbstractAnalysisApiSubstitutorsTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFirStandaloneModeTestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fir, + TestModuleKind.Source, + AnalysisSessionMode.Normal, + AnalysisApiMode.Standalone + ) + ); + } + + @Test + public void testAllFilesPresentInTypeSubstitution() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/substitutors/typeSubstitution"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("directSubstitution.kt") + public void testDirectSubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt"); + } + + @Test + @TestMetadata("emptySubstitution.kt") + public void testEmptySubstitution() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt"); + } + + @Test + @TestMetadata("notApplicableSubstitutor.kt") + public void testNotApplicableSubstitutor() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt"); + } + + @Test + @TestMetadata("substitutionWithTypeParams.kt") + public void testSubstitutionWithTypeParams() throws Exception { + runTest("analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt"); + } +} diff --git a/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/function.kt b/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/function.kt index 0c97d691abe..6b2c392db3c 100644 --- a/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/function.kt +++ b/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/function.kt @@ -1,3 +1,3 @@ -// SUBSTITUTOR: T->kotlin.collections.List;S->kotlin.Long +// SUBSTITUTOR: T -> kotlin.collections.List, S -> kotlin.Long fun foo(x: List, y: Map>, k: String): T \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/property.kt b/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/property.kt index 683119b8034..0f66470b663 100644 --- a/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/property.kt +++ b/analysis/analysis-api/testData/components/signatureSubstitution/signatureSubstitution/property.kt @@ -1,3 +1,3 @@ -// SUBSTITUTOR: T->kotlin.collections.List;S->kotlin.Long +// SUBSTITUTOR: T-> kotlin.collections.List, S -> kotlin.Long val Map.value: List \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/function.kt b/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/function.kt index 0c97d691abe..6b2c392db3c 100644 --- a/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/function.kt +++ b/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/function.kt @@ -1,3 +1,3 @@ -// SUBSTITUTOR: T->kotlin.collections.List;S->kotlin.Long +// SUBSTITUTOR: T -> kotlin.collections.List, S -> kotlin.Long fun foo(x: List, y: Map>, k: String): T \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/property.kt b/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/property.kt index 683119b8034..664ef44276f 100644 --- a/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/property.kt +++ b/analysis/analysis-api/testData/components/signatureSubstitution/symbolSubstitution/property.kt @@ -1,3 +1,3 @@ -// SUBSTITUTOR: T->kotlin.collections.List;S->kotlin.Long +// SUBSTITUTOR: T -> kotlin.collections.List, S -> kotlin.Long val Map.value: List \ No newline at end of file diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt b/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt new file mode 100644 index 00000000000..96c3758caf8 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.kt @@ -0,0 +1,3 @@ +// SUBSTITUTOR: A -> kotlin.Int, B -> kotlin.String + +fun foo(): Map, B> \ No newline at end of file diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.txt b/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.txt new file mode 100644 index 00000000000..a9d75ea4906 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/directSubstitution.txt @@ -0,0 +1,4 @@ +PSI type: Map, B> +KtType: kotlin.collections.Map, B> +substitutor.substitute: kotlin.collections.Map, kotlin.String> +substitutor.substituteOrNull: kotlin.collections.Map, kotlin.String> diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt b/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt new file mode 100644 index 00000000000..b34f23d30e7 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.kt @@ -0,0 +1,3 @@ +// SUBSTITUTOR: A -> kotlin.Int + +fun foo(): List \ No newline at end of file diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.txt b/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.txt new file mode 100644 index 00000000000..d407df295b6 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/emptySubstitution.txt @@ -0,0 +1,4 @@ +PSI type: List +KtType: kotlin.collections.List +substitutor.substitute: kotlin.collections.List +substitutor.substituteOrNull: null diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt b/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt new file mode 100644 index 00000000000..3496014c512 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.kt @@ -0,0 +1,3 @@ +// SUBSTITUTOR: + +fun foo(): List \ No newline at end of file diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.txt b/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.txt new file mode 100644 index 00000000000..d407df295b6 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/notApplicableSubstitutor.txt @@ -0,0 +1,4 @@ +PSI type: List +KtType: kotlin.collections.List +substitutor.substitute: kotlin.collections.List +substitutor.substituteOrNull: null diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt b/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt new file mode 100644 index 00000000000..a20bab44b8e --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.kt @@ -0,0 +1,3 @@ +// SUBSTITUTOR: A -> B, B -> kotlin.Int + +fun foo(): Map, B> \ No newline at end of file diff --git a/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.txt b/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.txt new file mode 100644 index 00000000000..17f4e765f60 --- /dev/null +++ b/analysis/analysis-api/testData/substitutors/typeSubstitution/substitutionWithTypeParams.txt @@ -0,0 +1,4 @@ +PSI type: Map, B> +KtType: kotlin.collections.Map, B> +substitutor.substitute: kotlin.collections.Map, kotlin.Int> +substitutor.substituteOrNull: kotlin.collections.Map, kotlin.Int> diff --git a/analysis/analysis-test-framework/build.gradle.kts b/analysis/analysis-test-framework/build.gradle.kts index 45dd3b408ec..19a73242f63 100644 --- a/analysis/analysis-test-framework/build.gradle.kts +++ b/analysis/analysis-test-framework/build.gradle.kts @@ -33,3 +33,7 @@ projectTest(jUnitMode = JUnitMode.JUnit5) { testsJar() + +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += "-Xcontext-receivers" +} \ No newline at end of file diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt index 5025e012159..55150325b08 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/base/AbstractAnalysisApiBasedTest.kt @@ -104,7 +104,6 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() { useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray()) useDirectives(JvmEnvironmentConfigurationDirectives) - useDirectives(SubstitutionParser.Directives) useSourcePreprocessor(::ExpressionMarkersSourceFilePreprocessor) useAdditionalService { ExpressionMarkerProvider() } diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/SubstitutionParser.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/SubstitutionParser.kt index 64fb9d5c8b9..998ae7e71f1 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/SubstitutionParser.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/SubstitutionParser.kt @@ -5,45 +5,62 @@ package org.jetbrains.kotlin.analysis.test.framework.services +import com.intellij.psi.PsiComment import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.components.buildSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType -import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer -import org.jetbrains.kotlin.test.model.TestModule object SubstitutionParser { - fun KtAnalysisSession.parseSubstitutors(module: TestModule, file: KtFile): List { - val directives = module.directives[Directives.SUBSTITUTOR] - if (directives.isEmpty()) return emptyList() - val allTypeParameterSymbols = file + context(KtAnalysisSession) + fun parseSubstitutor(declaration: KtCallableDeclaration): KtSubstitutor { + val comment = declaration.firstChild as PsiComment + return parseSubstitutor(comment, declaration) + } + + context(KtAnalysisSession) + fun parseSubstitutor(ktFile: KtFile, declaration: KtCallableDeclaration): KtSubstitutor { + val comment = ktFile.children.filterIsInstance().single { it.text.startsWith(SUBSTITUTOR_PREFIX) } + return parseSubstitutor(comment, declaration) + } + + + context(KtAnalysisSession) + fun parseSubstitutor(comment: PsiComment, scopeForTypeParameters: KtElement): KtSubstitutor { + val directivesAsString = comment.text.trim() + check(directivesAsString.startsWith(SUBSTITUTOR_PREFIX)) + val substitutorAsMap = parseSubstitutions(directivesAsString.removePrefix(SUBSTITUTOR_PREFIX)) + + val allTypeParameterSymbols = scopeForTypeParameters .collectDescendantsOfType() .map { it.getTypeParameterSymbol() } .groupBy { it.name.asString() } .mapValues { it.value.single() } - return directives.map { subsitutor -> - buildSubstitutor { - subsitutor.forEach { (typeParameterName, typeString) -> - val typeParameterSymbol = allTypeParameterSymbols.getValue(typeParameterName) - val type = with(TypeParser) { parseTypeFromString(typeString, file, allTypeParameterSymbols) } - substitution(typeParameterSymbol, type) - } + return buildSubstitutor { + substitutorAsMap.forEach { (typeParameterName, typeString) -> + val typeParameterSymbol = allTypeParameterSymbols.getValue(typeParameterName) + val type = TypeParser.parseTypeFromString(typeString, scopeForTypeParameters, allTypeParameterSymbols) + substitution(typeParameterSymbol, type) } } } - object Directives : SimpleDirectivesContainer() { - val SUBSTITUTOR by valueDirective("") { stringValue -> - stringValue.trim().split(";").map { it.trim() }.map { substitution -> + private fun parseSubstitutions(substitutionsAsString: String): List> = + substitutionsAsString.trim().split(",") + .map { it.trim() } + .filter { it.isNotEmpty() } + .map { substitution -> val asList = substitution.split("->").map { it.trim() } check(asList.size == 2) { "Substitution should look like `x -> y` but was `$substitution`" } asList[0] to asList[1] } - } - } + + const val SUBSTITUTOR_PREFIX = "// SUBSTITUTOR:" } \ No newline at end of file diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/TypeParser.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/TypeParser.kt index ac7b30f7ffb..a72bded5783 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/TypeParser.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/TypeParser.kt @@ -15,16 +15,18 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* object TypeParser { - fun KtAnalysisSession.parseTypeFromString( + context (KtAnalysisSession) + fun parseTypeFromString( stringType: String, - ktFile: KtFile, + contextElement: KtElement, typeParameterByName: Map ): KtType { - val type = KtPsiFactory(ktFile).createType(stringType) + val type = KtPsiFactory(contextElement).createType(stringType) return convertType(type.typeElement ?: incorrectType(type), typeParameterByName) } - private fun KtAnalysisSession.convertType(type: KtTypeElement, typeParameterByName: Map): KtType = + context (KtAnalysisSession) + private fun convertType(type: KtTypeElement, typeParameterByName: Map): KtType = when (type) { is KtUserType -> { val qualifier = fullQualifier(type) diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt index 2ae9a858164..badd43532a7 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.scopes.AbstractSub import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByFqNameTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByPsiTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByReferenceTest +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind @@ -133,6 +134,12 @@ private fun AnalysisApiTestGroup.generateAnalysisApiNonComponentsTests() { model("annotationsOnFiles") } } + + group("substitutors", filter = frontendIs(FrontendKind.Fir)) { + test(AbstractAnalysisApiSubstitutorsTest::class) { + model("typeSubstitution") + } + } }