Save project state for reproducer
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceProviders.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceProviders.kt index 59399cd..f88e032 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceProviders.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceProviders.kt
@@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization +import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile @@ -13,25 +14,37 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource internal interface DeserializedContainerSourceProvider { - fun getContainerSource(file: KtFile, origin: KotlinStubOrigin?): DeserializedContainerSource? + fun getContainerSource( + file: KtFile, + stubOrigin: KotlinStubOrigin?, + declarationOrigin: FirDeclarationOrigin, + ): DeserializedContainerSource? } // Currently, `null` is returned for KLIBs to avoid incorrect application of JVM file facade logic and overload filtering. // We might want to provide non-`null` container source for all types of binaries in the future. -internal object NoSourceDeserializedContainerSourceProvider : DeserializedContainerSourceProvider { - override fun getContainerSource(file: KtFile, origin: KotlinStubOrigin?): DeserializedContainerSource? = null +internal object NullDeserializedContainerSourceProvider : DeserializedContainerSourceProvider { + override fun getContainerSource( + file: KtFile, + stubOrigin: KotlinStubOrigin?, + declarationOrigin: FirDeclarationOrigin, + ): DeserializedContainerSource? = null } internal object JvmDeserializedContainerSourceProvider : DeserializedContainerSourceProvider { - override fun getContainerSource(file: KtFile, origin: KotlinStubOrigin?): DeserializedContainerSource { - return when (origin) { + override fun getContainerSource( + file: KtFile, + stubOrigin: KotlinStubOrigin?, + declarationOrigin: FirDeclarationOrigin, + ): DeserializedContainerSource { + return when (stubOrigin) { is KotlinStubOrigin.Facade -> { - val className = JvmClassName.byInternalName(origin.className) + val className = JvmClassName.byInternalName(stubOrigin.className) JvmStubDeserializedFacadeContainerSource(className, facadeClassName = null) } is KotlinStubOrigin.MultiFileFacade -> { - val className = JvmClassName.byInternalName(origin.className) - val facadeClassName = JvmClassName.byInternalName(origin.facadeClassName) + val className = JvmClassName.byInternalName(stubOrigin.className) + val facadeClassName = JvmClassName.byInternalName(stubOrigin.facadeClassName) JvmStubDeserializedFacadeContainerSource(className, facadeClassName) } else -> { @@ -45,13 +58,31 @@ } internal object BuiltinsDeserializedContainerSourceProvider : DeserializedContainerSourceProvider { - override fun getContainerSource(file: KtFile, origin: KotlinStubOrigin?): DeserializedContainerSource? { - require(origin is KotlinStubOrigin.Facade) { - "Expected builtins file to have Facade origin, got origin=$origin instead" + override fun getContainerSource( + file: KtFile, + stubOrigin: KotlinStubOrigin?, + declarationOrigin: FirDeclarationOrigin, + ): DeserializedContainerSource { + require(stubOrigin is KotlinStubOrigin.Facade) { + "Expected builtins file to have Facade origin, got origin=$stubOrigin instead" } return JvmStubDeserializedBuiltInsContainerSource( - facadeClassName = JvmClassName.byInternalName(origin.className) + facadeClassName = JvmClassName.byInternalName(stubOrigin.className) ) } } + +internal object JvmAndBuiltinsDeserializedContainerSourceProvider : DeserializedContainerSourceProvider { + override fun getContainerSource( + file: KtFile, + stubOrigin: KotlinStubOrigin?, + declarationOrigin: FirDeclarationOrigin + ): DeserializedContainerSource? { + if (declarationOrigin is FirDeclarationOrigin.BuiltIns) { + return BuiltinsDeserializedContainerSourceProvider.getContainerSource(file, stubOrigin, declarationOrigin) + } + + return JvmDeserializedContainerSourceProvider.getContainerSource(file, stubOrigin, declarationOrigin) + } +}
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirDeserializedSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirDeserializedSymbolProvider.kt index a0e8c50..f782427 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirDeserializedSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirDeserializedSymbolProvider.kt
@@ -30,9 +30,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentOfType import org.jetbrains.kotlin.psi.stubs.impl.* -import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty typealias DeserializedTypeAliasPostProcessor = (FirTypeAliasSymbol) -> Unit @@ -174,8 +172,9 @@ for (function in topLevelFunctions) { val functionStub = function.stub as? KotlinFunctionStubImpl ?: loadStubByElement(function) val functionFile = function.containingKtFile - val containerSource = deserializedContainerSourceProvider.getContainerSource(functionFile, functionStub?.origin) val functionOrigin = getDeclarationOriginFor(functionFile) + val containerSource = + deserializedContainerSourceProvider.getContainerSource(functionFile, functionStub?.origin, functionOrigin) if (functionOrigin != FirDeclarationOrigin.BuiltIns && containerSource is FacadeClassSource && @@ -200,8 +199,12 @@ for (property in topLevelProperties) { val propertyStub = property.stub as? KotlinPropertyStubImpl ?: loadStubByElement(property) val propertyFile = property.containingKtFile - val containerSource = deserializedContainerSourceProvider.getContainerSource(propertyFile, propertyStub?.origin) val propertyOrigin = getDeclarationOriginFor(propertyFile) + val containerSource = deserializedContainerSourceProvider.getContainerSource( + propertyFile, + propertyStub?.origin, + propertyOrigin, + ) val symbol = FirPropertySymbol(callableId) val rootContext = StubBasedFirDeserializationContext
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirSymbolProviderFactories.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirSymbolProviderFactories.kt index 15a60a5..0d554c7 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirSymbolProviderFactories.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirSymbolProviderFactories.kt
@@ -31,7 +31,7 @@ session, moduleDataProvider, kotlinScopeProvider, - JvmDeserializedContainerSourceProvider, + JvmAndBuiltinsDeserializedContainerSourceProvider, isFallbackDependenciesProvider, fileFilter = { file -> val extension = file.extension @@ -52,7 +52,7 @@ session, moduleDataProvider, kotlinScopeProvider, - NoSourceDeserializedContainerSourceProvider, + NullDeserializedContainerSourceProvider, isFallbackDependenciesProvider, fileFilter = { file -> val extension = file.extension @@ -76,7 +76,7 @@ session, moduleDataProvider, kotlinScopeProvider, - NoSourceDeserializedContainerSourceProvider, + NullDeserializedContainerSourceProvider, isFallbackDependenciesProvider, fileFilter = { file -> file.extension == KLIB_METADATA_FILE_EXTENSION }, )
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.kt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.kt new file mode 100644 index 0000000..e8bb35d --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.kt
@@ -0,0 +1,5 @@ +// DECLARATION_TYPE: org.jetbrains.kotlin.psi.KtNamedFunction + +package test + +fun fn() = Unit
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.txt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.txt new file mode 100644 index 0000000..d2758bf --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.txt
@@ -0,0 +1,8 @@ +KT element: KtNamedFunction +KT element text: +public fun fn(): kotlin.Unit { /* compiled code */ } +FIR element: FirSimpleFunctionImpl +FIR source kind: KtRealSourceElementKind + +FIR element rendered: +public final [ResolvedTo(BODY_RESOLVE)] fun fn(): R|kotlin/Unit|
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.kt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.kt new file mode 100644 index 0000000..aee7bb2 --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.kt
@@ -0,0 +1,7 @@ +// DECLARATION_TYPE: org.jetbrains.kotlin.psi.KtNamedFunction + +@file:JvmName("ChangedFileName") + +package test + +fun fn() = Unit
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.txt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.txt new file mode 100644 index 0000000..d2758bf --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.txt
@@ -0,0 +1,8 @@ +KT element: KtNamedFunction +KT element text: +public fun fn(): kotlin.Unit { /* compiled code */ } +FIR element: FirSimpleFunctionImpl +FIR source kind: KtRealSourceElementKind + +FIR element rendered: +public final [ResolvedTo(BODY_RESOLVE)] fun fn(): R|kotlin/Unit|
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.kt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.kt new file mode 100644 index 0000000..e8bb35d --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.kt
@@ -0,0 +1,5 @@ +// DECLARATION_TYPE: org.jetbrains.kotlin.psi.KtNamedFunction + +package test + +fun fn() = Unit
diff --git a/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.txt b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.txt new file mode 100644 index 0000000..d2758bf --- /dev/null +++ b/analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.txt
@@ -0,0 +1,8 @@ +KT element: KtNamedFunction +KT element text: +public fun fn(): kotlin.Unit { /* compiled code */ } +FIR element: FirSimpleFunctionImpl +FIR source kind: KtRealSourceElementKind + +FIR element rendered: +public final [ResolvedTo(BODY_RESOLVE)] fun fn(): R|kotlin/Unit|
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractDeserializedContainerSourceFirTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractDeserializedContainerSourceFirTest.kt new file mode 100644 index 0000000..d1659fd --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractDeserializedContainerSourceFirTest.kt
@@ -0,0 +1,109 @@ +/* + * Copyright 2010-2024 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.low.level.api.fir + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirLibraryBinaryDecompiledTestConfigurator +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher +import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiBasedTest +import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtTestModule +import org.jetbrains.kotlin.analysis.test.framework.services.libraries.CompiledLibraryProvider +import org.jetbrains.kotlin.analysis.test.framework.services.libraries.TestModuleDecompiler +import org.jetbrains.kotlin.analysis.test.framework.services.libraries.TestModuleDecompilerDirectory +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid +import org.jetbrains.kotlin.platform.CommonPlatforms +import org.jetbrains.kotlin.platform.js.JsPlatforms +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtConstructor +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtDeclarationContainer +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtTypeParameterListOwner +import org.jetbrains.kotlin.psi.KtVisitorVoid +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.services.TestModuleStructure +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions +import org.jetbrains.kotlin.test.services.moduleStructure +import org.jetbrains.kotlin.test.services.service +import kotlin.collections.firstOrNull +import kotlin.collections.forEach + +abstract class AbstractDeserializedContainerSourceFirTest : AbstractAnalysisApiBasedTest() { + override val configurator get() = AnalysisApiFirLibraryBinaryDecompiledTestConfigurator + + override fun configureTest(builder: TestConfigurationBuilder) { + builder.forTestsMatching("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/*") { + this.defaultsProviderBuilder.targetPlatform = CommonPlatforms.defaultCommonPlatform + this.useAdditionalService<TestModuleDecompiler> { TestModuleDecompilerDirectory() } + } + + builder.forTestsMatching("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/js/*") { + this.defaultsProviderBuilder.targetPlatform = JsPlatforms.defaultJsPlatform + } + + builder.forTestsMatching("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/*") { + this.defaultsProviderBuilder.targetPlatform = JvmPlatforms.defaultJvmPlatform + } + + super.configureTest(builder) + with(builder) { + useAdditionalServices(service(::CompiledLibraryProvider)) + } + } + + private fun renderDeserializedContainerSource(fir: FirDeclaration, declaration: KtDeclaration): String { + val str = "" + return str + } + + private fun renderContainerSource(fir: FirDeclaration): String { + return when (fir) { + is FirFunction -> fir.containerSource?.render().orEmpty() + is FirProperty -> fir.containerSource?.render().orEmpty() + else -> "" + } + } + + private fun DeserializedContainerSource.render() = + "${this::class.simpleName} ${this.presentableString}" + + override fun doTestByMainFile(mainFile: KtFile, mainModule: KtTestModule, testServices: TestServices) { + val declaration = getElementToSearch(mainFile) + + val ktModule = mainModule.ktModule + val resolveSession = LLFirResolveSessionService.getInstance(mainFile.project).getFirResolveSessionForBinaryModule(ktModule) + val symbolProvider = resolveSession.getSessionFor(ktModule).symbolProvider + val fir = FirDeclarationForCompiledElementSearcher(symbolProvider).findNonLocalDeclaration(declaration) + + testServices.assertions.assertEqualsToTestDataFileSibling(renderDeserializedContainerSource(fir, declaration)) + } + + private fun getElementToSearch(ktFile: KtFile): KtDeclaration { + var functionOrProperty: KtDeclaration? = null + + object : KtVisitorVoid() { + override fun visitNamedFunction(function: KtNamedFunction) { + functionOrProperty = function + } + + override fun visitProperty(property: KtProperty) { + functionOrProperty = property + } + }.visitKtFile(ktFile) + + return functionOrProperty ?: error("Expected to find one function or property in the test file to check its container source") + } +} \ No newline at end of file
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/DeserializedContainerSourceFirTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/DeserializedContainerSourceFirTestGenerated.java new file mode 100644 index 0000000..4f91f30 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/DeserializedContainerSourceFirTestGenerated.java
@@ -0,0 +1,64 @@ +/* + * Copyright 2010-2024 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.low.level.api.fir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +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/low-level-api-fir/testData/getOrBuildFirForFileFacade") +@TestDataPath("$PROJECT_ROOT") +public class DeserializedContainerSourceFirTestGenerated extends AbstractDeserializedContainerSourceFirTest { + @Test + public void testAllFilesPresentInGetOrBuildFirForFileFacade() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Nested + @TestMetadata("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm") + @TestDataPath("$PROJECT_ROOT") + public class Jvm { + @Test + public void testAllFilesPresentInJvm() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("topLevelFunction.kt") + public void testTopLevelFunction() { + runTest("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunction.kt"); + } + + @Test + @TestMetadata("topLevelFunctionWithJvmName.kt") + public void testTopLevelFunctionWithJvmName() { + runTest("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/jvm/topLevelFunctionWithJvmName.kt"); + } + } + + @Nested + @TestMetadata("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata") + @TestDataPath("$PROJECT_ROOT") + public class Metadata { + @Test + public void testAllFilesPresentInMetadata() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("topLevelFunction.kt") + public void testTopLevelFunction() { + runTest("analysis/low-level-api-fir/testData/getOrBuildFirForFileFacade/metadata/topLevelFunction.kt"); + } + } +}
diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt index 01c41b6..a040b09 100644 --- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt +++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/firLowLevel.kt
@@ -251,6 +251,10 @@ model("getOrBuildFirForStdLib") } + testClass<AbstractDeserializedContainerSourceFirTest> { + model("getOrBuildFirForFileFacade") + } + testClass<AbstractSourceFileBasedKotlinDeclarationProviderTest> { model("fileBasedDeclarationProvider", pattern = TestGeneratorUtil.KT) }