[Test] Support friend modules in new test infrastructure

This commit is contained in:
Dmitriy Novozhilov
2020-12-28 15:32:12 +03:00
committed by TeamCityServer
parent 7e92fb8eb9
commit 065255adbe
5 changed files with 60 additions and 15 deletions
@@ -91,11 +91,13 @@ object TopDownAnalyzerFacadeForJVM {
declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory, declarationProviderFactory: (StorageManager, Collection<KtFile>) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory,
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files), sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files),
klibList: List<KotlinLibrary> = emptyList(), klibList: List<KotlinLibrary> = emptyList(),
explicitModuleDependencyList: List<ModuleDescriptorImpl> = emptyList() explicitModuleDependencyList: List<ModuleDescriptorImpl> = emptyList(),
explicitModuleFriendsList: List<ModuleDescriptorImpl> = emptyList()
): AnalysisResult { ): AnalysisResult {
val container = createContainer( val container = createContainer(
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, CompilerEnvironment, project, files, trace, configuration, packagePartProvider, declarationProviderFactory, CompilerEnvironment,
sourceModuleSearchScope, klibList, explicitModuleDependencyList = explicitModuleDependencyList sourceModuleSearchScope, klibList, explicitModuleDependencyList = explicitModuleDependencyList,
explicitModuleFriendsList = explicitModuleFriendsList
) )
val module = container.get<ModuleDescriptor>() val module = container.get<ModuleDescriptor>()
@@ -140,7 +142,8 @@ object TopDownAnalyzerFacadeForJVM {
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files), sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files),
klibList: List<KotlinLibrary> = emptyList(), klibList: List<KotlinLibrary> = emptyList(),
implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter? = null, implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter? = null,
explicitModuleDependencyList: List<ModuleDescriptorImpl> = emptyList() explicitModuleDependencyList: List<ModuleDescriptorImpl> = emptyList(),
explicitModuleFriendsList: List<ModuleDescriptorImpl> = emptyList()
): ComponentProvider { ): ComponentProvider {
val jvmTarget = configuration.get(JVMConfigurationKeys.JVM_TARGET, JvmTarget.DEFAULT) val jvmTarget = configuration.get(JVMConfigurationKeys.JVM_TARGET, JvmTarget.DEFAULT)
val languageVersionSettings = configuration.languageVersionSettings val languageVersionSettings = configuration.languageVersionSettings
@@ -263,9 +266,15 @@ object TopDownAnalyzerFacadeForJVM {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
addAll(explicitModuleDependencyList) addAll(explicitModuleDependencyList)
} }
val friends = buildSet {
if (dependencyModule != null) {
add(dependencyModule)
}
addAll(explicitModuleFriendsList)
}
module.setDependencies( module.setDependencies(
dependencies, dependencies,
if (dependencyModule != null) setOf(dependencyModule) else emptySet() friends
) )
module.initialize( module.initialize(
CompositePackageFragmentProvider( CompositePackageFragmentProvider(
@@ -18,6 +18,7 @@ data class TestModule(
val frontendKind: FrontendKind<*>, val frontendKind: FrontendKind<*>,
val files: List<TestFile>, val files: List<TestFile>,
val dependencies: List<DependencyDescription>, val dependencies: List<DependencyDescription>,
val friends: List<DependencyDescription>,
val directives: RegisteredDirectives, val directives: RegisteredDirectives,
val languageVersionSettings: LanguageVersionSettings val languageVersionSettings: LanguageVersionSettings
) { ) {
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.config.JsConfig import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.native.FakeTopDownAnalyzerFacadeForNative import org.jetbrains.kotlin.native.FakeTopDownAnalyzerFacadeForNative
import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.isCommon
@@ -81,6 +82,10 @@ class ClassicFrontendFacade(
moduleDescriptorProvider.getModuleDescriptor(testModule) moduleDescriptorProvider.getModuleDescriptor(testModule)
} }
val friendDescriptors = module.friends.filter { it.kind == DependencyKind.Source }.map {
moduleDescriptorProvider.getModuleDescriptor(dependencyProvider.getTestModule(it.moduleName))
}
var hasCommonModules = false var hasCommonModules = false
sourceDependencies.forEach { sourceDependencies.forEach {
val dependencyModule = dependencyProvider.getTestModule(it.moduleName) val dependencyModule = dependencyProvider.getTestModule(it.moduleName)
@@ -104,6 +109,7 @@ class ClassicFrontendFacade(
packagePartProviderFactory, packagePartProviderFactory,
ktFiles, ktFiles,
dependentDescriptors, dependentDescriptors,
friendDescriptors,
hasCommonModules hasCommonModules
) )
moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor) moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor)
@@ -135,6 +141,7 @@ class ClassicFrontendFacade(
packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider, packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider,
files: List<KtFile>, files: List<KtFile>,
dependentDescriptors: List<ModuleDescriptorImpl>, dependentDescriptors: List<ModuleDescriptorImpl>,
friendsDescriptors: List<ModuleDescriptorImpl>,
hasCommonModules: Boolean hasCommonModules: Boolean
): AnalysisResult { ): AnalysisResult {
val targetPlatform = module.targetPlatform val targetPlatform = module.targetPlatform
@@ -146,6 +153,7 @@ class ClassicFrontendFacade(
packagePartProviderFactory, packagePartProviderFactory,
files, files,
dependentDescriptors, dependentDescriptors,
friendsDescriptors,
hasCommonModules hasCommonModules
) )
targetPlatform.isJs() -> performJsModuleResolve(project, configuration, files, dependentDescriptors) targetPlatform.isJs() -> performJsModuleResolve(project, configuration, files, dependentDescriptors)
@@ -163,8 +171,12 @@ class ClassicFrontendFacade(
packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider, packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider,
files: List<KtFile>, files: List<KtFile>,
dependentDescriptors: List<ModuleDescriptorImpl>, dependentDescriptors: List<ModuleDescriptorImpl>,
friendsDescriptors: List<ModuleDescriptorImpl>,
hasCommonModules: Boolean hasCommonModules: Boolean
): AnalysisResult { ): AnalysisResult {
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(project)
configuration.getList(JVMConfigurationKeys.FRIEND_PATHS).forEach { moduleVisibilityManager.addFriendPath(it) }
val moduleTrace = NoScopeRecordCliBindingTrace() val moduleTrace = NoScopeRecordCliBindingTrace()
if (!hasCommonModules) { if (!hasCommonModules) {
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
@@ -173,13 +185,14 @@ class ClassicFrontendFacade(
moduleTrace, moduleTrace,
configuration.copy(), configuration.copy(),
packagePartProviderFactory, packagePartProviderFactory,
explicitModuleDependencyList = dependentDescriptors explicitModuleDependencyList = dependentDescriptors,
explicitModuleFriendsList = friendsDescriptors
) )
} }
val moduleContentScope = GlobalSearchScope.allScope(project) val moduleContentScope = GlobalSearchScope.allScope(project)
val moduleClassResolver = SingleModuleClassResolver() val moduleClassResolver = SingleModuleClassResolver()
val moduleContext = createModuleContext(module, project, dependentDescriptors) { val moduleContext = createModuleContext(module, project, dependentDescriptors, friendsDescriptors) {
JvmBuiltIns(it, JvmBuiltIns.Kind.FROM_CLASS_LOADER) JvmBuiltIns(it, JvmBuiltIns.Kind.FROM_CLASS_LOADER)
} }
val moduleDescriptor = moduleContext.module as ModuleDescriptorImpl val moduleDescriptor = moduleContext.module as ModuleDescriptorImpl
@@ -242,7 +255,7 @@ class ClassicFrontendFacade(
files: List<KtFile>, files: List<KtFile>,
): AnalysisResult { ): AnalysisResult {
val moduleTrace = NoScopeRecordCliBindingTrace() val moduleTrace = NoScopeRecordCliBindingTrace()
val moduleContext = createModuleContext(module, project, dependentDescriptors = emptyList()) { val moduleContext = createModuleContext(module, project, dependentDescriptors = emptyList(), friendsDescriptors = emptyList()) {
DefaultBuiltIns() DefaultBuiltIns()
} }
return FakeTopDownAnalyzerFacadeForNative.analyzeFilesWithGivenTrace( return FakeTopDownAnalyzerFacadeForNative.analyzeFilesWithGivenTrace(
@@ -275,6 +288,7 @@ class ClassicFrontendFacade(
module: TestModule, module: TestModule,
project: Project, project: Project,
dependentDescriptors: List<ModuleDescriptorImpl>, dependentDescriptors: List<ModuleDescriptorImpl>,
friendsDescriptors: List<ModuleDescriptorImpl>,
builtInsFactory: (StorageManager) -> KotlinBuiltIns, builtInsFactory: (StorageManager) -> KotlinBuiltIns,
): ModuleContext { ): ModuleContext {
val projectContext = ProjectContext(project, "test project context") val projectContext = ProjectContext(project, "test project context")
@@ -287,7 +301,7 @@ class ClassicFrontendFacade(
add(moduleDescriptor.builtIns.builtInsModule) add(moduleDescriptor.builtIns.builtInsModule)
addAll(dependentDescriptors) addAll(dependentDescriptors)
} }
moduleDescriptor.setDependencies(dependencies) moduleDescriptor.setDependencies(dependencies, friendsDescriptors.toSet())
return projectContext.withModule(moduleDescriptor) return projectContext.withModule(moduleDescriptor)
} }
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirective
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.model.BackendKinds import org.jetbrains.kotlin.test.model.DependencyDescription
import org.jetbrains.kotlin.test.model.DependencyKind import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
@@ -30,7 +30,12 @@ class ModuleStructureExtractorImpl(
) : ModuleStructureExtractor(testServices, additionalSourceProviders) { ) : ModuleStructureExtractor(testServices, additionalSourceProviders) {
companion object { companion object {
private val allowedExtensionsForFiles = listOf(".kt", ".kts", ".java") private val allowedExtensionsForFiles = listOf(".kt", ".kts", ".java")
private val moduleDirectiveRegex = """([\w-]+)(\((.*)\))?""".toRegex() /*
* ([\w-]+) module name
* \((.*?)\) module dependencies
* (\((.*?)\))? module friends
*/
private val moduleDirectiveRegex = """([\w-]+)(\((.*?)\)(\((.*?)\))?)?""".toRegex()
} }
override fun splitTestDataByModules( override fun splitTestDataByModules(
@@ -66,6 +71,7 @@ class ModuleStructureExtractorImpl(
private var currentModuleTargetBackend: TargetBackend? = null private var currentModuleTargetBackend: TargetBackend? = null
private var currentModuleLanguageVersionSettingsBuilder: LanguageVersionSettingsBuilder = initLanguageSettingsBuilder() private var currentModuleLanguageVersionSettingsBuilder: LanguageVersionSettingsBuilder = initLanguageSettingsBuilder()
private var dependenciesOfCurrentModule = mutableListOf<DependencyDescription>() private var dependenciesOfCurrentModule = mutableListOf<DependencyDescription>()
private var friendsOfCurrentModule = mutableListOf<DependencyDescription>()
private var filesOfCurrentModule = mutableListOf<TestFile>() private var filesOfCurrentModule = mutableListOf<TestFile>()
private var currentFileName: String? = null private var currentFileName: String? = null
@@ -146,12 +152,16 @@ class ModuleStructureExtractorImpl(
} else { } else {
finishGlobalDirectives() finishGlobalDirectives()
} }
val (moduleName, dependencies) = splitRawModuleStringToNameAndDependencies(values.joinToString(separator = " ")) val (moduleName, dependencies, friends) = splitRawModuleStringToNameAndDependencies(values.joinToString(separator = " "))
currentModuleName = moduleName currentModuleName = moduleName
dependencies.mapTo(dependenciesOfCurrentModule) { name -> dependencies.mapTo(dependenciesOfCurrentModule) { name ->
val kind = defaultsProvider.defaultDependencyKind val kind = defaultsProvider.defaultDependencyKind
DependencyDescription(name, kind, DependencyRelation.Dependency) DependencyDescription(name, kind, DependencyRelation.Dependency)
} }
friends.mapTo(friendsOfCurrentModule) { name ->
val kind = defaultsProvider.defaultDependencyKind
DependencyDescription(name, kind, DependencyRelation.Dependency)
}
} }
ModuleStructureDirectives.DEPENDENCY, ModuleStructureDirectives.DEPENDENCY,
ModuleStructureDirectives.DEPENDS_ON -> { ModuleStructureDirectives.DEPENDS_ON -> {
@@ -190,12 +200,15 @@ class ModuleStructureExtractorImpl(
return true return true
} }
private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): Pair<String, List<String>> { private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): ModuleNameAndDependeciens {
val matchResult = moduleDirectiveRegex.matchEntire(moduleDirectiveString) val matchResult = moduleDirectiveRegex.matchEntire(moduleDirectiveString)
?: error("\"$moduleDirectiveString\" doesn't matches with pattern \"moduleName(dep1, dep2)\"") ?: error("\"$moduleDirectiveString\" doesn't matches with pattern \"moduleName(dep1, dep2)\"")
val (name, _, dependencies) = matchResult.destructured val (name, _, dependencies, _, friends) = matchResult.destructured
if (dependencies.isBlank()) return name to emptyList() return ModuleNameAndDependeciens(
return name to dependencies.split(" ") name,
dependencies.takeIf { it.isNotBlank() }?.split(" ") ?: emptyList(),
friends.takeIf { it.isNotBlank() }?.split(" ") ?: emptyList(),
)
} }
private fun finishGlobalDirectives() { private fun finishGlobalDirectives() {
@@ -216,6 +229,7 @@ class ModuleStructureExtractorImpl(
frontendKind = currentModuleFrontendKind ?: defaultsProvider.defaultFrontend, frontendKind = currentModuleFrontendKind ?: defaultsProvider.defaultFrontend,
files = filesOfCurrentModule, files = filesOfCurrentModule,
dependencies = dependenciesOfCurrentModule, dependencies = dependenciesOfCurrentModule,
friends = friendsOfCurrentModule,
directives = moduleDirectives, directives = moduleDirectives,
languageVersionSettings = currentModuleLanguageVersionSettingsBuilder.build() languageVersionSettings = currentModuleLanguageVersionSettingsBuilder.build()
) )
@@ -273,6 +287,7 @@ class ModuleStructureExtractorImpl(
currentModuleLanguageVersionSettingsBuilder = initLanguageSettingsBuilder() currentModuleLanguageVersionSettingsBuilder = initLanguageSettingsBuilder()
filesOfCurrentModule = mutableListOf() filesOfCurrentModule = mutableListOf()
dependenciesOfCurrentModule = mutableListOf() dependenciesOfCurrentModule = mutableListOf()
friendsOfCurrentModule = mutableListOf()
directivesBuilder = RegisteredDirectivesParser(directivesContainer, assertions) directivesBuilder = RegisteredDirectivesParser(directivesContainer, assertions)
} }
@@ -302,6 +317,12 @@ class ModuleStructureExtractorImpl(
return defaultsProvider.newLanguageSettingsBuilder() return defaultsProvider.newLanguageSettingsBuilder()
} }
} }
private data class ModuleNameAndDependeciens(
val name: String,
val dependencies: List<String>,
val friends: List<String>
)
} }
private operator fun RegisteredDirectives.plus(other: RegisteredDirectives?): RegisteredDirectives { private operator fun RegisteredDirectives.plus(other: RegisteredDirectives?): RegisteredDirectives {