[LL API] Add tests for 'out of content root' analysis mode
This commit is contained in:
+15
-13
@@ -21,8 +21,6 @@ abstract class AnalysisApiKtModuleProvider : TestService {
|
||||
|
||||
abstract fun registerProjectStructure(modules: KtModuleProjectStructure)
|
||||
|
||||
protected abstract fun getModuleName(ktModule: KtModule): String
|
||||
|
||||
abstract fun getModuleStructure(): KtModuleProjectStructure
|
||||
}
|
||||
|
||||
@@ -43,20 +41,24 @@ class AnalysisApiKtModuleProviderImpl(
|
||||
require(!this::modulesByName.isInitialized)
|
||||
|
||||
this.modulesStructure = modules
|
||||
this.modulesByName = modulesStructure.mainModules.associateBy { getModuleName(it.ktModule) }
|
||||
this.modulesByName = modulesStructure.mainModules.associateByName()
|
||||
}
|
||||
|
||||
override fun getModuleName(ktModule: KtModule): String = when (ktModule) {
|
||||
is KtLibraryModule -> ktModule.libraryName
|
||||
is KtSdkModule -> ktModule.sdkName
|
||||
is KtLibrarySourceModule -> ktModule.libraryName
|
||||
is KtSourceModule -> ktModule.moduleName
|
||||
is KtNotUnderContentRootModule -> TODO()
|
||||
is KtBuiltinsModule -> "Builtins for ${ktModule.platform}"
|
||||
}
|
||||
|
||||
|
||||
override fun getModuleStructure(): KtModuleProjectStructure = modulesStructure
|
||||
}
|
||||
|
||||
val TestServices.ktModuleProvider: AnalysisApiKtModuleProvider by TestServices.testServiceAccessor()
|
||||
|
||||
fun List<KtModuleWithFiles>.associateByName(): Map<String, KtModuleWithFiles> {
|
||||
return associateBy { (ktModule, _) ->
|
||||
when (ktModule) {
|
||||
is KtSourceModule -> ktModule.moduleName
|
||||
is KtLibraryModule -> ktModule.libraryName
|
||||
is KtLibrarySourceModule -> ktModule.libraryName
|
||||
is KtSdkModule -> ktModule.sdkName
|
||||
is KtBuiltinsModule -> "Builtins for ${ktModule.platform}"
|
||||
is KtNotUnderContentRootModuleForTest -> ktModule.moduleName
|
||||
else -> error("Unsupported module type: " + ktModule.javaClass.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestService
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
|
||||
fun interface KtModuleFactory : TestService {
|
||||
fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles
|
||||
}
|
||||
|
||||
val TestServices.ktModuleFactory: KtModuleFactory by TestServices.testServiceAccessor()
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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 com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.test.getAnalyzerServices
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
|
||||
class KtOutOfContentRootModuleFactory : KtModuleFactory {
|
||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||
val module = KtNotUnderContentRootModuleForTest(testModule.name, psiFiles.single(), testModule.targetPlatform)
|
||||
return KtModuleWithFiles(module, psiFiles)
|
||||
}
|
||||
}
|
||||
|
||||
internal class KtNotUnderContentRootModuleForTest(
|
||||
val moduleName: String,
|
||||
override val file: PsiFile,
|
||||
override val platform: TargetPlatform
|
||||
) : KtNotUnderContentRootModule {
|
||||
override val directRegularDependencies: List<KtModule>
|
||||
get() = emptyList()
|
||||
|
||||
override val directRefinementDependencies: List<KtModule>
|
||||
get() = emptyList()
|
||||
|
||||
override val directFriendDependencies: List<KtModule>
|
||||
get() = emptyList()
|
||||
|
||||
override val contentScope: GlobalSearchScope
|
||||
get() = GlobalSearchScope.fileScope(file)
|
||||
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
get() = platform.getAnalyzerServices()
|
||||
|
||||
override val project: Project
|
||||
get() = file.project
|
||||
|
||||
override val moduleDescription: String
|
||||
get() = "Not under content root for ${file.virtualFile.path}"
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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 com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
|
||||
class KtSourceModuleFactory : KtModuleFactory {
|
||||
override fun createModule(testModule: TestModule, testServices: TestServices, project: Project): KtModuleWithFiles {
|
||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||
|
||||
val module = KtSourceModuleImpl(
|
||||
testModule.name,
|
||||
testModule.targetPlatform,
|
||||
testModule.languageVersionSettings,
|
||||
project,
|
||||
GlobalSearchScope.filesScope(project, psiFiles.mapTo(mutableSetOf()) { it.virtualFile }),
|
||||
)
|
||||
|
||||
return KtModuleWithFiles(module, psiFiles)
|
||||
}
|
||||
}
|
||||
+27
-72
@@ -16,9 +16,8 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.Stand
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.allDirectDependenciesOfType
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
||||
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.checkIsInstance
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
@@ -37,66 +36,42 @@ import kotlin.io.path.exists
|
||||
import kotlin.io.path.extension
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
|
||||
fun interface KtMainModuleFactory {
|
||||
fun createMainModule(
|
||||
testModule: TestModule,
|
||||
testServices: TestServices,
|
||||
project: Project,
|
||||
): KtModuleWithFiles
|
||||
}
|
||||
|
||||
object KtMainModuleFactoryForSourceModules : KtMainModuleFactory {
|
||||
override fun createMainModule(
|
||||
testModule: TestModule,
|
||||
testServices: TestServices,
|
||||
project: Project,
|
||||
): KtModuleWithFiles {
|
||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||
return KtModuleWithFiles(
|
||||
KtSourceModuleImpl(
|
||||
testModule.name,
|
||||
testModule.targetPlatform,
|
||||
testModule.languageVersionSettings,
|
||||
project,
|
||||
GlobalSearchScope.filesScope(project, psiFiles.mapTo(mutableSetOf()) { it.virtualFile }),
|
||||
),
|
||||
psiFiles
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object TestModuleStructureFactory {
|
||||
fun createProjectStructureByTestStructure(
|
||||
moduleStructure: TestModuleStructure,
|
||||
testServices: TestServices,
|
||||
project: Project,
|
||||
mainModuleFactory: KtMainModuleFactory
|
||||
project: Project
|
||||
): KtModuleProjectStructure {
|
||||
val modulesFromTestServices = moduleStructure.modules.map { testModule ->
|
||||
testModule.toKtModule(testServices, project, mainModuleFactory)
|
||||
}
|
||||
val moduleByName = modulesFromTestServices.associateBy { getModuleName(it.ktModule) }
|
||||
val moduleEntries = moduleStructure.modules
|
||||
.map { testModule -> testServices.ktModuleFactory.createModule(testModule, testServices, project) }
|
||||
|
||||
val moduleEntriesByName = moduleEntries.associateByName()
|
||||
|
||||
val binaryModulesBySourceRoots = mutableMapOf<Set<Path>, KtBinaryModule>()
|
||||
|
||||
moduleStructure.modules.forEach { testModule ->
|
||||
val ktModule = moduleByName.getValue(testModule.name).ktModule
|
||||
checkIsInstance<KtModuleWithModifiableDependencies>(ktModule)
|
||||
for (testModule in moduleStructure.modules) {
|
||||
when (val ktModule = moduleEntriesByName.getValue(testModule.name).ktModule) {
|
||||
is KtNotUnderContentRootModule -> {
|
||||
// Not-under-content-root modules have no external dependencies on purpose
|
||||
}
|
||||
is KtModuleWithModifiableDependencies -> {
|
||||
addModuleDependencies(testModule, moduleEntriesByName, ktModule)
|
||||
|
||||
addModuleDependencies(testModule, moduleByName, ktModule)
|
||||
|
||||
buildList {
|
||||
addIfNotNull(getJdkModule(testModule, project, testServices))
|
||||
addAll(getStdlibModules(testModule, project, testServices))
|
||||
addAll(getLibraryModules(testServices, testModule, project))
|
||||
addAll(createLibrariesByCompilerConfigurators(testModule, testServices, project))
|
||||
}.forEach { library ->
|
||||
val cachedLibrary = binaryModulesBySourceRoots.getOrPut(library.getBinaryRoots().toSet()) { library }
|
||||
ktModule.directRegularDependencies.add(cachedLibrary)
|
||||
buildList {
|
||||
addIfNotNull(getJdkModule(testModule, project, testServices))
|
||||
addAll(getStdlibModules(testModule, project, testServices))
|
||||
addAll(getLibraryModules(testServices, testModule, project))
|
||||
addAll(createLibrariesByCompilerConfigurators(testModule, testServices, project))
|
||||
}.forEach { library ->
|
||||
val cachedLibrary = binaryModulesBySourceRoots.getOrPut(library.getBinaryRoots().toSet()) { library }
|
||||
ktModule.directRegularDependencies.add(cachedLibrary)
|
||||
}
|
||||
}
|
||||
else -> error("Unexpected module type: " + ktModule.javaClass.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return KtModuleProjectStructure(modulesFromTestServices, binaryModulesBySourceRoots.values)
|
||||
return KtModuleProjectStructure(moduleEntries, binaryModulesBySourceRoots.values)
|
||||
}
|
||||
|
||||
@OptIn(TestInfrastructureInternals::class)
|
||||
@@ -112,19 +87,7 @@ object TestModuleStructureFactory {
|
||||
.map { root -> createKtLibraryModuleByJar(root.file.toPath(), testServices, project) }
|
||||
}
|
||||
|
||||
|
||||
private fun getModuleName(ktModule: KtModule) = when (ktModule) {
|
||||
is KtSourceModuleImpl -> ktModule.moduleName
|
||||
is KtLibraryModuleImpl -> ktModule.libraryName
|
||||
is KtLibrarySourceModuleImpl -> ktModule.libraryName
|
||||
else -> error("Unknown module ${ktModule::class}")
|
||||
}
|
||||
|
||||
private fun addModuleDependencies(
|
||||
testModule: TestModule,
|
||||
moduleByName: Map<String, KtModuleWithFiles>,
|
||||
ktModule: KtModule
|
||||
) {
|
||||
private fun addModuleDependencies(testModule: TestModule, moduleByName: Map<String, KtModuleWithFiles>, ktModule: KtModule) {
|
||||
requireIsInstance<KtModuleWithModifiableDependencies>(ktModule)
|
||||
testModule.allDependencies.forEach { dependency ->
|
||||
val dependencyKtModule = moduleByName.getValue(dependency.moduleName).ktModule
|
||||
@@ -224,14 +187,6 @@ object TestModuleStructureFactory {
|
||||
)
|
||||
}
|
||||
|
||||
private fun TestModule.toKtModule(
|
||||
testServices: TestServices,
|
||||
project: Project,
|
||||
mainModuleFactory: KtMainModuleFactory,
|
||||
): KtModuleWithFiles {
|
||||
return mainModuleFactory.createMainModule(this, testServices, project)
|
||||
}
|
||||
|
||||
fun createSourcePsiFiles(
|
||||
testModule: TestModule,
|
||||
testServices: TestServices,
|
||||
|
||||
+6
-1
@@ -9,10 +9,12 @@ import com.intellij.mock.MockApplication
|
||||
import com.intellij.mock.MockProject
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
@@ -38,7 +40,10 @@ abstract class AnalysisApiTestConfigurator {
|
||||
|
||||
open fun prepareFilesInModule(files: List<PsiFile>, module: TestModule, testServices: TestServices) {}
|
||||
|
||||
abstract fun doOutOfBlockModification(file: KtFile)
|
||||
open fun doOutOfBlockModification(file: KtFile) {
|
||||
ServiceManager.getService(file.project, KotlinModificationTrackerFactory::class.java)
|
||||
.incrementModificationsCount()
|
||||
}
|
||||
|
||||
open fun preprocessTestDataPath(path: Path): Path = path
|
||||
|
||||
|
||||
Reference in New Issue
Block a user