diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt index 6f9bd00fe8c..5522d5d8f79 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt @@ -91,11 +91,13 @@ object TopDownAnalyzerFacadeForJVM { declarationProviderFactory: (StorageManager, Collection) -> DeclarationProviderFactory = ::FileBasedDeclarationProviderFactory, sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files), klibList: List = emptyList(), - explicitModuleDependencyList: List = emptyList() + explicitModuleDependencyList: List = emptyList(), + explicitModuleFriendsList: List = emptyList() ): AnalysisResult { val container = createContainer( project, files, trace, configuration, packagePartProvider, declarationProviderFactory, CompilerEnvironment, - sourceModuleSearchScope, klibList, explicitModuleDependencyList = explicitModuleDependencyList + sourceModuleSearchScope, klibList, explicitModuleDependencyList = explicitModuleDependencyList, + explicitModuleFriendsList = explicitModuleFriendsList ) val module = container.get() @@ -140,7 +142,8 @@ object TopDownAnalyzerFacadeForJVM { sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files), klibList: List = emptyList(), implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter? = null, - explicitModuleDependencyList: List = emptyList() + explicitModuleDependencyList: List = emptyList(), + explicitModuleFriendsList: List = emptyList() ): ComponentProvider { val jvmTarget = configuration.get(JVMConfigurationKeys.JVM_TARGET, JvmTarget.DEFAULT) val languageVersionSettings = configuration.languageVersionSettings @@ -263,9 +266,15 @@ object TopDownAnalyzerFacadeForJVM { @Suppress("UNCHECKED_CAST") addAll(explicitModuleDependencyList) } + val friends = buildSet { + if (dependencyModule != null) { + add(dependencyModule) + } + addAll(explicitModuleFriendsList) + } module.setDependencies( dependencies, - if (dependencyModule != null) setOf(dependencyModule) else emptySet() + friends ) module.initialize( CompositePackageFragmentProvider( diff --git a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt index 2d751ec9ea2..c2a02684c46 100644 --- a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt +++ b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt @@ -18,6 +18,7 @@ data class TestModule( val frontendKind: FrontendKind<*>, val files: List, val dependencies: List, + val friends: List, val directives: RegisteredDirectives, val languageVersionSettings: LanguageVersionSettings ) { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt index 2a8879be9bd..158edca9cdd 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.config.JsConfig 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.native.FakeTopDownAnalyzerFacadeForNative import org.jetbrains.kotlin.platform.isCommon @@ -81,6 +82,10 @@ class ClassicFrontendFacade( moduleDescriptorProvider.getModuleDescriptor(testModule) } + val friendDescriptors = module.friends.filter { it.kind == DependencyKind.Source }.map { + moduleDescriptorProvider.getModuleDescriptor(dependencyProvider.getTestModule(it.moduleName)) + } + var hasCommonModules = false sourceDependencies.forEach { val dependencyModule = dependencyProvider.getTestModule(it.moduleName) @@ -104,6 +109,7 @@ class ClassicFrontendFacade( packagePartProviderFactory, ktFiles, dependentDescriptors, + friendDescriptors, hasCommonModules ) moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor) @@ -135,6 +141,7 @@ class ClassicFrontendFacade( packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider, files: List, dependentDescriptors: List, + friendsDescriptors: List, hasCommonModules: Boolean ): AnalysisResult { val targetPlatform = module.targetPlatform @@ -146,6 +153,7 @@ class ClassicFrontendFacade( packagePartProviderFactory, files, dependentDescriptors, + friendsDescriptors, hasCommonModules ) targetPlatform.isJs() -> performJsModuleResolve(project, configuration, files, dependentDescriptors) @@ -163,8 +171,12 @@ class ClassicFrontendFacade( packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider, files: List, dependentDescriptors: List, + friendsDescriptors: List, hasCommonModules: Boolean ): AnalysisResult { + val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(project) + configuration.getList(JVMConfigurationKeys.FRIEND_PATHS).forEach { moduleVisibilityManager.addFriendPath(it) } + val moduleTrace = NoScopeRecordCliBindingTrace() if (!hasCommonModules) { return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( @@ -173,13 +185,14 @@ class ClassicFrontendFacade( moduleTrace, configuration.copy(), packagePartProviderFactory, - explicitModuleDependencyList = dependentDescriptors + explicitModuleDependencyList = dependentDescriptors, + explicitModuleFriendsList = friendsDescriptors ) } val moduleContentScope = GlobalSearchScope.allScope(project) val moduleClassResolver = SingleModuleClassResolver() - val moduleContext = createModuleContext(module, project, dependentDescriptors) { + val moduleContext = createModuleContext(module, project, dependentDescriptors, friendsDescriptors) { JvmBuiltIns(it, JvmBuiltIns.Kind.FROM_CLASS_LOADER) } val moduleDescriptor = moduleContext.module as ModuleDescriptorImpl @@ -242,7 +255,7 @@ class ClassicFrontendFacade( files: List, ): AnalysisResult { val moduleTrace = NoScopeRecordCliBindingTrace() - val moduleContext = createModuleContext(module, project, dependentDescriptors = emptyList()) { + val moduleContext = createModuleContext(module, project, dependentDescriptors = emptyList(), friendsDescriptors = emptyList()) { DefaultBuiltIns() } return FakeTopDownAnalyzerFacadeForNative.analyzeFilesWithGivenTrace( @@ -275,6 +288,7 @@ class ClassicFrontendFacade( module: TestModule, project: Project, dependentDescriptors: List, + friendsDescriptors: List, builtInsFactory: (StorageManager) -> KotlinBuiltIns, ): ModuleContext { val projectContext = ProjectContext(project, "test project context") @@ -287,7 +301,7 @@ class ClassicFrontendFacade( add(moduleDescriptor.builtIns.builtInsModule) addAll(dependentDescriptors) } - moduleDescriptor.setDependencies(dependencies) + moduleDescriptor.setDependencies(dependencies, friendsDescriptors.toSet()) return projectContext.withModule(moduleDescriptor) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt index 6e04b720395..109cff948d4 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirective import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives import org.jetbrains.kotlin.test.directives.model.DirectivesContainer 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.TestModule import org.jetbrains.kotlin.test.services.* diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt index b7eb4f12224..3d585a47645 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt @@ -30,7 +30,12 @@ class ModuleStructureExtractorImpl( ) : ModuleStructureExtractor(testServices, additionalSourceProviders) { companion object { 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( @@ -66,6 +71,7 @@ class ModuleStructureExtractorImpl( private var currentModuleTargetBackend: TargetBackend? = null private var currentModuleLanguageVersionSettingsBuilder: LanguageVersionSettingsBuilder = initLanguageSettingsBuilder() private var dependenciesOfCurrentModule = mutableListOf() + private var friendsOfCurrentModule = mutableListOf() private var filesOfCurrentModule = mutableListOf() private var currentFileName: String? = null @@ -146,12 +152,16 @@ class ModuleStructureExtractorImpl( } else { finishGlobalDirectives() } - val (moduleName, dependencies) = splitRawModuleStringToNameAndDependencies(values.joinToString(separator = " ")) + val (moduleName, dependencies, friends) = splitRawModuleStringToNameAndDependencies(values.joinToString(separator = " ")) currentModuleName = moduleName dependencies.mapTo(dependenciesOfCurrentModule) { name -> val kind = defaultsProvider.defaultDependencyKind DependencyDescription(name, kind, DependencyRelation.Dependency) } + friends.mapTo(friendsOfCurrentModule) { name -> + val kind = defaultsProvider.defaultDependencyKind + DependencyDescription(name, kind, DependencyRelation.Dependency) + } } ModuleStructureDirectives.DEPENDENCY, ModuleStructureDirectives.DEPENDS_ON -> { @@ -190,12 +200,15 @@ class ModuleStructureExtractorImpl( return true } - private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): Pair> { + private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): ModuleNameAndDependeciens { val matchResult = moduleDirectiveRegex.matchEntire(moduleDirectiveString) ?: error("\"$moduleDirectiveString\" doesn't matches with pattern \"moduleName(dep1, dep2)\"") - val (name, _, dependencies) = matchResult.destructured - if (dependencies.isBlank()) return name to emptyList() - return name to dependencies.split(" ") + val (name, _, dependencies, _, friends) = matchResult.destructured + return ModuleNameAndDependeciens( + name, + dependencies.takeIf { it.isNotBlank() }?.split(" ") ?: emptyList(), + friends.takeIf { it.isNotBlank() }?.split(" ") ?: emptyList(), + ) } private fun finishGlobalDirectives() { @@ -216,6 +229,7 @@ class ModuleStructureExtractorImpl( frontendKind = currentModuleFrontendKind ?: defaultsProvider.defaultFrontend, files = filesOfCurrentModule, dependencies = dependenciesOfCurrentModule, + friends = friendsOfCurrentModule, directives = moduleDirectives, languageVersionSettings = currentModuleLanguageVersionSettingsBuilder.build() ) @@ -273,6 +287,7 @@ class ModuleStructureExtractorImpl( currentModuleLanguageVersionSettingsBuilder = initLanguageSettingsBuilder() filesOfCurrentModule = mutableListOf() dependenciesOfCurrentModule = mutableListOf() + friendsOfCurrentModule = mutableListOf() directivesBuilder = RegisteredDirectivesParser(directivesContainer, assertions) } @@ -302,6 +317,12 @@ class ModuleStructureExtractorImpl( return defaultsProvider.newLanguageSettingsBuilder() } } + + private data class ModuleNameAndDependeciens( + val name: String, + val dependencies: List, + val friends: List + ) } private operator fun RegisteredDirectives.plus(other: RegisteredDirectives?): RegisteredDirectives {