[MPP][Test] Implement Diagnostics with mpp composite analysis tests
Using the 'MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE' test directive will add support for testing "cli metadata compilation" and "ide analysis" _like_ configurations. In this configuration, dependsOn modules will not be analyzed together with dependents in the same ModuleDescriptor, but will be passed as separate 'expectedBy' dependency descriptor. Used to cover ^KT-50120 inside kotlin.git
This commit is contained in:
committed by
Space
parent
7771e5914d
commit
3598ba1d45
+3
-2
@@ -95,10 +95,11 @@ object TopDownAnalyzerFacadeForJVM {
|
||||
sourceModuleSearchScope: GlobalSearchScope = newModuleSearchScope(project, files),
|
||||
klibList: List<KotlinLibrary> = emptyList(),
|
||||
explicitModuleDependencyList: List<ModuleDescriptorImpl> = emptyList(),
|
||||
explicitModuleFriendsList: List<ModuleDescriptorImpl> = emptyList()
|
||||
explicitModuleFriendsList: List<ModuleDescriptorImpl> = emptyList(),
|
||||
explicitCompilerEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): AnalysisResult {
|
||||
val container = createContainer(
|
||||
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, CompilerEnvironment,
|
||||
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, explicitCompilerEnvironment,
|
||||
sourceModuleSearchScope, klibList, explicitModuleDependencyList = explicitModuleDependencyList,
|
||||
explicitModuleFriendsList = explicitModuleFriendsList
|
||||
)
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
|
||||
@DefaultImplementation(ModuleStructureOracle.SingleModule::class)
|
||||
interface ModuleStructureOracle {
|
||||
// May be faster than `findAllImplementingModules(module).isNotEmpty()`
|
||||
// May be faster than `findAllReversedDependsOnPaths(module).isNotEmpty()`
|
||||
fun hasImplementingModules(module: ModuleDescriptor): Boolean
|
||||
|
||||
fun findAllReversedDependsOnPaths(module: ModuleDescriptor): List<ModulePath>
|
||||
@@ -31,4 +33,4 @@ interface ModuleStructureOracle {
|
||||
|
||||
class ModulePath(val nodes: List<ModuleDescriptor>) {
|
||||
constructor(vararg nodes: ModuleDescriptor) : this(nodes.toList())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ abstract class TargetEnvironment(private val name: String) {
|
||||
container.useInstance(BodyResolveCache.ThrowException)
|
||||
container.useImpl<CompilerLocalDescriptorResolver>()
|
||||
container.useImpl<BasicAbsentDescriptorHandler>()
|
||||
container.useInstance(ModuleStructureOracle.SingleModule)
|
||||
container.useImpl<MainFunctionDetector.Factory.Ordinary>()
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.test.directives
|
||||
|
||||
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
|
||||
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
|
||||
|
||||
object MultiplatformDiagnosticsDirectives : SimpleDirectivesContainer() {
|
||||
val MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE by directive(
|
||||
description = """
|
||||
Will setup the classical frontend similar to 'CLI metadata compilation' or 'IDE analysis' where dependsOn sources
|
||||
are located in separate module descriptors.
|
||||
""".trimIndent(),
|
||||
applicability = DirectiveApplicability.Global
|
||||
)
|
||||
}
|
||||
+94
-92
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.context.withModule
|
||||
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDependenciesImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.frontend.java.di.createContainerForLazyResolveWithJava
|
||||
import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis
|
||||
@@ -39,8 +40,6 @@ import org.jetbrains.kotlin.ir.backend.js.toResolverLogger
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
|
||||
import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
||||
@@ -52,75 +51,45 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.platform.konan.isNative
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.directives.MultiplatformDiagnosticsDirectives.MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE
|
||||
import org.jetbrains.kotlin.test.model.DependencyRelation
|
||||
import org.jetbrains.kotlin.test.model.FrontendFacade
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import org.jetbrains.kotlin.types.typeUtil.closure
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import java.io.File
|
||||
|
||||
class ClassicFrontendFacade(
|
||||
testServices: TestServices
|
||||
testServices: TestServices,
|
||||
) : FrontendFacade<ClassicFrontendOutputArtifact>(testServices, FrontendKinds.ClassicFrontend) {
|
||||
override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = listOf(service(::ModuleDescriptorProvider))
|
||||
|
||||
override fun analyze(module: TestModule): ClassicFrontendOutputArtifact {
|
||||
val dependencyProvider = testServices.dependencyProvider
|
||||
val moduleDescriptorProvider = testServices.moduleDescriptorProvider
|
||||
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
|
||||
val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
|
||||
val project = compilerConfigurationProvider.getProject(module)
|
||||
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
val multiplatformConfiguration = MultiplatformAnalysisConfiguration(testServices)
|
||||
|
||||
val ktFilesMap = testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).toMutableMap()
|
||||
val languageVersionSettings = module.languageVersionSettings
|
||||
|
||||
val sourceDependencies = module.allDependencies.filter { it.kind == DependencyKind.Source }
|
||||
val dependentDescriptors = sourceDependencies.mapNotNull {
|
||||
val testModule = dependencyProvider.getTestModule(it.moduleName)
|
||||
if (testModule.targetPlatform.isCommon()) return@mapNotNull null
|
||||
moduleDescriptorProvider.getModuleDescriptor(testModule)
|
||||
}
|
||||
|
||||
val friendDescriptors = module.friendDependencies.filter { it.kind == DependencyKind.Source }.map {
|
||||
moduleDescriptorProvider.getModuleDescriptor(dependencyProvider.getTestModule(it.moduleName))
|
||||
}
|
||||
|
||||
var hasCommonModules = false
|
||||
|
||||
fun addDependsOnSources(dependencies: List<DependencyDescription>) {
|
||||
if (dependencies.isEmpty()) return
|
||||
hasCommonModules = true
|
||||
for (dependency in dependencies) {
|
||||
val dependencyModule = dependencyProvider.getTestModule(dependency.moduleName)
|
||||
val artifact = dependencyProvider.getArtifact(dependencyModule, FrontendKinds.ClassicFrontend)
|
||||
/*
|
||||
* We need create KtFiles again with new project because otherwise we can access to some caches using
|
||||
* old project as key which may leads to missing services in core environment
|
||||
*/
|
||||
val ktFiles = testServices.sourceFileProvider.getKtFilesForSourceFiles(artifact.allKtFiles.keys, project)
|
||||
ktFiles.values.forEach { ktFile -> ktFile.isCommonSource = true }
|
||||
ktFilesMap.putAll(ktFiles)
|
||||
addDependsOnSources(dependencyModule.dependsOnDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
addDependsOnSources(module.dependsOnDependencies)
|
||||
|
||||
val ktFilesMap = multiplatformConfiguration.getKtFilesForForSourceFiles(project, module)
|
||||
val ktFiles = ktFilesMap.values.toList()
|
||||
|
||||
setupJavacIfNeeded(module, ktFiles, configuration)
|
||||
val analysisResult = performResolve(
|
||||
module,
|
||||
@@ -128,16 +97,17 @@ class ClassicFrontendFacade(
|
||||
configuration,
|
||||
packagePartProviderFactory,
|
||||
ktFiles,
|
||||
dependentDescriptors,
|
||||
friendDescriptors,
|
||||
hasCommonModules
|
||||
compilerEnvironment = multiplatformConfiguration.getCompilerEnvironment(module),
|
||||
dependencyDescriptors = multiplatformConfiguration.getDependencyDescriptors(module),
|
||||
friendsDescriptors = multiplatformConfiguration.getFriendDescriptors(module),
|
||||
dependsOnDescriptors = multiplatformConfiguration.getDependsOnDescriptors(module)
|
||||
)
|
||||
moduleDescriptorProvider.replaceModuleDescriptorForModule(module, analysisResult.moduleDescriptor)
|
||||
return ClassicFrontendOutputArtifact(
|
||||
ktFilesMap,
|
||||
analysisResult,
|
||||
project,
|
||||
languageVersionSettings
|
||||
module.languageVersionSettings
|
||||
)
|
||||
}
|
||||
|
||||
@@ -160,28 +130,29 @@ class ClassicFrontendFacade(
|
||||
configuration: CompilerConfiguration,
|
||||
packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider,
|
||||
files: List<KtFile>,
|
||||
dependentDescriptors: List<ModuleDescriptorImpl>,
|
||||
compilerEnvironment: TargetEnvironment,
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>,
|
||||
friendsDescriptors: List<ModuleDescriptorImpl>,
|
||||
hasCommonModules: Boolean
|
||||
dependsOnDescriptors: List<ModuleDescriptorImpl>
|
||||
): AnalysisResult {
|
||||
val targetPlatform = module.targetPlatform
|
||||
return when {
|
||||
targetPlatform.isJvm() -> performJvmModuleResolve(
|
||||
module,
|
||||
project,
|
||||
configuration,
|
||||
packagePartProviderFactory,
|
||||
files,
|
||||
dependentDescriptors,
|
||||
friendsDescriptors,
|
||||
hasCommonModules
|
||||
module, project, configuration, packagePartProviderFactory,
|
||||
files, compilerEnvironment, dependencyDescriptors, friendsDescriptors, dependencyDescriptors
|
||||
)
|
||||
targetPlatform.isJs() -> when {
|
||||
module.targetBackend?.isIR != true -> performJsModuleResolve(project, configuration, files, dependentDescriptors)
|
||||
else -> performJsIrModuleResolve(module, project, configuration, files, dependentDescriptors, friendsDescriptors)
|
||||
module.targetBackend?.isIR != true -> performJsModuleResolve(
|
||||
project, configuration, compilerEnvironment, files, dependencyDescriptors
|
||||
)
|
||||
else -> performJsIrModuleResolve(
|
||||
module, project, configuration, compilerEnvironment, files, dependencyDescriptors, friendsDescriptors
|
||||
)
|
||||
}
|
||||
targetPlatform.isNative() -> performNativeModuleResolve(module, project, files)
|
||||
targetPlatform.isCommon() -> performCommonModuleResolve(module, files)
|
||||
targetPlatform.isNative() -> performNativeModuleResolve(
|
||||
module, project, compilerEnvironment, files, dependencyDescriptors, friendsDescriptors, dependsOnDescriptors
|
||||
)
|
||||
targetPlatform.isCommon() -> performCommonModuleResolve(module, compilerEnvironment, files)
|
||||
else -> error("Should not be here")
|
||||
}
|
||||
}
|
||||
@@ -193,45 +164,48 @@ class ClassicFrontendFacade(
|
||||
configuration: CompilerConfiguration,
|
||||
packagePartProviderFactory: (GlobalSearchScope) -> JvmPackagePartProvider,
|
||||
files: List<KtFile>,
|
||||
dependentDescriptors: List<ModuleDescriptorImpl>,
|
||||
compilerEnviornment: TargetEnvironment,
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>,
|
||||
friendsDescriptors: List<ModuleDescriptorImpl>,
|
||||
hasCommonModules: Boolean
|
||||
dependsOnDescriptors: List<ModuleDescriptorImpl>
|
||||
): AnalysisResult {
|
||||
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(project)
|
||||
configuration.getList(JVMConfigurationKeys.FRIEND_PATHS).forEach { moduleVisibilityManager.addFriendPath(it) }
|
||||
|
||||
val moduleTrace = NoScopeRecordCliBindingTrace()
|
||||
if (!hasCommonModules) {
|
||||
if (module.dependsOnDependencies.isEmpty()) {
|
||||
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||
project,
|
||||
files,
|
||||
moduleTrace,
|
||||
configuration.copy(),
|
||||
packagePartProviderFactory,
|
||||
explicitModuleDependencyList = dependentDescriptors,
|
||||
explicitModuleFriendsList = friendsDescriptors
|
||||
explicitModuleDependencyList = dependencyDescriptors,
|
||||
explicitModuleFriendsList = friendsDescriptors,
|
||||
explicitCompilerEnvironment = compilerEnviornment
|
||||
)
|
||||
}
|
||||
|
||||
val moduleContentScope = GlobalSearchScope.allScope(project)
|
||||
val moduleClassResolver = SingleModuleClassResolver()
|
||||
val moduleContext = createModuleContext(module, project, dependentDescriptors, friendsDescriptors) {
|
||||
val moduleContext = createModuleContext(module, project, dependencyDescriptors, friendsDescriptors, dependsOnDescriptors) {
|
||||
JvmBuiltIns(it, JvmBuiltIns.Kind.FROM_CLASS_LOADER)
|
||||
}
|
||||
val moduleDescriptor = moduleContext.module as ModuleDescriptorImpl
|
||||
val jvmTarget = configuration[JVM_TARGET] ?: JvmTarget.DEFAULT
|
||||
val container = createContainerForLazyResolveWithJava(
|
||||
JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget), // TODO(dsavvinov): do not pass JvmTarget around
|
||||
moduleContext,
|
||||
moduleTrace,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
moduleContentScope,
|
||||
moduleClassResolver,
|
||||
CompilerEnvironment, LookupTracker.DO_NOTHING,
|
||||
ExpectActualTracker.DoNothing,
|
||||
InlineConstTracker.DoNothing,
|
||||
packagePartProviderFactory(moduleContentScope),
|
||||
module.languageVersionSettings,
|
||||
jvmPlatform = JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget), // TODO(dsavvinov): do not pass JvmTarget around
|
||||
moduleContext = moduleContext,
|
||||
bindingTrace = moduleTrace,
|
||||
declarationProviderFactory = FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
moduleContentScope = moduleContentScope,
|
||||
moduleClassResolver = moduleClassResolver,
|
||||
targetEnvironment = compilerEnviornment,
|
||||
lookupTracker = LookupTracker.DO_NOTHING,
|
||||
expectActualTracker = ExpectActualTracker.DoNothing,
|
||||
inlineConstTracker = InlineConstTracker.DoNothing,
|
||||
packagePartProvider = packagePartProviderFactory(moduleContentScope),
|
||||
languageVersionSettings = module.languageVersionSettings,
|
||||
useBuiltInsProvider = true
|
||||
)
|
||||
|
||||
@@ -257,17 +231,18 @@ class ClassicFrontendFacade(
|
||||
private fun performJsModuleResolve(
|
||||
project: Project,
|
||||
configuration: CompilerConfiguration,
|
||||
compilerEnvironment: TargetEnvironment,
|
||||
files: List<KtFile>,
|
||||
dependentDescriptors: List<ModuleDescriptorImpl>
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>
|
||||
): AnalysisResult {
|
||||
// `dependentDescriptors` - modules with source dependency kind
|
||||
// `dependencyDescriptors` - modules with source dependency kind
|
||||
// 'jsConfig.moduleDescriptors' - modules with binary dependency kind
|
||||
val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration)
|
||||
val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration, compilerEnvironment)
|
||||
return TopDownAnalyzerFacadeForJS.analyzeFiles(
|
||||
files,
|
||||
project = jsConfig.project,
|
||||
configuration = jsConfig.configuration,
|
||||
moduleDescriptors = dependentDescriptors + jsConfig.moduleDescriptors,
|
||||
moduleDescriptors = dependencyDescriptors + jsConfig.moduleDescriptors,
|
||||
friendModuleDescriptors = jsConfig.friendModuleDescriptors,
|
||||
targetEnvironment = jsConfig.targetEnvironment,
|
||||
)
|
||||
@@ -310,15 +285,16 @@ class ClassicFrontendFacade(
|
||||
module: TestModule,
|
||||
project: Project,
|
||||
configuration: CompilerConfiguration,
|
||||
compilerEnvironment: TargetEnvironment,
|
||||
files: List<KtFile>,
|
||||
dependentDescriptors: List<ModuleDescriptorImpl>,
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>,
|
||||
friendsDescriptors: List<ModuleDescriptorImpl>,
|
||||
): AnalysisResult {
|
||||
val runtimeKlibsNames = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices)
|
||||
val runtimeKlibs = loadKlib(runtimeKlibsNames, configuration)
|
||||
val transitiveLibraries = JsEnvironmentConfigurator.getDependencies(module, testServices, DependencyRelation.RegularDependency)
|
||||
val friendLibraries = JsEnvironmentConfigurator.getDependencies(module, testServices, DependencyRelation.FriendDependency)
|
||||
val allDependencies = runtimeKlibs + dependentDescriptors + transitiveLibraries
|
||||
val allDependencies = runtimeKlibs + dependencyDescriptors + transitiveLibraries
|
||||
|
||||
val analyzer = AnalyzerWithCompilerReport(configuration)
|
||||
val builtInModuleDescriptor = allDependencies.firstNotNullOfOrNull { it.builtIns }?.builtInsModule
|
||||
@@ -329,7 +305,7 @@ class ClassicFrontendFacade(
|
||||
configuration,
|
||||
allDependencies,
|
||||
friendsDescriptors + friendLibraries,
|
||||
CompilerEnvironment,
|
||||
compilerEnvironment,
|
||||
thisIsBuiltInsModule = builtInModuleDescriptor == null,
|
||||
customBuiltInsModule = builtInModuleDescriptor
|
||||
)
|
||||
@@ -341,31 +317,48 @@ class ClassicFrontendFacade(
|
||||
private fun performNativeModuleResolve(
|
||||
module: TestModule,
|
||||
project: Project,
|
||||
compilerEnvironment: TargetEnvironment,
|
||||
files: List<KtFile>,
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>,
|
||||
friendsDescriptors: List<ModuleDescriptorImpl>,
|
||||
dependsOnDescriptors: List<ModuleDescriptorImpl>,
|
||||
): AnalysisResult {
|
||||
val moduleTrace = NoScopeRecordCliBindingTrace()
|
||||
val moduleContext = createModuleContext(module, project, dependentDescriptors = emptyList(), friendsDescriptors = emptyList()) {
|
||||
val moduleContext = createModuleContext(
|
||||
module, project,
|
||||
dependencyDescriptors = dependencyDescriptors,
|
||||
friendsDescriptors = friendsDescriptors,
|
||||
dependsOnDescriptors = dependsOnDescriptors
|
||||
) {
|
||||
DefaultBuiltIns()
|
||||
}
|
||||
return FakeTopDownAnalyzerFacadeForNative.analyzeFilesWithGivenTrace(
|
||||
files,
|
||||
moduleTrace,
|
||||
moduleContext,
|
||||
module.languageVersionSettings
|
||||
module.languageVersionSettings,
|
||||
compilerEnvironment
|
||||
)
|
||||
}
|
||||
|
||||
private fun performCommonModuleResolve(
|
||||
module: TestModule,
|
||||
compilerEnvironment: TargetEnvironment,
|
||||
files: List<KtFile>,
|
||||
): AnalysisResult {
|
||||
// See 'TODO' for adding dependency manager
|
||||
require(module.dependsOnDependencies.isEmpty() || MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE !in module.directives) {
|
||||
"Analyzing common modules with 'dependsOn' edges in ${MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE.name} is not supported yet.\n" +
|
||||
"Module: ${module.name}\n" +
|
||||
"dependsOn: ${module.dependsOnDependencies.map { it.moduleName }}"
|
||||
}
|
||||
return CommonResolverForModuleFactory.analyzeFiles(
|
||||
files,
|
||||
Name.special("<${module.name}>"),
|
||||
dependOnBuiltIns = true,
|
||||
module.languageVersionSettings,
|
||||
module.targetPlatform,
|
||||
CompilerEnvironment,
|
||||
compilerEnvironment,
|
||||
// TODO: add dependency manager
|
||||
) {
|
||||
// TODO
|
||||
@@ -377,8 +370,9 @@ class ClassicFrontendFacade(
|
||||
private fun createModuleContext(
|
||||
module: TestModule,
|
||||
project: Project,
|
||||
dependentDescriptors: List<ModuleDescriptorImpl>,
|
||||
dependencyDescriptors: List<ModuleDescriptorImpl>,
|
||||
friendsDescriptors: List<ModuleDescriptorImpl>,
|
||||
dependsOnDescriptors: List<ModuleDescriptorImpl>,
|
||||
builtInsFactory: (StorageManager) -> KotlinBuiltIns,
|
||||
): ModuleContext {
|
||||
val projectContext = ProjectContext(project, "test project context")
|
||||
@@ -389,10 +383,18 @@ class ClassicFrontendFacade(
|
||||
val dependencies = buildList {
|
||||
add(moduleDescriptor)
|
||||
add(moduleDescriptor.builtIns.builtInsModule)
|
||||
addAll(dependentDescriptors)
|
||||
addAll(dependencyDescriptors)
|
||||
}
|
||||
moduleDescriptor.setDependencies(dependencies, friendsDescriptors.toSet())
|
||||
|
||||
moduleDescriptor.setDependencies(
|
||||
ModuleDependenciesImpl(
|
||||
allDependencies = dependencies,
|
||||
modulesWhoseInternalsAreVisible = friendsDescriptors.toSet(),
|
||||
directExpectedByDependencies = dependsOnDescriptors,
|
||||
allExpectedByDependencies = dependsOnDescriptors.closure { dependsOnModuleDescriptor ->
|
||||
dependsOnModuleDescriptor.expectedByModules.map { it as ModuleDescriptorImpl }
|
||||
}.toSet()
|
||||
),
|
||||
)
|
||||
return projectContext.withModule(moduleDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("TestFunctionName")
|
||||
|
||||
package org.jetbrains.kotlin.test.frontend.classic
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.ModulePath
|
||||
import org.jetbrains.kotlin.resolve.ModuleStructureOracle
|
||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import org.jetbrains.kotlin.test.directives.MultiplatformDiagnosticsDirectives.MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
|
||||
internal fun MultiplatformAnalysisConfiguration(testServices: TestServices): MultiplatformAnalysisConfiguration {
|
||||
return if (testServices.moduleStructure.allDirectives.contains(MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE))
|
||||
MultiplatformCompositeAnalysisConfiguration(
|
||||
testServices.dependencyProvider,
|
||||
testServices.sourceFileProvider,
|
||||
testServices.moduleDescriptorProvider,
|
||||
)
|
||||
else MultiplatformSeparateAnalysisConfiguration(
|
||||
testServices.dependencyProvider,
|
||||
testServices.sourceFileProvider,
|
||||
testServices.moduleDescriptorProvider
|
||||
)
|
||||
}
|
||||
|
||||
internal interface MultiplatformAnalysisConfiguration {
|
||||
fun getCompilerEnvironment(module: TestModule): TargetEnvironment
|
||||
fun getKtFilesForForSourceFiles(project: Project, module: TestModule): Map<TestFile, KtFile>
|
||||
fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl>
|
||||
fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl>
|
||||
fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl>
|
||||
}
|
||||
|
||||
/**
|
||||
* Traditional 'compiler cli' configuration...
|
||||
*/
|
||||
internal class MultiplatformSeparateAnalysisConfiguration(
|
||||
private val dependencyProvider: DependencyProvider,
|
||||
private val sourceFileProvider: SourceFileProvider,
|
||||
private val moduleDescriptorProvider: ModuleDescriptorProvider
|
||||
) : MultiplatformAnalysisConfiguration {
|
||||
|
||||
override fun getCompilerEnvironment(module: TestModule): TargetEnvironment {
|
||||
return CompilerEnvironment
|
||||
}
|
||||
|
||||
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return getDescriptors(
|
||||
module.allDependencies - module.dependsOnDependencies.toSet(),
|
||||
dependencyProvider, moduleDescriptorProvider
|
||||
)
|
||||
}
|
||||
|
||||
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return getDescriptors(
|
||||
module.friendDependencies, dependencyProvider, moduleDescriptorProvider
|
||||
)
|
||||
}
|
||||
|
||||
override fun getKtFilesForForSourceFiles(project: Project, module: TestModule): Map<TestFile, KtFile> {
|
||||
val ktFilesMap = sourceFileProvider.getKtFilesForSourceFiles(module.files, project).toMutableMap()
|
||||
fun addDependsOnSources(dependencies: List<DependencyDescription>) {
|
||||
if (dependencies.isEmpty()) return
|
||||
for (dependency in dependencies) {
|
||||
val dependencyModule = dependencyProvider.getTestModule(dependency.moduleName)
|
||||
val artifact = dependencyProvider.getArtifact(dependencyModule, FrontendKinds.ClassicFrontend)
|
||||
/*
|
||||
* We need create KtFiles again with new project because otherwise we can access to some caches using
|
||||
* old project as key which may leads to missing services in core environment
|
||||
*/
|
||||
val ktFiles = sourceFileProvider.getKtFilesForSourceFiles(artifact.allKtFiles.keys, project)
|
||||
ktFiles.values.forEach { ktFile -> ktFile.isCommonSource = true }
|
||||
ktFilesMap.putAll(ktFiles)
|
||||
addDependsOnSources(dependencyModule.dependsOnDependencies)
|
||||
}
|
||||
}
|
||||
addDependsOnSources(module.dependsOnDependencies)
|
||||
return ktFilesMap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata / IDE like configuration...
|
||||
*/
|
||||
internal class MultiplatformCompositeAnalysisConfiguration(
|
||||
private val dependencyProvider: DependencyProvider,
|
||||
private val sourceFileProvider: SourceFileProvider,
|
||||
private val moduleDescriptorProvider: ModuleDescriptorProvider,
|
||||
) : MultiplatformAnalysisConfiguration {
|
||||
|
||||
override fun getCompilerEnvironment(module: TestModule): TargetEnvironment {
|
||||
return CompositeAnalysisTargetEnvironment
|
||||
}
|
||||
|
||||
override fun getKtFilesForForSourceFiles(project: Project, module: TestModule): Map<TestFile, KtFile> {
|
||||
return sourceFileProvider.getKtFilesForSourceFiles(module.files, project)
|
||||
}
|
||||
|
||||
override fun getDependencyDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return getDescriptors(module.allDependencies, dependencyProvider, moduleDescriptorProvider)
|
||||
}
|
||||
|
||||
override fun getDependsOnDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return getDescriptors(module.dependsOnDependencies, dependencyProvider, moduleDescriptorProvider)
|
||||
}
|
||||
|
||||
override fun getFriendDescriptors(module: TestModule): List<ModuleDescriptorImpl> {
|
||||
return getDescriptors(module.friendDependencies, dependencyProvider, moduleDescriptorProvider)
|
||||
}
|
||||
}
|
||||
|
||||
private object CompositeAnalysisTargetEnvironment : TargetEnvironment("Test: Multiplatform with Composite Analysis") {
|
||||
override fun configure(container: StorageComponentContainer) {
|
||||
CompilerEnvironment.configure(container)
|
||||
container.useInstance(CompositeAnalysisModuleStructureOracle)
|
||||
}
|
||||
}
|
||||
|
||||
private object CompositeAnalysisModuleStructureOracle : ModuleStructureOracle {
|
||||
|
||||
override fun hasImplementingModules(module: ModuleDescriptor): Boolean {
|
||||
return findAllReversedDependsOnPaths(module).isNotEmpty()
|
||||
}
|
||||
|
||||
override fun findAllReversedDependsOnPaths(module: ModuleDescriptor): List<ModulePath> {
|
||||
return emptyList() // <- Not supported, yet
|
||||
}
|
||||
|
||||
override fun findAllDependsOnPaths(module: ModuleDescriptor): List<ModulePath> {
|
||||
return module.expectedByModules.flatMap { expectedByModule ->
|
||||
if (expectedByModule.expectedByModules.isEmpty()) listOf(ModulePath(listOf(expectedByModule)))
|
||||
else findAllDependsOnPaths(expectedByModule).map { path ->
|
||||
ModulePath(listOf(expectedByModule) + path.nodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Utils */
|
||||
|
||||
private fun getDescriptors(
|
||||
dependencies: Iterable<DependencyDescription>,
|
||||
dependencyProvider: DependencyProvider,
|
||||
moduleDescriptorProvider: ModuleDescriptorProvider
|
||||
): List<ModuleDescriptorImpl> {
|
||||
return dependencies.filter { it.kind == DependencyKind.Source }
|
||||
.map { dependencyDescription -> dependencyProvider.getTestModule(dependencyDescription.moduleName) }
|
||||
.map { dependencyModule -> moduleDescriptorProvider.getModuleDescriptor(dependencyModule) }
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.test.runners
|
||||
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
|
||||
import org.jetbrains.kotlin.test.directives.MultiplatformDiagnosticsDirectives
|
||||
|
||||
abstract class AbstractDiagnosticsWithMultiplatformCompositeAnalysisTest : AbstractDiagnosticTest() {
|
||||
override fun configure(builder: TestConfigurationBuilder) {
|
||||
super.configure(builder)
|
||||
builder.defaultDirectives {
|
||||
+MultiplatformDiagnosticsDirectives.MULTIPLATFORM_COMPOSITE_ANALYSIS_MODE
|
||||
LanguageSettingsDirectives.LANGUAGE with "+MultiPlatformProjects"
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -8,16 +8,17 @@ package org.jetbrains.kotlin.test.services.configuration
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.AnalysisFlags.allowFullyQualifiedNameInKClass
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.js.config.*
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.resolve.CompilerEnvironment
|
||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor
|
||||
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
@@ -31,9 +32,9 @@ import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.SOURCE_MAP_EMBED_SOURCES
|
||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.TYPED_ARRAYS
|
||||
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
|
||||
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
|
||||
import org.jetbrains.kotlin.test.model.ArtifactKinds
|
||||
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.model.DependencyDescription
|
||||
import org.jetbrains.kotlin.test.model.DependencyRelation
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
@@ -114,9 +115,11 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
|
||||
|
||||
fun getPostfixFile(module: TestModule): File? = getPrefixPostfixFile(module, prefix = false)
|
||||
|
||||
fun createJsConfig(project: Project, configuration: CompilerConfiguration): JsConfig {
|
||||
fun createJsConfig(
|
||||
project: Project, configuration: CompilerConfiguration, compilerEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): JsConfig {
|
||||
return JsConfig(
|
||||
project, configuration, CompilerEnvironment, METADATA_CACHE, (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).toSet()
|
||||
project, configuration, compilerEnvironment, METADATA_CACHE, (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).toSet()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -27,13 +27,15 @@ object FakeTopDownAnalyzerFacadeForNative {
|
||||
files: Collection<KtFile>,
|
||||
trace: BindingTrace,
|
||||
moduleContext: ModuleContext,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
compilerEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): AnalysisResult {
|
||||
|
||||
val analyzerForNative = createFakeTopDownAnalyzerForNative(
|
||||
moduleContext, trace,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
languageVersionSettings
|
||||
languageVersionSettings,
|
||||
compilerEnvironment
|
||||
)
|
||||
|
||||
analyzerForNative.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files as Collection<com.intellij.psi.PsiElement>)
|
||||
@@ -45,7 +47,8 @@ private fun createFakeTopDownAnalyzerForNative(
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
compilerEnvironment: TargetEnvironment = CompilerEnvironment
|
||||
): LazyTopDownAnalyzer = createContainer("FakeTopDownAnalyzerForNative", NativePlatformAnalyzerServices) {
|
||||
configureModule(
|
||||
moduleContext,
|
||||
@@ -59,7 +62,7 @@ private fun createFakeTopDownAnalyzerForNative(
|
||||
|
||||
useInstance(declarationProviderFactory)
|
||||
useInstance(InlineConstTracker.DoNothing)
|
||||
CompilerEnvironment.configure(this)
|
||||
compilerEnvironment.configure(this)
|
||||
}.apply {
|
||||
val moduleDescriptor = get<ModuleDescriptorImpl>()
|
||||
moduleDescriptor.initialize(get<KotlinCodeAnalyzer>().packageFragmentProvider)
|
||||
|
||||
+7
@@ -47,6 +47,13 @@ fun generateJUnit5CompilerTests(args: Array<String>) {
|
||||
model("diagnostics/nativeTests")
|
||||
}
|
||||
|
||||
testClass<AbstractDiagnosticsWithMultiplatformCompositeAnalysisTest> {
|
||||
model(
|
||||
"diagnostics/testsWithMultiplatformCompositeAnalysis",
|
||||
pattern = "^(.*)\\.kts?$", excludedPattern = excludedFirTestdataPattern
|
||||
)
|
||||
}
|
||||
|
||||
testClass<AbstractForeignAnnotationsSourceJavaTest> {
|
||||
model("diagnostics/foreignAnnotationsTests/tests", excludedPattern = excludedFirTestdataPattern)
|
||||
model("diagnostics/foreignAnnotationsTests/java8Tests", excludedPattern = excludedFirTestdataPattern)
|
||||
|
||||
Reference in New Issue
Block a user