Support different target platforms for modules in AnalyzerFacade

Instead of reusing the same AnalyzerFacade that is used for resolution
of a module to resolve its dependencies, analyze each dependency
module/library with a facade depending on its target platform. Introduce
and use CommonLibraryDetectionUtil in addition to
KotlinJavaScriptLibraryDetectionUtil, to detect common libraries (with
.kotlin_metadata files).

Note that before multi-platform projects, this was not needed because
there were only two platforms (JVM and JS), and JVM module had only JVM
modules/libraries as dependencies, JS module had only JS
modules/libraries as dependencies. Now, for example, a JVM module can
have a common module/library as a dependency, and it would be incorrect
to analyze that dependency with JvmAnalyzerFacade because that facade
does not know anything about .kotlin_metadata files.

The changes in Dsl.kt and KotlinCacheServiceImpl.kt are needed because
PsiElement.getJavaDescriptorResolver, called from some IDE code, started
to fail on a common module, because the container for a common module
does not have the JavaDescriptorResolver
This commit is contained in:
Alexander Udalov
2017-04-11 19:25:42 +03:00
parent 722687acd6
commit 7fe9b99087
18 changed files with 202 additions and 73 deletions
@@ -34,9 +34,12 @@ inline fun <reified T : Any> ComponentProvider.get(): T {
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> ComponentProvider.tryGetService(request: Class<T>): T? {
return resolve(request)?.getValue() as T?
}
fun <T : Any> ComponentProvider.getService(request: Class<T>): T {
val valueDescriptor = resolve(request) ?: throw IllegalArgumentException("Unresolved service: $request")
return valueDescriptor.getValue() as T
return tryGetService(request) ?: throw IllegalArgumentException("Unresolved service: $request")
}
fun StorageComponentContainer.useInstance(instance: Any) {
@@ -157,66 +157,71 @@ interface ModuleInfo {
}
abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
fun <M : ModuleInfo> setupResolverForProject(
debugName: String,
projectContext: ProjectContext,
modules: Collection<M>,
modulesContent: (M) -> ModuleContent,
platformParameters: P,
targetEnvironment: TargetEnvironment = CompilerEnvironment,
builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance },
delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
firstDependency: M? = null,
modulePlatforms: (M) -> MultiTargetPlatform?
): ResolverForProject<M> {
val storageManager = projectContext.storageManager
companion object {
fun <P : PlatformAnalysisParameters, M : ModuleInfo> setupResolverForProject(
debugName: String,
projectContext: ProjectContext,
modules: Collection<M>,
analyzerFacade: (M) -> AnalyzerFacade<P>,
modulesContent: (M) -> ModuleContent,
platformParameters: P,
targetEnvironment: TargetEnvironment = CompilerEnvironment,
builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance },
delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
firstDependency: M? = null,
modulePlatforms: (M) -> MultiTargetPlatform?
): ResolverForProject<M> {
val storageManager = projectContext.storageManager
val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module ->
ModuleDescriptorImpl(module.name, storageManager, builtIns(module), modulePlatforms(module), module.capabilities)
}, delegateResolver)
val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module ->
ModuleDescriptorImpl(module.name, storageManager, builtIns(module), modulePlatforms(module), module.capabilities)
}, delegateResolver)
for (module in modules) {
resolverForProject.descriptorForModule(module).setDependencies(LazyModuleDependencies(
storageManager,
computeDependencies = {
val orderedDependencies = listOfNotNull(firstDependency) + module.dependencies()
val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) { dependencyInfo ->
resolverForProject.descriptorForModule(dependencyInfo as M)
for (module in modules) {
resolverForProject.descriptorForModule(module).setDependencies(LazyModuleDependencies(
storageManager,
computeDependencies = {
val orderedDependencies = listOfNotNull(firstDependency) + module.dependencies()
val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) { dependencyInfo ->
resolverForProject.descriptorForModule(dependencyInfo as M)
}
module.dependencyOnBuiltIns().adjustDependencies(
resolverForProject.descriptorForModule(module).builtIns.builtInsModule, dependenciesDescriptors)
dependenciesDescriptors
},
computeModulesWhoseInternalsAreVisible = {
module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) {
resolverForProject.descriptorForModule(it as M)
}
},
computeImplementingModules = {
if (modulePlatforms(module) != MultiTargetPlatform.Common) emptySet()
else modules
.filter { modulePlatforms(it) != MultiTargetPlatform.Common && module in it.dependencies() }
.mapTo(mutableSetOf(), resolverForProject::descriptorForModule)
}
module.dependencyOnBuiltIns().adjustDependencies(
resolverForProject.descriptorForModule(module).builtIns.builtInsModule, dependenciesDescriptors)
dependenciesDescriptors
},
computeModulesWhoseInternalsAreVisible = {
module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) { resolverForProject.descriptorForModule(it as M) }
},
computeImplementingModules = {
if (modulePlatforms(module) != MultiTargetPlatform.Common) emptySet()
else modules
.filter { modulePlatforms(it) != MultiTargetPlatform.Common && module in it.dependencies() }
.mapTo(mutableSetOf(), resolverForProject::descriptorForModule)
}
)
)
}
for (module in modules) {
val descriptor = resolverForProject.descriptorForModule(module)
val computeResolverForModule = storageManager.createLazyValue {
val content = modulesContent(module)
createResolverForModule(
module, descriptor, projectContext.withModule(descriptor), modulesContent(module),
platformParameters, targetEnvironment, resolverForProject,
packagePartProviderFactory(module, content)
)
)
}
descriptor.initialize(DelegatingPackageFragmentProvider { computeResolverForModule().packageFragmentProvider })
resolverForProject.resolverByModuleDescriptor[descriptor] = computeResolverForModule
}
for (module in modules) {
val descriptor = resolverForProject.descriptorForModule(module)
val computeResolverForModule = storageManager.createLazyValue {
val content = modulesContent(module)
analyzerFacade(module).createResolverForModule(
module, descriptor, projectContext.withModule(descriptor), modulesContent(module),
platformParameters, targetEnvironment, resolverForProject,
packagePartProviderFactory(module, content)
)
}
return resolverForProject
descriptor.initialize(DelegatingPackageFragmentProvider { computeResolverForModule().packageFragmentProvider })
resolverForProject.resolverByModuleDescriptor[descriptor] = computeResolverForModule
}
return resolverForProject
}
}
protected abstract fun <M : ModuleInfo> createResolverForModule(
@@ -72,7 +72,7 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
val resolver = setupResolverForProject(
"sources for metadata serializer",
ProjectContext(project), listOf(moduleInfo),
ProjectContext(project), listOf(moduleInfo), { DefaultAnalyzerFacade },
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
object : PlatformAnalysisParameters {},
packagePartProviderFactory = packagePartProviderFactory,
@@ -61,6 +61,11 @@ public class ForTestCompileRuntime {
return assertExists(new File("dist/kotlinc/lib/kotlin-runtime-sources.jar"));
}
@NotNull
public static File stdlibCommonForTests() {
return assertExists(new File("dist/common/kotlin-stdlib-common.jar"));
}
// TODO: Do not use these classes, remove them after stdlib tests are merged in the same build as the compiler
@NotNull
@Deprecated
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.lazy
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.container.get
@@ -35,9 +36,9 @@ fun createResolveSessionForFiles(
): ResolveSession {
val projectContext = ProjectContext(project)
val testModule = TestModule(addBuiltIns)
val resolverForProject = JvmAnalyzerFacade.setupResolverForProject(
val resolverForProject = AnalyzerFacade.setupResolverForProject(
"test",
projectContext, listOf(testModule),
projectContext, listOf(testModule), { JvmAnalyzerFacade },
{ ModuleContent(syntheticFiles, GlobalSearchScope.allScope(project)) },
JvmPlatformParameters { testModule },
modulePlatforms = { MultiTargetPlatform.Specific("JVM") }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.jvm.compiler
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.DelegatingGlobalSearchScope
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForProject
@@ -65,9 +66,9 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() {
val modules = setupModules(environment, moduleDirs)
val projectContext = ProjectContext(environment.project)
val builtIns = JvmBuiltIns(projectContext.storageManager)
val resolverForProject = JvmAnalyzerFacade.setupResolverForProject(
val resolverForProject = AnalyzerFacade.setupResolverForProject(
"test",
projectContext, modules,
projectContext, modules, { JvmAnalyzerFacade },
{ module -> ModuleContent(module.kotlinFiles, module.javaFilesScope) },
JvmPlatformParameters {
javaClass ->