Parse compiler arguments and configure LV properly in Platform.kt

This commit is contained in:
Dmitry Savvinov
2018-05-29 16:05:53 +03:00
parent 5f819b589c
commit b8f8802cff
2 changed files with 64 additions and 69 deletions
@@ -38,31 +38,32 @@ import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.targetPlatform import org.jetbrains.kotlin.idea.project.targetPlatform
import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.utils.Jsr305State
object IDELanguageSettingsProvider : LanguageSettingsProvider { object IDELanguageSettingsProvider : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings = override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings =
when (moduleInfo) { when (moduleInfo) {
is ModuleSourceInfo -> moduleInfo.module.languageVersionSettings is ModuleSourceInfo -> moduleInfo.module.languageVersionSettings
is LibraryInfo -> project.getLanguageVersionSettings(extraAnalysisFlags = getExtraAnalysisFlags(project)) is LibraryInfo -> project.getLanguageVersionSettings(jsr305State = computeJsr305State(project))
is ScriptModuleInfo -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition) is ScriptModuleInfo -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition)
is ScriptDependenciesInfo.ForFile -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition) is ScriptDependenciesInfo.ForFile -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition)
is PlatformModuleInfo -> moduleInfo.platformModule.module.languageVersionSettings is PlatformModuleInfo -> moduleInfo.platformModule.module.languageVersionSettings
else -> project.getLanguageVersionSettings() else -> project.getLanguageVersionSettings()
} }
private fun getExtraAnalysisFlags(project: Project): Map<AnalysisFlag<*>, Any?> { private fun computeJsr305State(project: Project): Jsr305State? {
val map = mutableMapOf<AnalysisFlag<*>, Any>() var result: Jsr305State? = null
for (module in ModuleManager.getInstance(project).modules) { for (module in ModuleManager.getInstance(project).modules) {
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue
val jsr305State = Jsr305Parser(MessageCollector.NONE).parse( result = Jsr305Parser(MessageCollector.NONE).parse(
compilerArguments.jsr305, compilerArguments.jsr305,
compilerArguments.supportCompatqualCheckerFrameworkAnnotations compilerArguments.supportCompatqualCheckerFrameworkAnnotations
) )
map.put(AnalysisFlag.jsr305, jsr305State)
} }
return map return result
} }
override fun getTargetPlatform(moduleInfo: ModuleInfo): TargetPlatformVersion { override fun getTargetPlatform(moduleInfo: ModuleInfo): TargetPlatformVersion {
@@ -28,8 +28,7 @@ import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.common.arguments.Argument import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
@@ -39,6 +38,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.facet.getLibraryLanguageLevel import org.jetbrains.kotlin.idea.facet.getLibraryLanguageLevel
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.utils.Jsr305State
val KtElement.platform: TargetPlatform val KtElement.platform: TargetPlatform
get() = TargetPlatformDetector.getPlatform(containingKtFile) get() = TargetPlatformDetector.getPlatform(containingKtFile)
@@ -46,22 +46,6 @@ val KtElement.platform: TargetPlatform
val KtElement.builtIns: KotlinBuiltIns val KtElement.builtIns: KotlinBuiltIns
get() = getResolutionFacade().moduleDescriptor.builtIns get() = getResolutionFacade().moduleDescriptor.builtIns
private val multiPlatformProjectsArg: String by lazy {
CommonCompilerArguments::multiPlatform.annotations.filterIsInstance<Argument>().single().value
}
private val effectSystemArg: String by lazy {
CommonCompilerArguments::effectSystem.annotations.filterIsInstance<Argument>().single().value
}
private val readDeserializedContractsArg: String by lazy {
CommonCompilerArguments::readDeserializedContracts.annotations.filterIsInstance<Argument>().single().value
}
private val newInferenceArg: String by lazy {
CommonCompilerArguments::newInference.annotations.filterIsInstance<Argument>().single().value
}
fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion { fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this) val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
val languageLevel = getLibraryLanguageLevel(this, null, facetSettings.targetPlatformKind) val languageLevel = getLibraryLanguageLevel(this, null, facetSettings.targetPlatformKind)
@@ -93,7 +77,7 @@ fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
@JvmOverloads @JvmOverloads
fun Project.getLanguageVersionSettings( fun Project.getLanguageVersionSettings(
contextModule: Module? = null, contextModule: Module? = null,
extraAnalysisFlags: Map<AnalysisFlag<*>, Any?> = emptyMap() jsr305State: Jsr305State? = null // this is a temporary hack until we'll have a sane way to configure libraries analysis
): LanguageVersionSettings { ): LanguageVersionSettings {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion = val languageVersion =
@@ -102,16 +86,24 @@ fun Project.getLanguageVersionSettings(
?: LanguageVersion.LATEST_STABLE ?: LanguageVersion.LATEST_STABLE
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion) val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
val extraLanguageFeatures = getExtraLanguageFeatures(
null, val additionalArguments: CommonCompilerArguments = parseArguments(
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings), TargetPlatformKind.DEFAULT_PLATFORM,
compilerSettings, compilerSettings.additionalArgumentsAsList
null
) )
val extraLanguageFeatures = additionalArguments.configureLanguageFeatures(MessageCollector.NONE).apply {
configureCoroutinesSupport(CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this@getLanguageVersionSettings).settings))
}
val extraAnalysisFlags = additionalArguments.configureAnalysisFlags(MessageCollector.NONE).apply {
if (jsr305State != null) put(AnalysisFlag.jsr305, jsr305State)
}
return LanguageVersionSettingsImpl( return LanguageVersionSettingsImpl(
languageVersion, apiVersion, languageVersion, apiVersion,
arguments.configureAnalysisFlags(MessageCollector.NONE) + extraAnalysisFlags, arguments.configureAnalysisFlags(MessageCollector.NONE) + extraAnalysisFlags,
extraLanguageFeatures arguments.configureLanguageFeatures(MessageCollector.NONE) + extraLanguageFeatures
) )
} }
@@ -137,26 +129,30 @@ private fun Module.createCachedValueForLanguageVersionSettings(): CachedValue<La
}, false) }, false)
} }
private fun Module.computeLanguageVersionSettings(): LanguageVersionSettings { private fun Module.shouldUseProjectLanguageVersionSettings(): Boolean {
val facetSettingsProvider = KotlinFacetSettingsProvider.getInstance(project) val facetSettingsProvider = KotlinFacetSettingsProvider.getInstance(project)
if (facetSettingsProvider.getSettings(this) == null) return project.getLanguageVersionSettings(this) return facetSettingsProvider.getSettings(this) == null || facetSettingsProvider.getInitializedSettings(this).useProjectSettings
val facetSettings = facetSettingsProvider.getInitializedSettings(this) }
if (facetSettings.useProjectSettings) return project.getLanguageVersionSettings(this)
private fun Module.computeLanguageVersionSettings(): LanguageVersionSettings {
if (shouldUseProjectLanguageVersionSettings()) return project.getLanguageVersionSettings()
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
val languageVersion = facetSettings.languageLevel ?: getAndCacheLanguageLevelByDependencies() val languageVersion = facetSettings.languageLevel ?: getAndCacheLanguageLevelByDependencies()
val apiVersion = facetSettings.apiLevel ?: languageVersion val apiVersion = facetSettings.apiLevel ?: languageVersion
val extraLanguageFeatures = getExtraLanguageFeatures( val languageFeatures = facetSettings.mergedCompilerArguments?.configureLanguageFeatures(MessageCollector.NONE)?.apply {
facetSettings.targetPlatformKind ?: TargetPlatformKind.Common, configureCoroutinesSupport(facetSettings.coroutineSupport)
facetSettings.coroutineSupport, configureMultiplatformSupport(facetSettings.targetPlatformKind, this@computeLanguageVersionSettings)
facetSettings.compilerSettings, }.orEmpty()
this
) val analysisFlags = facetSettings.mergedCompilerArguments?.configureAnalysisFlags(MessageCollector.NONE).orEmpty()
return LanguageVersionSettingsImpl( return LanguageVersionSettingsImpl(
languageVersion, languageVersion,
ApiVersion.createByLanguageVersion(apiVersion), ApiVersion.createByLanguageVersion(apiVersion),
facetSettings.mergedCompilerArguments?.configureAnalysisFlags(MessageCollector.NONE).orEmpty(), analysisFlags,
extraLanguageFeatures languageFeatures
) )
} }
@@ -174,37 +170,35 @@ private val Module.implementsCommonModule: Boolean
get() = targetPlatform != TargetPlatformKind.Common get() = targetPlatform != TargetPlatformKind.Common
&& ModuleRootManager.getInstance(this).dependencies.any { it.targetPlatform == TargetPlatformKind.Common } && ModuleRootManager.getInstance(this).dependencies.any { it.targetPlatform == TargetPlatformKind.Common }
private fun getExtraLanguageFeatures( private fun parseArguments(
targetPlatformKind: TargetPlatformKind<*>,
additionalArguments: List<String>
): CommonCompilerArguments {
val arguments = when (targetPlatformKind) {
is TargetPlatformKind.Jvm -> K2JVMCompilerArguments()
TargetPlatformKind.JavaScript -> K2JSCompilerArguments()
TargetPlatformKind.Common -> K2MetadataCompilerArguments()
}
parseCommandLineArguments(additionalArguments, arguments)
return arguments
}
fun MutableMap<LanguageFeature, LanguageFeature.State>.configureCoroutinesSupport(coroutineSupport: LanguageFeature.State) {
put(LanguageFeature.Coroutines, coroutineSupport)
}
fun MutableMap<LanguageFeature, LanguageFeature.State>.configureMultiplatformSupport(
targetPlatformKind: TargetPlatformKind<*>?, targetPlatformKind: TargetPlatformKind<*>?,
coroutineSupport: LanguageFeature.State,
compilerSettings: CompilerSettings?,
module: Module? module: Module?
): Map<LanguageFeature, LanguageFeature.State> { ) {
return mutableMapOf<LanguageFeature, LanguageFeature.State>().apply { if (targetPlatformKind == TargetPlatformKind.Common || module?.implementsCommonModule == true) {
put(LanguageFeature.Coroutines, coroutineSupport) put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED)
if (targetPlatformKind == TargetPlatformKind.Common ||
// TODO: this is a dirty hack, parse arguments correctly here
compilerSettings?.additionalArguments?.contains(multiPlatformProjectsArg) == true ||
(module != null && module.implementsCommonModule)
) {
put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED)
}
if (compilerSettings?.additionalArguments?.contains(effectSystemArg) == true) {
put(LanguageFeature.UseReturnsEffect, LanguageFeature.State.ENABLED)
put(LanguageFeature.UseCallsInPlaceEffect, LanguageFeature.State.ENABLED)
}
if (compilerSettings?.additionalArguments?.contains(readDeserializedContractsArg) == true) {
put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED)
}
if (compilerSettings?.additionalArguments?.contains(newInferenceArg) == true) {
put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED)
}
} }
} }
val KtElement.languageVersionSettings: LanguageVersionSettings val KtElement.languageVersionSettings: LanguageVersionSettings
get() { get() {
if (ServiceManager.getService(project, ProjectFileIndex::class.java) == null) { if (ServiceManager.getService(project, ProjectFileIndex::class.java) == null) {