diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescNamedClassOrObjectSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescNamedClassOrObjectSymbol.kt index 226ba300ae7..67928f5dd87 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescNamedClassOrObjectSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescNamedClassOrObjectSymbol.kt @@ -50,6 +50,12 @@ internal class KtFe10DescNamedClassOrObjectSymbol( override val isExternal: Boolean get() = withValidityAssertion { descriptor.isExternal } + override val isActual: Boolean + get() = withValidityAssertion { descriptor.isActual } + + override val isExpect: Boolean + get() = withValidityAssertion { descriptor.isExpect } + override val companionObject: KtNamedClassOrObjectSymbol? get() { withValidityAssertion { diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescTypeAliasSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescTypeAliasSymbol.kt index b2203cb6b53..fef08a3e386 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescTypeAliasSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescTypeAliasSymbol.kt @@ -45,6 +45,9 @@ internal class KtFe10DescTypeAliasSymbol( override val classIdIfNonLocal: ClassId? get() = withValidityAssertion { descriptor.classId } + override val isActual: Boolean get() = withValidityAssertion { descriptor.isActual } + override val isExpect: Boolean get() = withValidityAssertion { descriptor.isExpect } + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer() diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiNamedClassOrObjectSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiNamedClassOrObjectSymbol.kt index 761917a520d..832ca3e9a36 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiNamedClassOrObjectSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiNamedClassOrObjectSymbol.kt @@ -36,6 +36,8 @@ import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtObjectDeclaration +import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.resolve.BindingContext internal class KtFe10PsiNamedClassOrObjectSymbol( @@ -62,6 +64,12 @@ internal class KtFe10PsiNamedClassOrObjectSymbol( override val isExternal: Boolean get() = withValidityAssertion { psi.hasModifier(KtTokens.EXTERNAL_KEYWORD) } + override val isActual: Boolean + get() = withValidityAssertion { descriptor?.isActual ?: psi.hasActualModifier() } + + override val isExpect: Boolean + get() = withValidityAssertion { descriptor?.isExpect ?: psi.hasExpectModifier() } + override val companionObject: KtNamedClassOrObjectSymbol? get() = withValidityAssertion { val companionObject = psi.companionObjects.firstOrNull() ?: return null diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiTypeAliasSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiTypeAliasSymbol.kt index d0f69f01560..d767850858d 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiTypeAliasSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiTypeAliasSymbol.kt @@ -30,6 +30,8 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtTypeAlias +import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.resolve.BindingContext internal class KtFe10PsiTypeAliasSymbol( @@ -59,6 +61,9 @@ internal class KtFe10PsiTypeAliasSymbol( override val symbolKind: KtSymbolKind get() = withValidityAssertion { psi.ktSymbolKind } + override val isActual: Boolean get() = withValidityAssertion { descriptor?.isActual ?: psi.hasActualModifier() } + override val isExpect: Boolean get() = withValidityAssertion { descriptor?.isExpect ?: psi.hasExpectModifier() } + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer() diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java new file mode 100644 index 00000000000..33921562ac0 --- /dev/null +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2023 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.fe10.test.cases.generated.cases.symbols; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.analysis.api.fe10.test.configurator.AnalysisApiFe10TestConfiguratorFactory; +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.symbols.AbstractMultiModuleSymbolByPsiTest; +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 org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi") +@TestDataPath("$PROJECT_ROOT") +public class Fe10IdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated extends AbstractMultiModuleSymbolByPsiTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFe10TestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fe10, + TestModuleKind.Source, + AnalysisSessionMode.Normal, + AnalysisApiMode.Ide + ) + ); + } + + @Test + public void testAllFilesPresentInMultiModuleSymbolByPsi() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("expectActual.kt") + public void testExpectActual() throws Exception { + runTest("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt"); + } +} diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt index 2d508f21d19..7a9d86f8c90 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbol.kt @@ -71,6 +71,8 @@ internal class KtFirNamedClassOrObjectSymbol( override val isInline: Boolean get() = withValidityAssertion { firSymbol.isInline } override val isFun: Boolean get() = withValidityAssertion { firSymbol.isFun } override val isExternal: Boolean get() = withValidityAssertion { firSymbol.isExternal } + override val isActual: Boolean get() = withValidityAssertion { firSymbol.isActual } + override val isExpect: Boolean get() = withValidityAssertion { firSymbol.isExpect } override val contextReceivers: List get() = withValidityAssertion { firSymbol.createContextReceivers(builder) } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt index 16dfc6d04e1..bff0b032c99 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt @@ -107,6 +107,9 @@ internal class KtFirPsiJavaClassSymbol( override val isInline: Boolean get() = withValidityAssertion { false } override val isFun: Boolean get() = withValidityAssertion { false } override val isExternal: Boolean get() = withValidityAssertion { false } + override val isActual: Boolean get() = withValidityAssertion { false } + override val isExpect: Boolean get() = withValidityAssertion { false } + override val companionObject: KtNamedClassOrObjectSymbol? get() = withValidityAssertion { null } override val contextReceivers: List get() = withValidityAssertion { emptyList() } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAliasSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAliasSymbol.kt index e5680a7491b..3ade118fdf7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAliasSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAliasSymbol.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.analysis.api.symbols.pointers.UnsupportedSymbolKind import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.fir.declarations.utils.isActual +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.name.ClassId @@ -54,6 +56,9 @@ internal class KtFirTypeAliasSymbol( override val symbolKind: KtSymbolKind get() = withValidityAssertion { getSymbolKind() } + override val isActual: Boolean get() = withValidityAssertion { firSymbol.isActual } + override val isExpect: Boolean get() = withValidityAssertion { firSymbol.isExpect } + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java new file mode 100644 index 00000000000..3dbbd660e57 --- /dev/null +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2023 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.symbols; + +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.symbols.AbstractMultiModuleSymbolByPsiTest; +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 org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi") +@TestDataPath("$PROJECT_ROOT") +public class FirIdeNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated extends AbstractMultiModuleSymbolByPsiTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fir, + TestModuleKind.Source, + AnalysisSessionMode.Normal, + AnalysisApiMode.Ide + ) + ); + } + + @Test + public void testAllFilesPresentInMultiModuleSymbolByPsi() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("expectActual.kt") + public void testExpectActual() throws Exception { + runTest("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt"); + } +} diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractMultiModuleSymbolByPsiTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractMultiModuleSymbolByPsiTest.kt new file mode 100644 index 00000000000..ea1ec9c3f98 --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractMultiModuleSymbolByPsiTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2023 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.symbols + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForDebug +import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer +import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiBasedTest +import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider +import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter +import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.services.TestModuleStructure +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions + +abstract class AbstractMultiModuleSymbolByPsiTest : AbstractAnalysisApiBasedTest() { + override fun doTestByModuleStructure(moduleStructure: TestModuleStructure, testServices: TestServices) { + val modules = moduleStructure.modules + val files = modules.flatMap { testServices.ktModuleProvider.getModuleFiles(it).filterIsInstance() } + + val debugRenderer = DebugSymbolRenderer() + + val debugPrinter = PrettyPrinter() + val prettyPrinter = PrettyPrinter(indentSize = 4) + + for (file in files) { + val fileDirective = "// FILE: ${file.name}\n" + debugPrinter.appendLine(fileDirective) + prettyPrinter.appendLine(fileDirective) + + analyseForTest(file) { + file.forEachDescendantOfType(predicate = { it.isValidForSymbolCreation }) { declaration -> + val symbol = declaration.getSymbol() + + debugPrinter.appendLine(debugRenderer.render(symbol)) + debugPrinter.appendLine() + + prettyPrinter.withIndents(indentCount = declaration.parentsOfType(withSelf = false).count()) { + prettyPrinter.appendLine(symbol.render(KtDeclarationRendererForDebug.WITH_QUALIFIED_NAMES)) + prettyPrinter.appendLine() + } + } + } + } + + testServices.assertions.assertEqualsToTestDataFileSibling(debugPrinter.toString()) + testServices.assertions.assertEqualsToTestDataFileSibling(prettyPrinter.toString(), extension = ".pretty.txt") + } + + /** + * Processes the descendants of the element using the preorder implementation of tree traversal. + */ + private inline fun PsiElement.forEachDescendantOfType( + noinline predicate: (T) -> Boolean = { true }, + noinline action: (T) -> Unit, + ) = this.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + if (element is T && predicate(element)) { + action(element) + } + super.visitElement(element) + } + }) +} \ No newline at end of file diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt index 1f97f652059..360cee546da 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt @@ -6,7 +6,8 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.test.services.TestServices @@ -23,14 +24,4 @@ abstract class AbstractSymbolByPsiTest : AbstractSymbolTest() { listOf(ktFile.getFileSymbol()), ) } - - private val KtDeclaration.isValidForSymbolCreation - get() = when (this) { - is KtBackingField -> false - is KtDestructuringDeclaration -> false - is KtPropertyAccessor -> false - is KtParameter -> !this.isFunctionTypeParameter && this.parent !is KtParameterList - is KtNamedFunction -> this.name != null - else -> true - } } diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt index 3e777f04baa..4d81ee16a13 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSing import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind import org.jetbrains.kotlin.analysis.test.framework.utils.executeOnPooledThreadInReadAction import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint -import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.directives.model.Directive import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives @@ -345,6 +345,16 @@ enum class PrettyRendererOption(val transformation: (KtDeclarationRenderer) -> K ) } +internal val KtDeclaration.isValidForSymbolCreation + get() = when (this) { + is KtBackingField -> false + is KtDestructuringDeclaration -> false + is KtPropertyAccessor -> false + is KtParameter -> !this.isFunctionTypeParameter && this.parent !is KtParameterList + is KtNamedFunction -> this.name != null + else -> true + } + data class SymbolsData( val symbols: List, val symbolsForPrettyRendering: List = symbols, diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java new file mode 100644 index 00000000000..f90ee1a3627 --- /dev/null +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2023 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.symbols; + +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.symbols.AbstractMultiModuleSymbolByPsiTest; +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 org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi") +@TestDataPath("$PROJECT_ROOT") +public class FirStandaloneNormalAnalysisSourceModuleMultiModuleSymbolByPsiTestGenerated extends AbstractMultiModuleSymbolByPsiTest { + @NotNull + @Override + public AnalysisApiTestConfigurator getConfigurator() { + return AnalysisApiFirStandaloneModeTestConfiguratorFactory.INSTANCE.createConfigurator( + new AnalysisApiTestConfiguratorFactoryData( + FrontendKind.Fir, + TestModuleKind.Source, + AnalysisSessionMode.Normal, + AnalysisApiMode.Standalone + ) + ); + } + + @Test + public void testAllFilesPresentInMultiModuleSymbolByPsi() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("expectActual.kt") + public void testExpectActual() throws Exception { + runTest("analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt"); + } +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtClassLikeSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtClassLikeSymbol.kt index 6068a4c4c8a..0b026358f5e 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtClassLikeSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtClassLikeSymbol.kt @@ -33,7 +33,7 @@ public abstract class KtTypeParameterSymbol : KtClassifierSymbol(), KtNamedSymbo public abstract val isReified: Boolean } -public sealed class KtClassLikeSymbol : KtClassifierSymbol(), KtSymbolWithKind, KtPossibleMemberSymbol { +public sealed class KtClassLikeSymbol : KtClassifierSymbol(), KtSymbolWithKind, KtPossibleMemberSymbol, KtPossibleMultiplatformSymbol { public abstract val classIdIfNonLocal: ClassId? context(KtAnalysisSession) @@ -68,6 +68,8 @@ public abstract class KtAnonymousObjectSymbol : KtClassOrObjectSymbol() { final override val classIdIfNonLocal: ClassId? get() = withValidityAssertion { null } final override val symbolKind: KtSymbolKind get() = withValidityAssertion { KtSymbolKind.LOCAL } final override val name: Name? get() = withValidityAssertion { null } + final override val isActual: Boolean get() = withValidityAssertion { false } + final override val isExpect: Boolean get() = withValidityAssertion { false } final override val typeParameters: List get() = withValidityAssertion { emptyList() } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt index ec443d067d8..084fda9eb73 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt @@ -19,4 +19,27 @@ public interface KtNamedSymbol : KtPossiblyNamedSymbol { public interface KtSymbolWithTypeParameters : KtSymbol { public val typeParameters: List +} + +/** + * A marker interface for symbols which could potentially be `expect` or `actual`. For more details about `expect` and `actual` + * declarations, see [documentation](https://kotlinlang.org/docs/multiplatform-connect-to-apis.html). + */ +public interface KtPossibleMultiplatformSymbol : KtSymbol { + /** + * Returns true if the declaration is a platform-specific implementation in a multiplatform project. + */ + public val isActual: Boolean + + /** + * Returns true if the declaration is platform-specific declaration in a multiplatform project. An implementation + * in platform modules is expected. Note, that in the following example: + * ``` + * expect class A { + * class Nested + * } + * ``` + * `isExpect` returns `true` for both `A` and `A.Nested`. + */ + public val isExpect: Boolean } \ No newline at end of file diff --git a/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt new file mode 100644 index 00000000000..1c7d862d8a6 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.kt @@ -0,0 +1,30 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: commonMain +// FILE: Common.kt + +package sample +expect object A + +expect class B { + class Nested +} + +expect class C { + class Nested +} + +// MODULE: androidMain(commonMain) +// FILE: JvmAndroid.kt + +package sample +actual object A + +actual class B { + actual class Nested +} + +actual typealias C = D + +class D { + class Nested +} diff --git a/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.pretty.txt b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.pretty.txt new file mode 100644 index 00000000000..049dd67a8d0 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.pretty.txt @@ -0,0 +1,26 @@ +// FILE: Common.kt + +object A + +class B + + class Nested + +class C + + class Nested + +// FILE: JvmAndroid.kt + +object A + +class B + + class Nested + +typealias C = sample.D + +class D + + class Nested + diff --git a/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.txt b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.txt new file mode 100644 index 00000000000..df00e46dde1 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/multiModuleSymbolByPsi/expectActual.txt @@ -0,0 +1,278 @@ +// FILE: Common.kt + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/A + classKind: OBJECT + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: true + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: A + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/B + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: true + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: B + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/B.Nested + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: true + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: Nested + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: CLASS_MEMBER + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/C + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: true + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: C + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/C.Nested + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: true + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: Nested + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: CLASS_MEMBER + typeParameters: [] + visibility: Public + +// FILE: JvmAndroid.kt + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/A + classKind: OBJECT + companionObject: null + contextReceivers: [] + isActual: true + isData: false + isExpect: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: A + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/B + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: true + isData: false + isExpect: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: B + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/B.Nested + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: true + isData: false + isExpect: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: Nested + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: CLASS_MEMBER + typeParameters: [] + visibility: Public + +KtTypeAliasSymbol: + annotationsList: [] + classIdIfNonLocal: sample/C + expandedType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: sample/D + isActual: true + isExpect: false + name: C + origin: SOURCE + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/D + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: D + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + +KtNamedClassOrObjectSymbol: + annotationsList: [] + classIdIfNonLocal: sample/D.Nested + classKind: CLASS + companionObject: null + contextReceivers: [] + isActual: false + isData: false + isExpect: false + isExternal: false + isFun: false + isInline: false + isInner: false + modality: FINAL + name: Nested + origin: SOURCE + superTypes: [ + KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Any + ] + symbolKind: CLASS_MEMBER + typeParameters: [] + visibility: Public diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/printer/PrettyPrinter.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/printer/PrettyPrinter.kt index 7f638f753d8..f99b963d754 100644 --- a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/printer/PrettyPrinter.kt +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/printer/PrettyPrinter.kt @@ -61,6 +61,13 @@ public class PrettyPrinter(public val indentSize: Int = 2) : Appendable { indent -= 1 } + public inline fun withIndents(indentCount: Int, block: PrettyPrinter.() -> Unit) { + require(indentCount >= 0) { "Number of indents should be non-negative" } + indent += indentCount + block(this) + indent -= indentCount + } + public inline fun withIndentInBraces(block: PrettyPrinter.() -> Unit) { withIndentWrapped(before = "{", after = "}", block) } 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 c6130b585ae..eebc36b3f36 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 @@ -44,7 +44,10 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeInf import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractAnalysisApiGetSuperTypesTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractHasCommonSubtypeTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractTypeReferenceTest -import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.* +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceResolveTest +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceResolveWithResolveExtensionTest +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerForWholeFileTest +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.* import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractTypeByDeclarationReturnTypeTest @@ -111,6 +114,10 @@ private fun AnalysisApiTestGroup.generateAnalysisApiNonComponentsTests() { model("symbolRestoreFromDifferentModule") } + test(AbstractMultiModuleSymbolByPsiTest::class) { + model("multiModuleSymbolByPsi") + } + test( AbstractSymbolByFqNameTest::class ) {