[Analysis API Standalone] simplify adding source binary roots for KtSourceModuleBuilder

- allow providing source files instead of PsiFile
- automatically provide GlobalSearchScope for created `KtSourceModule`

^KT-60884
This commit is contained in:
Ilya Kirillov
2023-08-30 14:49:19 +02:00
committed by Space Team
parent 67f4ebc022
commit 180434951b
2 changed files with 38 additions and 22 deletions
@@ -5,18 +5,22 @@
package org.jetbrains.kotlin.analysis.project.structure.builder
import com.intellij.psi.PsiFileSystemItem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.project.structure.impl.KtSourceModuleImpl
import org.jetbrains.kotlin.analysis.project.structure.impl.collectSourceFilePaths
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import java.nio.file.Path
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.io.path.isDirectory
@KtModuleBuilderDsl
public class KtSourceModuleBuilder(
@@ -25,19 +29,22 @@ public class KtSourceModuleBuilder(
public lateinit var moduleName: String
public var languageVersionSettings: LanguageVersionSettings =
LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST)
public lateinit var contentScope: GlobalSearchScope
private val sourceRoots: MutableList<PsiFileSystemItem> = mutableListOf()
private val sourceRoots: MutableList<Path> = mutableListOf()
public fun addSourceRoot(file: PsiFileSystemItem) {
sourceRoots.add(file)
public fun addSourceRoot(path: Path) {
sourceRoots.add(path)
}
public fun addSourceRoots(files: Collection<PsiFileSystemItem>) {
sourceRoots.addAll(files)
public fun addSourceRoots(paths: Collection<Path>) {
sourceRoots.addAll(paths)
}
override fun build(): KtSourceModule {
val virtualFiles = collectVirtualFilesByRoots()
val psiManager = PsiManager.getInstance(kotlinCoreProjectEnvironment.project)
val psiFiles = virtualFiles.mapNotNull { psiManager.findFile(it) }
val contentScope = GlobalSearchScope.filesScope(kotlinCoreProjectEnvironment.project, virtualFiles)
return KtSourceModuleImpl(
directRegularDependencies,
directDependsOnDependencies,
@@ -47,9 +54,26 @@ public class KtSourceModuleBuilder(
kotlinCoreProjectEnvironment.project,
moduleName,
languageVersionSettings,
sourceRoots,
psiFiles,
)
}
private fun collectVirtualFilesByRoots(): List<VirtualFile> {
val localFileSystem = kotlinCoreProjectEnvironment.environment.localFileSystem
return buildList {
for (root in sourceRoots) {
val files = if (root.isDirectory()) {
collectSourceFilePaths(root)
} else {
listOf(root)
}
for (file in files) {
val virtualFile = localFileSystem.findFileByIoFile(file.toFile()) ?: continue
add(virtualFile)
}
}
}
}
}
@OptIn(ExperimentalContracts::class)
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtSta
import org.jetbrains.kotlin.analysis.project.structure.builder.*
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.cli.jvm.config.javaSourceRoots
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots
@@ -67,7 +66,7 @@ internal fun getSourceFilePaths(
val path = Paths.get(srcRoot)
if (Files.isDirectory(path)) {
// E.g., project/app/src
collectSourceFilePaths(path, this)
addAll(collectSourceFilePaths(path))
if (includeDirectoryRoot) {
add(path)
}
@@ -80,19 +79,17 @@ internal fun getSourceFilePaths(
}
/**
* Collect source file path from the given [root] store them in [result].
* Collect source file path from the given [root]
*
* E.g., for `project/app/src` as a [root], this will walk the file tree and
* collect all `.kt`, `.kts`, and `.java` files under that folder.
*
* Note that this util gracefully skips [IOException] during file tree traversal.
*/
private fun collectSourceFilePaths(
root: Path,
result: MutableSet<Path>
) {
internal fun collectSourceFilePaths(root: Path): List<Path> {
// 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.
val result = mutableListOf<Path>()
Files.walkFileTree(
root,
object : SimpleFileVisitor<Path>() {
@@ -125,6 +122,7 @@ private fun collectSourceFilePaths(
}
}
)
return result
}
internal inline fun <reified T : PsiFileSystemItem> getPsiFilesFromPaths(
@@ -197,13 +195,7 @@ internal fun buildKtModuleProviderByCompilerConfiguration(
addModuleDependencies(moduleName)
contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(kotlinCoreProjectEnvironment.project, ordinaryFiles)
addSourceRoots(
getPsiFilesFromPaths(
kotlinCoreProjectEnvironment,
getSourceFilePaths(compilerConfig, includeDirectoryRoot = true)
)
)
addSourceRoots(compilerConfig.javaSourceRoots.map { Paths.get(it) })
}.apply(::addModule)