diff --git a/dokka-subprojects/analysis-kotlin-descriptors-compiler/api/analysis-kotlin-descriptors-compiler.api b/dokka-subprojects/analysis-kotlin-descriptors-compiler/api/analysis-kotlin-descriptors-compiler.api index 81e38d335a..e7a5234fe6 100644 --- a/dokka-subprojects/analysis-kotlin-descriptors-compiler/api/analysis-kotlin-descriptors-compiler.api +++ b/dokka-subprojects/analysis-kotlin-descriptors-compiler/api/analysis-kotlin-descriptors-compiler.api @@ -84,33 +84,3 @@ public abstract class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/c public final fun get (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext; } -public final class org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl : com/intellij/core/CoreJavaFileManager, org/jetbrains/kotlin/resolve/jvm/KotlinCliJavaFileManager { - public static final field Companion Lorg/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl$Companion; - public fun (Lcom/intellij/psi/PsiManager;)V - public fun findClass (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)Lcom/intellij/psi/PsiClass; - public fun findClass (Lorg/jetbrains/kotlin/load/java/JavaClassFinder$Request;Lcom/intellij/psi/search/GlobalSearchScope;)Lorg/jetbrains/kotlin/load/java/structure/JavaClass; - public final fun findClass (Lorg/jetbrains/kotlin/name/ClassId;Lcom/intellij/psi/search/GlobalSearchScope;)Lorg/jetbrains/kotlin/load/java/structure/JavaClass; - public fun findClasses (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)[Lcom/intellij/psi/PsiClass; - public fun findModules (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)Ljava/util/Collection; - public fun findPackage (Ljava/lang/String;)Lcom/intellij/psi/PsiPackage; - public fun getNonTrivialPackagePrefixes ()Ljava/util/Collection; - public final fun initialize (Lorg/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndex;Ljava/util/List;Lorg/jetbrains/kotlin/cli/jvm/index/SingleJavaFileRootsIndex;Z)V - public fun knownClassNamesInPackage (Lorg/jetbrains/kotlin/name/FqName;)Ljava/util/Set; -} - -public final class org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl$Companion { -} - -public final class org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl : org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndex { - public fun (Ljava/util/List;)V - public fun findClass (Lorg/jetbrains/kotlin/name/ClassId;Ljava/util/Set;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public fun getIndexedRoots ()Lkotlin/sequences/Sequence; - public fun traverseDirectoriesInPackage (Lorg/jetbrains/kotlin/name/FqName;Ljava/util/Set;Lkotlin/jvm/functions/Function2;)V -} - -public final class org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer { - public fun (Lorg/jetbrains/kotlin/descriptors/ModuleDescriptor;Lorg/jetbrains/kotlin/descriptors/NotFoundClasses;)V - public final fun deserializeAnnotation (Lorg/jetbrains/kotlin/metadata/ProtoBuf$Annotation;Lorg/jetbrains/kotlin/metadata/deserialization/NameResolver;)Lorg/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor; - public final fun resolveValue (Lorg/jetbrains/kotlin/types/KotlinType;Lorg/jetbrains/kotlin/metadata/ProtoBuf$Annotation$Argument$Value;Lorg/jetbrains/kotlin/metadata/deserialization/NameResolver;)Lorg/jetbrains/kotlin/resolve/constants/ConstantValue; -} - diff --git a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt b/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt deleted file mode 100644 index afcb3738eb..0000000000 --- a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -/** - * DO NOT MOVE IT - * This is a hack for https://github.com/Kotlin/dokka/issues/1599 - * - * Copy-pasted from 1.9.20-Beta-1 - * Can be removed for Kotlin compiler 1.9.20 and later - * - * It makes this class threadsafe for Dokka - */ -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.cli.jvm.index - -import com.intellij.ide.highlighter.JavaClassFileType -import com.intellij.ide.highlighter.JavaFileType -import com.intellij.openapi.vfs.VfsUtilCore -import com.intellij.openapi.vfs.VirtualFile -import gnu.trove.THashMap -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import java.util.* -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock - -// speeds up finding files/classes in classpath/java source roots -// TODO: KT-58327 needs to be adapted/removed if we want compiler to be multithreaded -// the main idea of this class is for each package to store roots which contains it to avoid excessive file system traversal -public class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex { - private val lock = ReentrantLock() - - //these fields are computed based on _roots passed to constructor which are filled in later - private val roots: List by lazy { _roots.toList() } - - private val maxIndex: Int - get() = roots.size - - // each "Cache" object corresponds to a package - private class Cache { - private val innerPackageCaches = HashMap() - - operator fun get(name: String) = innerPackageCaches.getOrPut(name, ::Cache) - - // indices of roots that are known to contain this package - // if this list contains [1, 3, 5] then roots with indices 1, 3 and 5 are known to contain this package, 2 and 4 are known not to (no information about roots 6 or higher) - // if this list contains maxIndex that means that all roots containing this package are known - @Suppress("DEPRECATION") // TODO: fix deprecation - val rootIndices = com.intellij.util.containers.IntArrayList(2) - } - - // root "Cache" object corresponds to DefaultPackage which exists in every root. Roots with non-default fqname are also listed here but - // they will be ignored on requests with invalid fqname prefix. - private val rootCache: Cache by lazy { - Cache().apply { - roots.indices.forEach(rootIndices::add) - rootIndices.add(maxIndex) - rootIndices.trimToSize() - } - } - - // holds the request and the result last time we searched for class - // helps improve several scenarios, LazyJavaResolverContext.findClassInJava being the most important - private var lastClassSearch: Pair? = null - - override val indexedRoots: Sequence by lazy { roots.asSequence() } - - private val packageCache: Array> by lazy { - Array(roots.size) { THashMap() } - } - - override fun traverseDirectoriesInPackage( - packageFqName: FqName, - acceptedRootTypes: Set, - continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean - ) { - lock.withLock { - search(TraverseRequest(packageFqName, acceptedRootTypes)) { dir, rootType -> - if (continueSearch(dir, rootType)) null else Unit - } - } - } - - // findClassGivenDirectory MUST check whether the class with this classId exists in given package - override fun findClass( - classId: ClassId, - acceptedRootTypes: Set, - findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T? - ): T? { - lock.withLock { - // TODO: KT-58327 probably should be changed to thread local to fix fast-path - // make a decision based on information saved from last class search - if (lastClassSearch?.first?.classId != classId) { - return search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory) - } - - val (cachedRequest, cachedResult) = lastClassSearch!! - return when (cachedResult) { - is SearchResult.NotFound -> { - val limitedRootTypes = acceptedRootTypes - cachedRequest.acceptedRootTypes - if (limitedRootTypes.isEmpty()) { - null - } else { - search(FindClassRequest(classId, limitedRootTypes), findClassGivenDirectory) - } - } - is SearchResult.Found -> { - if (cachedRequest.acceptedRootTypes == acceptedRootTypes) { - findClassGivenDirectory(cachedResult.packageDirectory, cachedResult.root.type) - } else { - search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory) - } - } - } - } - } - - private fun search(request: SearchRequest, handler: (VirtualFile, JavaRoot.RootType) -> T?): T? { - // a list of package sub names, ["org", "jb", "kotlin"] - val packagesPath = request.packageFqName.pathSegments().map { it.identifierOrNullIfSpecial ?: return null } - // a list of caches corresponding to packages, [default, "org", "org.jb", "org.jb.kotlin"] - val caches = cachesPath(packagesPath) - - var processedRootsUpTo = -1 - // traverse caches starting from last, which contains most specific information - - // NOTE: indices manipulation instead of using caches.reversed() is here for performance reasons - for (cacheIndex in caches.lastIndex downTo 0) { - val cacheRootIndices = caches[cacheIndex].rootIndices - for (i in 0 until cacheRootIndices.size()) { - val rootIndex = cacheRootIndices[i] - if (rootIndex <= processedRootsUpTo) continue // roots with those indices have been processed by now - - val directoryInRoot = travelPath(rootIndex, request.packageFqName, packagesPath, cacheIndex, caches) ?: continue - val root = roots[rootIndex] - if (root.type in request.acceptedRootTypes) { - val result = handler(directoryInRoot, root.type) - if (result != null) { - if (request is FindClassRequest) { - lastClassSearch = Pair(request, SearchResult.Found(directoryInRoot, root)) - } - return result - } - } - } - processedRootsUpTo = if (cacheRootIndices.isEmpty) processedRootsUpTo else cacheRootIndices[cacheRootIndices.size() - 1] - } - - if (request is FindClassRequest) { - lastClassSearch = Pair(request, SearchResult.NotFound) - } - return null - } - - // try to find a target directory corresponding to package represented by packagesPath in a given root represented by index - // possibly filling "Cache" objects with new information - private fun travelPath( - rootIndex: Int, - packageFqName: FqName, - packagesPath: List, - fillCachesAfter: Int, - cachesPath: List - ): VirtualFile? { - if (rootIndex >= maxIndex) { - for (i in (fillCachesAfter + 1) until cachesPath.size) { - // we all know roots that contain this package by now - cachesPath[i].rootIndices.add(maxIndex) - cachesPath[i].rootIndices.trimToSize() - } - return null - } - - return packageCache[rootIndex].getOrPut(packageFqName.asString()) { - doTravelPath(rootIndex, packagesPath, fillCachesAfter, cachesPath) - } - } - - private fun doTravelPath(rootIndex: Int, packagesPath: List, fillCachesAfter: Int, cachesPath: List): VirtualFile? { - val pathRoot = roots[rootIndex] - val prefixPathSegments = pathRoot.prefixFqName?.pathSegments() - - var currentFile = pathRoot.file - - for (pathIndex in packagesPath.indices) { - val subPackageName = packagesPath[pathIndex] - if (prefixPathSegments != null && pathIndex < prefixPathSegments.size) { - // Traverse prefix first instead of traversing real directories - if (prefixPathSegments[pathIndex].identifier != subPackageName) { - return null - } - } else { - currentFile = currentFile.findChildPackage(subPackageName, pathRoot.type) ?: return null - } - - val correspondingCacheIndex = pathIndex + 1 - if (correspondingCacheIndex > fillCachesAfter) { - // subPackageName exists in this root - cachesPath[correspondingCacheIndex].rootIndices.add(rootIndex) - } - } - - return currentFile - } - - private fun VirtualFile.findChildPackage(subPackageName: String, rootType: JavaRoot.RootType): VirtualFile? { - val childDirectory = findChild(subPackageName) ?: return null - - val fileExtension = when (rootType) { - JavaRoot.RootType.BINARY -> JavaClassFileType.INSTANCE.defaultExtension - JavaRoot.RootType.BINARY_SIG -> "sig" - JavaRoot.RootType.SOURCE -> JavaFileType.INSTANCE.defaultExtension - } - - // If in addition to a directory "foo" there's a class file "foo.class" AND there are no classes anywhere in the directory "foo", - // then we ignore the directory and let the resolution choose the class "foo" instead. - if (findChild("$subPackageName.$fileExtension")?.isDirectory == false) { - if (VfsUtilCore.processFilesRecursively(childDirectory) { file -> file.extension != fileExtension }) { - return null - } - } - - return childDirectory - } - - private fun cachesPath(path: List): List { - val caches = ArrayList(path.size + 1) - caches.add(rootCache) - var currentCache = rootCache - for (subPackageName in path) { - currentCache = currentCache[subPackageName] - caches.add(currentCache) - } - return caches - } - - private data class FindClassRequest(val classId: ClassId, override val acceptedRootTypes: Set) : SearchRequest { - override val packageFqName: FqName - get() = classId.packageFqName - } - - private data class TraverseRequest( - override val packageFqName: FqName, - override val acceptedRootTypes: Set - ) : SearchRequest - - private interface SearchRequest { - val packageFqName: FqName - val acceptedRootTypes: Set - } - - private sealed class SearchResult { - class Found(val packageDirectory: VirtualFile, val root: JavaRoot) : SearchResult() - - object NotFound : SearchResult() - } -} diff --git a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt b/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt deleted file mode 100644 index 3dd9fa606b..0000000000 --- a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -/** - * DO NOT MOVE IT - * This is a hack for https://github.com/Kotlin/dokka/issues/1599 - * - * Copy-pasted from Kotlin compiler - * - * It makes this class threadsafe (`topLevelClassesCache` and `binaryCache`) for Dokka - * - */ -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.cli.jvm.compiler - -import com.intellij.core.CoreJavaFileManager -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.* -import com.intellij.psi.impl.file.PsiPackageImpl -import com.intellij.psi.search.GlobalSearchScope -import gnu.trove.THashMap -import gnu.trove.THashSet -import org.jetbrains.kotlin.cli.jvm.index.JavaRoot -import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex -import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex -import org.jetbrains.kotlin.load.java.JavaClassFinder -import org.jetbrains.kotlin.load.java.structure.JavaClass -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.isNotTopLevelClass -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager -import org.jetbrains.kotlin.util.PerformanceCounter - -// TODO: do not inherit from CoreJavaFileManager to avoid accidental usage of its methods which do not use caches/indices -// Currently, the only relevant usage of this class as CoreJavaFileManager is at CoreJavaDirectoryService.getPackage, -// which is indirectly invoked from PsiPackage.getSubPackages -public class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager { - private val perfCounter = PerformanceCounter.create("Find Java class") - private lateinit var index: JvmDependenciesIndex - private lateinit var singleJavaFileRootsIndex: SingleJavaFileRootsIndex - private lateinit var packagePartProviders: List - private val topLevelClassesCache: MutableMap = THashMap() - private val allScope = GlobalSearchScope.allScope(myPsiManager.project) - private var usePsiClassFilesReading = false - - public fun initialize( - index: JvmDependenciesIndex, - packagePartProviders: List, - singleJavaFileRootsIndex: SingleJavaFileRootsIndex, - usePsiClassFilesReading: Boolean - ) { - this.index = index - this.packagePartProviders = packagePartProviders - this.singleJavaFileRootsIndex = singleJavaFileRootsIndex - this.usePsiClassFilesReading = usePsiClassFilesReading - } - - private fun findPsiClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? = perfCounter.time { - findVirtualFileForTopLevelClass(classId, searchScope)?.findPsiClassInVirtualFile(classId.relativeClassName.asString()) - } - - private fun findVirtualFileForTopLevelClass(classId: ClassId, searchScope: GlobalSearchScope): VirtualFile? { - val relativeClassName = classId.relativeClassName.asString() - synchronized(topLevelClassesCache) { - return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) { - index.findClass(classId) { dir, type -> - findVirtualFileGivenPackage(dir, relativeClassName, type) - } ?: singleJavaFileRootsIndex.findJavaSourceClass(classId) - }?.takeIf { it in searchScope } - } - } - - private val binaryCache: MutableMap = THashMap() - private val signatureParsingComponent = BinaryClassSignatureParser() - - public fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope) - - override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? { - val (classId, classFileContentFromRequest, outerClassFromRequest) = request - val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null - - if (!usePsiClassFilesReading && (virtualFile.extension == "class" || virtualFile.extension == "sig")) { - synchronized(binaryCache){ - // We return all class files' names in the directory in knownClassNamesInPackage method, so one may request an inner class - return binaryCache.getOrPut(classId) { - // Note that currently we implicitly suppose that searchScope for binary classes is constant and we do not use it - // as a key in cache - // This is a true assumption by now since there are two search scopes in compiler: one for sources and another one for binary - // When it become wrong because we introduce the modules into CLI, it's worth to consider - // having different KotlinCliJavaFileManagerImpl's for different modules - - classId.outerClassId?.let { outerClassId -> - val outerClass = outerClassFromRequest ?: findClass(outerClassId, searchScope) - - return if (outerClass is BinaryJavaClass) - outerClass.findInnerClass(classId.shortClassName, classFileContentFromRequest) - else - outerClass?.findInnerClass(classId.shortClassName) - } - - // Here, we assume the class is top-level - val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray() - if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null - - val resolver = ClassifierResolutionContext { findClass(it, allScope) } - - BinaryJavaClass( - virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent, - outerClass = null, classContent = classContent - ) - } - } - } - - return virtualFile.findPsiClassInVirtualFile(classId.relativeClassName.asString())?.let(::JavaClassImpl) - } - - // this method is called from IDEA to resolve dependencies in Java code - // which supposedly shouldn't have errors so the dependencies exist in general - override fun findClass(qName: String, scope: GlobalSearchScope): PsiClass? { - // String cannot be reliably converted to ClassId because we don't know where the package name ends and class names begin. - // For example, if qName is "a.b.c.d.e", we should either look for a top level class "e" in the package "a.b.c.d", - // or, for example, for a nested class with the relative qualified name "c.d.e" in the package "a.b". - // Below, we start by looking for the top level class "e" in the package "a.b.c.d" first, then for the class "d.e" in the package - // "a.b.c", and so on, until we find something. Most classes are top level, so most of the times the search ends quickly - - forEachClassId(qName) { classId -> - findPsiClass(classId, scope)?.let { return it } - } - - return null - } - - private inline fun forEachClassId(fqName: String, block: (ClassId) -> Unit) { - var classId = fqName.toSafeTopLevelClassId() ?: return - - while (true) { - block(classId) - - val packageFqName = classId.packageFqName - if (packageFqName.isRoot) break - - classId = ClassId( - packageFqName.parent(), - FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), - false - ) - } - } - - override fun findClasses(qName: String, scope: GlobalSearchScope): Array = perfCounter.time { - val result = ArrayList(1) - forEachClassId(qName) { classId -> - val relativeClassName = classId.relativeClassName.asString() - index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> - val psiClass = - findVirtualFileGivenPackage(dir, relativeClassName, rootType) - ?.takeIf { it in scope } - ?.findPsiClassInVirtualFile(relativeClassName) - if (psiClass != null) { - result.add(psiClass) - } - // traverse all - true - } - - singleJavaFileRootsIndex.findJavaSourceClass(classId) - ?.takeIf { it in scope } - ?.findPsiClassInVirtualFile(relativeClassName) - ?.let { result.add(it) } - - if (result.isNotEmpty()) { - return@time result.toTypedArray() - } - } - - PsiClass.EMPTY_ARRAY - } - - override fun findPackage(packageName: String): PsiPackage? { - var found = false - val packageFqName = packageName.toSafeFqName() ?: return null - index.traverseDirectoriesInPackage(packageFqName) { _, _ -> - found = true - //abort on first found - false - } - if (!found) { - found = packagePartProviders.any { it.findPackageParts(packageName).isNotEmpty() } - } - if (!found) { - found = singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName).isNotEmpty() - } - return if (found) PsiPackageImpl(myPsiManager, packageName) else null - } - - private fun findVirtualFileGivenPackage( - packageDir: VirtualFile, - classNameWithInnerClasses: String, - rootType: JavaRoot.RootType - ): VirtualFile? { - val topLevelClassName = classNameWithInnerClasses.substringBefore('.') - - val vFile = when (rootType) { - JavaRoot.RootType.BINARY -> packageDir.findChild("$topLevelClassName.class") - JavaRoot.RootType.BINARY_SIG -> packageDir.findChild("$topLevelClassName.sig") - JavaRoot.RootType.SOURCE -> packageDir.findChild("$topLevelClassName.java") - } ?: return null - - if (!vFile.isValid) { - LOG.error("Invalid child of valid parent: ${vFile.path}; ${packageDir.isValid} path=${packageDir.path}") - return null - } - - return vFile - } - - private fun VirtualFile.findPsiClassInVirtualFile(classNameWithInnerClasses: String): PsiClass? { - val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null - return findClassInPsiFile(classNameWithInnerClasses, file) - } - - override fun knownClassNamesInPackage(packageFqName: FqName): Set { - val result = THashSet() - index.traverseDirectoriesInPackage(packageFqName, continueSearch = { dir, _ -> - for (child in dir.children) { - if (child.extension == "class" || child.extension == "java" || child.extension == "sig") { - result.add(child.nameWithoutExtension) - } - } - - true - }) - - for (classId in singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName)) { - assert(!classId.isNestedClass) { "ClassId of a single .java source class should not be nested: $classId" } - result.add(classId.shortClassName.asString()) - } - - return result - } - - override fun findModules(moduleName: String, scope: GlobalSearchScope): Collection { - // TODO - return emptySet() - } - - override fun getNonTrivialPackagePrefixes(): Collection = emptyList() - - public companion object { - private val LOG = Logger.getInstance(KotlinCliJavaFileManagerImpl::class.java) - - private fun findClassInPsiFile(classNameWithInnerClassesDotSeparated: String, file: PsiClassOwner): PsiClass? { - for (topLevelClass in file.classes) { - val candidate = findClassByTopLevelClass(classNameWithInnerClassesDotSeparated, topLevelClass) - if (candidate != null) { - return candidate - } - } - return null - } - - private fun findClassByTopLevelClass(className: String, topLevelClass: PsiClass): PsiClass? { - if (className.indexOf('.') < 0) { - return if (className == topLevelClass.name) topLevelClass else null - } - - val segments = StringUtil.split(className, ".").iterator() - if (!segments.hasNext() || segments.next() != topLevelClass.name) { - return null - } - var curClass = topLevelClass - while (segments.hasNext()) { - val innerClassName = segments.next() - val innerClass = curClass.findInnerClassByName(innerClassName, false) ?: return null - curClass = innerClass - } - return curClass - } - } -} - -// a sad workaround to avoid throwing exception when called from inside IDEA code -private fun safely(compute: () -> T): T? = - try { - compute() - } catch (e: IllegalArgumentException) { - null - } catch (e: AssertionError) { - null - } - -private fun String.toSafeFqName(): FqName? = safely { FqName(this) } -private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) } diff --git a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt b/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt deleted file mode 100644 index e2e8ce84bc..0000000000 --- a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -/** - * DO NOT MOVE IT - * This is a hack for https://github.com/Kotlin/dokka/issues/1599, https://youtrack.jetbrains.com/issue/KT-72154. - * - * This file was copy-pasted from Kotlin compiler sources with the patch applied based on the changes in: - * https://github.com/jetbrains/kotlin/commit/f34ab0eccd9ef01476f82e86e741a4703fd551f7. - * The changes are different from commit changes as we can't hack `KotlinBuiltIns.java` in the same way. - * - * Patch is highlighted by `TODO: PATCH` - * - * This should be removed after updating to Kotlin Compiler 2.1.0. - */ -package org.jetbrains.kotlin.serialization.deserialization - -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl -import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation -import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument -import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value -import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type -import org.jetbrains.kotlin.metadata.deserialization.Flags -import org.jetbrains.kotlin.metadata.deserialization.NameResolver -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.constants.* -import org.jetbrains.kotlin.types.error.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType - -public class AnnotationDeserializer(private val module: ModuleDescriptor, private val notFoundClasses: NotFoundClasses) { - private val builtIns: KotlinBuiltIns - get() = module.builtIns - - public fun deserializeAnnotation(proto: Annotation, nameResolver: NameResolver): AnnotationDescriptor { - val annotationClass = resolveClass(nameResolver.getClassId(proto.id)) - - var arguments = emptyMap>() - if (proto.argumentCount != 0 && !ErrorUtils.isError(annotationClass) && DescriptorUtils.isAnnotationClass(annotationClass)) { - val constructor = annotationClass.constructors.singleOrNull() - if (constructor != null) { - val parameterByName = constructor.valueParameters.associateBy { it.name } - arguments = proto.argumentList.mapNotNull { resolveArgument(it, parameterByName, nameResolver) }.toMap() - } - } - - return AnnotationDescriptorImpl(annotationClass.defaultType, arguments, SourceElement.NO_SOURCE) - } - - private fun resolveArgument( - proto: Argument, - parameterByName: Map, - nameResolver: NameResolver - ): Pair>? { - val parameter = parameterByName[nameResolver.getName(proto.nameId)] ?: return null - return Pair(nameResolver.getName(proto.nameId), resolveValueAndCheckExpectedType(parameter.type, proto.value, nameResolver)) - } - - private fun resolveValueAndCheckExpectedType(expectedType: KotlinType, value: Value, nameResolver: NameResolver): ConstantValue<*> { - return resolveValue(expectedType, value, nameResolver).takeIf { - doesValueConformToExpectedType(it, expectedType, value) - } ?: ErrorValue.create("Unexpected argument value: actual type ${value.type} != expected type $expectedType") - } - - public fun resolveValue(expectedType: KotlinType, value: Value, nameResolver: NameResolver): ConstantValue<*> { - val isUnsigned = Flags.IS_UNSIGNED.get(value.flags) - - return when (value.type) { - Type.BYTE -> value.intValue.toByte().letIf(isUnsigned, ::UByteValue, ::ByteValue) - Type.CHAR -> CharValue(value.intValue.toInt().toChar()) - Type.SHORT -> value.intValue.toShort().letIf(isUnsigned, ::UShortValue, ::ShortValue) - Type.INT -> value.intValue.toInt().letIf(isUnsigned, ::UIntValue, ::IntValue) - Type.LONG -> value.intValue.letIf(isUnsigned, ::ULongValue, ::LongValue) - Type.FLOAT -> FloatValue(value.floatValue) - Type.DOUBLE -> DoubleValue(value.doubleValue) - Type.BOOLEAN -> BooleanValue(value.intValue != 0L) - Type.STRING -> StringValue(nameResolver.getString(value.stringValue)) - Type.CLASS -> KClassValue(nameResolver.getClassId(value.classId), value.arrayDimensionCount) - Type.ENUM -> EnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId)) - Type.ANNOTATION -> AnnotationValue(deserializeAnnotation(value.annotation, nameResolver)) - Type.ARRAY -> ConstantValueFactory.createArrayValue( - value.arrayElementList.map { resolveValue(builtIns.anyType, it, nameResolver) }, - expectedType - ) - else -> error("Unsupported annotation argument type: ${value.type} (expected $expectedType)") - } - } - - // This method returns false if the actual value loaded from an annotation argument does not conform to the expected type of the - // corresponding parameter in the annotation class. This usually means that the annotation class has been changed incompatibly - // without recompiling clients, in which case we prefer not to load the annotation argument value at all, to avoid constructing - // an incorrect model and breaking some assumptions in the compiler. - private fun doesValueConformToExpectedType(result: ConstantValue<*>, expectedType: KotlinType, value: Value): Boolean { - return when (value.type) { - Type.CLASS -> { - val expectedClass = expectedType.constructor.declarationDescriptor as? ClassDescriptor - // We could also check that the class value's type is a subtype of the expected type, but loading the definition of the - // referenced class here is undesirable and may even be incorrect (because the module might be different at the - // destination where these constant values are read). This can lead to slightly incorrect model in some edge cases. - expectedClass == null || KotlinBuiltIns.isKClass(expectedClass) - } - Type.ARRAY -> { - check(result is ArrayValue && result.value.size == value.arrayElementList.size) { - "Deserialized ArrayValue should have the same number of elements as the original array value: $result" - } - - // TODO: PATCH START - val expectedElementType = try { - builtIns.getArrayElementType(expectedType) - } catch (e: IllegalStateException) { - return false - } - // TODO: PATCH END - - result.value.indices.all { i -> - doesValueConformToExpectedType(result.value[i], expectedElementType, value.getArrayElement(i)) - } - } - else -> result.getType(module) == expectedType - } - } - - private inline fun T.letIf(predicate: Boolean, f: (T) -> R, g: (T) -> R): R = - if (predicate) f(this) else g(this) - - private fun resolveClass(classId: ClassId): ClassDescriptor { - return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses) - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9bf97de3b3..94a447ea4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ kotlinx-bcv = "0.13.2" ktor = "2.3.11" ## Analysis -kotlin-compiler = "2.0.20" +kotlin-compiler = "2.1.0-RC-330" kotlin-compiler-k2 = "2.1.0-dev-5441" # MUST match the version of the intellij platform used in the kotlin compiler,