[Analysis API] Add test infrastructure for code fragments
Now, Analysis API tests can define modules with code fragments. The preceding module will be used as a context module.
This commit is contained in:
+7
-2
@@ -29,11 +29,16 @@ object AnalysisApiFe10TestConfiguratorFactory : AnalysisApiTestConfiguratorFacto
|
|||||||
data.analysisSessionMode != AnalysisSessionMode.Normal -> false
|
data.analysisSessionMode != AnalysisSessionMode.Normal -> false
|
||||||
data.analysisApiMode != AnalysisApiMode.Ide -> false
|
data.analysisApiMode != AnalysisApiMode.Ide -> false
|
||||||
else -> when (data.moduleKind) {
|
else -> when (data.moduleKind) {
|
||||||
TestModuleKind.Source -> true
|
TestModuleKind.Source -> {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
TestModuleKind.ScriptSource,
|
TestModuleKind.ScriptSource,
|
||||||
TestModuleKind.LibraryBinary,
|
TestModuleKind.LibraryBinary,
|
||||||
TestModuleKind.LibrarySource,
|
TestModuleKind.LibrarySource,
|
||||||
-> false
|
TestModuleKind.CodeFragment -> {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-3
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.api.fir.test.configurators
|
package org.jetbrains.kotlin.analysis.api.fir.test.configurators
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirCodeFragmentTestConfigurator
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirLibraryBinaryTestConfigurator
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirLibraryBinaryTestConfigurator
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirLibrarySourceTestConfigurator
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirLibrarySourceTestConfigurator
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirScriptTestConfigurator
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.configurators.AnalysisApiFirScriptTestConfigurator
|
||||||
@@ -35,6 +36,11 @@ object AnalysisApiFirTestConfiguratorFactory : AnalysisApiTestConfiguratorFactor
|
|||||||
require(data.analysisSessionMode == AnalysisSessionMode.Normal)
|
require(data.analysisSessionMode == AnalysisSessionMode.Normal)
|
||||||
AnalysisApiFirLibrarySourceTestConfigurator
|
AnalysisApiFirLibrarySourceTestConfigurator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestModuleKind.CodeFragment -> when (data.analysisSessionMode) {
|
||||||
|
AnalysisSessionMode.Normal -> AnalysisApiFirCodeFragmentTestConfigurator(analyseInDependentSession = false)
|
||||||
|
AnalysisSessionMode.Dependent -> AnalysisApiFirCodeFragmentTestConfigurator(analyseInDependentSession = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,11 +49,16 @@ object AnalysisApiFirTestConfiguratorFactory : AnalysisApiTestConfiguratorFactor
|
|||||||
data.frontend != FrontendKind.Fir -> false
|
data.frontend != FrontendKind.Fir -> false
|
||||||
data.analysisApiMode != AnalysisApiMode.Ide -> false
|
data.analysisApiMode != AnalysisApiMode.Ide -> false
|
||||||
else -> when (data.moduleKind) {
|
else -> when (data.moduleKind) {
|
||||||
TestModuleKind.Source, TestModuleKind.ScriptSource -> true
|
TestModuleKind.Source,
|
||||||
|
TestModuleKind.ScriptSource -> {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
TestModuleKind.LibraryBinary,
|
TestModuleKind.LibraryBinary,
|
||||||
TestModuleKind.LibrarySource
|
TestModuleKind.LibrarySource,
|
||||||
->
|
TestModuleKind.CodeFragment -> {
|
||||||
data.analysisSessionMode == AnalysisSessionMode.Normal
|
data.analysisSessionMode == AnalysisSessionMode.Normal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -36,10 +36,14 @@ object AnalysisApiFirStandaloneModeTestConfiguratorFactory : AnalysisApiTestConf
|
|||||||
else -> when (data.moduleKind) {
|
else -> when (data.moduleKind) {
|
||||||
TestModuleKind.Source,
|
TestModuleKind.Source,
|
||||||
TestModuleKind.LibraryBinary,
|
TestModuleKind.LibraryBinary,
|
||||||
-> true
|
TestModuleKind.CodeFragment -> {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
TestModuleKind.ScriptSource,
|
TestModuleKind.ScriptSource,
|
||||||
TestModuleKind.LibrarySource
|
TestModuleKind.LibrarySource -> {
|
||||||
-> false
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable
|
|||||||
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
|
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProvider
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProvider
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProviderImpl
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProviderImpl
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiTestCodeFragmentDirectives
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.services.*
|
import org.jetbrains.kotlin.analysis.test.framework.services.*
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
|
||||||
import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider
|
import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider
|
||||||
@@ -33,4 +34,5 @@ fun TestConfigurationBuilder.registerAnalysisApiBaseTestServices(
|
|||||||
useCustomCompilerConfigurationProvider(::AnalysisApiTestCompilerConfiguratorProvider)
|
useCustomCompilerConfigurationProvider(::AnalysisApiTestCompilerConfiguratorProvider)
|
||||||
usePreAnalysisHandlers(::ProjectStructureInitialisationPreAnalysisHandler.bind(configurator))
|
usePreAnalysisHandlers(::ProjectStructureInitialisationPreAnalysisHandler.bind(configurator))
|
||||||
useDirectives(AnalysisApiTestDirectives)
|
useDirectives(AnalysisApiTestDirectives)
|
||||||
|
useDirectives(AnalysisApiTestCodeFragmentDirectives)
|
||||||
}
|
}
|
||||||
+1
@@ -67,6 +67,7 @@ fun List<KtModuleWithFiles>.associateByName(): Map<String, KtModuleWithFiles> {
|
|||||||
is KtBuiltinsModule -> "Builtins for ${ktModule.platform}"
|
is KtBuiltinsModule -> "Builtins for ${ktModule.platform}"
|
||||||
is KtNotUnderContentRootModule -> ktModule.name
|
is KtNotUnderContentRootModule -> ktModule.name
|
||||||
is KtScriptModule -> ktModule.file.name
|
is KtScriptModule -> ktModule.file.name
|
||||||
|
is KtDanglingFileModule -> ktModule.file.name
|
||||||
else -> error("Unsupported module type: " + ktModule.javaClass.name)
|
else -> error("Unsupported module type: " + ktModule.javaClass.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.test.framework.project.structure
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.impl.KtDanglingFileModuleImpl
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
|
||||||
|
import org.jetbrains.kotlin.psi.KtBlockCodeFragment
|
||||||
|
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpressionCodeFragment
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeCodeFragment
|
||||||
|
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
|
||||||
|
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
|
||||||
|
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
|
||||||
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import org.jetbrains.kotlin.test.services.sourceFileProvider
|
||||||
|
|
||||||
|
object KtCodeFragmentModuleFactory : KtModuleFactory {
|
||||||
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
|
requireNotNull(contextModule) { "Context module should precede the code fragment module" }
|
||||||
|
|
||||||
|
val testFile = testModule.files.singleOrNull() ?: error("A single file is expected for a code fragment module")
|
||||||
|
|
||||||
|
val fileName = testFile.name
|
||||||
|
val fileText = testServices.sourceFileProvider.getContentOfSourceFile(testFile)
|
||||||
|
|
||||||
|
val codeFragmentKind = testFile.directives
|
||||||
|
.singleOrZeroValue(AnalysisApiTestCodeFragmentDirectives.CODE_FRAGMENT_KIND)
|
||||||
|
?: CodeFragmentKind.BLOCK
|
||||||
|
|
||||||
|
val codeFragmentImports = testFile
|
||||||
|
.directives[AnalysisApiTestCodeFragmentDirectives.CODE_FRAGMENT_IMPORT]
|
||||||
|
.joinToString(KtCodeFragment.IMPORT_SEPARATOR)
|
||||||
|
.takeIf { it.isNotEmpty() }
|
||||||
|
|
||||||
|
if (codeFragmentKind == CodeFragmentKind.TYPE && codeFragmentImports != null) {
|
||||||
|
error("Imports cannot be configured for type code fragments")
|
||||||
|
}
|
||||||
|
|
||||||
|
val expressionMarkerProvider = testServices.expressionMarkerProvider
|
||||||
|
val contextElement = contextModule.files
|
||||||
|
.filterIsInstance<KtFile>()
|
||||||
|
.firstNotNullOfOrNull { expressionMarkerProvider.getElementOfTypeAtCaret<KtElement>(it, "context") }
|
||||||
|
|
||||||
|
val codeFragment = when (codeFragmentKind) {
|
||||||
|
CodeFragmentKind.EXPRESSION -> KtExpressionCodeFragment(project, fileName, fileText, codeFragmentImports, contextElement)
|
||||||
|
CodeFragmentKind.BLOCK -> KtBlockCodeFragment(project, fileName, fileText, codeFragmentImports, contextElement)
|
||||||
|
CodeFragmentKind.TYPE -> KtTypeCodeFragment(project, fileName, fileText, contextElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
val module = KtDanglingFileModuleImpl(
|
||||||
|
codeFragment,
|
||||||
|
contextModule.ktModule,
|
||||||
|
DanglingFileResolutionMode.PREFER_SELF
|
||||||
|
)
|
||||||
|
|
||||||
|
return KtModuleWithFiles(module, listOf(codeFragment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AnalysisApiTestCodeFragmentDirectives : SimpleDirectivesContainer() {
|
||||||
|
val CODE_FRAGMENT_KIND by enumDirective<CodeFragmentKind>(
|
||||||
|
description = "Code fragment kind",
|
||||||
|
applicability = DirectiveApplicability.File
|
||||||
|
)
|
||||||
|
|
||||||
|
val CODE_FRAGMENT_IMPORT by stringDirective(
|
||||||
|
description = "Import local to the code fragment content",
|
||||||
|
applicability = DirectiveApplicability.File
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CodeFragmentKind {
|
||||||
|
EXPRESSION, BLOCK, TYPE
|
||||||
|
}
|
||||||
+6
-1
@@ -18,7 +18,12 @@ import org.jetbrains.kotlin.test.services.TestServices
|
|||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibraryBinary
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibraryBinary
|
||||||
*/
|
*/
|
||||||
object KtLibraryBinaryModuleFactory : KtModuleFactory {
|
object KtLibraryBinaryModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
val library = testServices.compiledLibraryProvider.compileToLibrary(testModule).artifact
|
val library = testServices.compiledLibraryProvider.compileToLibrary(testModule).artifact
|
||||||
val decompiledFiles = testServices.testModuleDecompiler.getAllPsiFilesFromLibrary(library, project)
|
val decompiledFiles = testServices.testModuleDecompiler.getAllPsiFilesFromLibrary(library, project)
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -22,7 +22,12 @@ import java.nio.file.Path
|
|||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibrarySource
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibrarySource
|
||||||
*/
|
*/
|
||||||
object KtLibrarySourceModuleFactory : KtModuleFactory {
|
object KtLibrarySourceModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
Assume.assumeFalse("Compilation of multi-platform libraries is not supported", testModule.targetPlatform.isMultiPlatform())
|
Assume.assumeFalse("Compilation of multi-platform libraries is not supported", testModule.targetPlatform.isMultiPlatform())
|
||||||
|
|
||||||
val (libraryJar, librarySourcesJar) = testServices.compiledLibraryProvider.compileToLibrary(testModule)
|
val (libraryJar, librarySourcesJar) = testServices.compiledLibraryProvider.compileToLibrary(testModule)
|
||||||
|
|||||||
+15
-2
@@ -14,7 +14,19 @@ import org.jetbrains.kotlin.test.services.TestService
|
|||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
|
||||||
fun interface KtModuleFactory : TestService {
|
fun interface KtModuleFactory : TestService {
|
||||||
fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles
|
/**
|
||||||
|
* Creates a [KtModule](org.jetbrains.kotlin.analysis.project.structure.KtModule) for the given [testModule].
|
||||||
|
*
|
||||||
|
* @param contextModule a module to use as a context module. Some kinds of modules (such as dangling file modules) require a
|
||||||
|
* context module. Modules representing code fragments also require a context element – that is why the [KtModuleWithFiles] is passed,
|
||||||
|
* instead of a plain (KtModule)[org.jetbrains.kotlin.analysis.project.structure.KtModule].
|
||||||
|
*/
|
||||||
|
fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
private val TestServices.ktModuleFactory: KtModuleFactory by TestServices.testServiceAccessor()
|
private val TestServices.ktModuleFactory: KtModuleFactory by TestServices.testServiceAccessor()
|
||||||
@@ -27,7 +39,7 @@ private val TestServices.ktModuleFactory: KtModuleFactory by TestServices.testSe
|
|||||||
* [MODULE_KIND][org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives.MODULE_KIND] directive for a specific test module.
|
* [MODULE_KIND][org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives.MODULE_KIND] directive for a specific test module.
|
||||||
*
|
*
|
||||||
* [DependencyKindModuleStructureTransformer][org.jetbrains.kotlin.analysis.test.framework.services.DependencyKindModuleStructureTransformer]
|
* [DependencyKindModuleStructureTransformer][org.jetbrains.kotlin.analysis.test.framework.services.DependencyKindModuleStructureTransformer]
|
||||||
* should be used to properly set up [DependencyKind][org.jetbrains.kotlin.test.model.DependencyKind] for module dependencies
|
* should be used to properly set up the [DependencyKind][org.jetbrains.kotlin.test.model.DependencyKind] for module dependencies.
|
||||||
*
|
*
|
||||||
* @see org.jetbrains.kotlin.analysis.test.framework.services.DependencyKindModuleStructureTransformer
|
* @see org.jetbrains.kotlin.analysis.test.framework.services.DependencyKindModuleStructureTransformer
|
||||||
*/
|
*/
|
||||||
@@ -36,5 +48,6 @@ fun TestServices.getKtModuleFactoryForTestModule(testModule: TestModule): KtModu
|
|||||||
TestModuleKind.LibraryBinary -> KtLibraryBinaryModuleFactory
|
TestModuleKind.LibraryBinary -> KtLibraryBinaryModuleFactory
|
||||||
TestModuleKind.LibrarySource -> KtLibrarySourceModuleFactory
|
TestModuleKind.LibrarySource -> KtLibrarySourceModuleFactory
|
||||||
TestModuleKind.ScriptSource -> KtScriptModuleFactory
|
TestModuleKind.ScriptSource -> KtScriptModuleFactory
|
||||||
|
TestModuleKind.CodeFragment -> KtCodeFragmentModuleFactory
|
||||||
else -> ktModuleFactory
|
else -> ktModuleFactory
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -15,7 +15,12 @@ import org.jetbrains.kotlin.test.services.TestServices
|
|||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.ScriptSource
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.ScriptSource
|
||||||
*/
|
*/
|
||||||
object KtScriptModuleFactory : KtModuleFactory {
|
object KtScriptModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
val ktFile = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project).single() as KtFile
|
val ktFile = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project).single() as KtFile
|
||||||
val module = KtScriptModuleImpl(
|
val module = KtScriptModuleImpl(
|
||||||
ktFile,
|
ktFile,
|
||||||
|
|||||||
+6
-1
@@ -15,7 +15,12 @@ import org.jetbrains.kotlin.test.services.TestServices
|
|||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.Source
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.Source
|
||||||
*/
|
*/
|
||||||
object KtSourceModuleFactory : KtModuleFactory {
|
object KtSourceModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||||
|
|
||||||
val module = KtSourceModuleImpl(
|
val module = KtSourceModuleImpl(
|
||||||
|
|||||||
+19
-4
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtMod
|
|||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
|
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
|
||||||
@@ -45,11 +46,11 @@ object TestModuleStructureFactory {
|
|||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project
|
project: Project
|
||||||
): KtModuleProjectStructure {
|
): KtModuleProjectStructure {
|
||||||
val moduleEntries = moduleStructure.modules.map { testModule ->
|
val modules = moduleStructure.modules.mapWithPrevious<TestModule, KtModuleWithFiles> { contextModule, testModule ->
|
||||||
testServices.getKtModuleFactoryForTestModule(testModule).createModule(testModule, testServices, project)
|
testServices.getKtModuleFactoryForTestModule(testModule).createModule(testModule, contextModule, testServices, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
val modulesByName = moduleEntries.associateByName()
|
val modulesByName = modules.associateByName()
|
||||||
|
|
||||||
val libraryCache: LibraryCache = mutableMapOf()
|
val libraryCache: LibraryCache = mutableMapOf()
|
||||||
|
|
||||||
@@ -60,7 +61,18 @@ object TestModuleStructureFactory {
|
|||||||
ktModule.addDependencies(testModule, testServices, modulesByName, libraryCache)
|
ktModule.addDependencies(testModule, testServices, modulesByName, libraryCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
return KtModuleProjectStructure(moduleEntries, libraryCache.values)
|
return KtModuleProjectStructure(modules, libraryCache.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any, R> List<T>.mapWithPrevious(transform: (R?, T) -> R): List<R> {
|
||||||
|
val result = ArrayList<R>(this.size)
|
||||||
|
var previousResult: R? = null
|
||||||
|
for (item in this) {
|
||||||
|
val newResult = transform(previousResult, item)
|
||||||
|
result.add(newResult)
|
||||||
|
previousResult = newResult
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ModulesByName.getByTestModule(testModule: TestModule): KtModuleWithFiles =
|
private fun ModulesByName.getByTestModule(testModule: TestModule): KtModuleWithFiles =
|
||||||
@@ -87,6 +99,9 @@ object TestModuleStructureFactory {
|
|||||||
is KtNotUnderContentRootModule -> {
|
is KtNotUnderContentRootModule -> {
|
||||||
// Not-under-content-root modules have no external dependencies on purpose
|
// Not-under-content-root modules have no external dependencies on purpose
|
||||||
}
|
}
|
||||||
|
is KtDanglingFileModule -> {
|
||||||
|
// Dangling file modules get dependencies from their context
|
||||||
|
}
|
||||||
is KtModuleWithModifiableDependencies -> {
|
is KtModuleWithModifiableDependencies -> {
|
||||||
addModuleDependencies(testModule, modulesByName, this)
|
addModuleDependencies(testModule, modulesByName, this)
|
||||||
addLibraryDependencies(testModule, testServices, project, this, libraryCache::getOrPut)
|
addLibraryDependencies(testModule, testServices, project, this, libraryCache::getOrPut)
|
||||||
|
|||||||
+15
-4
@@ -47,10 +47,21 @@ object DependencyKindModuleStructureTransformer : ModuleStructureTransformer() {
|
|||||||
): DependencyDescription {
|
): DependencyDescription {
|
||||||
val dependencyModule = moduleMapping.getValue(dependency.moduleName)
|
val dependencyModule = moduleMapping.getValue(dependency.moduleName)
|
||||||
val newKind = when (dependencyModule.moduleKind) {
|
val newKind = when (dependencyModule.moduleKind) {
|
||||||
TestModuleKind.Source, TestModuleKind.LibrarySource, TestModuleKind.ScriptSource -> DependencyKind.Source
|
TestModuleKind.Source,
|
||||||
TestModuleKind.LibraryBinary -> DependencyKind.Binary
|
TestModuleKind.LibrarySource,
|
||||||
// There is no explicit module kind, so the dependency already has the right kind
|
TestModuleKind.ScriptSource,
|
||||||
null -> return dependency
|
TestModuleKind.CodeFragment -> {
|
||||||
|
DependencyKind.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
TestModuleKind.LibraryBinary -> {
|
||||||
|
DependencyKind.Binary
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> {
|
||||||
|
// There is no explicit module kind, so the dependency already has the right kind
|
||||||
|
return dependency
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dependency.copy(kind = newKind)
|
return dependency.copy(kind = newKind)
|
||||||
|
|||||||
+5
@@ -38,6 +38,11 @@ enum class TestModuleKind(val suffix: String) {
|
|||||||
* @see org.jetbrains.kotlin.analysis.test.framework.project.structure.KtScriptModuleFactory
|
* @see org.jetbrains.kotlin.analysis.test.framework.project.structure.KtScriptModuleFactory
|
||||||
*/
|
*/
|
||||||
ScriptSource("ScriptSource"),
|
ScriptSource("ScriptSource"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.analysis.test.framework.project.structure.KtCodeFragmentModuleFactory
|
||||||
|
*/
|
||||||
|
CodeFragment("CodeFragment")
|
||||||
}
|
}
|
||||||
|
|
||||||
val TestModule.moduleKind: TestModuleKind?
|
val TestModule.moduleKind: TestModuleKind?
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.test.configurators
|
||||||
|
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiLibraryBaseTestServiceRegistrar
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtCodeFragmentModuleFactory
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtModuleFactory
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.services.DependencyKindModuleStructureTransformer
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
|
||||||
|
import org.jetbrains.kotlin.test.TestInfrastructureInternals
|
||||||
|
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||||
|
|
||||||
|
class AnalysisApiFirCodeFragmentTestConfigurator(
|
||||||
|
analyseInDependentSession: Boolean
|
||||||
|
) : AnalysisApiFirSourceLikeTestConfigurator(analyseInDependentSession) {
|
||||||
|
override fun configureTest(builder: TestConfigurationBuilder, disposable: Disposable) {
|
||||||
|
super.configureTest(builder, disposable)
|
||||||
|
|
||||||
|
builder.apply {
|
||||||
|
useAdditionalService<KtModuleFactory> { KtCodeFragmentModuleFactory }
|
||||||
|
|
||||||
|
@OptIn(TestInfrastructureInternals::class)
|
||||||
|
useModuleStructureTransformers(DependencyKindModuleStructureTransformer)
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalysisApiFirLibraryBinaryTestConfigurator.configureLibraryCompilationSupport(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar>
|
||||||
|
get() = super.serviceRegistrars + AnalysisApiLibraryBaseTestServiceRegistrar
|
||||||
|
}
|
||||||
+6
-1
@@ -57,7 +57,12 @@ object AnalysisApiFirOutOfContentRootTestConfigurator : AnalysisApiFirSourceLike
|
|||||||
private class SkipWhenOutOfContentRootException : SkipTestException()
|
private class SkipWhenOutOfContentRootException : SkipTestException()
|
||||||
|
|
||||||
private object KtOutOfContentRootModuleFactory : KtModuleFactory {
|
private object KtOutOfContentRootModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||||
val platform = testModule.targetPlatform
|
val platform = testModule.targetPlatform
|
||||||
val module = KtNotUnderContentRootModuleForTest(testModule.name, psiFiles.first(), platform)
|
val module = KtNotUnderContentRootModuleForTest(testModule.name, psiFiles.first(), platform)
|
||||||
|
|||||||
+6
-1
@@ -25,7 +25,12 @@ object AnalysisApiFirStdlibSourceTestConfigurator : AnalysisApiFirSourceLikeTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
private object KtStdlibSourceModuleFactory : KtModuleFactory {
|
private object KtStdlibSourceModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
override fun createModule(
|
||||||
|
testModule: TestModule,
|
||||||
|
contextModule: KtModuleWithFiles?,
|
||||||
|
testServices: TestServices,
|
||||||
|
project: Project,
|
||||||
|
): KtModuleWithFiles {
|
||||||
val libraryJar = ForTestCompileRuntime.runtimeJarForTests().toPath()
|
val libraryJar = ForTestCompileRuntime.runtimeJarForTests().toPath()
|
||||||
val librarySourcesJar = ForTestCompileRuntime.runtimeSourcesJarForTests().toPath()
|
val librarySourcesJar = ForTestCompileRuntime.runtimeSourcesJarForTests().toPath()
|
||||||
return createKtLibrarySourceModule(
|
return createKtLibrarySourceModule(
|
||||||
|
|||||||
Reference in New Issue
Block a user