From de4cce8dc88382c9aec120f0a92eaf1d3db6a69e Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 13 Feb 2024 10:28:07 -0800 Subject: [PATCH] AA: add support VirtualFile inputs to source module ^KT-65571 fixed --- .../builder/KtSourceModuleBuilder.kt | 10 +++ .../builder/StandaloneSessionBuilderTest.kt | 41 ++++++++++++ .../builder/sessionBuilderTestUtils.kt | 62 ++++++++++++++++++- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtSourceModuleBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtSourceModuleBuilder.kt index 6c8339e502d..aec66eb3c63 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtSourceModuleBuilder.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtSourceModuleBuilder.kt @@ -32,6 +32,7 @@ public class KtSourceModuleBuilder( LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST) private val sourceRoots: MutableList = mutableListOf() + private val sourceVirtualFiles: MutableList = mutableListOf() public fun addSourceRoot(path: Path) { sourceRoots.add(path) @@ -41,6 +42,14 @@ public class KtSourceModuleBuilder( sourceRoots.addAll(paths) } + public fun addSourceVirtualFile(virtualFile: VirtualFile) { + sourceVirtualFiles.add(virtualFile) + } + + public fun addSourceVirtualFiles(virtualFiles: Collection) { + sourceVirtualFiles.addAll(virtualFiles) + } + override fun build(): KtSourceModule { val virtualFiles = collectVirtualFilesByRoots() val psiManager = PsiManager.getInstance(kotlinCoreProjectEnvironment.project) @@ -73,6 +82,7 @@ public class KtSourceModuleBuilder( add(virtualFile) } } + addAll(sourceVirtualFiles) } } } diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt index b6803b30751..565fca1f48b 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt @@ -248,4 +248,45 @@ class StandaloneSessionBuilderTest : TestWithDisposable() { val ktCallExpression = ktFile.findDescendantOfType()!! ktCallExpression.assertIsCallOf(CallableId(FqName.ROOT, Name.identifier("foo"))) } + + @Test + fun testKotlinSourceModuleSessionWithVirtualFile() { + val root = "otherModuleUsage" + lateinit var sourceModule: KtSourceModule + val session = buildStandaloneAnalysisAPISession(disposable) { + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + + buildKtModuleProvider { + platform = JvmPlatforms.defaultJvmPlatform + val dep = addModule( + buildKtSourceModule { + addSourceRoot(testDataPath(root).resolve("dependent")) + platform = JvmPlatforms.defaultJvmPlatform + moduleName = "dependent" + } + ) + sourceModule = addModule( + buildKtSourceModule { + // addSourceRoot(testDataPath(root).resolve("main")) + // Instead, add [VirtualFile] on-the-fly + val virtualFile = createVirtualFileOnTheFly( + project, + """ + fun main() { + foo() + } + """.trimIndent() + ) + addSourceVirtualFile(virtualFile) + addRegularDependency(dep) + platform = JvmPlatforms.defaultJvmPlatform + moduleName = "main" + } + ) + } + } + val ktFile = session.modulesWithFiles.getValue(sourceModule).single() as KtFile + val ktCallExpression = ktFile.findDescendantOfType()!! + ktCallExpression.assertIsCallOf(CallableId(FqName.ROOT, Name.identifier("foo"))) + } } \ No newline at end of file diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt index 1b252c3b1e1..bb71c5ad93a 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt @@ -5,6 +5,10 @@ package org.jetbrains.kotlin.analysis.api.standalone.fir.test.cases.session.builder +import com.intellij.mock.MockVirtualFileSystem +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileSystem import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.calls.KtSuccessCallInfo import org.jetbrains.kotlin.analysis.api.calls.successfulFunctionCallOrNull @@ -12,6 +16,7 @@ import org.jetbrains.kotlin.analysis.api.calls.symbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.test.MockLibraryUtil import org.jetbrains.kotlin.test.util.KtTestUtil import java.nio.file.Files @@ -21,6 +26,10 @@ import kotlin.io.path.absolutePathString import kotlin.io.path.extension import kotlin.streams.asSequence import org.junit.jupiter.api.Assertions +import java.io.InputStream +import java.io.OutputStream +import java.time.LocalDateTime +import java.time.ZoneOffset internal fun testDataPath(path: String): Path { return Paths.get("analysis/analysis-api-standalone/testData/sessionBuilder").resolve(path) @@ -36,7 +45,6 @@ fun KtCallExpression.assertIsCallOf(callableId: CallableId) { } } - internal fun compileCommonKlib(kLibSourcesRoot: Path): Path { val ktFiles = Files.walk(kLibSourcesRoot).asSequence().filter { it.extension == "kt" }.toList() val testKlib = KtTestUtil.tmpDir("testLibrary").resolve("library.klib").toPath() @@ -49,4 +57,54 @@ internal fun compileCommonKlib(kLibSourcesRoot: Path): Path { MockLibraryUtil.runMetadataCompiler(arguments) return testKlib -} \ No newline at end of file +} + +internal fun createVirtualFileOnTheFly( + project: Project, + text: String, + fs: VirtualFileSystem = MockVirtualFileSystem(), +): VirtualFile { + val factory = KtPsiFactory(project, markGenerated = false) + val ktFile = factory.createFile(text) + return object : VirtualFile() { + override fun getName(): String = ktFile.name + + override fun getFileSystem(): VirtualFileSystem = fs + + override fun getPath(): String { + error("Not yet implemented") + } + + override fun isWritable(): Boolean = false + + override fun isDirectory(): Boolean = false + + override fun isValid(): Boolean = ktFile.isValid + + override fun getParent(): VirtualFile { + error("Not yet implemented") + } + + override fun getChildren(): Array = emptyArray() + + override fun getOutputStream(requestor: Any?, newModificationStamp: Long, newTimeStamp: Long): OutputStream { + error("Not yet implemented") + } + + override fun contentsToByteArray(): ByteArray = ktFile.text.toByteArray() + + private val timeStamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) + + override fun getTimeStamp(): Long = timeStamp + + override fun getLength(): Long = ktFile.textLength.toLong() + + override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) { + error("Not yet implemented") + } + + override fun getInputStream(): InputStream { + error("Not yet implemented") + } + } +}