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") @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 { fun <T : Any> ComponentProvider.getService(request: Class<T>): T {
val valueDescriptor = resolve(request) ?: throw IllegalArgumentException("Unresolved service: $request") return tryGetService(request) ?: throw IllegalArgumentException("Unresolved service: $request")
return valueDescriptor.getValue() as T
} }
fun StorageComponentContainer.useInstance(instance: Any) { fun StorageComponentContainer.useInstance(instance: Any) {
@@ -157,66 +157,71 @@ interface ModuleInfo {
} }
abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> { abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
fun <M : ModuleInfo> setupResolverForProject( companion object {
debugName: String, fun <P : PlatformAnalysisParameters, M : ModuleInfo> setupResolverForProject(
projectContext: ProjectContext, debugName: String,
modules: Collection<M>, projectContext: ProjectContext,
modulesContent: (M) -> ModuleContent, modules: Collection<M>,
platformParameters: P, analyzerFacade: (M) -> AnalyzerFacade<P>,
targetEnvironment: TargetEnvironment = CompilerEnvironment, modulesContent: (M) -> ModuleContent,
builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance }, platformParameters: P,
delegateResolver: ResolverForProject<M> = EmptyResolverForProject(), targetEnvironment: TargetEnvironment = CompilerEnvironment,
packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty }, builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance },
firstDependency: M? = null, delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
modulePlatforms: (M) -> MultiTargetPlatform? packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
): ResolverForProject<M> { firstDependency: M? = null,
val storageManager = projectContext.storageManager modulePlatforms: (M) -> MultiTargetPlatform?
): ResolverForProject<M> {
val storageManager = projectContext.storageManager
val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module -> val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module ->
ModuleDescriptorImpl(module.name, storageManager, builtIns(module), modulePlatforms(module), module.capabilities) ModuleDescriptorImpl(module.name, storageManager, builtIns(module), modulePlatforms(module), module.capabilities)
}, delegateResolver) }, delegateResolver)
for (module in modules) { for (module in modules) {
resolverForProject.descriptorForModule(module).setDependencies(LazyModuleDependencies( resolverForProject.descriptorForModule(module).setDependencies(LazyModuleDependencies(
storageManager, storageManager,
computeDependencies = { computeDependencies = {
val orderedDependencies = listOfNotNull(firstDependency) + module.dependencies() val orderedDependencies = listOfNotNull(firstDependency) + module.dependencies()
val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) { dependencyInfo -> val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) { dependencyInfo ->
resolverForProject.descriptorForModule(dependencyInfo as M) 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 }) for (module in modules) {
resolverForProject.resolverByModuleDescriptor[descriptor] = computeResolverForModule 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( 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 project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
val resolver = setupResolverForProject( val resolver = setupResolverForProject(
"sources for metadata serializer", "sources for metadata serializer",
ProjectContext(project), listOf(moduleInfo), ProjectContext(project), listOf(moduleInfo), { DefaultAnalyzerFacade },
{ ModuleContent(files, GlobalSearchScope.allScope(project)) }, { ModuleContent(files, GlobalSearchScope.allScope(project)) },
object : PlatformAnalysisParameters {}, object : PlatformAnalysisParameters {},
packagePartProviderFactory = packagePartProviderFactory, packagePartProviderFactory = packagePartProviderFactory,
@@ -61,6 +61,11 @@ public class ForTestCompileRuntime {
return assertExists(new File("dist/kotlinc/lib/kotlin-runtime-sources.jar")); 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 // TODO: Do not use these classes, remove them after stdlib tests are merged in the same build as the compiler
@NotNull @NotNull
@Deprecated @Deprecated
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.lazy
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.get
@@ -35,9 +36,9 @@ fun createResolveSessionForFiles(
): ResolveSession { ): ResolveSession {
val projectContext = ProjectContext(project) val projectContext = ProjectContext(project)
val testModule = TestModule(addBuiltIns) val testModule = TestModule(addBuiltIns)
val resolverForProject = JvmAnalyzerFacade.setupResolverForProject( val resolverForProject = AnalyzerFacade.setupResolverForProject(
"test", "test",
projectContext, listOf(testModule), projectContext, listOf(testModule), { JvmAnalyzerFacade },
{ ModuleContent(syntheticFiles, GlobalSearchScope.allScope(project)) }, { ModuleContent(syntheticFiles, GlobalSearchScope.allScope(project)) },
JvmPlatformParameters { testModule }, JvmPlatformParameters { testModule },
modulePlatforms = { MultiTargetPlatform.Specific("JVM") } modulePlatforms = { MultiTargetPlatform.Specific("JVM") }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.jvm.compiler
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.DelegatingGlobalSearchScope
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.analyzer.ResolverForProject
@@ -65,9 +66,9 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() {
val modules = setupModules(environment, moduleDirs) val modules = setupModules(environment, moduleDirs)
val projectContext = ProjectContext(environment.project) val projectContext = ProjectContext(environment.project)
val builtIns = JvmBuiltIns(projectContext.storageManager) val builtIns = JvmBuiltIns(projectContext.storageManager)
val resolverForProject = JvmAnalyzerFacade.setupResolverForProject( val resolverForProject = AnalyzerFacade.setupResolverForProject(
"test", "test",
projectContext, modules, projectContext, modules, { JvmAnalyzerFacade },
{ module -> ModuleContent(module.kotlinFiles, module.javaFilesScope) }, { module -> ModuleContent(module.kotlinFiles, module.javaFilesScope) },
JvmPlatformParameters { JvmPlatformParameters {
javaClass -> javaClass ->
@@ -67,7 +67,7 @@ object JsAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
) )
var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
if (moduleInfo is LibraryModuleInfo && moduleInfo.isJsLibrary()) { if (moduleInfo is LibraryModuleInfo && moduleInfo.libraryPlatform == JsPlatform) {
val providers = moduleInfo.getLibraryRoots() val providers = moduleInfo.getLibraryRoots()
.flatMap { KotlinJavascriptMetadataUtils.loadMetadata(it) } .flatMap { KotlinJavascriptMetadataUtils.loadMetadata(it) }
.filter { it.version.isCompatible() } .filter { it.version.isCompatible() }
@@ -17,8 +17,10 @@
package org.jetbrains.kotlin.caches.resolve package org.jetbrains.kotlin.caches.resolve
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.resolve.TargetPlatform
interface LibraryModuleInfo : ModuleInfo { interface LibraryModuleInfo : ModuleInfo {
fun isJsLibrary(): Boolean val libraryPlatform: TargetPlatform
fun getLibraryRoots(): Collection<String> fun getLibraryRoots(): Collection<String>
} }
@@ -32,11 +32,15 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.caches.resolve.LibraryModuleInfo import org.jetbrains.kotlin.caches.resolve.LibraryModuleInfo
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.framework.CommonLibraryDetectionUtil
import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.GlobalSearchScopeWithModuleSources import org.jetbrains.kotlin.resolve.jvm.GlobalSearchScopeWithModuleSources
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import java.util.* import java.util.*
interface IdeaModuleInfo : ModuleInfo { interface IdeaModuleInfo : ModuleInfo {
@@ -200,7 +204,12 @@ class LibraryInfo(val project: Project, val library: Library) : IdeaModuleInfo,
return result.toList() return result.toList()
} }
override fun isJsLibrary(): Boolean = KotlinJavaScriptLibraryDetectionUtil.isKotlinJavaScriptLibrary(library) override val libraryPlatform: TargetPlatform
get() = when {
KotlinJavaScriptLibraryDetectionUtil.isKotlinJavaScriptLibrary(library) -> JsPlatform
CommonLibraryDetectionUtil.isCommonLibrary(library) -> TargetPlatform.Default
else -> JvmPlatform
}
override val sourcesModuleInfo: SourceForBinaryModuleInfo override val sourcesModuleInfo: SourceForBinaryModuleInfo
get() = LibrarySourceInfo(project, library) get() = LibrarySourceInfo(project, library)
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.container.tryGetService
import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContext
import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -164,7 +165,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
} }
fun <T : Any> tryGetProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T? { fun <T : Any> tryGetProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T? {
return globalFacade(platform, ideaModuleInfo.sdk).tryGetResolverForModuleInfo(ideaModuleInfo)?.componentProvider?.getService(serviceClass) return globalFacade(platform, ideaModuleInfo.sdk).tryGetResolverForModuleInfo(ideaModuleInfo)?.componentProvider?.tryGetService(serviceClass)
} }
private fun globalFacade(platform: TargetPlatform, sdk: Sdk?) = private fun globalFacade(platform: TargetPlatform, sdk: Sdk?) =
@@ -23,10 +23,12 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.JdkOrderEntry import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootManager
import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.LibraryModuleInfo
import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider
@@ -78,15 +80,13 @@ fun createModuleResolverProvider(
psiClass.getNullableModuleInfo() psiClass.getNullableModuleInfo()
} }
return AnalyzerFacadeProvider.getAnalyzerFacade(platform).setupResolverForProject( return AnalyzerFacade.setupResolverForProject(
debugName, globalContext.withProject(project), modulesToCreateResolversFor, modulesContent, debugName, globalContext.withProject(project), modulesToCreateResolversFor,
jvmPlatformParameters, IdeaEnvironment, builtInsProvider, { module -> AnalyzerFacadeProvider.getAnalyzerFacade(module.getTargetPlatform() ?: platform) },
modulesContent, jvmPlatformParameters, IdeaEnvironment, builtInsProvider,
delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) }, delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) },
sdk?.let { SdkInfo(project, it) }, sdk?.let { SdkInfo(project, it) },
modulePlatforms = { moduleInfo -> modulePlatforms = { module -> module.getTargetPlatform()?.multiTargetPlatform }
val module = (moduleInfo as? ModuleSourceInfo)?.module
module?.let { TargetPlatformDetector.getPlatform(module).multiTargetPlatform }
}
) )
} }
@@ -105,6 +105,13 @@ fun createModuleResolverProvider(
) )
} }
private fun ModuleInfo.getTargetPlatform(): TargetPlatform? =
when (this) {
is ModuleSourceInfo -> TargetPlatformDetector.getPlatform(module)
is LibraryModuleInfo -> libraryPlatform
else -> null
}
fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> { fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
val ideaModules = ModuleManager.getInstance(project).modules.toList() val ideaModules = ModuleManager.getInstance(project).modules.toList()
val modulesSourcesInfos = ideaModules.flatMap { listOf(it.productionSourceInfo(), it.testSourceInfo()) } val modulesSourcesInfos = ideaModules.flatMap { listOf(it.productionSourceInfo(), it.testSourceInfo()) }
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.framework
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.caches.JarUserDataManager
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
object CommonLibraryDetectionUtil {
fun isCommonLibrary(library: Library): Boolean {
if (library is LibraryEx && library.isDisposed) return false
for (root in library.getFiles(OrderRootType.CLASSES)) {
val hasMetadata = JarUserDataManager.hasFileWithProperty(HasCommonKotlinMetadataInJar, root)
if (hasMetadata != null) {
return hasMetadata
}
if (!VfsUtilCore.processFilesRecursively(root) { !isKotlinMetadataFile(it) }) {
return true
}
}
return false
}
private fun isKotlinMetadataFile(file: VirtualFile): Boolean =
!file.isDirectory &&
file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION
object HasCommonKotlinMetadataInJar : JarUserDataManager.JarBooleanPropertyCounter(HasCommonKotlinMetadataInJar::class.simpleName!!) {
override fun hasProperty(file: VirtualFile) = isKotlinMetadataFile(file)
}
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.caches.JarUserDataManager; import org.jetbrains.kotlin.idea.caches.JarUserDataManager;
import org.jetbrains.kotlin.idea.debugger.filter.DebuggerFiltersUtilKt; import org.jetbrains.kotlin.idea.debugger.filter.DebuggerFiltersUtilKt;
import org.jetbrains.kotlin.idea.framework.CommonLibraryDetectionUtil;
import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil; import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil;
import org.jetbrains.kotlin.utils.PathUtil; import org.jetbrains.kotlin.utils.PathUtil;
@@ -59,6 +60,7 @@ public class PluginStartupComponent implements ApplicationComponent {
} }
JarUserDataManager.INSTANCE.register(KotlinJavaScriptLibraryDetectionUtil.HasKotlinJSMetadataInJar.INSTANCE); JarUserDataManager.INSTANCE.register(KotlinJavaScriptLibraryDetectionUtil.HasKotlinJSMetadataInJar.INSTANCE);
JarUserDataManager.INSTANCE.register(CommonLibraryDetectionUtil.HasCommonKotlinMetadataInJar.INSTANCE);
DebuggerFiltersUtilKt.addKotlinStdlibDebugFilterIfNeeded(); DebuggerFiltersUtilKt.addKotlinStdlibDebugFilterIfNeeded();
@@ -0,0 +1,3 @@
package test
class MyException : Exception()
@@ -0,0 +1,10 @@
package test
fun test(f: () -> Unit) {
try {
f()
}
catch (e: MyException) {
f()
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.caches.resolve package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.roots.DependencyScope
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.TargetPlatformKind import org.jetbrains.kotlin.config.TargetPlatformKind
@@ -64,9 +65,12 @@ class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() {
class MultiPlatform : AbstractMultiModuleHighlightingTest() { class MultiPlatform : AbstractMultiModuleHighlightingTest() {
override val testPath get() = super.testPath + "multiplatform/" override val testPath get() = super.testPath + "multiplatform/"
private fun doTest(vararg platforms: TargetPlatformKind<*>) { private fun doTest(vararg platforms: TargetPlatformKind<*>, withStdlibCommon: Boolean = false) {
val commonModule = module("common") val commonModule = module("common")
commonModule.createFacet(TargetPlatformKind.Common) commonModule.createFacet(TargetPlatformKind.Common)
if (withStdlibCommon) {
commonModule.addLibrary(ForTestCompileRuntime.stdlibCommonForTests())
}
for (platform in platforms) { for (platform in platforms) {
val path = when (platform) { val path = when (platform) {
@@ -106,5 +110,9 @@ class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() {
fun testSuppressHeaderWithoutImpl() { fun testSuppressHeaderWithoutImpl() {
doTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) doTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
} }
fun testCatchHeaderExceptionInPlatformModule() {
doTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], withStdlibCommon = true)
}
} }
} }
@@ -24,8 +24,11 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.module.StdModuleTypes import com.intellij.openapi.module.StdModuleTypes
import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.PsiTestUtil
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument
@@ -35,6 +38,7 @@ import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
import org.jetbrains.kotlin.idea.facet.initializeIfNeeded import org.jetbrains.kotlin.idea.facet.initializeIfNeeded
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinJdkAndLibraryProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import java.io.File import java.io.File
@@ -75,6 +79,13 @@ abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() {
exported: Boolean = false exported: Boolean = false
) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported) ) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported)
protected fun Module.addLibrary(jar: File) {
ConfigLibraryUtil.addLibrary(NewLibraryEditor().apply {
name = KotlinJdkAndLibraryProjectDescriptor.LIBRARY_NAME
addRoot(VfsUtil.getUrlForLibraryRoot(jar), OrderRootType.CLASSES)
}, this)
}
protected fun Module.createFacet(platformKind: TargetPlatformKind<*>? = null) { protected fun Module.createFacet(platformKind: TargetPlatformKind<*>? = null) {
val accessToken = WriteAction.start() val accessToken = WriteAction.start()
try { try {
+10 -1
View File
@@ -43,4 +43,13 @@ task sourcesJar(type: Jar, dependsOn: classes) {
artifacts { artifacts {
archives sourcesJar archives sourcesJar
archives javadocJar archives javadocJar
} }
// TODO: call the "dist" task instead, once we need to publish kotlin-stdlib-common.jar with the compiler distribution
task distCommon(type: Copy) {
from(jar)
into "$distDir/common"
rename "-${java.util.regex.Pattern.quote(version)}", ''
}
dist.dependsOn distCommon