Use correct LanguageVersionSettings in MetadataSerializer

Also, require users of K2MetadataCompiler to pass "-Xmulti-platform"
manually. Gradle and Maven plugins already do that, so only users who
invoke kotlinc directly are going to be affected by this

 #KT-19287 Fixed
This commit is contained in:
Alexander Udalov
2017-07-28 14:04:31 +03:00
parent 4923589b38
commit 2e82bb5632
7 changed files with 45 additions and 17 deletions
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.serializeToByteArray import org.jetbrains.kotlin.codegen.serializeToByteArray
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -63,7 +64,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
val analyzer = AnalyzerWithCompilerReport(messageCollector) val analyzer = AnalyzerWithCompilerReport(messageCollector)
analyzer.analyzeAndReport(files) { analyzer.analyzeAndReport(files) {
DefaultAnalyzerFacade.analyzeFiles(files, moduleName, dependOnOldBuiltIns) { _, content -> DefaultAnalyzerFacade.analyzeFiles(files, moduleName, dependOnOldBuiltIns, configuration.languageVersionSettings) { _, content ->
environment.createPackagePartProvider(content.moduleContentScope) environment.createPackagePartProvider(content.moduleContentScope)
} }
} }
@@ -43,15 +43,10 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmentProvider import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmentProvider
/** /**
* A facade that is used to analyze platform independent modules in multi-platform projects. * A facade that is used to analyze common (platform-independent) modules in multi-platform projects.
* See [TargetPlatform.Default] * See [TargetPlatform.Default]
*/ */
object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() { object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
private val languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE,
specificFeatures = mapOf(LanguageFeature.MultiPlatformProjects to LanguageFeature.State.ENABLED)
)
private class SourceModuleInfo( private class SourceModuleInfo(
override val name: Name, override val name: Name,
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>, override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
@@ -64,12 +59,19 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
} }
fun analyzeFiles( fun analyzeFiles(
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common), capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
): AnalysisResult { ): AnalysisResult {
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns) val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze") val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
else languageVersionSettings.getFeatureSupport(feature)
}
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
val resolver = setupResolverForProject( val resolver = setupResolverForProject(
"sources for metadata serializer", "sources for metadata serializer",
@@ -77,7 +79,7 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
{ ModuleContent(files, GlobalSearchScope.allScope(project)) }, { ModuleContent(files, GlobalSearchScope.allScope(project)) },
object : PlatformAnalysisParameters {}, object : PlatformAnalysisParameters {},
object : LanguageSettingsProvider { object : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = languageVersionSettings override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
}, },
packagePartProviderFactory = packagePartProviderFactory, packagePartProviderFactory = packagePartProviderFactory,
@@ -113,7 +115,8 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace() val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val container = createContainerToResolveCommonCode( val container = createContainerToResolveCommonCode(
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
) )
val packageFragmentProviders = listOf( val packageFragmentProviders = listOf(
@@ -130,7 +133,8 @@ object DefaultAnalyzerFacade : AnalyzerFacade<PlatformAnalysisParameters>() {
declarationProviderFactory: DeclarationProviderFactory, declarationProviderFactory: DeclarationProviderFactory,
moduleContentScope: GlobalSearchScope, moduleContentScope: GlobalSearchScope,
targetEnvironment: TargetEnvironment, targetEnvironment: TargetEnvironment,
packagePartProvider: PackagePartProvider packagePartProvider: PackagePartProvider,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) { ): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) {
configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace) configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace)
@@ -0,0 +1,9 @@
// ADDITIONAL_COMPILER_ARGUMENTS: -Xcoroutines=enable
fun f(g: suspend () -> Unit): Any = g
suspend fun h() = f { }
header suspend fun k()
header fun l(g: suspend () -> Unit): Any
@@ -0,0 +1,3 @@
-- Common --
Exit code: OK
Output:
@@ -291,7 +291,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
val platform = moduleDescriptor.getMultiTargetPlatform() val platform = moduleDescriptor.getMultiTargetPlatform()
if (platform == MultiTargetPlatform.Common) { if (platform == MultiTargetPlatform.Common) {
return DefaultAnalyzerFacade.analyzeFiles( return DefaultAnalyzerFacade.analyzeFiles(
files, moduleDescriptor.name, true, files, moduleDescriptor.name, true, languageVersionSettings,
mapOf( mapOf(
MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common, MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common,
MODULE_FILES to files MODULE_FILES to files
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.js.K2JSCompiler import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
@@ -68,9 +69,9 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
KotlinTestUtils.assertEqualsToFile(File(root, "output.txt"), result.replace('\\', '/')) KotlinTestUtils.assertEqualsToFile(File(root, "output.txt"), result.replace('\\', '/'))
} }
private fun CLICompiler<*>.compileBothWays(commonSource: File, platformSource: File, vararg additionalArguments: String): String { private fun CLICompiler<*>.compileBothWays(commonSource: File, platformSource: File, vararg mainArguments: String): String {
val platformFirst = compile(listOf(platformSource, commonSource), *additionalArguments) val platformFirst = compile(listOf(platformSource, commonSource), *mainArguments)
val commonFirst = compile(listOf(commonSource, platformSource), *additionalArguments) val commonFirst = compile(listOf(commonSource, platformSource), *mainArguments)
if (platformFirst != commonFirst) { if (platformFirst != commonFirst) {
assertEquals( assertEquals(
"Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]", "Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]",
@@ -81,13 +82,17 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
return platformFirst return platformFirst
} }
private fun CLICompiler<*>.compile(sources: List<File>, vararg additionalArguments: String): String = buildString { private fun CLICompiler<*>.compile(sources: List<File>, vararg mainArguments: String): String = buildString {
val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput( val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput(
this@compile, this@compile,
sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + additionalArguments sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + mainArguments + loadExtraArguments(sources)
) )
appendln("Exit code: $exitCode") appendln("Exit code: $exitCode")
appendln("Output:") appendln("Output:")
appendln(output) appendln(output)
}.trimTrailingWhitespacesAndAddNewlineAtEOF().trimEnd('\r', '\n') }.trimTrailingWhitespacesAndAddNewlineAtEOF().trimEnd('\r', '\n')
private fun loadExtraArguments(sources: List<File>): List<String> = sources.flatMap { source ->
InTextDirectivesUtils.findListWithPrefixes(source.readText(), "// ADDITIONAL_COMPILER_ARGUMENTS:")
}
} }
@@ -42,6 +42,12 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compilerArguments")
public void testCompilerArguments() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/multiplatform/compilerArguments/");
doTest(fileName);
}
@TestMetadata("createImplClassInPlatformModule") @TestMetadata("createImplClassInPlatformModule")
public void testCreateImplClassInPlatformModule() throws Exception { public void testCreateImplClassInPlatformModule() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/multiplatform/createImplClassInPlatformModule/"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/multiplatform/createImplClassInPlatformModule/");