diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolContainingDeclarationProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolContainingDeclarationProvider.kt index 56913814a8d..73fb8de2ee8 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolContainingDeclarationProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolContainingDeclarationProvider.kt @@ -11,23 +11,28 @@ import com.intellij.psi.search.ProjectScope import org.jetbrains.kotlin.analysis.api.components.KtSymbolContainingDeclarationProvider import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent -import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.KtFe10DescDefaultBackingFieldSymbol import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.KtFe10DynamicFunctionDescValueParameterSymbol import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getDescriptor import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtSymbol import org.jetbrains.kotlin.analysis.api.getModule import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken -import org.jetbrains.kotlin.analysis.api.symbols.KtBackingFieldSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind import org.jetbrains.kotlin.analysis.project.structure.* -import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource +import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName +import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment +import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.descriptorUtil.platform +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import java.nio.file.Path @@ -46,13 +51,89 @@ internal class KtFe10SymbolContainingDeclarationProvider( return when (symbol) { is KtBackingFieldSymbol -> symbol.owningProperty - else -> symbol.getDescriptor()?.containingDeclaration?.toKtSymbol(analysisContext) as? KtDeclarationSymbol + is KtPropertyAccessorSymbol -> { + (symbol.getDescriptor() as? PropertyAccessorDescriptor)?.correspondingProperty + ?.toKtSymbol(analysisContext) as? KtDeclarationSymbol + } + else -> { + symbol.getDescriptor()?.containingDeclaration + ?.toKtSymbol(analysisContext) as? KtDeclarationSymbol + } + } + } + + private val KtSymbol.containingSymbolOrSelf: KtSymbol + get() { + return when (this) { + is KtValueParameterSymbol -> { + getContainingDeclaration(this) as? KtFunctionLikeSymbol ?: this + } + is KtPropertyAccessorSymbol -> { + getContainingDeclaration(this) as? KtPropertySymbol ?: this + } + is KtBackingFieldSymbol -> this.owningProperty + else -> this + } + } + + override fun getContainingFileSymbol(symbol: KtSymbol): KtFileSymbol? { + if (symbol is KtFileSymbol) return null + // psiBased + (symbol.psi?.containingFile as? KtFile)?.let { ktFile -> + with(analysisSession) { + return ktFile.getFileSymbol() + } + } + // descriptorBased + val descriptor = symbol.containingSymbolOrSelf.getDescriptor() + val ktFile = descriptor?.let(DescriptorToSourceUtils::getContainingFile) ?: return null + with(analysisSession) { + return ktFile.getFileSymbol() + } + } + + override fun getContainingJvmClassName(symbol: KtCallableSymbol): JvmClassName? { + val platform = getContainingModule(symbol).platform + if (!platform.isCommon() && !platform.isJvm()) return null + + val containingSymbolOrSelf = symbol.containingSymbolOrSelf as KtSymbolWithKind + return when (val descriptor = containingSymbolOrSelf.getDescriptor()) { + is DescriptorWithContainerSource -> { + when (val containerSource = descriptor.containerSource) { + is FacadeClassSource -> containerSource.facadeClassName ?: containerSource.className + is KotlinJvmBinarySourceElement -> JvmClassName.byClassId(containerSource.binaryClass.classId) + else -> null + } + } + else -> { + return if (containingSymbolOrSelf.symbolKind == KtSymbolKind.TOP_LEVEL) { + descriptor?.let(DescriptorToSourceUtils::getContainingFile) + ?.takeUnless { it.isScript() } + ?.let { JvmClassName.byFqNameWithoutInnerClasses(it.javaFileFacadeFqName) } + } else { + val classId = (containingSymbolOrSelf as? KtConstructorSymbol)?.containingClassIdIfNonLocal + ?: (containingSymbolOrSelf as? KtCallableSymbol)?.callableIdIfNonLocal?.classId + classId?.takeUnless { it.shortClassName.isSpecial } + ?.let { JvmClassName.byClassId(it) } + } + } } } // TODO this is a dummy and incorrect implementation just to satisfy some tests override fun getContainingModule(symbol: KtSymbol): KtModule { - val descriptor = symbol.getDescriptor() + val descriptor = when (symbol) { + is KtValueParameterSymbol -> { + val paramDescriptor = symbol.getDescriptor() + (paramDescriptor as? ValueParameterDescriptor)?.containingDeclaration ?: paramDescriptor + } + is KtPropertyAccessorSymbol -> { + val accessorDescriptor = symbol.getDescriptor() + (accessorDescriptor as? PropertyAccessorDescriptor)?.correspondingProperty ?: accessorDescriptor + } + else -> + symbol.getDescriptor() + } val symbolPsi = descriptor?.let(DescriptorToSourceUtils::getContainingFile) ?: symbol.psi if (symbolPsi != null) { @@ -75,7 +156,24 @@ internal class KtFe10SymbolContainingDeclarationProvider( } private fun getFakeContainingKtModule(descriptor: DescriptorWithContainerSource): KtModule { - val libraryPath = Paths.get((descriptor.containerSource as JvmPackagePartSource).knownJvmBinaryClass?.containingLibrary!!) + val library = when (val containerSource = descriptor.containerSource) { + is JvmPackagePartSource -> containerSource.knownJvmBinaryClass?.containingLibrary + is KotlinJvmBinarySourceElement -> containerSource.binaryClass.containingLibrary + else -> { + when (val containingDeclaration = descriptor.containingDeclaration) { + is DescriptorWithContainerSource -> { + // Deserialized member + return getFakeContainingKtModule(containingDeclaration) + } + is LazyJavaPackageFragment -> { + // Deserialized top-level + (containingDeclaration.source as KotlinJvmBinarySourceElement).binaryClass.containingLibrary + } + else -> null + } + } + } ?: TODO(descriptor::class.java.name) + val libraryPath = Paths.get(library) return object : KtLibraryModule { override val libraryName: String = libraryPath.fileName.toString().substringBeforeLast(".") override val librarySources: KtLibrarySourceModule? = null diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt index 226098bb308..c9dbb9c0caa 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt @@ -139,8 +139,8 @@ internal fun KtSymbol.getDescriptor(): DeclarationDescriptor? { is KtFe10DescSymbol<*> -> descriptor is KtFe10DescSyntheticFieldSymbol -> descriptor is KtFe10PsiDefaultPropertyGetterSymbol -> descriptor + is KtFe10PsiDefaultPropertySetterSymbol -> descriptor is KtFe10PsiDefaultSetterParameterSymbol -> descriptor - is KtFe10PsiDefaultPropertySetterSymbol -> null is KtFe10DescDefaultPropertySetterSymbol -> null is KtFe10DynamicFunctionDescValueParameterSymbol -> null is KtFe10FileSymbol -> null diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java index de6a621b348..35f9cf034f9 100644 --- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java @@ -172,6 +172,12 @@ public class Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated extends A runTest("analysis/analysis-api/testData/symbols/symbolByPsi/extensionFunction.kt"); } + @Test + @TestMetadata("facadeWithJvmName.kt") + public void testFacadeWithJvmName() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt"); + } + @Test @TestMetadata("forLoopVariable.kt") public void testForLoopVariable() throws Exception { @@ -250,6 +256,12 @@ public class Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated extends A runTest("analysis/analysis-api/testData/symbols/symbolByPsi/memberProperties.kt"); } + @Test + @TestMetadata("multifilePart.kt") + public void testMultifilePart() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt"); + } + @Test @TestMetadata("outerAndInnerClasses.kt") public void testOuterAndInnerClasses() throws Exception { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt index 03d7c4f9329..62e58ee3ce8 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolContainingDeclarationProvider.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.analysis.api.components.KtSymbolContainingDeclarationProvider import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession +import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirReceiverParameterSymbol import org.jetbrains.kotlin.analysis.api.fir.utils.firSymbol import org.jetbrains.kotlin.analysis.api.fir.utils.getContainingKtModule import org.jetbrains.kotlin.analysis.api.fir.utils.withSymbolAttachment @@ -17,20 +18,26 @@ import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.jvmClassNameIfDeserialized import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.utils.printer.parentOfType +import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirScript import org.jetbrains.kotlin.fir.diagnostics.ConeDestructuringDeclarationsOnTopLevel +import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.impl.FirErrorPropertySymbol +import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment internal class KtFirSymbolContainingDeclarationProvider( @@ -53,7 +60,7 @@ internal class KtFirSymbolContainingDeclarationProvider( if (firSymbol is FirErrorPropertySymbol && firSymbol.diagnostic is ConeDestructuringDeclarationsOnTopLevel) return null fun getParentSymbolByPsi() = getContainingPsi(symbol).let { with(analysisSession) { it.getSymbol() } } return when (symbol) { - is KtPropertyAccessorSymbol -> firSymbolBuilder.buildSymbol(symbol.firSymbol.fir.propertySymbol) as? KtDeclarationSymbol + is KtPropertyAccessorSymbol -> firSymbolBuilder.buildSymbol(symbol.firSymbol.propertySymbol) as? KtDeclarationSymbol is KtBackingFieldSymbol -> symbol.owningProperty is KtTypeParameterSymbol -> firSymbolBuilder.buildSymbol(symbol.firSymbol.containingDeclarationSymbol) as? KtDeclarationSymbol is KtLocalVariableSymbol -> getParentSymbolByPsi() @@ -98,11 +105,56 @@ internal class KtFirSymbolContainingDeclarationProvider( } } + override fun getContainingFileSymbol(symbol: KtSymbol): KtFileSymbol? { + if (symbol is KtFileSymbol) return null + val firSymbol = when (symbol) { + is KtFirReceiverParameterSymbol -> { + // symbol from receiver parameter + symbol.firSymbol + } + else -> { + // general FIR-based symbol + symbol.firSymbol + } + } + val firFileSymbol = firSymbol.fir.getContainingFile()?.symbol ?: return null + return firSymbolBuilder.buildFileSymbol(firFileSymbol) + } + + override fun getContainingJvmClassName(symbol: KtCallableSymbol): JvmClassName? { + val platform = getContainingModule(symbol).platform + if (!platform.isCommon() && !platform.isJvm()) return null + + val containingSymbolOrSelf = when (symbol) { + is KtValueParameterSymbol -> { + getContainingDeclaration(symbol) as? KtFunctionLikeSymbol ?: symbol + } + is KtPropertyAccessorSymbol -> { + getContainingDeclaration(symbol) as? KtPropertySymbol ?: symbol + } + is KtBackingFieldSymbol -> symbol.owningProperty + else -> symbol + } + val firSymbol = containingSymbolOrSelf.firSymbol + + firSymbol.jvmClassNameIfDeserialized()?.let { return it } + + return if (containingSymbolOrSelf.symbolKind == KtSymbolKind.TOP_LEVEL) { + (firSymbol.fir.getContainingFile()?.psi as? KtFile) + ?.takeUnless { it.isScript() } + ?.let { JvmClassName.byFqNameWithoutInnerClasses(it.javaFileFacadeFqName) } + } else { + val classId = (containingSymbolOrSelf as? KtConstructorSymbol)?.containingClassIdIfNonLocal + ?: containingSymbolOrSelf.callableIdIfNonLocal?.classId + classId?.takeUnless { it.shortClassName.isSpecial } + ?.let { JvmClassName.byClassId(it) } + } + } + override fun getContainingModule(symbol: KtSymbol): KtModule { return symbol.getContainingKtModule(analysisSession.firResolveSession) } - private fun getContainingPsi(symbol: KtSymbol): KtDeclaration { val source = symbol.firSymbol.source val thisSource = when (source?.kind) { diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java index 03e51a713dd..2398d5a8d0e 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java @@ -172,6 +172,12 @@ public class FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated extends Ab runTest("analysis/analysis-api/testData/symbols/symbolByPsi/extensionFunction.kt"); } + @Test + @TestMetadata("facadeWithJvmName.kt") + public void testFacadeWithJvmName() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt"); + } + @Test @TestMetadata("forLoopVariable.kt") public void testForLoopVariable() throws Exception { @@ -250,6 +256,12 @@ public class FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated extends Ab runTest("analysis/analysis-api/testData/symbols/symbolByPsi/memberProperties.kt"); } + @Test + @TestMetadata("multifilePart.kt") + public void testMultifilePart() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt"); + } + @Test @TestMetadata("outerAndInnerClasses.kt") public void testOuterAndInnerClasses() throws Exception { diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/containingDeclarationProvider/AbstractContainingDeclarationProviderByPsiTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/containingDeclarationProvider/AbstractContainingDeclarationProviderByPsiTest.kt index 119c61abc41..3fc996d4385 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/containingDeclarationProvider/AbstractContainingDeclarationProviderByPsiTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/containingDeclarationProvider/AbstractContainingDeclarationProviderByPsiTest.kt @@ -6,12 +6,12 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.containingDeclarationProvider import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.checkContainingFileSymbol +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.checkContainingJvmClassName +import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtScriptSymbol import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtScriptInitializer -import org.jetbrains.kotlin.psi.KtVisitorVoid +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.assertions @@ -19,7 +19,9 @@ import org.jetbrains.kotlin.test.services.assertions abstract class AbstractContainingDeclarationProviderByPsiTest : AbstractAnalysisApiSingleFileTest() { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { val currentPath = mutableListOf() + val ktClasses = mutableListOf() analyseForTest(ktFile.declarations.first()) { + val expectedFileSymbol = ktFile.getFileSymbol() ktFile.accept(object : KtVisitorVoid() { override fun visitElement(element: PsiElement) { element.acceptChildren(this) @@ -39,9 +41,20 @@ abstract class AbstractContainingDeclarationProviderByPsiTest : AbstractAnalysis } } + checkContainingFileSymbol(expectedFileSymbol, currentDeclarationSymbol, testServices) + if (currentDeclarationSymbol is KtCallableSymbol) { + checkContainingJvmClassName(ktFile, ktClasses.lastOrNull(), currentDeclarationSymbol, testServices) + } + currentPath.add(dcl) + if (dcl is KtClassOrObject) { + ktClasses.add(dcl) + } super.visitDeclaration(dcl) currentPath.removeLast() + if (dcl is KtClassOrObject) { + ktClasses.removeLast() + } } }) } 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 index ea1ec9c3f98..fe761a073ba 100644 --- 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 @@ -9,6 +9,7 @@ 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.api.symbols.KtCallableSymbol 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 @@ -35,9 +36,12 @@ abstract class AbstractMultiModuleSymbolByPsiTest : AbstractAnalysisApiBasedTest prettyPrinter.appendLine(fileDirective) analyseForTest(file) { + val fileSymbol = file.getFileSymbol() file.forEachDescendantOfType(predicate = { it.isValidForSymbolCreation }) { declaration -> val symbol = declaration.getSymbol() + checkContainingFileSymbol(fileSymbol, symbol, testServices) + debugPrinter.appendLine(debugRenderer.render(symbol)) debugPrinter.appendLine() 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 f42f69447f6..36b08ae790c 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 @@ -91,6 +91,9 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { val pointersWithRendered = executeOnPooledThreadInReadAction { analyseForTest(ktFile) { val (symbols, symbolForPrettyRendering) = collectSymbols(ktFile, testServices) + for (symbol in symbols) { + checkContainingFileSymbol(ktFile.getFileSymbol(), symbol, testServices) + } val pointerWithRenderedSymbol = symbols .asSequence() diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/symbolTestUtils.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/symbolTestUtils.kt new file mode 100644 index 00000000000..5009075bbcf --- /dev/null +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/symbolTestUtils.kt @@ -0,0 +1,56 @@ +/* + * 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 org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind +import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.assertions + +context(KtAnalysisSession) +internal fun checkContainingFileSymbol( + ktFileSymbol: KtFileSymbol, + symbol: KtSymbol, + testServices: TestServices +) { + if (symbol.origin != KtSymbolOrigin.SOURCE) return + val containingFileSymbol = symbol.getContainingFileSymbol() + testServices.assertions.assertEquals(ktFileSymbol, containingFileSymbol) { + "Invalid file for $symbol, expected $ktFileSymbol but $containingFileSymbol found" + } +} + +context(KtAnalysisSession) +internal fun checkContainingJvmClassName( + ktFile: KtFile, + ktClass: KtClassOrObject?, + symbol: KtCallableSymbol, + testServices: TestServices +) { + if (ktFile.isScript()) return + val expectedClassName = when { + symbol.symbolKind == KtSymbolKind.LOCAL -> + null + ktClass != null -> + // member + ktClass.getClassId()?.let { JvmClassName.byClassId(it) } + else -> + // top-level + JvmClassName.byFqNameWithoutInnerClasses(ktFile.javaFileFacadeFqName) + } + val actualClassName = symbol.getContainingJvmClassName() + testServices.assertions.assertEquals(expectedClassName, actualClassName) { + "Invalid JvmClassName for $symbol, expected $expectedClassName but $actualClassName found" + } +} \ No newline at end of file diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java index e3873334a93..339f17eddd8 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java @@ -172,6 +172,12 @@ public class FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated ext runTest("analysis/analysis-api/testData/symbols/symbolByPsi/extensionFunction.kt"); } + @Test + @TestMetadata("facadeWithJvmName.kt") + public void testFacadeWithJvmName() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt"); + } + @Test @TestMetadata("forLoopVariable.kt") public void testForLoopVariable() throws Exception { @@ -250,6 +256,12 @@ public class FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated ext runTest("analysis/analysis-api/testData/symbols/symbolByPsi/memberProperties.kt"); } + @Test + @TestMetadata("multifilePart.kt") + public void testMultifilePart() throws Exception { + runTest("analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt"); + } + @Test @TestMetadata("outerAndInnerClasses.kt") public void testOuterAndInnerClasses() throws Exception { diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtSymbolContainingDeclarationProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtSymbolContainingDeclarationProvider.kt index 3ef239e060f..9fa6effde7f 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtSymbolContainingDeclarationProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtSymbolContainingDeclarationProvider.kt @@ -6,14 +6,20 @@ package org.jetbrains.kotlin.analysis.api.components import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.resolve.jvm.JvmClassName public abstract class KtSymbolContainingDeclarationProvider : KtAnalysisSessionComponent() { public abstract fun getContainingDeclaration(symbol: KtSymbol): KtDeclarationSymbol? + public abstract fun getContainingFileSymbol(symbol: KtSymbol): KtFileSymbol? + + public abstract fun getContainingJvmClassName(symbol: KtCallableSymbol): JvmClassName? + public abstract fun getContainingModule(symbol: KtSymbol): KtModule } @@ -27,6 +33,25 @@ public interface KtSymbolContainingDeclarationProviderMixIn : KtAnalysisSessionM public fun KtSymbol.getContainingSymbol(): KtDeclarationSymbol? = withValidityAssertion { analysisSession.containingDeclarationProvider.getContainingDeclaration(this) } + /** + * Returns containing [KtFile] as [KtFileSymbol] + * + * Caveat: returns null if the given symbol is already [KtFileSymbol], since there is no containing file. + */ + public fun KtSymbol.getContainingFileSymbol(): KtFileSymbol? = + withValidityAssertion { analysisSession.containingDeclarationProvider.getContainingFileSymbol(this) } + + /** + * Returns containing class's [JvmClassName] if any for [KtCallableSymbol] + * + * even for deserialized callables! (which is useful to look up the containing facade in [PsiElement]) + * for regular, non-local callables from source, it is a mere conversion of [ClassId] inside [CallableId] + * + * Note that this API is applicable for common or JVM modules only. + */ + public fun KtCallableSymbol.getContainingJvmClassName(): JvmClassName? = + withValidityAssertion { analysisSession.containingDeclarationProvider.getContainingJvmClassName(this) } + public fun KtSymbol.getContainingModule(): KtModule = withValidityAssertion { analysisSession.containingDeclarationProvider.getContainingModule(this) } } \ No newline at end of file diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt index c504d239308..b6a11248f3b 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo import org.jetbrains.kotlin.types.Variance @@ -71,9 +72,24 @@ public class DebugSymbolRenderer( KtSymbolContainingDeclarationProviderMixIn::class .declaredMemberExtensionFunctions .filter { it.name == "getContainingModule" } + .filterNot { + // Rendering a containing symbol is prone to stack overflow. + // * function symbol will render its value parameter symbol(s) + // whose containing symbol is that function symbol. + // * property symbol contains accessor symbol(s) and/or backing field symbol + // whose containing symbol is that property symbol. + it.name == "getContainingSymbol" + } .forEach { - appendLine() - renderFunction(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol) + if (it.name == "getContainingJvmClassName") { + if (symbol is KtCallableSymbol) { + appendLine() + renderFunction(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol) + } + } else { + appendLine() + renderFunction(it, renderSymbolsFully = false, this@KtAnalysisSession, symbol) + } } KtSymbolInfoProviderMixIn::class.declaredMemberExtensionProperties @@ -188,6 +204,7 @@ public class DebugSymbolRenderer( is KtClassLikeSymbol -> renderId(symbol.classIdIfNonLocal, symbol) is KtCallableSymbol -> renderId(symbol.callableIdIfNonLocal, symbol) is KtNamedSymbol -> renderValue(symbol.name, renderSymbolsFully = false) + is KtFileSymbol -> renderValue((symbol.psi as KtFile).name, renderSymbolsFully = false) else -> error("Unsupported symbol ${symbol::class}") } append(")") diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt new file mode 100644 index 00000000000..202259f0725 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.kt @@ -0,0 +1,10 @@ +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +@file:kotlin.jvm.JvmName("DifferentFacadeName") + +fun foo() {} + +fun String.foo(): Int = 42 + +val x: Int = 42 + +val Int.y get() = this diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.pretty.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.pretty.txt new file mode 100644 index 00000000000..1eec8a1beaa --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.pretty.txt @@ -0,0 +1,8 @@ +fun foo() + +fun kotlin.String.foo(): kotlin.Int + +val x: kotlin.Int + +val kotlin.Int.y: kotlin.Int + get() diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.txt new file mode 100644 index 00000000000..625dc7235e1 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/facadeWithJvmName.txt @@ -0,0 +1,244 @@ +KtFunctionSymbol: + annotationsList: [] + callableIdIfNonLocal: /foo + contextReceivers: [] + contractEffects: [] + hasStableParameterNames: true + isActual: false + isBuiltinFunctionInvoke: false + isExpect: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: foo + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + +KtFunctionSymbol: + annotationsList: [] + callableIdIfNonLocal: /foo + contextReceivers: [] + contractEffects: [] + hasStableParameterNames: true + isActual: false + isBuiltinFunctionInvoke: false + isExpect: false + isExtension: true + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: foo + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/foo) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/String + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + +KtKotlinPropertySymbol: + annotationsList: [] + backingFieldSymbol: KtBackingFieldSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + isExtension: false + name: field + origin: PROPERTY_BACKING_FIELD + owningProperty: KtKotlinPropertySymbol(/x) + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + callableIdIfNonLocal: /x + contextReceivers: [] + getter: KtPropertyGetterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + hasBody: false + hasStableParameterNames: true + isDefault: true + isExtension: false + isInline: false + isOverride: false + modality: FINAL + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: ACCESSOR + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + hasBackingField: true + hasGetter: true + hasSetter: false + initializer: KtConstantInitializerValue(42) + isActual: false + isConst: false + isDelegatedProperty: false + isExpect: false + isExtension: false + isFromPrimaryConstructor: false + isLateInit: false + isOverride: false + isStatic: false + isVal: true + modality: FINAL + name: x + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + setter: null + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + getterDeprecationStatus: null + javaGetterName: getX + javaSetterName: null + setterDeprecationStatus: null + +KtKotlinPropertySymbol: + annotationsList: [] + backingFieldSymbol: KtBackingFieldSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + isExtension: false + name: field + origin: PROPERTY_BACKING_FIELD + owningProperty: KtKotlinPropertySymbol(/y) + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + callableIdIfNonLocal: /y + contextReceivers: [] + getter: KtPropertyGetterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + hasBody: true + hasStableParameterNames: true + isDefault: false + isExtension: false + isInline: false + isOverride: false + modality: FINAL + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtKotlinPropertySymbol(/y) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: ACCESSOR + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + hasBackingField: false + hasGetter: true + hasSetter: false + initializer: null + isActual: false + isConst: false + isDelegatedProperty: false + isExpect: false + isExtension: true + isFromPrimaryConstructor: false + isLateInit: false + isOverride: false + isStatic: false + isVal: true + modality: FINAL + name: y + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtKotlinPropertySymbol(/y) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + setter: null + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + getterDeprecationStatus: null + javaGetterName: getY + javaSetterName: null + setterDeprecationStatus: null \ No newline at end of file diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt new file mode 100644 index 00000000000..b7cd6e8ebfd --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.kt @@ -0,0 +1,11 @@ +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("NotMultiFilePartKt") + +fun foo() {} + +fun String.foo(): Int = 42 + +val x: Int = 42 + +val Int.y get() = this diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.pretty.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.pretty.txt new file mode 100644 index 00000000000..1eec8a1beaa --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.pretty.txt @@ -0,0 +1,8 @@ +fun foo() + +fun kotlin.String.foo(): kotlin.Int + +val x: kotlin.Int + +val kotlin.Int.y: kotlin.Int + get() diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.txt new file mode 100644 index 00000000000..429e0b9b72e --- /dev/null +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/multifilePart.txt @@ -0,0 +1,244 @@ +KtFunctionSymbol: + annotationsList: [] + callableIdIfNonLocal: /foo + contextReceivers: [] + contractEffects: [] + hasStableParameterNames: true + isActual: false + isBuiltinFunctionInvoke: false + isExpect: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: foo + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + +KtFunctionSymbol: + annotationsList: [] + callableIdIfNonLocal: /foo + contextReceivers: [] + contractEffects: [] + hasStableParameterNames: true + isActual: false + isBuiltinFunctionInvoke: false + isExpect: false + isExtension: true + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: foo + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/foo) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/String + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + +KtKotlinPropertySymbol: + annotationsList: [] + backingFieldSymbol: KtBackingFieldSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + isExtension: false + name: field + origin: PROPERTY_BACKING_FIELD + owningProperty: KtKotlinPropertySymbol(/x) + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + callableIdIfNonLocal: /x + contextReceivers: [] + getter: KtPropertyGetterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + hasBody: false + hasStableParameterNames: true + isDefault: true + isExtension: false + isInline: false + isOverride: false + modality: FINAL + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: ACCESSOR + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + hasBackingField: true + hasGetter: true + hasSetter: false + initializer: KtConstantInitializerValue(42) + isActual: false + isConst: false + isDelegatedProperty: false + isExpect: false + isExtension: false + isFromPrimaryConstructor: false + isLateInit: false + isOverride: false + isStatic: false + isVal: true + modality: FINAL + name: x + origin: SOURCE + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + setter: null + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + getterDeprecationStatus: null + javaGetterName: getX + javaSetterName: null + setterDeprecationStatus: null + +KtKotlinPropertySymbol: + annotationsList: [] + backingFieldSymbol: KtBackingFieldSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + isExtension: false + name: field + origin: PROPERTY_BACKING_FIELD + owningProperty: KtKotlinPropertySymbol(/y) + receiverParameter: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + callableIdIfNonLocal: /y + contextReceivers: [] + getter: KtPropertyGetterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + hasBody: true + hasStableParameterNames: true + isDefault: false + isExtension: false + isInline: false + isOverride: false + modality: FINAL + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtKotlinPropertySymbol(/y) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + symbolKind: ACCESSOR + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + hasBackingField: false + hasGetter: true + hasSetter: false + initializer: null + isActual: false + isConst: false + isDelegatedProperty: false + isExpect: false + isExtension: true + isFromPrimaryConstructor: false + isLateInit: false + isOverride: false + isStatic: false + isVal: true + modality: FINAL + name: y + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtKotlinPropertySymbol(/y) + type: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: KtUsualClassType: + annotationsList: [] + ownTypeArguments: [] + type: kotlin/Int + setter: null + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + getterDeprecationStatus: null + javaGetterName: getY + javaSetterName: null + setterDeprecationStatus: null diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt index cbfa62c93ee..617f60d8574 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers -import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubDeserializedBuiltInsContainerSource import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.StubBasedFirDeserializedSymbolProvider import org.jetbrains.kotlin.analysis.utils.collections.buildSmartList import org.jetbrains.kotlin.fir.FirSession @@ -17,7 +16,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.load.kotlin.FacadeClassSource import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -169,7 +167,7 @@ internal class LLFirDependenciesSymbolProvider( if (newSymbols.isEmpty()) return val newFacades = SmartSet.create() for (symbol in newSymbols) { - val facade = symbol.jvmClassName() + val facade = symbol.jvmClassNameIfDeserialized() if (facade != null) { newFacades += facade if (facade !in facades) { @@ -181,16 +179,4 @@ internal class LLFirDependenciesSymbolProvider( } facades += newFacades } - - private fun FirCallableSymbol<*>.jvmClassName(): JvmClassName? { - val containerSource = fir.containerSource - - return when (containerSource) { - is JvmStubDeserializedBuiltInsContainerSource -> containerSource.facadeClassName - - is FacadeClassSource -> containerSource.facadeClassName ?: containerSource.className - - else -> null - } - } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/providerUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/providerUtils.kt index 26e82cac7c4..741625ca9dd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/providerUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/providerUtils.kt @@ -5,6 +5,22 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers +import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.DeserializedContainerSourceWithJvmClassName +import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubDeserializedBuiltInsContainerSource +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.load.kotlin.FacadeClassSource +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import java.util.* internal fun Optional.getOrNull(): T? = orElse(null) + +fun FirCallableSymbol<*>.jvmClassNameIfDeserialized(): JvmClassName? { + return when (val containerSource = fir.containerSource) { + is JvmStubDeserializedBuiltInsContainerSource -> containerSource.facadeClassName + is FacadeClassSource -> containerSource.facadeClassName ?: containerSource.className + is DeserializedContainerSourceWithJvmClassName -> containerSource.className + is KotlinJvmBinarySourceElement -> JvmClassName.byClassId(containerSource.binaryClass.classId) + else -> null + } +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceWithJvmClassName.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceWithJvmClassName.kt new file mode 100644 index 00000000000..079d6c6a318 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/DeserializedContainerSourceWithJvmClassName.kt @@ -0,0 +1,13 @@ +/* + * 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.low.level.api.fir.stubBased.deserialization + +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource + +interface DeserializedContainerSourceWithJvmClassName : DeserializedContainerSource { + val className: JvmClassName +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedContainerSource.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedContainerSource.kt index ef7dfdd3844..5d66a1650bd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedContainerSource.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedContainerSource.kt @@ -14,8 +14,8 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ //required for LLFirDependenciesSymbolProvider#jvmClassName, to resolve ambiguities //todo check if moving builtins to stubs would solve the issue -internal class JvmStubDeserializedContainerSource(classId: ClassId) : DeserializedContainerSource { - private val className = JvmClassName.byClassId(classId) +internal class JvmStubDeserializedContainerSource(classId: ClassId) : DeserializedContainerSourceWithJvmClassName { + override val className = JvmClassName.byClassId(classId) override val incompatibility: IncompatibleVersionErrorData<*>? get() = null diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedFacadeContainerSource.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedFacadeContainerSource.kt index 55584de1f05..42450ee9cbe 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedFacadeContainerSource.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubDeserializedFacadeContainerSource.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ internal class JvmStubDeserializedFacadeContainerSource( override val className: JvmClassName, override val facadeClassName: JvmClassName? -) : DeserializedContainerSource, FacadeClassSource { +) : DeserializedContainerSourceWithJvmClassName, FacadeClassSource { override val incompatibility: IncompatibleVersionErrorData<*>? get() = null diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/containingFileUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/containingFileUtils.kt index daea8b1842c..721ba33e7c3 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/containingFileUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/containingFileUtils.kt @@ -25,7 +25,17 @@ fun FirElementWithResolveState.getContainingFile(): FirFile? { is FirBackingField -> propertySymbol.fir.getContainingFile() is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol) is FirClassLikeDeclaration -> provider.getFirClassifierContainerFileIfAny(symbol) - is FirAnonymousInitializer -> containingDeclarationSymbol?.fir?.getContainingFile() + is FirAnonymousInitializer -> { + val classId = containingClassIdOrNull() + if (classId?.isLocal == true) { + containingKtFileIfAny?.let { + val moduleComponents = llFirResolvableSession?.moduleComponents + moduleComponents?.cache?.getCachedFirFile(it) + } + } else { + containingDeclarationSymbol?.fir?.getContainingFile() + } + } is FirDanglingModifierList, is FirCodeFragment -> { val ktFile = psi?.containingFile as? KtFile ?: error("File for dangling modifier list cannot be null")