[AA, LL] use stubs to build deserialized Fir elements in IDE
^KTIJ-24638 Notice on `DebugSymbolRenderer`: stub based deserializer sets source directly, but it's available in IDE mode only. Thus, standalone and IDE tests have different results. In order to avoid this, sources for compiled code are explicitly ignored Notice on distinct callables: for a file which belong to multiple libraries, decompiled code would be build per library. In order to avoid ambiguity errors for members in that file, we need to distinct provided elements by origins failed test from IJ repo: FirReferenceResolveWithCrossLibTestGenerated#testSetWithTypeParameters
This commit is contained in:
+2
@@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtModuleFactory
|
||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleFactory
|
||||
@@ -43,6 +44,7 @@ object AnalysisApiFe10TestConfigurator : AnalysisApiTestConfigurator() {
|
||||
|
||||
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> = listOf(
|
||||
AnalysisApiBaseTestServiceRegistrar,
|
||||
AnalysisApiDecompiledCodeTestServiceRegistrar,
|
||||
AnalysisApiFe10TestServiceRegistrar,
|
||||
)
|
||||
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiLibraryBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
@@ -47,6 +48,7 @@ object AnalysisApiFirLibraryBinaryTestConfigurator : AnalysisApiTestConfigurator
|
||||
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> =
|
||||
listOf(
|
||||
AnalysisApiBaseTestServiceRegistrar,
|
||||
AnalysisApiDecompiledCodeTestServiceRegistrar,
|
||||
AnalysisApiFirTestServiceRegistrar,
|
||||
AnalysisApiLibraryBaseTestServiceRegistrar,
|
||||
)
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiLibraryBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
@@ -57,6 +58,7 @@ object AnalysisApiFirLibrarySourceTestConfigurator : AnalysisApiTestConfigurator
|
||||
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> =
|
||||
listOf(
|
||||
AnalysisApiBaseTestServiceRegistrar,
|
||||
AnalysisApiDecompiledCodeTestServiceRegistrar,
|
||||
AnalysisApiFirTestServiceRegistrar,
|
||||
AnalysisApiLibraryBaseTestServiceRegistrar,
|
||||
)
|
||||
|
||||
+20
-4
@@ -12,12 +12,17 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtDefaultLifetimeTokenProvider
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtReadActionConfinementDefaultLifetimeTokenProvider
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.files.DummyFileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProvider
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProviderImpl
|
||||
import org.jetbrains.kotlin.analysis.providers.*
|
||||
import org.jetbrains.kotlin.analysis.providers.impl.*
|
||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
|
||||
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
|
||||
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.psi.KotlinReferenceProvidersService
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -45,17 +50,28 @@ object AnalysisApiBaseTestServiceRegistrar: AnalysisApiTestServiceRegistrar() {
|
||||
}
|
||||
|
||||
override fun registerProjectModelServices(project: MockProject, testServices: TestServices) {
|
||||
val allKtFiles = testServices.ktModuleProvider.getModuleStructure().mainModules.flatMap { it.files.filterIsInstance<KtFile>() }
|
||||
|
||||
val moduleStructure = testServices.ktModuleProvider.getModuleStructure()
|
||||
val allKtFiles = moduleStructure.mainModules.flatMap { it.files.filterIsInstance<KtFile>() }
|
||||
val roots = StandaloneProjectFactory.getVirtualFilesForLibraryRoots(
|
||||
moduleStructure.binaryModules.flatMap { binary -> binary.getBinaryRoots() },
|
||||
testServices.environmentManager.getProjectEnvironment()
|
||||
).distinct()
|
||||
project.apply {
|
||||
registerService(KtModuleScopeProvider::class.java, KtModuleScopeProviderImpl())
|
||||
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(allKtFiles))
|
||||
registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(project, allKtFiles))
|
||||
|
||||
registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(
|
||||
project,
|
||||
allKtFiles,
|
||||
additionalRoots = roots
|
||||
))
|
||||
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(project, allKtFiles))
|
||||
registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java)
|
||||
registerService(KotlinResolutionScopeProvider::class.java, KotlinByModulesResolutionScopeProvider::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerApplicationServices(application: MockApplication, testServices: TestServices) {}
|
||||
override fun registerApplicationServices(application: MockApplication, testServices: TestServices) {
|
||||
application.registerService(KotlinFakeClsStubsCache::class.java, KotlinFakeClsStubsCache())
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.impl.base.test.configurators
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.mock.MockApplication
|
||||
import com.intellij.mock.MockProject
|
||||
import com.intellij.openapi.extensions.LoadingOrder
|
||||
import com.intellij.psi.ClassFileViewProviderFactory
|
||||
import com.intellij.psi.FileTypeFileViewProviders
|
||||
import com.intellij.psi.compiled.ClassFileDecompilers
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.files.DummyFileAttributeService
|
||||
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.test.TestInfrastructureInternals
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.analysis.test.framework.services.disposableProvider
|
||||
|
||||
|
||||
object AnalysisApiDecompiledCodeTestServiceRegistrar : AnalysisApiTestServiceRegistrar() {
|
||||
override fun registerProjectExtensionPoints(project: MockProject, testServices: TestServices) {
|
||||
}
|
||||
|
||||
override fun registerProjectServices(project: MockProject, testServices: TestServices) {
|
||||
}
|
||||
|
||||
override fun registerProjectModelServices(project: MockProject, testServices: TestServices) {
|
||||
}
|
||||
|
||||
override fun registerApplicationServices(application: MockApplication, testServices: TestServices) {
|
||||
application.apply {
|
||||
registerService(ClsKotlinBinaryClassCache::class.java)
|
||||
registerService(FileAttributeService::class.java, DummyFileAttributeService)
|
||||
}
|
||||
}
|
||||
}
|
||||
-5
@@ -34,11 +34,6 @@ object AnalysisApiLibraryBaseTestServiceRegistrar : AnalysisApiTestServiceRegist
|
||||
}
|
||||
|
||||
override fun registerApplicationServices(application: MockApplication, testServices: TestServices) {
|
||||
application.apply {
|
||||
registerService(ClsKotlinBinaryClassCache::class.java)
|
||||
registerService(FileAttributeService::class.java, DummyFileAttributeService)
|
||||
}
|
||||
|
||||
FileTypeFileViewProviders.INSTANCE.addExplicitExtension(JavaClassFileType.INSTANCE, ClassFileViewProviderFactory())
|
||||
|
||||
ClassFileDecompilers.getInstance().EP_NAME.point.apply {
|
||||
|
||||
+2
@@ -42,6 +42,8 @@ public abstract class KotlinDeclarationProvider {
|
||||
public abstract fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile>
|
||||
|
||||
public abstract fun findFilesForScript(scriptFqName: FqName): Collection<KtScript>
|
||||
|
||||
public abstract fun computePackageSetWithTopLevelCallableDeclarations(): Set<String>
|
||||
}
|
||||
|
||||
public abstract class KotlinDeclarationProviderFactory {
|
||||
|
||||
+74
-1
@@ -5,24 +5,34 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.providers.impl
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.SingleRootFileViewProvider
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.util.containers.CollectionFactory
|
||||
import com.intellij.util.indexing.FileContent
|
||||
import com.intellij.util.indexing.FileContentImpl
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
|
||||
|
||||
@@ -84,6 +94,11 @@ public class KotlinStaticDeclarationProvider internal constructor(
|
||||
return index.scriptMap[scriptFqName].orEmpty().filter { it.containingKtFile.virtualFile in scope }
|
||||
}
|
||||
|
||||
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> {
|
||||
val packageNames = index.topLevelPropertyMap.keys + index.topLevelFunctionMap.keys
|
||||
return packageNames.mapTo(mutableSetOf()) { it.asString() }
|
||||
}
|
||||
|
||||
override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> =
|
||||
index.topLevelPropertyMap[callableId.packageName]
|
||||
?.filter { ktProperty ->
|
||||
@@ -109,6 +124,7 @@ public class KotlinStaticDeclarationProviderFactory(
|
||||
private val project: Project,
|
||||
files: Collection<KtFile>,
|
||||
private val jarFileSystem: CoreJarFileSystem = CoreJarFileSystem(),
|
||||
additionalRoots: List<VirtualFile> = emptyList(),
|
||||
) : KotlinDeclarationProviderFactory() {
|
||||
|
||||
private val index = KotlinStaticDeclarationIndex()
|
||||
@@ -247,13 +263,23 @@ public class KotlinStaticDeclarationProviderFactory(
|
||||
// member functions and properties
|
||||
stub.childrenStubs.forEach(::indexStub)
|
||||
}
|
||||
is KotlinObjectStubImpl -> {
|
||||
addToClassMap(stub.psi)
|
||||
// member functions and properties
|
||||
stub.childrenStubs.forEach(::indexStub)
|
||||
}
|
||||
is KotlinTypeAliasStubImpl -> addToTypeAliasMap(stub.psi)
|
||||
is KotlinFunctionStubImpl -> addToFunctionMap(stub.psi)
|
||||
is KotlinPropertyStubImpl -> addToPropertyMap(stub.psi)
|
||||
is KotlinPlaceHolderStubImpl -> {
|
||||
if (stub.stubType == KtStubElementTypes.CLASS_BODY) {
|
||||
stub.getChildrenStubs().filterIsInstance<KotlinClassOrObjectStub<*>>().forEach(::indexStub)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadBuiltIns().forEach { ktFileStub ->
|
||||
fun processStub(ktFileStub: KotlinFileStubImpl) {
|
||||
val ktFile: KtFile = ktFileStub.psi
|
||||
addToFacadeFileMap(ktFile)
|
||||
|
||||
@@ -270,6 +296,32 @@ public class KotlinStaticDeclarationProviderFactory(
|
||||
ktFileStub.childrenStubs.forEach(::indexStub)
|
||||
}
|
||||
|
||||
loadBuiltIns().forEach { processStub(it) }
|
||||
|
||||
val binaryClassCache = ClsKotlinBinaryClassCache.getInstance()
|
||||
for (root in additionalRoots) {
|
||||
KotlinFakeClsStubsCache.processAdditionalRoot(root) { additionalRoot ->
|
||||
val stubs = mutableListOf<KotlinFileStubImpl>()
|
||||
VfsUtilCore.visitChildrenRecursively(additionalRoot, object : VirtualFileVisitor<Void>() {
|
||||
override fun visitFile(file: VirtualFile): Boolean {
|
||||
if (!file.isDirectory && file.fileType == JavaClassFileType.INSTANCE) {
|
||||
val fileContent = FileContentImpl.createByFile(file)
|
||||
if (!binaryClassCache.isKotlinJvmCompiledFile(file, fileContent.content)) return true
|
||||
val stub = KotlinClsStubBuilder().buildFileStub(fileContent) as? KotlinFileStubImpl ?: return true
|
||||
val fakeFile = object : KtFile(KtClassFileViewProvider(psiManager, fileContent.file), isCompiled = true) {
|
||||
override fun getStub() = stub
|
||||
override fun isPhysical() = false
|
||||
}
|
||||
stub.psi = fakeFile
|
||||
stubs.add(stub)
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
stubs
|
||||
}?.forEach { processStub(it) }
|
||||
}
|
||||
|
||||
// Indexing user source files
|
||||
files.forEach {
|
||||
it.accept(recorder)
|
||||
@@ -280,3 +332,24 @@ public class KotlinStaticDeclarationProviderFactory(
|
||||
return KotlinStaticDeclarationProvider(index, searchScope)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test application service to store stubs of shared between tests libraries.
|
||||
*
|
||||
* Otherwise, each test would start indexing of stdlib from scratch,
|
||||
* and under the lock which makes tests extremely slow*/
|
||||
class KotlinFakeClsStubsCache {
|
||||
private val fakeFileClsStubs = CollectionFactory.createConcurrentWeakValueMap<String, List<KotlinFileStubImpl>>()
|
||||
|
||||
companion object {
|
||||
fun processAdditionalRoot(root: VirtualFile, storage: (VirtualFile) -> List<KotlinFileStubImpl>): List<KotlinFileStubImpl>? {
|
||||
val service = ApplicationManager.getApplication().getService(KotlinFakeClsStubsCache::class.java) ?: return null
|
||||
if (service.fakeFileClsStubs[root.path] == null) {
|
||||
service.fakeFileClsStubs[root.path] = storage(root)
|
||||
}
|
||||
return service.fakeFileClsStubs.computeIfAbsent(root.path) { _ ->
|
||||
storage(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -25,6 +25,10 @@ class KtStaticModuleProvider(
|
||||
|
||||
containingFileAsVirtualFile.analysisExtensionFileContextModule?.let { return it }
|
||||
|
||||
projectStructure.binaryModules.firstOrNull { binaryModule ->
|
||||
containingFileAsVirtualFile in binaryModule.contentScope
|
||||
}?.let { return it }
|
||||
|
||||
return projectStructure.mainModules
|
||||
.first { module ->
|
||||
element in module.ktModule.contentScope
|
||||
|
||||
+2
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.ClsJavaStubByVirtualFileCache
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionConfigurator
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProvider
|
||||
@@ -167,6 +168,7 @@ public class StandaloneAnalysisAPISessionBuilder(
|
||||
registerService(ClsJavaStubByVirtualFileCache::class.java, ClsJavaStubByVirtualFileCache())
|
||||
registerService(KotlinAsJavaSupport::class.java, SymbolKotlinAsJavaSupport(this))
|
||||
registerService(ReadWriteAccessChecker::class.java, ReadWriteAccessCheckerFirImpl())
|
||||
registerService(JvmFirDeserializedSymbolProviderFactory::class.java, JvmFirDeserializedSymbolProviderFactory())
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
|
||||
+4
@@ -10,9 +10,12 @@ import com.intellij.mock.MockProject
|
||||
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtStaticModuleProvider
|
||||
import org.jetbrains.kotlin.analysis.decompiled.light.classes.ClsJavaStubByVirtualFileCache
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinPsiDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticPsiDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
|
||||
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
|
||||
@@ -41,6 +44,7 @@ object StandaloneModeTestServiceRegistrar : AnalysisApiTestServiceRegistrar() {
|
||||
projectEnvironment.environment.jarFileSystem as CoreJarFileSystem
|
||||
)
|
||||
)
|
||||
registerService(JvmFirDeserializedSymbolProviderFactory::class.java, JvmFirDeserializedSymbolProviderFactory::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -266,7 +266,11 @@ public class DebugSymbolRenderer(
|
||||
|
||||
withIndent {
|
||||
appendLine().append("psi: ")
|
||||
renderValue(call.psi?.javaClass?.simpleName, renderSymbolsFully = false)
|
||||
val psi =
|
||||
if (call.psi?.containingKtFile?.isCompiled == true) {
|
||||
null
|
||||
} else call.psi
|
||||
renderValue(psi?.javaClass?.simpleName, renderSymbolsFully = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
KtNamedClassOrObjectSymbol:
|
||||
annotationsList: []
|
||||
classIdIfNonLocal: java/lang/String
|
||||
classKind: CLASS
|
||||
companionObject: null
|
||||
contextReceivers: []
|
||||
isData: false
|
||||
isExternal: false
|
||||
isFun: false
|
||||
isInline: false
|
||||
isInner: false
|
||||
modality: FINAL
|
||||
name: String
|
||||
origin: JAVA
|
||||
superTypes: [
|
||||
KtUsualClassType:
|
||||
annotationsList: []
|
||||
ownTypeArguments: []
|
||||
type: kotlin/Any
|
||||
KtUsualClassType:
|
||||
annotationsList: []
|
||||
ownTypeArguments: []
|
||||
type: java/io/Serializable
|
||||
KtUsualClassType:
|
||||
annotationsList: []
|
||||
ownTypeArguments: [
|
||||
KtFlexibleType:
|
||||
annotationsList: []
|
||||
type: kotlin/String!
|
||||
]
|
||||
type: kotlin/Comparable<kotlin/String!>
|
||||
KtUsualClassType:
|
||||
annotationsList: []
|
||||
ownTypeArguments: []
|
||||
type: kotlin/CharSequence
|
||||
]
|
||||
symbolKind: TOP_LEVEL
|
||||
typeParameters: []
|
||||
visibility: Public
|
||||
getContainingModule: Could not render due to java.util.NoSuchElementException: Collection contains no element matching the predicate.
|
||||
|
||||
annotationApplicableTargets: null
|
||||
deprecationStatus: null
|
||||
Vendored
+2
-4
@@ -40,11 +40,9 @@ KtConstructorSymbol:
|
||||
type: (kotlin/collections/MutableCollection<out E!>..kotlin/collections/Collection<E!>?)
|
||||
symbolKind: LOCAL
|
||||
typeParameters: []
|
||||
getContainingModule: Could not render due to java.util.NoSuchElementException: Collection contains no element matching the predicate.
|
||||
|
||||
getContainingModule: KtSdkModule "SDK jdk"
|
||||
deprecationStatus: null
|
||||
]
|
||||
visibility: Public
|
||||
getContainingModule: Could not render due to java.util.NoSuchElementException: Collection contains no element matching the predicate.
|
||||
|
||||
getContainingModule: KtSdkModule "SDK jdk"
|
||||
deprecationStatus: null
|
||||
+1
-2
@@ -43,6 +43,5 @@ KtSamConstructorSymbol:
|
||||
|
||||
deprecationStatus: null
|
||||
]
|
||||
getContainingModule: Could not render due to java.util.NoSuchElementException: Collection contains no element matching the predicate.
|
||||
|
||||
getContainingModule: KtSdkModule "SDK jdk"
|
||||
deprecationStatus: null
|
||||
+2
-1
@@ -141,6 +141,7 @@ fun createStubForTypeName(
|
||||
|
||||
val segments = fqName.pathSegments().asReversed()
|
||||
assert(segments.isNotEmpty())
|
||||
val packageLength = if (substituteWithAny) 1 else typeClassId.packageFqName.pathSegments().size
|
||||
|
||||
fun recCreateStubForType(current: StubElement<out PsiElement>, level: Int): KotlinUserTypeStub {
|
||||
val lastSegment = segments[level]
|
||||
@@ -148,7 +149,7 @@ fun createStubForTypeName(
|
||||
if (level + 1 < segments.size) {
|
||||
recCreateStubForType(userTypeStub, level + 1)
|
||||
}
|
||||
KotlinNameReferenceExpressionStubImpl(userTypeStub, lastSegment.ref())
|
||||
KotlinNameReferenceExpressionStubImpl(userTypeStub, lastSegment.ref(), level < segments.size - packageLength)
|
||||
if (!substituteWithAny) {
|
||||
bindTypeArguments(userTypeStub, level)
|
||||
}
|
||||
|
||||
+4
@@ -65,6 +65,10 @@ private constructor(
|
||||
return providers.flatMapTo(mutableListOf()) { it.findFilesForScript(scriptFqName) }
|
||||
}
|
||||
|
||||
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> {
|
||||
return providers.flatMapTo(mutableSetOf()) { it.computePackageSetWithTopLevelCallableDeclarations() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(providers: List<KotlinDeclarationProvider>): KotlinDeclarationProvider {
|
||||
return when (providers.size) {
|
||||
|
||||
+1
@@ -25,4 +25,5 @@ internal object EmptyKotlinDeclarationProvider : KotlinDeclarationProvider() {
|
||||
override fun findFilesForFacade(facadeFqName: FqName) = emptyList<KtFile>()
|
||||
override fun findInternalFilesForFacade(facadeFqName: FqName) = emptyList<KtFile>()
|
||||
override fun findFilesForScript(scriptFqName: FqName) = emptyList<KtScript>()
|
||||
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> = emptySet()
|
||||
}
|
||||
|
||||
+3
@@ -129,6 +129,9 @@ internal class FileBasedKotlinDeclarationProvider(val kotlinFile: KtFile) : Kotl
|
||||
}
|
||||
|
||||
override fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile> = emptyList()
|
||||
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> {
|
||||
return setOf(kotlinFile.packageFqName.asString())
|
||||
}
|
||||
|
||||
override fun findFilesForScript(scriptFqName: FqName): Collection<KtScript> =
|
||||
listOfNotNull(kotlinFile.script?.takeIf { it.fqName == scriptFqName })
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.project.structure
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaFacade
|
||||
import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
|
||||
|
||||
open class JvmFirDeserializedSymbolProviderFactory {
|
||||
open fun createJvmFirDeserializedSymbolProviders(
|
||||
project: Project,
|
||||
session: FirSession,
|
||||
moduleData: LLFirModuleData,
|
||||
kotlinScopeProvider: FirKotlinScopeProvider,
|
||||
moduleDataProvider: SingleModuleDataProvider,
|
||||
firJavaFacade: FirJavaFacade,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
scope: GlobalSearchScope
|
||||
): List<FirSymbolProvider> {
|
||||
return listOf(
|
||||
JvmClassFileBasedSymbolProvider(
|
||||
session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
packagePartProvider,
|
||||
VirtualFileFinderFactory.getInstance(project).create(scope),
|
||||
firJavaFacade
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+21
-24
@@ -11,8 +11,10 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirDependenci
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirJavaFacadeForBinaries
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubBasedFirDeserializedSymbolProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.createPackagePartProvider
|
||||
import org.jetbrains.kotlin.fir.BuiltinTypes
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
|
||||
import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.java.deserialization.OptionalAnnotationClassesProvider
|
||||
@@ -20,6 +22,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
|
||||
import org.jetbrains.kotlin.load.java.createJavaClassFinder
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
internal object LLFirLibraryProviderFactory {
|
||||
fun createLibraryProvidersForScope(
|
||||
@@ -31,21 +34,9 @@ internal object LLFirLibraryProviderFactory {
|
||||
scope: GlobalSearchScope,
|
||||
builtinSymbolProvider: FirSymbolProvider,
|
||||
): LLFirModuleWithDependenciesSymbolProvider {
|
||||
val moduleDataProvider = SingleModuleDataProvider(moduleData)
|
||||
val packagePartProvider = project.createPackagePartProvider(scope)
|
||||
return LLFirModuleWithDependenciesSymbolProvider(
|
||||
session,
|
||||
providers = listOfNotNull(
|
||||
JvmClassFileBasedSymbolProvider(
|
||||
session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
packagePartProvider,
|
||||
VirtualFileFinderFactory.getInstance(project).create(scope),
|
||||
LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
|
||||
),
|
||||
OptionalAnnotationClassesProvider.createIfNeeded(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider),
|
||||
),
|
||||
providers = createLibraryProvidersForAllProjectLibraries(session, moduleData, kotlinScopeProvider, project, builtinTypes, scope),
|
||||
LLFirDependenciesSymbolProvider(session, listOf(builtinSymbolProvider)),
|
||||
)
|
||||
}
|
||||
@@ -60,16 +51,22 @@ internal object LLFirLibraryProviderFactory {
|
||||
): List<FirSymbolProvider> {
|
||||
val moduleDataProvider = SingleModuleDataProvider(moduleData)
|
||||
val packagePartProvider = project.createPackagePartProvider(scope)
|
||||
return listOfNotNull(
|
||||
JvmClassFileBasedSymbolProvider(
|
||||
session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
packagePartProvider,
|
||||
VirtualFileFinderFactory.getInstance(project).create(scope),
|
||||
LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
|
||||
),
|
||||
OptionalAnnotationClassesProvider.createIfNeeded(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider),
|
||||
)
|
||||
return buildList {
|
||||
val firJavaFacade = LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
|
||||
val service = project.getService(JvmFirDeserializedSymbolProviderFactory::class.java)
|
||||
addAll(
|
||||
service.createJvmFirDeserializedSymbolProviders(
|
||||
project,
|
||||
session,
|
||||
moduleData,
|
||||
kotlinScopeProvider,
|
||||
moduleDataProvider,
|
||||
firJavaFacade,
|
||||
packagePartProvider,
|
||||
scope
|
||||
)
|
||||
)
|
||||
addIfNotNull(OptionalAnnotationClassesProvider.createIfNeeded(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider))
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -94,7 +94,7 @@ internal fun LLFirSourcesSession.registerCompilerPluginServices(
|
||||
}
|
||||
|
||||
internal fun createJavaSymbolProvider(
|
||||
firSession: LLFirSession,
|
||||
firSession: FirSession,
|
||||
moduleData: LLFirModuleData,
|
||||
project: Project,
|
||||
contentScope: GlobalSearchScope
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ 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.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -161,7 +162,7 @@ internal class LLFirDependenciesSymbolProvider(
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.jvmClassName(): JvmClassName? {
|
||||
val jvmPackagePartSource = fir.containerSource as? JvmPackagePartSource ?: return null
|
||||
val jvmPackagePartSource = fir.containerSource as? FacadeClassSource ?: return null
|
||||
return jvmPackagePartSource.facadeClassName ?: jvmPackagePartSource.className
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -238,6 +238,10 @@ class LLFirResolveExtensionToolDeclarationProvider internal constructor(
|
||||
.mapNotNullTo(mutableListOf()) { it.kotlinFile.script }
|
||||
}
|
||||
|
||||
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> {
|
||||
return emptySet() //todo
|
||||
}
|
||||
|
||||
private inline fun getDeclarationProvidersByPackage(
|
||||
packageFqName: FqName,
|
||||
crossinline filter: (KtResolveExtensionFile) -> Boolean
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
//required for LLFirDependenciesSymbolProvider#jvmClassName, to resolve ambiguities
|
||||
//todo check if moving builtins to stubs would solve the issue
|
||||
class JvmFromStubDecompilerSource(
|
||||
override val className: JvmClassName,
|
||||
override val facadeClassName: JvmClassName? = null,
|
||||
override val incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
|
||||
override val isPreReleaseInvisible: Boolean = false,
|
||||
override val abiStability: DeserializedContainerAbiStability = DeserializedContainerAbiStability.STABLE,
|
||||
) : DeserializedContainerSource, FacadeClassSource {
|
||||
constructor(packageName: FqName) :
|
||||
this(JvmClassName.byClassId(ClassId.topLevel(JvmClassName.byInternalName(packageName.asString()).fqNameForTopLevelClassMaybeWithDollars)))
|
||||
|
||||
override fun getContainingFile(): SourceFile {
|
||||
return SourceFile.NO_SOURCE_FILE
|
||||
}
|
||||
|
||||
override val presentableString: String
|
||||
get() = className.internalName
|
||||
}
|
||||
+56
@@ -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.low.level.api.fir.stubBased.deserialization
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.createJavaSymbolProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaFacade
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
|
||||
|
||||
class JvmStubBasedDeserializedSymbolProviderFactory : JvmFirDeserializedSymbolProviderFactory() {
|
||||
override fun createJvmFirDeserializedSymbolProviders(
|
||||
project: Project,
|
||||
session: FirSession,
|
||||
moduleData: LLFirModuleData,
|
||||
kotlinScopeProvider: FirKotlinScopeProvider,
|
||||
moduleDataProvider: SingleModuleDataProvider,
|
||||
firJavaFacade: FirJavaFacade,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
scope: GlobalSearchScope
|
||||
): List<FirSymbolProvider> {
|
||||
return buildList {
|
||||
//stub based provider here works over kotlin-only indices and thus provides only kotlin declarations
|
||||
//in order to find java declarations, one need to explicitly setup java symbol provider.
|
||||
//for ProtoBuf based provider (used in compiler), there is no need in separated java provider,
|
||||
//because all declarations are retrieved at once and are not distinguished
|
||||
add(
|
||||
JvmStubBasedFirDeserializedSymbolProvider(
|
||||
session,
|
||||
moduleDataProvider,
|
||||
kotlinScopeProvider,
|
||||
project.createDeclarationProvider(object : DelegatingGlobalSearchScope(project, scope) {
|
||||
override fun contains(file: VirtualFile): Boolean {
|
||||
if (file.extension == BuiltInSerializerProtocol.BUILTINS_FILE_EXTENSION) return false
|
||||
return super.contains(file)
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
add(createJavaSymbolProvider(session, moduleData, project, scope))
|
||||
}
|
||||
}
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolProviderNameCache
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
import org.jetbrains.kotlin.fir.caches.createCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
|
||||
import org.jetbrains.kotlin.fir.java.deserialization.KotlinBuiltins
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
|
||||
|
||||
typealias DeserializedTypeAliasPostProcessor = (FirTypeAliasSymbol) -> Unit
|
||||
|
||||
/**
|
||||
* [JvmStubBasedFirDeserializedSymbolProvider] works over existing stubs,
|
||||
* retrieving them by classId/callableId from [KotlinDeclarationProvider].
|
||||
*
|
||||
* It works in IDE only, in standalone mode works [JvmClassFileBasedSymbolProvider].
|
||||
*
|
||||
* Because it works over existing stubs, there is no need to keep huge protobuf in memory.
|
||||
* At the same time, there is no need to guess sources for fir elements anymore,
|
||||
* they are set during deserialization.
|
||||
*
|
||||
* Same as [JvmClassFileBasedSymbolProvider], resulting fir elements are already resolved.
|
||||
*/
|
||||
class JvmStubBasedFirDeserializedSymbolProvider(
|
||||
session: FirSession,
|
||||
moduleDataProvider: SingleModuleDataProvider,
|
||||
private val kotlinScopeProvider: FirKotlinScopeProvider,
|
||||
private val declarationProvider: KotlinDeclarationProvider
|
||||
) : FirSymbolProvider(session) {
|
||||
private val moduleData = moduleDataProvider.getModuleData(null)
|
||||
private val packageSetWithTopLevelCallableDeclarations: Set<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
declarationProvider.computePackageSetWithTopLevelCallableDeclarations()
|
||||
}
|
||||
|
||||
private val namesByPackageCache = LLFirKotlinSymbolProviderNameCache(session, declarationProvider)
|
||||
|
||||
private val typeAliasCache: FirCache<ClassId, FirTypeAliasSymbol?, StubBasedFirDeserializationContext?> =
|
||||
session.firCachesFactory.createCacheWithPostCompute(
|
||||
createValue = { classId, _ -> findAndDeserializeTypeAlias(classId) },
|
||||
postCompute = { _, symbol, postProcessor ->
|
||||
if (postProcessor != null && symbol != null) {
|
||||
postProcessor.invoke(symbol)
|
||||
}
|
||||
}
|
||||
)
|
||||
private val classCache: FirCache<ClassId, FirRegularClassSymbol?, StubBasedFirDeserializationContext?> =
|
||||
session.firCachesFactory.createCache(
|
||||
createValue = { classId, context -> findAndDeserializeClass(classId, context) }
|
||||
)
|
||||
|
||||
private val functionCache = session.firCachesFactory.createCache(::loadFunctionsByCallableId)
|
||||
private val propertyCache = session.firCachesFactory.createCache(::loadPropertiesByCallableId)
|
||||
|
||||
override fun computePackageSetWithTopLevelCallables(): Set<String> {
|
||||
return packageSetWithTopLevelCallableDeclarations
|
||||
}
|
||||
|
||||
override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name>? =
|
||||
namesByPackageCache.getTopLevelCallableNamesInPackage(packageFqName)
|
||||
|
||||
override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String>? {
|
||||
return namesByPackageCache.getTopLevelClassifierNamesInPackage(packageFqName)
|
||||
}
|
||||
|
||||
private fun findAndDeserializeTypeAlias(classId: ClassId): Pair<FirTypeAliasSymbol?, DeserializedTypeAliasPostProcessor?> {
|
||||
val classLikeDeclaration = declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement
|
||||
if (classLikeDeclaration is KtTypeAlias) {
|
||||
val symbol = FirTypeAliasSymbol(classId)
|
||||
val postProcessor: DeserializedTypeAliasPostProcessor = {
|
||||
val rootContext = StubBasedFirDeserializationContext.createRootContext(
|
||||
moduleData,
|
||||
StubBasedAnnotationDeserializer(session),
|
||||
classId.packageFqName,
|
||||
classId.relativeClassName,
|
||||
classLikeDeclaration,
|
||||
null, null, symbol
|
||||
)
|
||||
rootContext.memberDeserializer.loadTypeAlias(classLikeDeclaration, symbol)
|
||||
}
|
||||
return symbol to postProcessor
|
||||
}
|
||||
return null to null
|
||||
}
|
||||
|
||||
private fun findAndDeserializeClass(
|
||||
classId: ClassId,
|
||||
parentContext: StubBasedFirDeserializationContext? = null
|
||||
): FirRegularClassSymbol? {
|
||||
val classLikeDeclaration = declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement ?: return null
|
||||
val symbol = FirRegularClassSymbol(classId)
|
||||
if (classLikeDeclaration is KtClassOrObject) {
|
||||
deserializeClassToSymbol(
|
||||
classId,
|
||||
classLikeDeclaration,
|
||||
symbol,
|
||||
session,
|
||||
moduleData,
|
||||
StubBasedAnnotationDeserializer(session),
|
||||
kotlinScopeProvider,
|
||||
parentContext,
|
||||
JvmFromStubDecompilerSource(JvmClassName.byClassId(classId)),
|
||||
deserializeNestedClass = this::getClass,
|
||||
)
|
||||
return symbol
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun loadFunctionsByCallableId(callableId: CallableId): List<FirNamedFunctionSymbol> {
|
||||
val topLevelFunctions = declarationProvider.getTopLevelFunctions(callableId)
|
||||
val origins = if (topLevelFunctions.size > 1) mutableSetOf<KtNamedFunction>() else null
|
||||
return topLevelFunctions
|
||||
.mapNotNull { function ->
|
||||
val original = function.originalElement as? KtNamedFunction ?: return@mapNotNull null
|
||||
if (origins != null && !origins.add(original)) return@mapNotNull null
|
||||
val file = original.containingKtFile
|
||||
val virtualFile = file.virtualFile
|
||||
if (virtualFile.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION) return@mapNotNull null
|
||||
if (file.packageFqName.asString()
|
||||
.replace(".", "/") + "/" + virtualFile.nameWithoutExtension in KotlinBuiltins
|
||||
) return@mapNotNull null
|
||||
val symbol = FirNamedFunctionSymbol(callableId)
|
||||
val rootContext =
|
||||
StubBasedFirDeserializationContext.createRootContext(session, moduleData, callableId, original, symbol)
|
||||
rootContext.memberDeserializer.loadFunction(original, null, session, symbol).symbol
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPropertiesByCallableId(callableId: CallableId): List<FirPropertySymbol> {
|
||||
val topLevelProperties = declarationProvider.getTopLevelProperties(callableId)
|
||||
val origins = if (topLevelProperties.size > 1) mutableSetOf<KtProperty>() else null
|
||||
return topLevelProperties
|
||||
.mapNotNull { property ->
|
||||
val original = property.originalElement as? KtProperty ?: return@mapNotNull null
|
||||
if (origins != null && !origins.add(original)) return@mapNotNull null
|
||||
val symbol = FirPropertySymbol(callableId)
|
||||
val rootContext =
|
||||
StubBasedFirDeserializationContext.createRootContext(session, moduleData, callableId, original, symbol)
|
||||
rootContext.memberDeserializer.loadProperty(original, null, symbol).symbol
|
||||
}
|
||||
}
|
||||
|
||||
private fun getClass(
|
||||
classId: ClassId,
|
||||
parentContext: StubBasedFirDeserializationContext? = null
|
||||
): FirRegularClassSymbol? {
|
||||
return classCache.getValue(classId, parentContext)
|
||||
}
|
||||
|
||||
private fun getTypeAlias(classId: ClassId): FirTypeAliasSymbol? {
|
||||
if (!classId.relativeClassName.isOneSegmentFQN()) return null
|
||||
return typeAliasCache.getValue(classId)
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
|
||||
val callableId = CallableId(packageFqName, name)
|
||||
destination += functionCache.getCallables(callableId)
|
||||
destination += propertyCache.getCallables(callableId)
|
||||
}
|
||||
|
||||
private fun <C : FirCallableSymbol<*>> FirCache<CallableId, List<C>, Nothing?>.getCallables(id: CallableId): List<C> {
|
||||
if (id.packageName.asString() !in packageSetWithTopLevelCallableDeclarations) return emptyList()
|
||||
if (!namesByPackageCache.mayHaveTopLevelCallable(id.packageName, id.callableName)) return emptyList()
|
||||
return getValue(id)
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += functionCache.getCallables(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
@FirSymbolProviderInternals
|
||||
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
|
||||
destination += propertyCache.getCallables(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
override fun getPackage(fqName: FqName): FqName? {
|
||||
return if (!namesByPackageCache.getTopLevelClassifierNamesInPackage(fqName)
|
||||
.isNullOrEmpty() || packageSetWithTopLevelCallableDeclarations.contains(fqName.asString())
|
||||
) {
|
||||
fqName
|
||||
} else null
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||
if (!namesByPackageCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null
|
||||
return getClass(classId) ?: getTypeAlias(classId)
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.constant.*
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtRealPsiSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.collectEnumEntries
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildFromMissingDependenciesNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
class StubBasedAnnotationDeserializer(
|
||||
private val session: FirSession,
|
||||
) {
|
||||
//fun inheritAnnotationInfo(parent: StubBasedAnnotationDeserializer) {}
|
||||
|
||||
fun loadAnnotations(
|
||||
ktAnnotated: KtAnnotated,
|
||||
useSiteTarget: AnnotationUseSiteTarget? = null
|
||||
): List<FirAnnotation> {
|
||||
val annotations = ktAnnotated.annotationEntries
|
||||
if (annotations.isEmpty()) return emptyList()
|
||||
return annotations.map { deserializeAnnotation(it, useSiteTarget) }
|
||||
}
|
||||
|
||||
private val constantCache = mutableMapOf<CallableId, FirExpression>()
|
||||
|
||||
fun loadConstant(property: KtProperty, callableId: CallableId): FirExpression? {
|
||||
if (!property.hasModifier(KtTokens.CONST_KEYWORD)) return null
|
||||
constantCache[callableId]?.let { return it }
|
||||
val propertyStub = property.stub as? KotlinPropertyStubImpl ?: return null
|
||||
val constantValue = propertyStub.constantInitializer ?: return null
|
||||
return resolveValue(property, constantValue)
|
||||
}
|
||||
|
||||
private fun deserializeAnnotation(
|
||||
ktAnnotation: KtAnnotationEntry,
|
||||
useSiteTarget: AnnotationUseSiteTarget? = null
|
||||
): FirAnnotation {
|
||||
val userType =
|
||||
ktAnnotation.getStubOrPsiChild(KtStubElementTypes.CONSTRUCTOR_CALLEE)?.getStubOrPsiChild(KtStubElementTypes.TYPE_REFERENCE)
|
||||
?.getStubOrPsiChild(KtStubElementTypes.USER_TYPE)!!
|
||||
return deserializeAnnotation(
|
||||
ktAnnotation,
|
||||
userType.classId(),
|
||||
(ktAnnotation.stub as? KotlinAnnotationEntryStubImpl)?.valueArguments,
|
||||
useSiteTarget
|
||||
)
|
||||
}
|
||||
|
||||
private fun deserializeAnnotation(
|
||||
ktAnnotation: PsiElement,
|
||||
classId: ClassId,
|
||||
valueArguments: Map<Name, ConstantValue<*>>?,
|
||||
useSiteTarget: AnnotationUseSiteTarget? = null
|
||||
): FirAnnotation {
|
||||
return buildAnnotation {
|
||||
source = KtRealPsiSourceElement(ktAnnotation)
|
||||
annotationTypeRef = buildResolvedTypeRef {
|
||||
type = classId.toLookupTag().constructClassType(emptyArray(), isNullable = false)
|
||||
}
|
||||
session.lazyDeclarationResolver.disableLazyResolveContractChecksInside {
|
||||
this.argumentMapping = buildAnnotationArgumentMapping {
|
||||
valueArguments?.forEach { (name, constantValue) ->
|
||||
mapping[name] = resolveValue(ktAnnotation, constantValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
useSiteTarget?.let {
|
||||
this.useSiteTarget = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveValue(
|
||||
sourceElement: PsiElement,
|
||||
value: ConstantValue<*>
|
||||
): FirExpression {
|
||||
return when (value) {
|
||||
is EnumValue -> sourceElement.toEnumEntryReferenceExpression(value.enumClassId, value.enumEntryName)
|
||||
is KClassValue -> buildGetClassCall {
|
||||
source = KtRealPsiSourceElement(sourceElement)
|
||||
val lookupTag = (value.value as KClassValue.Value.NormalClass).classId.toLookupTag()
|
||||
val referencedType = lookupTag.constructType(emptyArray(), isNullable = false)
|
||||
val resolvedTypeRef = buildResolvedTypeRef {
|
||||
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(referencedType), false)
|
||||
}
|
||||
argumentList = buildUnaryArgumentList(
|
||||
buildClassReferenceExpression {
|
||||
classTypeRef = buildResolvedTypeRef { type = referencedType }
|
||||
typeRef = resolvedTypeRef
|
||||
}
|
||||
)
|
||||
}
|
||||
is ArrayValue -> buildArrayOfCall {
|
||||
source = KtRealPsiSourceElement(sourceElement)
|
||||
argumentList = buildArgumentList {
|
||||
value.value.mapTo(arguments) { resolveValue(sourceElement, it) }
|
||||
}
|
||||
// typeRef = buildResolvedTypeRef {
|
||||
// type = expectedArrayElementType.createArrayType() //todo
|
||||
// }
|
||||
}
|
||||
is AnnotationValue -> {
|
||||
deserializeAnnotation(
|
||||
sourceElement,
|
||||
(value.value.type as KotlinClassTypeBean).classId,
|
||||
value.value.argumentsMapping
|
||||
)
|
||||
}
|
||||
is BooleanValue -> const(ConstantValueKind.Boolean, value.value, session.builtinTypes.booleanType, sourceElement)
|
||||
is ByteValue -> const(ConstantValueKind.Byte, value.value, session.builtinTypes.byteType, sourceElement)
|
||||
is CharValue -> const(ConstantValueKind.Char, value.value, session.builtinTypes.charType, sourceElement)
|
||||
is ShortValue -> const(ConstantValueKind.Short, value.value, session.builtinTypes.shortType, sourceElement)
|
||||
is LongValue -> const(ConstantValueKind.Long, value.value, session.builtinTypes.longType, sourceElement)
|
||||
is FloatValue -> const(ConstantValueKind.Float, value.value, session.builtinTypes.floatType, sourceElement)
|
||||
is DoubleValue -> const(ConstantValueKind.Double, value.value, session.builtinTypes.doubleType, sourceElement)
|
||||
is UByteValue -> const(ConstantValueKind.UnsignedByte, value.value, session.builtinTypes.byteType, sourceElement)
|
||||
is UShortValue -> const(ConstantValueKind.UnsignedShort, value.value, session.builtinTypes.shortType, sourceElement)
|
||||
is UIntValue -> const(ConstantValueKind.UnsignedInt, value.value, session.builtinTypes.intType, sourceElement)
|
||||
is ULongValue -> const(ConstantValueKind.UnsignedLong, value.value, session.builtinTypes.longType, sourceElement)
|
||||
is IntValue -> const(ConstantValueKind.Int, value.value, session.builtinTypes.intType, sourceElement)
|
||||
NullValue -> const(ConstantValueKind.Null, null, session.builtinTypes.nullableAnyType, sourceElement)
|
||||
is StringValue -> const(ConstantValueKind.String, value.value, session.builtinTypes.stringType, sourceElement)
|
||||
else -> error("Unexpected value $value")
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> const(kind: ConstantValueKind<T>, value: T, typeRef: FirResolvedTypeRef, sourceElement: PsiElement): FirConstExpression<T> {
|
||||
return buildConstExpression(
|
||||
KtRealPsiSourceElement(sourceElement),
|
||||
kind,
|
||||
value,
|
||||
setType = true
|
||||
).apply { this.replaceTypeRef(typeRef) }
|
||||
}
|
||||
|
||||
private fun PsiElement.toEnumEntryReferenceExpression(classId: ClassId, entryName: Name): FirExpression {
|
||||
return buildPropertyAccessExpression {
|
||||
source = KtRealPsiSourceElement(this@toEnumEntryReferenceExpression)
|
||||
val enumLookupTag = classId.toLookupTag()
|
||||
val enumSymbol = enumLookupTag.toSymbol(session)
|
||||
val firClass = enumSymbol?.fir as? FirRegularClass
|
||||
val enumEntries = firClass?.collectEnumEntries() ?: emptyList()
|
||||
val enumEntrySymbol = enumEntries.find { it.name == entryName }
|
||||
calleeReference = enumEntrySymbol?.let {
|
||||
buildResolvedNamedReference {
|
||||
name = entryName
|
||||
resolvedSymbol = it.symbol
|
||||
}
|
||||
} ?: buildFromMissingDependenciesNamedReference {
|
||||
name = entryName
|
||||
}
|
||||
if (enumEntrySymbol != null) {
|
||||
typeRef = enumEntrySymbol.returnTypeRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtFakeSourceElement
|
||||
import org.jetbrains.kotlin.KtRealPsiSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.builder.createDataClassCopyFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.comparators.FirMemberDeclarationComparator
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.deserialization.*
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
internal val KtModifierListOwner.visibility: Visibility
|
||||
get() = with(modifierList) {
|
||||
when {
|
||||
this == null -> Visibilities.Public
|
||||
hasModifier(KtTokens.PRIVATE_KEYWORD) -> Visibilities.Private
|
||||
hasModifier(KtTokens.PUBLIC_KEYWORD) -> Visibilities.Public
|
||||
hasModifier(KtTokens.PROTECTED_KEYWORD) -> Visibilities.Protected
|
||||
else -> if (hasModifier(KtTokens.INTERNAL_KEYWORD)) Visibilities.Internal else Visibilities.Public
|
||||
}
|
||||
}
|
||||
|
||||
internal val KtDeclaration.modality: Modality
|
||||
get() {
|
||||
return when {
|
||||
hasModifier(KtTokens.SEALED_KEYWORD) -> Modality.SEALED
|
||||
hasModifier(KtTokens.ABSTRACT_KEYWORD) || this is KtClass && isInterface() -> Modality.ABSTRACT
|
||||
hasModifier(KtTokens.OPEN_KEYWORD) -> Modality.OPEN
|
||||
else -> Modality.FINAL
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeClassToSymbol(
|
||||
classId: ClassId,
|
||||
classOrObject: KtClassOrObject,
|
||||
symbol: FirRegularClassSymbol,
|
||||
session: FirSession,
|
||||
moduleData: FirModuleData,
|
||||
defaultAnnotationDeserializer: StubBasedAnnotationDeserializer?,
|
||||
scopeProvider: FirScopeProvider,
|
||||
parentContext: StubBasedFirDeserializationContext? = null,
|
||||
containerSource: DeserializedContainerSource? = null,
|
||||
deserializeNestedClass: (ClassId, StubBasedFirDeserializationContext) -> FirRegularClassSymbol?
|
||||
) {
|
||||
val kind = when (classOrObject) {
|
||||
is KtObjectDeclaration -> ClassKind.OBJECT
|
||||
is KtClass -> when {
|
||||
classOrObject.isInterface() -> ClassKind.INTERFACE
|
||||
classOrObject.isEnum() -> ClassKind.ENUM_CLASS
|
||||
classOrObject.isAnnotation() -> ClassKind.ANNOTATION_CLASS
|
||||
else -> ClassKind.CLASS
|
||||
}
|
||||
else -> throw AssertionError("Unexpected class or object: ${classOrObject.text}")
|
||||
}
|
||||
val modality = classOrObject.modality
|
||||
val visibility = classOrObject.visibility
|
||||
val status = FirResolvedDeclarationStatusImpl(
|
||||
visibility,
|
||||
modality,
|
||||
visibility.toEffectiveVisibility(parentContext?.outerClassSymbol, forClass = true)
|
||||
).apply {
|
||||
isExpect = classOrObject.hasModifier(KtTokens.EXPECT_KEYWORD)
|
||||
isActual = false
|
||||
isInner = classOrObject.hasModifier(KtTokens.INNER_KEYWORD)
|
||||
isCompanion = (classOrObject as? KtObjectDeclaration)?.isCompanion() == true
|
||||
isData = classOrObject.hasModifier(KtTokens.DATA_KEYWORD)
|
||||
isInline = classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) || classOrObject.hasModifier(KtTokens.VALUE_KEYWORD)
|
||||
isFun = classOrObject.hasModifier(KtTokens.FUN_KEYWORD)
|
||||
isExternal = classOrObject.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
}
|
||||
val annotationDeserializer = defaultAnnotationDeserializer ?: StubBasedAnnotationDeserializer(session)
|
||||
val context =
|
||||
parentContext?.childContext(
|
||||
classOrObject,
|
||||
classId.relativeClassName,
|
||||
containerSource,
|
||||
symbol,
|
||||
annotationDeserializer,
|
||||
status.isInner
|
||||
) ?: StubBasedFirDeserializationContext.createForClass(
|
||||
classId,
|
||||
classOrObject,
|
||||
moduleData,
|
||||
annotationDeserializer,
|
||||
containerSource,
|
||||
symbol
|
||||
)
|
||||
// if (status.isCompanion) {
|
||||
// parentContext?.let {
|
||||
// context.annotationDeserializer.inheritAnnotationInfo(it.annotationDeserializer)
|
||||
// }
|
||||
// }
|
||||
buildRegularClass {
|
||||
source = KtRealPsiSourceElement(classOrObject)
|
||||
this.moduleData = moduleData
|
||||
this.origin = FirDeclarationOrigin.Library
|
||||
name = classId.shortClassName
|
||||
this.status = status
|
||||
classKind = kind
|
||||
this.scopeProvider = scopeProvider
|
||||
this.symbol = symbol
|
||||
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
|
||||
typeParameters += context.typeDeserializer.ownTypeParameters.map { it.fir }
|
||||
if (status.isInner)
|
||||
typeParameters += parentContext?.allTypeParameters?.map { buildOuterClassTypeParameterRef { this.symbol = it } }.orEmpty()
|
||||
|
||||
val typeDeserializer = context.typeDeserializer
|
||||
val memberDeserializer = context.memberDeserializer
|
||||
|
||||
val superTypeList = classOrObject.getSuperTypeList()
|
||||
if (superTypeList != null) {
|
||||
superTypeRefs.addAll(superTypeList.entries.map {
|
||||
typeDeserializer.typeRef(
|
||||
it.typeReference ?: error("Super entry doesn't have type reference $it")
|
||||
)
|
||||
})
|
||||
} else if (StandardClassIds.Any != classId) {
|
||||
superTypeRefs.add(session.builtinTypes.anyType)
|
||||
}
|
||||
|
||||
val firPrimaryConstructor = classOrObject.primaryConstructor?.let {
|
||||
val constructor = memberDeserializer.loadConstructor(it, classOrObject, this)
|
||||
addDeclaration(constructor)
|
||||
constructor
|
||||
}
|
||||
classOrObject.body?.declarations?.forEach { declaration ->
|
||||
when (declaration) {
|
||||
is KtConstructor<*> -> addDeclaration(memberDeserializer.loadConstructor(declaration, classOrObject, this))
|
||||
is KtNamedFunction -> addDeclaration(memberDeserializer.loadFunction(declaration, symbol, session))
|
||||
is KtProperty -> addDeclaration(memberDeserializer.loadProperty(declaration, symbol))
|
||||
is KtEnumEntry -> addDeclaration(memberDeserializer.loadEnumEntry(declaration, symbol, classId))
|
||||
is KtClassOrObject -> {
|
||||
val nestedClassId =
|
||||
classId.createNestedClassId(Name.identifier(declaration.name ?: error("Class doesn't have name $declaration")))
|
||||
deserializeNestedClass(nestedClassId, context)?.fir?.let { addDeclaration(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classKind == ClassKind.ENUM_CLASS) {
|
||||
generateValuesFunction(
|
||||
moduleData,
|
||||
classId.packageFqName,
|
||||
classId.relativeClassName,
|
||||
origin = FirDeclarationOrigin.Library
|
||||
)
|
||||
generateValueOfFunction(moduleData, classId.packageFqName, classId.relativeClassName, origin = FirDeclarationOrigin.Library)
|
||||
generateEntriesGetter(moduleData, classId.packageFqName, classId.relativeClassName, origin = FirDeclarationOrigin.Library)
|
||||
}
|
||||
|
||||
if (classOrObject.isData() && firPrimaryConstructor != null) {
|
||||
val zippedParameters =
|
||||
classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() } zip declarations.filterIsInstance<FirProperty>()
|
||||
addDeclaration(createDataClassCopyFunction(classId, classOrObject, context.dispatchReceiver, zippedParameters,
|
||||
createClassTypeRefWithSourceKind = { firPrimaryConstructor.returnTypeRef.copyWithNewSourceKind(it) },
|
||||
createParameterTypeRefWithSourceKind = { property, newKind ->
|
||||
property.returnTypeRef.copyWithNewSourceKind(newKind)
|
||||
}) { src, kind ->
|
||||
KtFakeSourceElement(src as PsiElement, kind)
|
||||
})
|
||||
}
|
||||
|
||||
addCloneForArrayIfNeeded(classId, context.dispatchReceiver)
|
||||
session.deserializedClassConfigurator?.run {
|
||||
configure(classId)
|
||||
}
|
||||
|
||||
declarations.sortWith(object : Comparator<FirDeclaration> {
|
||||
override fun compare(a: FirDeclaration, b: FirDeclaration): Int {
|
||||
// Reorder members based on their type and name only.
|
||||
// See FE 1.0's [DeserializedMemberScope#addMembers].
|
||||
if (a is FirMemberDeclaration && b is FirMemberDeclaration) {
|
||||
return FirMemberDeclarationComparator.TypeAndNameComparator.compare(a, b)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
})
|
||||
companionObjectSymbol = (declarations.firstOrNull { it is FirRegularClass && it.isCompanion } as FirRegularClass?)?.symbol
|
||||
|
||||
contextReceivers.addAll(memberDeserializer.createContextReceiversForClass(classOrObject))
|
||||
}.apply {
|
||||
//todo sealed inheritors
|
||||
//if (modality == Modality.SEALED) {
|
||||
// val inheritors = classOrObject.sealedSubclassFqNameList.map { nameIndex ->
|
||||
// ClassId.fromString(nameResolver.getQualifiedClassName(nameIndex))
|
||||
// }
|
||||
// setSealedClassInheritors(inheritors)
|
||||
//}
|
||||
|
||||
valueClassRepresentation = computeValueClassRepresentation(this, session)
|
||||
|
||||
replaceAnnotations(
|
||||
context.annotationDeserializer.loadAnnotations(classOrObject)
|
||||
)
|
||||
|
||||
|
||||
sourceElement = containerSource
|
||||
|
||||
replaceDeprecationsProvider(getDeprecationsProvider(session))
|
||||
|
||||
session.deserializedClassConfigurator?.run {
|
||||
configure(classId)
|
||||
}
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.contracts.description.*
|
||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildEffectDeclaration
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildResolvedContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
|
||||
class StubBasedFirContractDeserializer(
|
||||
private val simpleFunction: FirSimpleFunction,
|
||||
private val typeDeserializer: StubBasedFirTypeDeserializer
|
||||
) {
|
||||
fun loadContract(function: KtNamedFunction): FirContractDescription? {
|
||||
val functionStub = function.stub as? KotlinFunctionStubImpl ?: return null
|
||||
val effects = functionStub.contract?.map {
|
||||
it.accept(ContractDescriptionConvertingVisitor(), null)
|
||||
}
|
||||
|
||||
if (effects.isNullOrEmpty()) return null
|
||||
return buildResolvedContractDescription {
|
||||
this.effects += effects.map { description ->
|
||||
buildEffectDeclaration {
|
||||
effect = description as ConeEffectDeclaration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ContractDescriptionConvertingVisitor :
|
||||
KtContractDescriptionVisitor<ConeContractDescriptionElement, Nothing?, KotlinTypeBean, Nothing?>() {
|
||||
override fun visitCallsEffectDeclaration(
|
||||
callsEffect: KtCallsEffectDeclaration<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeCallsEffectDeclaration(
|
||||
callsEffect.valueParameterReference.accept(
|
||||
this,
|
||||
data
|
||||
) as KtValueParameterReference<ConeKotlinType, ConeDiagnostic>, callsEffect.kind
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitReturnsEffectDeclaration(
|
||||
returnsEffect: KtReturnsEffectDeclaration<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeReturnsEffectDeclaration(
|
||||
returnsEffect.value.accept(
|
||||
this,
|
||||
data
|
||||
) as KtConstantReference<ConeKotlinType, ConeDiagnostic>
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitConditionalEffectDeclaration(
|
||||
conditionalEffect: KtConditionalEffectDeclaration<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeConditionalEffectDeclaration(
|
||||
conditionalEffect.effect.accept(this, data) as KtEffectDeclaration<ConeKotlinType, ConeDiagnostic>,
|
||||
conditionalEffect.condition.accept(this, data) as KtBooleanExpression<ConeKotlinType, ConeDiagnostic>
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitLogicalBinaryOperationContractExpression(
|
||||
binaryLogicExpression: KtBinaryLogicExpression<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeBinaryLogicExpression(
|
||||
binaryLogicExpression.left.accept(this, data) as KtBooleanExpression<ConeKotlinType, ConeDiagnostic>,
|
||||
binaryLogicExpression.right.accept(this, data) as KtBooleanExpression<ConeKotlinType, ConeDiagnostic>,
|
||||
binaryLogicExpression.kind
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitLogicalNot(
|
||||
logicalNot: KtLogicalNot<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeLogicalNot(logicalNot.arg.accept(this, data) as KtBooleanExpression<ConeKotlinType, ConeDiagnostic>)
|
||||
}
|
||||
|
||||
override fun visitIsInstancePredicate(
|
||||
isInstancePredicate: KtIsInstancePredicate<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeIsInstancePredicate(
|
||||
isInstancePredicate.arg.accept(this, data) as KtValueParameterReference<ConeKotlinType, ConeDiagnostic>,
|
||||
typeDeserializer.type(isInstancePredicate.type)!!,
|
||||
isInstancePredicate.isNegated
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitIsNullPredicate(
|
||||
isNullPredicate: KtIsNullPredicate<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeIsNullPredicate(
|
||||
isNullPredicate.arg.accept(this, data) as KtValueParameterReference<ConeKotlinType, ConeDiagnostic>,
|
||||
isNullPredicate.isNegated
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitValueParameterReference(
|
||||
valueParameterReference: KtValueParameterReference<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
val parameterIndex = valueParameterReference.parameterIndex
|
||||
return ConeValueParameterReference(parameterIndex, getParameterName(parameterIndex))
|
||||
}
|
||||
|
||||
override fun visitBooleanValueParameterReference(
|
||||
booleanValueParameterReference: KtBooleanValueParameterReference<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return ConeBooleanValueParameterReference(booleanValueParameterReference.parameterIndex,
|
||||
getParameterName(booleanValueParameterReference.parameterIndex))
|
||||
}
|
||||
|
||||
private fun getParameterName(parameterIndex: Int): String {
|
||||
return if (parameterIndex < 0) "this" else simpleFunction.valueParameters[parameterIndex].name.asString()
|
||||
}
|
||||
|
||||
override fun visitConstantDescriptor(
|
||||
constantReference: KtConstantReference<KotlinTypeBean, Nothing?>,
|
||||
data: Nothing?
|
||||
): ConeContractDescriptionElement {
|
||||
return when (constantReference) {
|
||||
KotlinContractConstantValues.FALSE -> ConeContractConstantValues.FALSE
|
||||
KotlinContractConstantValues.TRUE -> ConeContractConstantValues.TRUE
|
||||
KotlinContractConstantValues.NULL -> ConeContractConstantValues.NULL
|
||||
KotlinContractConstantValues.NOT_NULL -> ConeContractConstantValues.NOT_NULL
|
||||
KotlinContractConstantValues.WILDCARD -> ConeContractConstantValues.WILDCARD
|
||||
else -> {
|
||||
error("Unexpected constant: $constantReference")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+547
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElement
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtRealPsiSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.toEffectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
class StubBasedFirDeserializationContext(
|
||||
val moduleData: FirModuleData,
|
||||
val packageFqName: FqName,
|
||||
val relativeClassName: FqName?,
|
||||
val typeDeserializer: StubBasedFirTypeDeserializer,
|
||||
val annotationDeserializer: StubBasedAnnotationDeserializer,
|
||||
val containerSource: DeserializedContainerSource?,
|
||||
val outerClassSymbol: FirRegularClassSymbol?,
|
||||
val outerTypeParameters: List<FirTypeParameterSymbol>
|
||||
) {
|
||||
val session: FirSession = moduleData.session
|
||||
|
||||
val allTypeParameters: List<FirTypeParameterSymbol> =
|
||||
typeDeserializer.ownTypeParameters + outerTypeParameters
|
||||
|
||||
fun childContext(
|
||||
owner: KtTypeParameterListOwner,
|
||||
relativeClassName: FqName? = this.relativeClassName,
|
||||
containerSource: DeserializedContainerSource? = this.containerSource,
|
||||
outerClassSymbol: FirRegularClassSymbol? = this.outerClassSymbol,
|
||||
annotationDeserializer: StubBasedAnnotationDeserializer = this.annotationDeserializer,
|
||||
capturesTypeParameters: Boolean = true,
|
||||
containingDeclarationSymbol: FirBasedSymbol<*>? = this.outerClassSymbol
|
||||
): StubBasedFirDeserializationContext = StubBasedFirDeserializationContext(
|
||||
moduleData,
|
||||
packageFqName,
|
||||
relativeClassName,
|
||||
StubBasedFirTypeDeserializer(
|
||||
moduleData,
|
||||
annotationDeserializer,
|
||||
typeDeserializer,
|
||||
containingDeclarationSymbol,
|
||||
owner
|
||||
),
|
||||
annotationDeserializer,
|
||||
containerSource,
|
||||
outerClassSymbol,
|
||||
if (capturesTypeParameters) allTypeParameters else emptyList()
|
||||
)
|
||||
|
||||
val memberDeserializer: StubBasedFirMemberDeserializer = StubBasedFirMemberDeserializer(this)
|
||||
val dispatchReceiver = relativeClassName?.let { ClassId(packageFqName, it, false).defaultType(allTypeParameters) }
|
||||
|
||||
companion object {
|
||||
|
||||
fun createForClass(
|
||||
classId: ClassId,
|
||||
classOrObject: KtClassOrObject,
|
||||
moduleData: FirModuleData,
|
||||
annotationDeserializer: StubBasedAnnotationDeserializer,
|
||||
containerSource: DeserializedContainerSource?,
|
||||
outerClassSymbol: FirRegularClassSymbol
|
||||
): StubBasedFirDeserializationContext = createRootContext(
|
||||
moduleData,
|
||||
annotationDeserializer,
|
||||
classId.packageFqName,
|
||||
classId.relativeClassName,
|
||||
classOrObject,
|
||||
containerSource,
|
||||
outerClassSymbol,
|
||||
outerClassSymbol
|
||||
)
|
||||
|
||||
fun createRootContext(
|
||||
moduleData: FirModuleData,
|
||||
annotationDeserializer: StubBasedAnnotationDeserializer,
|
||||
packageFqName: FqName,
|
||||
relativeClassName: FqName?,
|
||||
owner: KtTypeParameterListOwner,
|
||||
containerSource: DeserializedContainerSource?,
|
||||
outerClassSymbol: FirRegularClassSymbol?,
|
||||
containingDeclarationSymbol: FirBasedSymbol<*>?
|
||||
): StubBasedFirDeserializationContext = StubBasedFirDeserializationContext(
|
||||
moduleData,
|
||||
packageFqName,
|
||||
relativeClassName,
|
||||
StubBasedFirTypeDeserializer(
|
||||
moduleData,
|
||||
annotationDeserializer,
|
||||
null,
|
||||
containingDeclarationSymbol,
|
||||
owner
|
||||
),
|
||||
annotationDeserializer,
|
||||
containerSource,
|
||||
outerClassSymbol,
|
||||
emptyList()
|
||||
)
|
||||
|
||||
fun createRootContext(
|
||||
session: FirSession,
|
||||
moduleData: FirModuleData,
|
||||
callableId: CallableId,
|
||||
parameterListOwner: KtTypeParameterListOwner,
|
||||
symbol: FirBasedSymbol<*>
|
||||
): StubBasedFirDeserializationContext = createRootContext(
|
||||
moduleData,
|
||||
StubBasedAnnotationDeserializer(session),
|
||||
callableId.packageName,
|
||||
callableId.className,
|
||||
parameterListOwner,
|
||||
JvmFromStubDecompilerSource(callableId.packageName),
|
||||
null,
|
||||
symbol
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StubBasedFirMemberDeserializer(private val c: StubBasedFirDeserializationContext) {
|
||||
|
||||
fun loadTypeAlias(typeAlias: KtTypeAlias, aliasSymbol: FirTypeAliasSymbol): FirTypeAlias {
|
||||
val name = typeAlias.nameAsSafeName
|
||||
val local = c.childContext(typeAlias, containingDeclarationSymbol = aliasSymbol)
|
||||
return buildTypeAlias {
|
||||
source = KtRealPsiSourceElement(typeAlias)
|
||||
moduleData = c.moduleData
|
||||
origin = FirDeclarationOrigin.Library
|
||||
this.name = name
|
||||
val visibility = typeAlias.visibility
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
visibility,
|
||||
Modality.FINAL,
|
||||
visibility.toEffectiveVisibility(owner = null)
|
||||
).apply {
|
||||
isExpect = typeAlias.hasModifier(KtTokens.EXPECT_KEYWORD)
|
||||
isActual = false
|
||||
}
|
||||
|
||||
annotations += c.annotationDeserializer.loadAnnotations(typeAlias)
|
||||
symbol = aliasSymbol
|
||||
expandedTypeRef = typeAlias.getTypeReference()?.toTypeRef(local) ?: error("Type alias doesn't have type reference $typeAlias")
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
|
||||
}.apply {
|
||||
sourceElement = c.containerSource
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPropertyGetter(
|
||||
getter: KtPropertyAccessor,
|
||||
classSymbol: FirClassSymbol<*>?,
|
||||
returnTypeRef: FirTypeRef,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
): FirPropertyAccessor {
|
||||
val visibility = getter.visibility
|
||||
val accessorModality = getter.modality
|
||||
val effectiveVisibility = visibility.toEffectiveVisibility(classSymbol)
|
||||
return buildPropertyAccessor {
|
||||
source = KtRealPsiSourceElement(getter)
|
||||
moduleData = c.moduleData
|
||||
origin = FirDeclarationOrigin.Library
|
||||
this.returnTypeRef = returnTypeRef
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
isGetter = true
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, accessorModality, effectiveVisibility).apply {
|
||||
isInline = getter.hasModifier(KtTokens.INLINE_KEYWORD)
|
||||
isExternal = getter.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
}
|
||||
this.symbol = FirPropertyAccessorSymbol()
|
||||
dispatchReceiverType = c.dispatchReceiver
|
||||
this.propertySymbol = propertySymbol
|
||||
}.apply {
|
||||
replaceAnnotations(
|
||||
c.annotationDeserializer.loadAnnotations(
|
||||
getter, AnnotationUseSiteTarget.PROPERTY_GETTER
|
||||
)
|
||||
)
|
||||
containingClassForStaticMemberAttr = c.dispatchReceiver?.lookupTag
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPropertySetter(
|
||||
setter: KtPropertyAccessor,
|
||||
classSymbol: FirClassSymbol<*>?,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
local: StubBasedFirDeserializationContext,
|
||||
): FirPropertyAccessor {
|
||||
val visibility = setter.visibility
|
||||
val accessorModality = setter.modality
|
||||
val effectiveVisibility = visibility.toEffectiveVisibility(classSymbol)
|
||||
return buildPropertyAccessor {
|
||||
source = KtRealPsiSourceElement(setter)
|
||||
moduleData = c.moduleData
|
||||
origin = FirDeclarationOrigin.Library
|
||||
this.returnTypeRef = FirImplicitUnitTypeRef(source)
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
isGetter = false
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, accessorModality, effectiveVisibility).apply {
|
||||
isInline = setter.hasModifier(KtTokens.INLINE_KEYWORD)
|
||||
isExternal = setter.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
}
|
||||
this.symbol = FirPropertyAccessorSymbol()
|
||||
dispatchReceiverType = c.dispatchReceiver
|
||||
valueParameters += local.memberDeserializer.valueParameters(
|
||||
setter.valueParameters,
|
||||
symbol
|
||||
)
|
||||
this.propertySymbol = propertySymbol
|
||||
}.apply {
|
||||
replaceAnnotations(
|
||||
c.annotationDeserializer.loadAnnotations(
|
||||
setter, AnnotationUseSiteTarget.PROPERTY_SETTER
|
||||
)
|
||||
)
|
||||
containingClassForStaticMemberAttr = c.dispatchReceiver?.lookupTag
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProperty(
|
||||
property: KtProperty,
|
||||
classSymbol: FirClassSymbol<*>? = null,
|
||||
existingSymbol: FirPropertySymbol? = null
|
||||
): FirProperty {
|
||||
val callableName = property.nameAsSafeName
|
||||
val callableId = CallableId(c.packageFqName, c.relativeClassName, callableName)
|
||||
val symbol = existingSymbol ?: FirPropertySymbol(callableId)
|
||||
val local = c.childContext(property, containingDeclarationSymbol = symbol)
|
||||
|
||||
val returnTypeRef = property.typeReference?.toTypeRef(local) ?: error("Property doesn't have type reference, $property")
|
||||
|
||||
val getter = property.getter
|
||||
val receiverTypeReference = property.receiverTypeReference
|
||||
val receiverAnnotations = if (getter != null && receiverTypeReference != null) {
|
||||
c.annotationDeserializer.loadAnnotations(receiverTypeReference, AnnotationUseSiteTarget.PROPERTY_GETTER)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val propertyModality = property.modality
|
||||
|
||||
val isVar = property.isVar
|
||||
return buildProperty {
|
||||
source = KtRealPsiSourceElement(property)
|
||||
moduleData = c.moduleData
|
||||
origin = FirDeclarationOrigin.Library
|
||||
this.returnTypeRef = returnTypeRef
|
||||
receiverParameter = receiverTypeReference?.toTypeRef(local)?.let { receiverType ->
|
||||
buildReceiverParameter {
|
||||
typeRef = receiverType
|
||||
annotations += receiverAnnotations
|
||||
}
|
||||
}
|
||||
|
||||
name = callableName
|
||||
this.isVar = isVar
|
||||
this.symbol = symbol
|
||||
dispatchReceiverType = c.dispatchReceiver
|
||||
isLocal = false
|
||||
val visibility = property.visibility
|
||||
status = FirResolvedDeclarationStatusImpl(visibility, propertyModality, visibility.toEffectiveVisibility(classSymbol)).apply {
|
||||
isExpect = property.hasExpectModifier()
|
||||
isActual = false
|
||||
isOverride = false
|
||||
isConst = property.hasModifier(KtTokens.CONST_KEYWORD)
|
||||
isLateInit = property.hasModifier(KtTokens.LATEINIT_KEYWORD)
|
||||
isExternal = property.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
}
|
||||
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
|
||||
annotations +=
|
||||
c.annotationDeserializer.loadAnnotations(property, AnnotationUseSiteTarget.PROPERTY)
|
||||
if (getter != null) {
|
||||
this.getter = loadPropertyGetter(
|
||||
getter,
|
||||
classSymbol,
|
||||
returnTypeRef,
|
||||
symbol
|
||||
)
|
||||
}
|
||||
val setter = property.setter
|
||||
if (setter != null) {
|
||||
this.setter = loadPropertySetter(
|
||||
setter,
|
||||
classSymbol,
|
||||
symbol,
|
||||
local
|
||||
)
|
||||
}
|
||||
this.containerSource = c.containerSource
|
||||
this.initializer = c.annotationDeserializer.loadConstant(property, symbol.callableId)
|
||||
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
|
||||
|
||||
property.contextReceivers.mapNotNull { it.typeReference() }.mapTo(contextReceivers, ::loadContextReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadContextReceiver(typeReference: KtTypeReference): FirContextReceiver {
|
||||
val typeRef = typeReference.toTypeRef(c)
|
||||
return buildContextReceiver {
|
||||
source = KtRealPsiSourceElement(typeReference)
|
||||
val type = typeRef.coneType
|
||||
this.labelNameFromTypeRef = (type as? ConeLookupTagBasedType)?.lookupTag?.name
|
||||
this.typeRef = typeRef
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createContextReceiversForClass(classOrObject: KtClassOrObject): List<FirContextReceiver> =
|
||||
classOrObject.contextReceivers.mapNotNull { it.typeReference() }.map(::loadContextReceiver)
|
||||
|
||||
fun loadFunction(
|
||||
function: KtNamedFunction,
|
||||
classSymbol: FirClassSymbol<*>? = null,
|
||||
session: FirSession,
|
||||
existingSymbol: FirNamedFunctionSymbol? = null
|
||||
): FirSimpleFunction {
|
||||
val receiverAnnotations = if (function.receiverTypeReference != null) {
|
||||
c.annotationDeserializer.loadAnnotations(
|
||||
function
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val callableName = function.nameAsSafeName
|
||||
val callableId = CallableId(c.packageFqName, c.relativeClassName, callableName)
|
||||
val symbol = existingSymbol ?: FirNamedFunctionSymbol(callableId)
|
||||
val local = c.childContext(function, containingDeclarationSymbol = symbol)
|
||||
|
||||
val simpleFunction = buildSimpleFunction {
|
||||
moduleData = c.moduleData
|
||||
origin = FirDeclarationOrigin.Library
|
||||
source = KtRealPsiSourceElement(function)
|
||||
returnTypeRef = function.typeReference?.toTypeRef(local) ?: session.builtinTypes.unitType
|
||||
receiverParameter = function.receiverTypeReference?.toTypeRef(local)?.let { receiverType ->
|
||||
buildReceiverParameter {
|
||||
typeRef = receiverType
|
||||
annotations += receiverAnnotations
|
||||
}
|
||||
}
|
||||
|
||||
name = callableName
|
||||
val visibility = function.visibility
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
visibility,
|
||||
function.modality,
|
||||
visibility.toEffectiveVisibility(classSymbol)
|
||||
).apply {
|
||||
isExpect = function.hasExpectModifier()
|
||||
isActual = false
|
||||
isOverride = false
|
||||
isOperator = function.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
||||
isInfix = function.hasModifier(KtTokens.INFIX_KEYWORD)
|
||||
isInline = function.hasModifier(KtTokens.INLINE_KEYWORD)
|
||||
isTailRec = function.hasModifier(KtTokens.TAILREC_KEYWORD)
|
||||
isExternal = function.hasModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
isSuspend = function.hasModifier(KtTokens.SUSPEND_KEYWORD)
|
||||
}
|
||||
this.symbol = symbol
|
||||
dispatchReceiverType = c.dispatchReceiver
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
|
||||
valueParameters += local.memberDeserializer.valueParameters(
|
||||
function.valueParameters,
|
||||
symbol
|
||||
)
|
||||
annotations +=
|
||||
c.annotationDeserializer.loadAnnotations(function)
|
||||
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
|
||||
this.containerSource = c.containerSource
|
||||
|
||||
function.contextReceivers.mapNotNull { it.typeReference() }.mapTo(contextReceivers, ::loadContextReceiver)
|
||||
}
|
||||
if (function.mayHaveContract()) {
|
||||
val resolvedDescription = StubBasedFirContractDeserializer(simpleFunction, local.typeDeserializer).loadContract(function)
|
||||
if (resolvedDescription != null) {
|
||||
simpleFunction.replaceContractDescription(resolvedDescription)
|
||||
}
|
||||
}
|
||||
return simpleFunction
|
||||
}
|
||||
|
||||
fun loadConstructor(
|
||||
constructor: KtConstructor<*>,
|
||||
classOrObject: KtClassOrObject,
|
||||
classBuilder: FirRegularClassBuilder
|
||||
): FirConstructor {
|
||||
val relativeClassName = c.relativeClassName!!
|
||||
val callableId = CallableId(c.packageFqName, relativeClassName, relativeClassName.shortName())
|
||||
val symbol = FirConstructorSymbol(callableId)
|
||||
val local = c.childContext(constructor, containingDeclarationSymbol = symbol)
|
||||
val isPrimary = constructor is KtPrimaryConstructor
|
||||
|
||||
val typeParameters = classBuilder.typeParameters
|
||||
|
||||
val delegatedSelfType = buildResolvedTypeRef {
|
||||
type = ConeClassLikeTypeImpl(
|
||||
classBuilder.symbol.toLookupTag(),
|
||||
typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
|
||||
false
|
||||
)
|
||||
source = KtFakeSourceElement(classOrObject, KtFakeSourceElementKind.ClassSelfTypeRef)
|
||||
}
|
||||
|
||||
return if (isPrimary) {
|
||||
FirPrimaryConstructorBuilder()
|
||||
} else {
|
||||
FirConstructorBuilder()
|
||||
}.apply {
|
||||
moduleData = c.moduleData
|
||||
source = KtRealPsiSourceElement(constructor)
|
||||
origin = FirDeclarationOrigin.Library
|
||||
returnTypeRef = delegatedSelfType
|
||||
val visibility = constructor.visibility
|
||||
val isInner = classBuilder.status.isInner
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
visibility,
|
||||
Modality.FINAL,
|
||||
visibility.toEffectiveVisibility(classBuilder.symbol)
|
||||
).apply {
|
||||
isExpect = constructor.hasExpectModifier() || classOrObject.hasExpectModifier()
|
||||
isActual = false
|
||||
isOverride = false
|
||||
this.isInner = isInner
|
||||
}
|
||||
this.symbol = symbol
|
||||
dispatchReceiverType =
|
||||
if (!isInner) null
|
||||
else with(c) {
|
||||
ClassId(packageFqName, relativeClassName.parent(), false).defaultType(outerTypeParameters)
|
||||
}
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
this.typeParameters +=
|
||||
typeParameters.filterIsInstance<FirTypeParameter>()
|
||||
.map { buildConstructedClassTypeParameterRef { this.symbol = it.symbol } }
|
||||
valueParameters += local.memberDeserializer.valueParameters(
|
||||
constructor.valueParameters,
|
||||
symbol,
|
||||
addDefaultValue = classBuilder.symbol.classId == StandardClassIds.Enum
|
||||
)
|
||||
annotations +=
|
||||
c.annotationDeserializer.loadAnnotations(constructor)
|
||||
containerSource = c.containerSource
|
||||
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
|
||||
|
||||
contextReceivers.addAll(createContextReceiversForClass(classOrObject))
|
||||
}.build().apply {
|
||||
containingClassForStaticMemberAttr = c.dispatchReceiver!!.lookupTag
|
||||
}
|
||||
}
|
||||
|
||||
private fun valueParameters(
|
||||
valueParameters: List<KtParameter>,
|
||||
functionSymbol: FirFunctionSymbol<*>,
|
||||
addDefaultValue: Boolean = false
|
||||
): List<FirValueParameter> {
|
||||
return valueParameters.map { ktParameter ->
|
||||
val name = ktParameter.nameAsSafeName
|
||||
buildValueParameter {
|
||||
source = KtRealPsiSourceElement(ktParameter)
|
||||
moduleData = c.moduleData
|
||||
this.containingFunctionSymbol = functionSymbol
|
||||
origin = FirDeclarationOrigin.Library
|
||||
returnTypeRef =
|
||||
ktParameter.typeReference?.toTypeRef(c) ?: error("KtParameter $ktParameter doesn't have type, $functionSymbol")
|
||||
isVararg = ktParameter.isVarArg
|
||||
if (isVararg) {
|
||||
returnTypeRef = returnTypeRef.withReplacedReturnType(returnTypeRef.coneType.createOutArrayType())
|
||||
}
|
||||
this.name = name
|
||||
symbol = FirValueParameterSymbol(name)
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
|
||||
defaultValue = if (ktParameter.hasDefaultValue()) {
|
||||
buildExpressionStub()
|
||||
} else null
|
||||
if (addDefaultValue) {
|
||||
defaultValue = buildExpressionStub()
|
||||
}
|
||||
isCrossinline = ktParameter.hasModifier(KtTokens.CROSSINLINE_KEYWORD)
|
||||
isNoinline = ktParameter.hasModifier(KtTokens.NOINLINE_KEYWORD)
|
||||
annotations += c.annotationDeserializer.loadAnnotations(
|
||||
ktParameter
|
||||
)
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private fun KtTypeReference.toTypeRef(context: StubBasedFirDeserializationContext): FirTypeRef =
|
||||
context.typeDeserializer.typeRef(this)
|
||||
|
||||
fun loadEnumEntry(
|
||||
declaration: KtEnumEntry,
|
||||
symbol: FirRegularClassSymbol,
|
||||
classId: ClassId
|
||||
): FirEnumEntry {
|
||||
val enumEntryName = declaration.name ?: error("Enum entry doesn't provide name $declaration")
|
||||
|
||||
val enumType = ConeClassLikeTypeImpl(symbol.toLookupTag(), emptyArray(), false)
|
||||
val enumEntry = buildEnumEntry {
|
||||
source = KtRealPsiSourceElement(declaration)
|
||||
this.moduleData = c.moduleData
|
||||
this.origin = FirDeclarationOrigin.Library
|
||||
returnTypeRef = buildResolvedTypeRef { type = enumType }
|
||||
name = Name.identifier(enumEntryName)
|
||||
this.symbol = FirEnumEntrySymbol(CallableId(classId, name))
|
||||
this.status = FirResolvedDeclarationStatusImpl(
|
||||
Visibilities.Public,
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
).apply {
|
||||
isStatic = true
|
||||
}
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
}.apply {
|
||||
containingClassForStaticMemberAttr = c.dispatchReceiver!!.lookupTag
|
||||
}
|
||||
return enumEntry
|
||||
}
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.KtRealPsiSourceElement
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.computeTypeAttributes
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.addDefaultBoundIfNecessary
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class StubBasedFirTypeDeserializer(
|
||||
private val moduleData: FirModuleData,
|
||||
private val annotationDeserializer: StubBasedAnnotationDeserializer,
|
||||
private val parent: StubBasedFirTypeDeserializer?,
|
||||
private val containingSymbol: FirBasedSymbol<*>?,
|
||||
owner: KtTypeParameterListOwner
|
||||
) {
|
||||
private val typeParametersByName: Map<String, FirTypeParameterSymbol>
|
||||
|
||||
val ownTypeParameters: List<FirTypeParameterSymbol>
|
||||
get() = typeParametersByName.values.toList()
|
||||
|
||||
init {
|
||||
val typeParameters = owner.typeParameters
|
||||
if (typeParameters.isNotEmpty()) {
|
||||
typeParametersByName = mutableMapOf()
|
||||
val builders = mutableListOf<FirTypeParameterBuilder>()
|
||||
for (typeParameter in typeParameters) {
|
||||
val name = typeParameter.nameAsSafeName
|
||||
val symbol = FirTypeParameterSymbol().also {
|
||||
typeParametersByName[name.asString()] = it
|
||||
}
|
||||
builders += FirTypeParameterBuilder().apply {
|
||||
source = KtRealPsiSourceElement(typeParameter)
|
||||
moduleData = this@StubBasedFirTypeDeserializer.moduleData
|
||||
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
|
||||
origin = FirDeclarationOrigin.Library
|
||||
this.name = name
|
||||
this.symbol = symbol
|
||||
this.containingDeclarationSymbol = containingSymbol ?: error("Top-level type parameter ???")
|
||||
variance = typeParameter.variance
|
||||
isReified = typeParameter.hasModifier(KtTokens.REIFIED_KEYWORD)
|
||||
annotations += annotationDeserializer.loadAnnotations(typeParameter)
|
||||
}
|
||||
}
|
||||
|
||||
for ((index, typeParameter) in typeParameters.withIndex()) {
|
||||
val builder = builders[index]
|
||||
builder.apply {
|
||||
typeParameter.extendsBound?.let { bounds.add(typeRef(it)) }
|
||||
owner.typeConstraints
|
||||
.filter { it.subjectTypeParameterName?.getReferencedNameAsName() == typeParameter.nameAsName }
|
||||
.forEach { typeConstraint -> typeConstraint.boundTypeReference?.let { bounds += typeRef(it) } }
|
||||
addDefaultBoundIfNecessary()
|
||||
}.build()
|
||||
}
|
||||
} else {
|
||||
typeParametersByName = emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeClassifier(classId: ClassId?): ConeClassLikeLookupTag? {
|
||||
return classId?.toLookupTag()
|
||||
}
|
||||
|
||||
fun typeRef(typeReference: KtTypeReference): FirTypeRef {
|
||||
return buildResolvedTypeRef {
|
||||
source = KtRealPsiSourceElement(typeReference)
|
||||
annotations += annotationDeserializer.loadAnnotations(typeReference)
|
||||
type = type(typeReference, annotations.computeTypeAttributes(moduleData.session, shouldExpandTypeAliases = false))
|
||||
}
|
||||
}
|
||||
|
||||
private fun attributesFromAnnotations(typeReference: KtTypeReference): ConeAttributes =
|
||||
annotationDeserializer.loadAnnotations(typeReference).computeTypeAttributes(moduleData.session, shouldExpandTypeAliases = false)
|
||||
|
||||
fun type(typeReference: KtTypeReference): ConeKotlinType {
|
||||
return type(typeReference, attributesFromAnnotations(typeReference))
|
||||
}
|
||||
|
||||
fun type(type: KotlinTypeBean): ConeKotlinType? {
|
||||
when (type) {
|
||||
is KotlinTypeParameterTypeBean -> {
|
||||
val lookupTag =
|
||||
typeParametersByName[type.typeParameterName]?.toLookupTag() ?: parent?.typeParameterSymbol(type.typeParameterName)
|
||||
?: return null
|
||||
return ConeTypeParameterTypeImpl(lookupTag, isNullable = type.nullable).let {
|
||||
if (type.definitelyNotNull)
|
||||
ConeDefinitelyNotNullType.create(it, moduleData.session.typeContext, avoidComprehensiveCheck = true) ?: it
|
||||
else
|
||||
it
|
||||
}
|
||||
}
|
||||
is KotlinClassTypeBean -> {
|
||||
val projections = type.arguments.map { typeArgumentBean ->
|
||||
val kind = typeArgumentBean.projectionKind
|
||||
if (kind == KtProjectionKind.STAR) {
|
||||
return@map ConeStarProjection
|
||||
}
|
||||
val argBean = typeArgumentBean.type!!
|
||||
val lowerBound = type(argBean) ?: error("Broken type argument ${typeArgumentBean.type}")
|
||||
typeArgument(lowerBound, kind)
|
||||
}
|
||||
return ConeClassLikeTypeImpl(
|
||||
type.classId.toLookupTag(),
|
||||
projections.toTypedArray(),
|
||||
isNullable = type.nullable,
|
||||
ConeAttributes.Empty
|
||||
)
|
||||
}
|
||||
is KotlinFlexibleTypeBean -> {
|
||||
val lowerBound = type(type.lowerBound)
|
||||
val upperBound = type(type.upperBound)
|
||||
return ConeFlexibleType(
|
||||
lowerBound as? ConeSimpleKotlinType ?: error("Unexpected lower bound $lowerBound"),
|
||||
upperBound as? ConeSimpleKotlinType ?: error("Unexpected upper bound $upperBound")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun type(typeReference: KtTypeReference, attributes: ConeAttributes): ConeKotlinType {
|
||||
val upperBoundType = ((typeReference.typeElement as? KtUserType)?.stub as? KotlinUserTypeStubImpl)?.upperBound
|
||||
if (upperBoundType != null) {
|
||||
val lowerBound = simpleType(typeReference, attributes)
|
||||
val upperBound = type(upperBoundType)
|
||||
|
||||
val isDynamic = lowerBound == moduleData.session.builtinTypes.nothingType.coneType &&
|
||||
upperBound == moduleData.session.builtinTypes.nullableAnyType.coneType
|
||||
|
||||
return if (isDynamic) {
|
||||
ConeDynamicType.create(moduleData.session)
|
||||
} else {
|
||||
ConeFlexibleType(lowerBound!!, upperBound as ConeSimpleKotlinType)
|
||||
}
|
||||
}
|
||||
|
||||
return simpleType(typeReference, attributes) ?: ConeErrorType(ConeSimpleDiagnostic("?!id:0", DiagnosticKind.DeserializationError))
|
||||
}
|
||||
|
||||
private fun typeParameterSymbol(typeParameterName: String): ConeTypeParameterLookupTag? =
|
||||
typeParametersByName[typeParameterName]?.toLookupTag() ?: parent?.typeParameterSymbol(typeParameterName)
|
||||
|
||||
fun FirClassLikeSymbol<*>.typeParameters(): List<FirTypeParameterSymbol> =
|
||||
(fir as? FirTypeParameterRefsOwner)?.typeParameters?.map { it.symbol }.orEmpty()
|
||||
|
||||
private fun simpleType(typeReference: KtTypeReference, attributes: ConeAttributes): ConeSimpleKotlinType? {
|
||||
val constructor = typeSymbol(typeReference) ?: return null
|
||||
val isNullable = typeReference.typeElement is KtNullableType
|
||||
if (constructor is ConeTypeParameterLookupTag) {
|
||||
return ConeTypeParameterTypeImpl(constructor, isNullable = isNullable).let {
|
||||
if (typeReference.typeElement?.unwrapNullability() is KtIntersectionType) {
|
||||
ConeDefinitelyNotNullType.create(it, moduleData.session.typeContext, avoidComprehensiveCheck = true) ?: it
|
||||
} else it
|
||||
}
|
||||
}
|
||||
if (constructor !is ConeClassLikeLookupTag) return null
|
||||
|
||||
val typeElement = typeReference.typeElement?.unwrapNullability()
|
||||
val arguments = when (typeElement) {
|
||||
is KtUserType -> typeElement.typeArguments.map { typeArgument(it) }.toTypedArray()
|
||||
is KtFunctionType -> buildList {
|
||||
typeElement.receiver?.let { add(type(it.typeReference).toTypeProjection(Variance.INVARIANT)) }
|
||||
addAll(typeElement.parameters.map { type(it.typeReference!!).toTypeProjection(Variance.INVARIANT) })
|
||||
add(type(typeElement.returnTypeReference!!).toTypeProjection(Variance.INVARIANT))
|
||||
}.toTypedArray()
|
||||
else -> error("not supported $typeElement")
|
||||
}
|
||||
|
||||
return ConeClassLikeTypeImpl(
|
||||
constructor,
|
||||
arguments,
|
||||
isNullable = isNullable,
|
||||
if (typeElement is KtFunctionType && typeElement.receiver != null) ConeAttributes.WithExtensionFunctionType else attributes
|
||||
)
|
||||
}
|
||||
|
||||
private fun KtElementImplStub<*>.getAllModifierLists(): Array<out KtDeclarationModifierList> =
|
||||
getStubOrPsiChildren(KtStubElementTypes.MODIFIER_LIST, KtStubElementTypes.MODIFIER_LIST.arrayFactory)
|
||||
|
||||
private fun typeSymbol(typeReference: KtTypeReference): ConeClassifierLookupTag? {
|
||||
val typeElement = typeReference.typeElement?.unwrapNullability()
|
||||
if (typeElement is KtFunctionType) {
|
||||
val arity = (if (typeElement.receiver != null) 1 else 0) + typeElement.parameters.size
|
||||
val isSuspend = typeReference.getAllModifierLists().any { it.hasSuspendModifier() }
|
||||
val functionClassId = if (isSuspend) StandardNames.getSuspendFunctionClassId(arity) else StandardNames.getFunctionClassId(arity)
|
||||
return computeClassifier(functionClassId)
|
||||
}
|
||||
if (typeElement is KtIntersectionType) {
|
||||
val leftTypeRef = typeElement.getLeftTypeRef() ?: return null
|
||||
//T&Any
|
||||
return typeSymbol(leftTypeRef)
|
||||
}
|
||||
val type = typeElement as KtUserType
|
||||
val referencedName = type.referencedName
|
||||
return typeParameterSymbol(referencedName!!) ?: computeClassifier(type.classId())
|
||||
}
|
||||
|
||||
|
||||
private fun typeArgument(projection: KtTypeProjection): ConeTypeProjection {
|
||||
if (projection.projectionKind == KtProjectionKind.STAR) {
|
||||
return ConeStarProjection
|
||||
}
|
||||
|
||||
val type = type(projection.typeReference!!)
|
||||
return typeArgument(type, projection.projectionKind)
|
||||
}
|
||||
|
||||
private fun typeArgument(
|
||||
type: ConeKotlinType,
|
||||
projectionKind: KtProjectionKind
|
||||
): ConeTypeProjection {
|
||||
val variance = when (projectionKind) {
|
||||
KtProjectionKind.IN -> Variance.IN_VARIANCE
|
||||
KtProjectionKind.OUT -> Variance.OUT_VARIANCE
|
||||
KtProjectionKind.NONE -> Variance.INVARIANT
|
||||
KtProjectionKind.STAR -> throw AssertionError("* should not be here")
|
||||
}
|
||||
return type.toTypeProjection(variance)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves classId from [KtUserType] for compiled code only.
|
||||
*
|
||||
* It relies on [org.jetbrains.kotlin.psi.stubs.impl.KotlinNameReferenceExpressionStubImpl.isClassRef],
|
||||
* which is set during cls analysis only.
|
||||
*/
|
||||
internal fun KtUserType.classId(): ClassId {
|
||||
val packageFragments = mutableListOf<String>()
|
||||
val classFragments = mutableListOf<String>()
|
||||
|
||||
fun collectFragments(type: KtUserType) {
|
||||
val userType = type.getStubOrPsiChild(KtStubElementTypes.USER_TYPE)
|
||||
if (userType != null) {
|
||||
collectFragments(userType)
|
||||
}
|
||||
val referenceExpression = type.referenceExpression as? KtNameReferenceExpression
|
||||
if (referenceExpression != null) {
|
||||
val referencedName = referenceExpression.getReferencedName()
|
||||
val stub = referenceExpression.stub
|
||||
if (stub is KotlinNameReferenceExpressionStubImpl && stub.isClassRef) {
|
||||
classFragments.add(referencedName)
|
||||
} else {
|
||||
packageFragments.add(referencedName)
|
||||
}
|
||||
}
|
||||
}
|
||||
collectFragments(this)
|
||||
return ClassId(
|
||||
FqName.fromSegments(packageFragments),
|
||||
FqName.fromSegments(classFragments),
|
||||
false
|
||||
)
|
||||
}
|
||||
+3
@@ -16,10 +16,12 @@ import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.JvmFirDeserializedSymbolProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.services.NoOpKtCompilerPluginsProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLFirSealedClassInheritorsProcessorFactoryForTests
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.services.PackagePartProviderTestImpl
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubBasedDeserializedSymbolProviderFactory
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionConfigurator
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider
|
||||
@@ -59,6 +61,7 @@ object AnalysisApiFirTestServiceRegistrar : AnalysisApiTestServiceRegistrar() {
|
||||
registerService(KtCompilerPluginsProvider::class.java, NoOpKtCompilerPluginsProvider)
|
||||
registerService(ReadWriteAccessChecker::class.java, ReadWriteAccessCheckerFirImpl())
|
||||
registerService(KotlinReferenceProviderContributor::class.java, KotlinFirReferenceContributor::class.java)
|
||||
registerService(JvmFirDeserializedSymbolProviderFactory::class.java, JvmStubBasedDeserializedSymbolProviderFactory::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -14,6 +14,7 @@ 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.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||
@@ -33,6 +34,7 @@ object FirLowLevelCompilerBasedTestConfigurator : AnalysisApiTestConfigurator()
|
||||
|
||||
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> = listOf(
|
||||
AnalysisApiBaseTestServiceRegistrar,
|
||||
AnalysisApiDecompiledCodeTestServiceRegistrar,
|
||||
AnalysisApiFirTestServiceRegistrar,
|
||||
)
|
||||
|
||||
|
||||
+2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.SealedClassesInheritorsCaclulatorPreAnalysisHandler
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AnalysisApiFirTestServiceRegistrar
|
||||
@@ -35,6 +36,7 @@ abstract class AnalysisApiFirSourceLikeTestConfigurator(override val analyseInDe
|
||||
|
||||
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> = listOf(
|
||||
AnalysisApiBaseTestServiceRegistrar,
|
||||
AnalysisApiDecompiledCodeTestServiceRegistrar,
|
||||
AnalysisApiFirTestServiceRegistrar,
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ private fun FirRegularClassBuilder.addSerializableIfNeeded(classId: ClassId) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId, dispatchReceiver: ConeClassLikeType?) {
|
||||
fun FirRegularClassBuilder.addCloneForArrayIfNeeded(classId: ClassId, dispatchReceiver: ConeClassLikeType?) {
|
||||
if (classId.packageFqName != StandardClassIds.BASE_KOTLIN_PACKAGE) return
|
||||
if (classId.shortClassName !in ARRAY_CLASSES) return
|
||||
superTypeRefs += buildResolvedTypeRef {
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
// Use it in application sessions for loading classes from Java files listed on the command line.
|
||||
// For library and incremental compilation sessions use `KotlinDeserializedJvmSymbolsProvider`
|
||||
// in order to load Kotlin classes as well.
|
||||
//Also used in IDE for loading java classes separately from stub based kotlin classes
|
||||
class JavaSymbolProvider(
|
||||
session: FirSession,
|
||||
private val javaFacade: FirJavaFacade,
|
||||
|
||||
+1
@@ -1056,6 +1056,7 @@ fun <T> FirRegularClassBuilder.createDataClassCopyFunction(
|
||||
status = FirDeclarationStatusImpl(Visibilities.Public, Modality.FINAL)
|
||||
symbol = FirNamedFunctionSymbol(CallableId(classId.packageFqName, classId.relativeClassName, StandardNames.DATA_CLASS_COPY))
|
||||
dispatchReceiverType = dispatchReceiver
|
||||
resolvePhase = this@createDataClassCopyFunction.resolvePhase
|
||||
for ((ktParameter, firProperty) in zippedParameters) {
|
||||
val propertyName = firProperty.name
|
||||
val parameterSource = toFirSource(ktParameter, KtFakeSourceElementKind.DataClassGeneratedMembers)
|
||||
|
||||
@@ -160,7 +160,7 @@ fun FirRegularClassBuilder.generateEntriesGetter(
|
||||
getter = FirDefaultPropertyGetter(
|
||||
sourceElement?.fakeElement(KtFakeSourceElementKind.EnumGeneratedDeclaration),
|
||||
moduleData, origin, returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.EnumGeneratedDeclaration),
|
||||
Visibilities.Public, symbol
|
||||
Visibilities.Public, symbol, resolvePhase = this@generateEntriesGetter.resolvePhase
|
||||
).apply {
|
||||
this.status = createStatus(this@generateEntriesGetter.status).apply {
|
||||
isStatic = true
|
||||
|
||||
+4
-1
@@ -41,12 +41,15 @@ public class KtNameReferenceExpressionElementType extends KtStubElementType<Kotl
|
||||
@Override
|
||||
public void serialize(@NotNull KotlinNameReferenceExpressionStub stub, @NotNull StubOutputStream dataStream) throws IOException {
|
||||
dataStream.writeName(stub.getReferencedName());
|
||||
dataStream.writeBoolean(
|
||||
stub instanceof KotlinNameReferenceExpressionStubImpl && ((KotlinNameReferenceExpressionStubImpl) stub).isClassRef());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KotlinNameReferenceExpressionStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
|
||||
StringRef referencedName = dataStream.readName();
|
||||
return new KotlinNameReferenceExpressionStubImpl(parentStub, referencedName);
|
||||
boolean isClassRef = dataStream.readBoolean();
|
||||
return new KotlinNameReferenceExpressionStubImpl(parentStub, referencedName, isClassRef);
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -16,9 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi.stubs.impl;
|
||||
|
||||
import com.intellij.psi.stubs.IStubElementType;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.util.io.StringRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinNameReferenceExpressionStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||
@@ -27,10 +29,26 @@ public class KotlinNameReferenceExpressionStubImpl extends KotlinStubBaseImpl<Kt
|
||||
KotlinNameReferenceExpressionStub {
|
||||
@NotNull
|
||||
private final StringRef referencedName;
|
||||
private final boolean myClassRef;
|
||||
|
||||
public KotlinNameReferenceExpressionStubImpl(StubElement parent, @NotNull StringRef referencedName) {
|
||||
super(parent, KtStubElementTypes.REFERENCE_EXPRESSION);
|
||||
this.referencedName = referencedName;
|
||||
myClassRef = false;
|
||||
}
|
||||
|
||||
public KotlinNameReferenceExpressionStubImpl(
|
||||
@Nullable StubElement<?> parent,
|
||||
@NotNull StringRef referencedName,
|
||||
boolean myClassRef
|
||||
) {
|
||||
super(parent, KtStubElementTypes.REFERENCE_EXPRESSION);
|
||||
this.referencedName = referencedName;
|
||||
this.myClassRef = myClassRef;
|
||||
}
|
||||
|
||||
public boolean isClassRef() {
|
||||
return myClassRef;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user