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.targetPlatform
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.utils.Jsr305State
object IDELanguageSettingsProvider : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings =
when (moduleInfo) {
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 ScriptDependenciesInfo.ForFile -> getVersionLanguageSettingsForScripts(project, moduleInfo.scriptDefinition)
is PlatformModuleInfo -> moduleInfo.platformModule.module.languageVersionSettings
else -> project.getLanguageVersionSettings()
}
private fun getExtraAnalysisFlags(project: Project): Map<AnalysisFlag<*>, Any?> {
val map = mutableMapOf<AnalysisFlag<*>, Any>()
private fun computeJsr305State(project: Project): Jsr305State? {
var result: Jsr305State? = null
for (module in ModuleManager.getInstance(project).modules) {
val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue
val compilerArguments = settings.mergedCompilerArguments as? K2JVMCompilerArguments ?: continue
val jsr305State = Jsr305Parser(MessageCollector.NONE).parse(
result = Jsr305Parser(MessageCollector.NONE).parse(
compilerArguments.jsr305,
compilerArguments.supportCompatqualCheckerFrameworkAnnotations
)
map.put(AnalysisFlag.jsr305, jsr305State)
}
return map
return result
}
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.CachedValuesManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.common.arguments.Argument
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.*
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.psi.KtElement
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.utils.Jsr305State
val KtElement.platform: TargetPlatform
get() = TargetPlatformDetector.getPlatform(containingKtFile)
@@ -46,22 +46,6 @@ val KtElement.platform: TargetPlatform
val KtElement.builtIns: KotlinBuiltIns
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 {
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
val languageLevel = getLibraryLanguageLevel(this, null, facetSettings.targetPlatformKind)
@@ -93,7 +77,7 @@ fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
@JvmOverloads
fun Project.getLanguageVersionSettings(
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 {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion =
@@ -102,16 +86,24 @@ fun Project.getLanguageVersionSettings(
?: LanguageVersion.LATEST_STABLE
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
val extraLanguageFeatures = getExtraLanguageFeatures(
null,
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
compilerSettings,
null
val additionalArguments: CommonCompilerArguments = parseArguments(
TargetPlatformKind.DEFAULT_PLATFORM,
compilerSettings.additionalArgumentsAsList
)
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(
languageVersion, apiVersion,
arguments.configureAnalysisFlags(MessageCollector.NONE) + extraAnalysisFlags,
extraLanguageFeatures
arguments.configureLanguageFeatures(MessageCollector.NONE) + extraLanguageFeatures
)
}
@@ -137,26 +129,30 @@ private fun Module.createCachedValueForLanguageVersionSettings(): CachedValue<La
}, false)
}
private fun Module.computeLanguageVersionSettings(): LanguageVersionSettings {
private fun Module.shouldUseProjectLanguageVersionSettings(): Boolean {
val facetSettingsProvider = KotlinFacetSettingsProvider.getInstance(project)
if (facetSettingsProvider.getSettings(this) == null) return project.getLanguageVersionSettings(this)
val facetSettings = facetSettingsProvider.getInitializedSettings(this)
if (facetSettings.useProjectSettings) return project.getLanguageVersionSettings(this)
return facetSettingsProvider.getSettings(this) == null || facetSettingsProvider.getInitializedSettings(this).useProjectSettings
}
private fun Module.computeLanguageVersionSettings(): LanguageVersionSettings {
if (shouldUseProjectLanguageVersionSettings()) return project.getLanguageVersionSettings()
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
val languageVersion = facetSettings.languageLevel ?: getAndCacheLanguageLevelByDependencies()
val apiVersion = facetSettings.apiLevel ?: languageVersion
val extraLanguageFeatures = getExtraLanguageFeatures(
facetSettings.targetPlatformKind ?: TargetPlatformKind.Common,
facetSettings.coroutineSupport,
facetSettings.compilerSettings,
this
)
val languageFeatures = facetSettings.mergedCompilerArguments?.configureLanguageFeatures(MessageCollector.NONE)?.apply {
configureCoroutinesSupport(facetSettings.coroutineSupport)
configureMultiplatformSupport(facetSettings.targetPlatformKind, this@computeLanguageVersionSettings)
}.orEmpty()
val analysisFlags = facetSettings.mergedCompilerArguments?.configureAnalysisFlags(MessageCollector.NONE).orEmpty()
return LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
facetSettings.mergedCompilerArguments?.configureAnalysisFlags(MessageCollector.NONE).orEmpty(),
extraLanguageFeatures
analysisFlags,
languageFeatures
)
}
@@ -174,37 +170,35 @@ private val Module.implementsCommonModule: Boolean
get() = 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<*>?,
coroutineSupport: LanguageFeature.State,
compilerSettings: CompilerSettings?,
module: Module?
): Map<LanguageFeature, LanguageFeature.State> {
return mutableMapOf<LanguageFeature, LanguageFeature.State>().apply {
put(LanguageFeature.Coroutines, coroutineSupport)
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)
}
) {
if (targetPlatformKind == TargetPlatformKind.Common || module?.implementsCommonModule == true) {
put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED)
}
}
val KtElement.languageVersionSettings: LanguageVersionSettings
get() {
if (ServiceManager.getService(project, ProjectFileIndex::class.java) == null) {