From 1a27698a8f04c51640c0aa6c4ec371113a248691 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 31 Aug 2023 12:46:53 +0200 Subject: [PATCH 1/4] Migrate K2-Based dokka to use the new standalone mode API see https://youtrack.jetbrains.com/issue/KT-60884 --- .../kotlin/symbols/plugin/KotlinAnalysis.kt | 83 +++++++------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt index 9419ec651c..e102969aa5 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt @@ -15,8 +15,11 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.ProjectScope import com.intellij.util.io.URLUtil import org.jetbrains.dokka.Platform +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider +import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule @@ -71,6 +74,7 @@ internal fun getLanguageVersionSettings( } // it should be changed after https://github.com/Kotlin/dokka/issues/3114 +@OptIn(KtAnalysisApiInternals::class) internal fun createAnalysisSession( classpath: List, sourceRoots: Set, @@ -87,72 +91,41 @@ internal fun createAnalysisSession( projectDisposable = projectDisposable, withPsiDeclarationFromBinaryModuleProvider = false ) { - val project = project + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) val targetPlatform = analysisPlatform.toTargetPlatform() - fun KtModuleBuilder.addModuleDependencies(moduleName: String) { + + buildKtModuleProvider { val libraryRoots = classpath - addRegularDependency( - buildKtLibraryModule { - contentScope = ProjectScope.getLibrariesScope(project) - this.platform = targetPlatform - this.project = project - binaryRoots = libraryRoots.map { it.toPath() } - libraryName = "Library for $moduleName" - } - ) - getJdkHomeFromSystemProperty()?.let { jdkHome -> - val vfm = VirtualFileManager.getInstance() - val jdkHomePath = jdkHome.toPath() - val jdkHomeVirtualFile = vfm.findFileByNioPath(jdkHome.toPath())//vfm.findFileByPath(jdkHomePath) - val binaryRoots = LibraryUtils.findClassesFromJdkHome(jdkHomePath).map { - Paths.get(URLUtil.extractPath(it)) - } + fun KtModuleBuilder.addModuleDependencies(moduleName: String) { addRegularDependency( - buildKtSdkModule { - contentScope = GlobalSearchScope.fileScope(project, jdkHomeVirtualFile) + buildKtLibraryModule { this.platform = targetPlatform - this.project = project - this.binaryRoots = binaryRoots - sdkName = "JDK for $moduleName" + addBinaryRoots(libraryRoots.map { it.toPath() }) + libraryName = "Library for $moduleName" } ) + getJdkHomeFromSystemProperty()?.let { jdkHome -> + addRegularDependency( + buildKtSdkModule { + this.platform = targetPlatform + addBinaryRootsFromJdkHome(jdkHome.toPath(), isJre = true) + sdkName = "JDK for $moduleName" + } + ) + } + } + sourceModule = buildKtSourceModule { + languageVersionSettings = getLanguageVersionSettings(languageVersion, apiVersion) + platform = targetPlatform + moduleName = "" + // TODO: We should handle (virtual) file changes announced via LSP with the VFS + addSourceRoots(sourceRoots.map { it.toPath() }) + addModuleDependencies(moduleName) } - } - sourceModule = buildKtSourceModule { - this.languageVersionSettings = getLanguageVersionSettings(languageVersion, apiVersion) - - //val fs = StandardFileSystems.local() - //val psiManager = PsiManager.getInstance(project) - // TODO: We should handle (virtual) file changes announced via LSP with the VFS - /*val ktFiles = sources - .flatMap { Files.walk(it).toList() } - .mapNotNull { fs.findFileByPath(it.toString()) } - .mapNotNull { psiManager.findFile(it) } - .map { it as KtFile }*/ - val sourcePaths = sourceRoots.map { it.absolutePath } - val (ktFilePath, javaFilePath) = getSourceFilePaths(sourcePaths).partition { it.endsWith(KotlinFileType.EXTENSION) } - val javaFiles: List = getPsiFilesFromPaths(project, javaFilePath) - val ktFiles: List = getPsiFilesFromPaths(project, getSourceFilePaths(ktFilePath)) - addSourceRoots(ktFiles + javaFiles) - contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles) - platform = targetPlatform - moduleName = "" - this.project = project - addModuleDependencies(moduleName) - } - - buildKtModuleProvider { platform = targetPlatform - this.project = project addModule(sourceModule!!) } } - // TODO remove further - CoreApplicationEnvironment.registerExtensionPoint( - analysisSession.project.extensionArea, - KtResolveExtensionProvider.EP_NAME.name, - KtResolveExtensionProvider::class.java - ) return Pair(analysisSession, sourceModule ?: throw IllegalStateException()) } From 6b6cdbfecb8685abc3ac3fd84d71c7e3fb865de3 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 31 Aug 2023 14:04:42 +0200 Subject: [PATCH 2/4] Do not use copy-n-pasted code from Analysis API in K2-Based Dokka see https://youtrack.jetbrains.com/issue/KT-60884 --- .../dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt | 3 ++- .../translators/DefaultSymbolToDocumentableTranslator.kt | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt index 9ccd52b297..cf57e81539 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt @@ -125,11 +125,12 @@ internal open class EnvironmentKotlinAnalysis( internal interface AnalysisContext: Closeable { val project: Project val mainModule: KtSourceModule + val analysisSession: StandaloneAnalysisAPISession } private class AnalysisContextImpl( override val mainModule: KtSourceModule, - private val analysisSession: StandaloneAnalysisAPISession, + override val analysisSession: StandaloneAnalysisAPISession, private val applicationDisposable: Disposable, private val projectDisposable: Disposable ) : AnalysisContext { diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt index f217c88f9f..74d312690f 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt @@ -118,10 +118,7 @@ internal class DokkaSymbolVisitor( } fun visitModule(): DModule { - val ktFiles: List = getPsiFilesFromPaths( - analysisContext.project, - getSourceFilePaths(sourceSet.sourceRoots.map { it.canonicalPath }) - ) + val ktFiles = analysisContext.analysisSession.modulesWithFiles.entries.single().value.filterIsInstance() val processedPackages: MutableSet = mutableSetOf() return analyze(analysisContext.mainModule) { val packageSymbols: List = ktFiles From 714de11bfdd2117caff7f3c00ccc4aef3239580d Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 31 Aug 2023 14:05:51 +0200 Subject: [PATCH 3/4] Remove copy-n-pasted API from Analysis API in K2-Based Dokka as it's now unused see https://youtrack.jetbrains.com/issue/KT-60884 --- .../kotlin/symbols/plugin/KotlinAnalysis.kt | 111 +----------------- 1 file changed, 1 insertion(+), 110 deletions(-) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt index e102969aa5..a6155fb028 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt @@ -4,21 +4,10 @@ package org.jetbrains.dokka.analysis.kotlin.symbols.plugin -import com.intellij.core.CoreApplicationEnvironment import com.intellij.openapi.Disposable -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.psi.PsiFileSystemItem -import com.intellij.psi.PsiManager -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.search.ProjectScope -import com.intellij.util.io.URLUtil import org.jetbrains.dokka.Platform import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals -import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider -import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession @@ -27,18 +16,12 @@ import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule -import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.js.JsPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.konan.NativePlatforms -import org.jetbrains.kotlin.psi.KtFile import java.io.File -import java.io.IOException -import java.nio.file.* -import java.nio.file.attribute.BasicFileAttributes internal fun Platform.toTargetPlatform() = when (this) { Platform.js, Platform.wasm -> JsPlatforms.defaultJsPlatform @@ -127,96 +110,4 @@ internal fun createAnalysisSession( } } return Pair(analysisSession, sourceModule ?: throw IllegalStateException()) -} - -// ----------- copy-paste from Analysis API ---------------------------------------------------------------------------- -/** - * Collect source file path from the given [root] store them in [result]. - * - * E.g., for `project/app/src` as a [root], this will walk the file tree and - * collect all `.kt` and `.java` files under that folder. - * - * Note that this util gracefully skips [IOException] during file tree traversal. - */ -internal fun collectSourceFilePaths( - root: Path, - result: MutableSet -) { - // NB: [Files#walk] throws an exception if there is an issue during IO. - // With [Files#walkFileTree] with a custom visitor, we can take control of exception handling. - Files.walkFileTree( - root, - object : SimpleFileVisitor() { - override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { - return if (Files.isReadable(dir)) - FileVisitResult.CONTINUE - else - FileVisitResult.SKIP_SUBTREE - } - - override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { - if (!Files.isRegularFile(file) || !Files.isReadable(file)) - return FileVisitResult.CONTINUE - val ext = file.toFile().extension - if (ext == KotlinFileType.EXTENSION || ext == "java"/*JavaFileType.DEFAULT_EXTENSION*/) { - result.add(file.toString()) - } - return FileVisitResult.CONTINUE - } - - override fun visitFileFailed(file: Path, exc: IOException?): FileVisitResult { - // TODO: report or log [IOException]? - // NB: this intentionally swallows the exception, hence fail-safe. - // Skipping subtree doesn't make any sense, since this is not a directory. - // Skipping sibling may drop valid file paths afterward, so we just continue. - return FileVisitResult.CONTINUE - } - } - ) -} - -/** - * Collect source file path as [String] from the given source roots in [sourceRoot]. - * - * this util collects all `.kt` and `.java` files under source roots. - */ -internal fun getSourceFilePaths( - sourceRoot: Collection, - includeDirectoryRoot: Boolean = false, -): Set { - val result = mutableSetOf() - sourceRoot.forEach { srcRoot -> - val path = Paths.get(srcRoot) - if (Files.isDirectory(path)) { - // E.g., project/app/src - collectSourceFilePaths(path, result) - if (includeDirectoryRoot) { - result.add(srcRoot) - } - } else { - // E.g., project/app/src/some/pkg/main.kt - result.add(srcRoot) - } - } - - return result -} - -internal inline fun getPsiFilesFromPaths( - project: Project, - paths: Collection, -): List { - val fs = StandardFileSystems.local() - val psiManager = PsiManager.getInstance(project) - val result = mutableListOf() - for (path in paths) { - val vFile = fs.findFileByPath(path) ?: continue - val psiFileSystemItem = - if (vFile.isDirectory) - psiManager.findDirectory(vFile) as? T - else - psiManager.findFile(vFile) as? T - psiFileSystemItem?.let { result.add(it) } - } - return result -} +} \ No newline at end of file From bfbb0d16e60dfb6a162ce3c28905a440d65bd6de Mon Sep 17 00:00:00 2001 From: vmishenev Date: Wed, 11 Oct 2023 18:02:08 +0300 Subject: [PATCH 4/4] Update version Analysis API to 1.9.30-dev-3330 --- gradle/libs.versions.toml | 2 +- subprojects/analysis-kotlin-symbols/build.gradle.kts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6acd2a57a1..83bfe621f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ kotlinx-bcv = "0.12.1" ## Analysis kotlin-compiler = "1.9.10" -kotlin-compiler-k2 = "1.9.0-release-358" +kotlin-compiler-k2 = "1.9.30-dev-3330" # MUST match the version of the intellij platform used in the kotlin compiler, # otherwise this will lead to different versions of psi API and implementations diff --git a/subprojects/analysis-kotlin-symbols/build.gradle.kts b/subprojects/analysis-kotlin-symbols/build.gradle.kts index c1705e9f3a..6733b7788a 100644 --- a/subprojects/analysis-kotlin-symbols/build.gradle.kts +++ b/subprojects/analysis-kotlin-symbols/build.gradle.kts @@ -54,7 +54,6 @@ dependencies { listOf( libs.kotlin.high.level.api.api, libs.kotlin.analysis.api.standalone, - libs.kotlin.high.level.api.impl // for Standalone prototype ).forEach { implementation(it) { isTransitive = false // see KTIJ-19820 @@ -67,7 +66,7 @@ dependencies { libs.kotlin.low.level.api.fir, libs.kotlin.analysis.project.structure, libs.kotlin.analysis.api.providers, - libs.kotlin.symbol.light.classes + libs.kotlin.symbol.light.classes, ).forEach { runtimeOnly(it) { isTransitive = false // see KTIJ-19820