Refactor AnalysisFlags and their support in IDE

* Support flags with any value (not just Boolean)
* Support all flags by parsing arguments in KotlinFacetSettings, instead
  of manually listing known flags

 #KT-19210 Fixed
This commit is contained in:
Alexander Udalov
2017-07-24 20:49:00 +03:00
parent 845de7aa4d
commit 2f99f6ad34
18 changed files with 99 additions and 80 deletions
@@ -16,6 +16,13 @@
package org.jetbrains.kotlin.cli.common.arguments;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.config.AnalysisFlag;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("WeakerAccess")
public abstract class CommonCompilerArguments extends CommonToolArguments {
public static final long serialVersionUID = 0L;
@@ -89,6 +96,14 @@ public abstract class CommonCompilerArguments extends CommonToolArguments {
public static final String ERROR = "error";
public static final String ENABLE = "enable";
@NotNull
public Map<AnalysisFlag<?>, Object> configureAnalysisFlags() {
Map<AnalysisFlag<?>, Object> result = new HashMap<>();
result.put(AnalysisFlag.getSkipMetadataVersionCheck(), skipMetadataVersionCheck);
result.put(AnalysisFlag.getMultiPlatformDoNotCheckImpl(), noCheckImpl);
return result;
}
// Used only for serialize and deserialize settings. Don't use in other places!
public static final class DummyImpl extends CommonCompilerArguments {}
}
@@ -16,8 +16,13 @@
package org.jetbrains.kotlin.cli.common.arguments;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.config.AnalysisFlag;
import org.jetbrains.kotlin.config.JvmTarget;
import java.util.Map;
@SuppressWarnings("WeakerAccess")
public class K2JVMCompilerArguments extends CommonCompilerArguments {
public static final long serialVersionUID = 0L;
@@ -162,4 +167,12 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
// Paths to output directories for friend modules.
public String[] friendPaths;
@Override
@NotNull
public Map<AnalysisFlag<?>, Object> configureAnalysisFlags() {
Map<AnalysisFlag<?>, Object> result = super.configureAnalysisFlags();
result.put(AnalysisFlag.getLoadJsr305Annotations(), loadJsr305annotations);
return result;
}
}
@@ -189,15 +189,12 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
extraLanguageFeatures.put(LanguageFeature.Coroutines, coroutinesState);
}
LanguageVersionSettingsImpl settings =
new LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion), extraLanguageFeatures);
settings.switchFlag(AnalysisFlags.getSkipMetadataVersionCheck(), arguments.skipMetadataVersionCheck);
settings.switchFlag(AnalysisFlags.getMultiPlatformDoNotCheckImpl(), arguments.noCheckImpl);
configureAnalysisFlags(settings, arguments);
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, settings);
}
protected void configureAnalysisFlags(@NotNull LanguageVersionSettingsImpl settings, @NotNull A arguments) {
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
arguments.configureAnalysisFlags(),
extraLanguageFeatures
));
}
@Nullable
@@ -303,10 +303,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
override fun configureAnalysisFlags(settings: LanguageVersionSettingsImpl, arguments: K2JVMCompilerArguments) {
settings.switchFlag(AnalysisFlags.loadJsr305Annotations, arguments.loadJsr305annotations)
}
override fun createArguments(): K2JVMCompilerArguments = K2JVMCompilerArguments().apply {
if (System.getenv("KOTLIN_REPORT_PERF") != null) {
reportPerf = true
@@ -54,9 +54,9 @@ open class KotlinJvmReplService(
addJvmClasspathRoots(PathUtil.getKotlinPathsForCompiler().let { listOf(it.stdlibPath, it.reflectPath, it.scriptRuntimePath) })
addJvmClasspathRoots(templateClasspath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE).apply {
switchFlag(AnalysisFlags.skipMetadataVersionCheck, true)
}
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.skipMetadataVersionCheck to true)
)
}
protected fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition? {
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.frontend.java.di
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.JvmBuiltInsPackageFragmentProvider
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -103,7 +103,7 @@ fun createContainerForLazyResolveWithJava(
useInstance(languageVersionSettings)
if (languageVersionSettings.isFlagEnabled(AnalysisFlags.loadJsr305Annotations)) {
if (languageVersionSettings.getFlag(AnalysisFlag.loadJsr305Annotations)) {
useImpl<AnnotationTypeQualifierResolverImpl>()
}
else {
@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
@@ -24,5 +24,5 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfigu
class CompilerDeserializationConfiguration(languageVersionSettings: LanguageVersionSettings) : DeserializationConfiguration {
override val typeAliasesAllowed = languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)
override val skipMetadataVersionCheck = languageVersionSettings.isFlagEnabled(AnalysisFlags.skipMetadataVersionCheck)
override val skipMetadataVersionCheck = languageVersionSettings.getFlag(AnalysisFlag.skipMetadataVersionCheck)
}
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
@@ -61,7 +61,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
if (descriptor !is MemberDescriptor) return
val checkImpl = !languageVersionSettings.isFlagEnabled(AnalysisFlags.multiPlatformDoNotCheckImpl)
val checkImpl = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckImpl)
if (descriptor.isHeader && declaration.hasModifier(KtTokens.HEADER_KEYWORD)) {
checkHeaderDeclarationHasImplementation(declaration, descriptor, diagnosticHolder, descriptor.module, checkImpl)
}
@@ -121,7 +121,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
languageFeatures[feature] ?: delegate.getFeatureSupport(feature)
override fun isFlagEnabled(flag: AnalysisFlag): Boolean = false
override fun <T> getFlag(flag: AnalysisFlag<T>): T = flag.defaultValue
}
inner class TestFile(
@@ -29,9 +29,7 @@ abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsWithFullJdkTe
open protected val annotationsPath: String
get() = FOREIGN_ANNOTATIONS_SOURCES_PATH
override fun loadLanguageVersionSettings(module: List<TestFile>): LanguageVersionSettings {
return LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE).apply {
switchFlag(AnalysisFlags.loadJsr305Annotations, true)
}
}
override fun loadLanguageVersionSettings(module: List<TestFile>): LanguageVersionSettings =
LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE,
mapOf(AnalysisFlag.loadJsr305Annotations to true))
}
@@ -45,9 +45,9 @@ class LoadJavaPackageAnnotationsTest : KtUsefulTestCase() {
if (useJavac) {
put(JVMConfigurationKeys.USE_JAVAC, true)
}
languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE).apply {
switchFlag(AnalysisFlags.loadJsr305Annotations, true)
}
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.loadJsr305Annotations to true)
)
configurator(this)
}
val environment =
@@ -94,9 +94,9 @@ class TypeQualifierAnnotationResolverTest : KtUsefulTestCase() {
),
listOf(File(TEST_DATA_PATH))
).apply {
languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE).apply {
switchFlag(AnalysisFlags.loadJsr305Annotations, true)
}
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.loadJsr305Annotations to true)
)
}
val environment = KotlinCoreEnvironment.createForTests(myTestRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
@@ -19,30 +19,34 @@ package org.jetbrains.kotlin.config
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class AnalysisFlag internal constructor(private val name: String) {
override fun equals(other: Any?): Boolean = other is AnalysisFlag && other.name == name
class AnalysisFlag<out T> internal constructor(
private val name: String,
val defaultValue: T
) {
override fun equals(other: Any?): Boolean = other is AnalysisFlag<*> && other.name == name
override fun hashCode(): Int = name.hashCode()
override fun toString(): String = name
companion object
}
private class Flag<out T>(name: String, defaultValue: T) : ReadOnlyProperty<Any?, AnalysisFlag<T>> {
private val flag = AnalysisFlag(name, defaultValue)
private operator fun @Suppress("unused") AnalysisFlag.Companion.provideDelegate(instance: Any?, property: KProperty<*>) =
object : ReadOnlyProperty<Any?, AnalysisFlag> {
private val flag = AnalysisFlag(property.name)
override fun getValue(thisRef: Any?, property: KProperty<*>): AnalysisFlag<T> = flag
override fun getValue(thisRef: Any?, property: KProperty<*>): AnalysisFlag = flag
object Boolean {
operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Flag(property.name, false)
}
}
object AnalysisFlags {
@JvmStatic
val skipMetadataVersionCheck by AnalysisFlag
companion object Flags {
@JvmStatic
val skipMetadataVersionCheck by Flag.Boolean
@JvmStatic
val multiPlatformDoNotCheckImpl by AnalysisFlag
@JvmStatic
val multiPlatformDoNotCheckImpl by Flag.Boolean
@JvmStatic
val loadJsr305Annotations by AnalysisFlag
@JvmStatic
val loadJsr305Annotations by Flag.Boolean
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.config
import org.jetbrains.kotlin.config.LanguageVersion.KOTLIN_1_1
import org.jetbrains.kotlin.config.LanguageVersion.KOTLIN_1_2
import org.jetbrains.kotlin.utils.DescriptionAware
import java.util.*
enum class LanguageFeature(
val sinceVersion: LanguageVersion?,
@@ -115,7 +116,7 @@ interface LanguageVersionSettings {
fun supportsFeature(feature: LanguageFeature): Boolean =
getFeatureSupport(feature).let { it == LanguageFeature.State.ENABLED || it == LanguageFeature.State.ENABLED_WITH_WARNING }
fun isFlagEnabled(flag: AnalysisFlag): Boolean
fun <T> getFlag(flag: AnalysisFlag<T>): T
val apiVersion: ApiVersion
@@ -126,20 +127,14 @@ interface LanguageVersionSettings {
class LanguageVersionSettingsImpl @JvmOverloads constructor(
override val languageVersion: LanguageVersion,
override val apiVersion: ApiVersion,
private val specificFeatures: Map<LanguageFeature, LanguageFeature.State> = emptyMap()
analysisFlags: Map<AnalysisFlag<*>, Any?> = emptyMap(),
specificFeatures: Map<LanguageFeature, LanguageFeature.State> = emptyMap()
) : LanguageVersionSettings {
private val enabledFlags = hashSetOf<AnalysisFlag>()
private val analysisFlags: Map<AnalysisFlag<*>, *> = Collections.unmodifiableMap(analysisFlags)
private val specificFeatures: Map<LanguageFeature, LanguageFeature.State> = Collections.unmodifiableMap(specificFeatures)
override fun isFlagEnabled(flag: AnalysisFlag): Boolean = flag in enabledFlags
fun switchFlag(flag: AnalysisFlag, enable: Boolean) {
if (enable) {
enabledFlags.add(flag)
}
else {
enabledFlags.remove(flag)
}
}
@Suppress("UNCHECKED_CAST")
override fun <T> getFlag(flag: AnalysisFlag<T>): T = analysisFlags[flag] as T? ?: flag.defaultValue
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State {
specificFeatures[feature]?.let { return it }
@@ -25,7 +25,7 @@ import com.intellij.openapi.roots.ProjectFileIndex
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.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
@@ -88,9 +88,7 @@ fun Project.getLanguageVersionSettings(contextModule: Module? = null): LanguageV
compilerSettings,
null
)
return LanguageVersionSettingsImpl(languageVersion, apiVersion, extraLanguageFeatures).apply {
switchFlag(AnalysisFlags.skipMetadataVersionCheck, arguments.skipMetadataVersionCheck)
}
return LanguageVersionSettingsImpl(languageVersion, apiVersion, arguments.configureAnalysisFlags(), extraLanguageFeatures)
}
val Module.languageVersionSettings: LanguageVersionSettings
@@ -109,9 +107,19 @@ val Module.languageVersionSettings: LanguageVersionSettings
this
)
return LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion), extraLanguageFeatures).apply {
switchFlag(AnalysisFlags.skipMetadataVersionCheck, facetSettings.skipMetadataVersionCheck)
val arguments = facetSettings.compilerArguments
if (arguments != null) {
facetSettings.compilerSettings?.let { compilerSettings ->
parseCommandLineArguments(compilerSettings.additionalArgumentsAsList, arguments)
}
}
return LanguageVersionSettingsImpl(
languageVersion,
ApiVersion.createByLanguageVersion(apiVersion),
arguments?.configureAnalysisFlags().orEmpty(),
extraLanguageFeatures
)
}
val Module.targetPlatform: TargetPlatformKind<*>?
@@ -124,12 +124,6 @@ class KotlinFacetSettings {
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> CommonCompilerArguments.ERROR
}
}
var skipMetadataVersionCheck: Boolean
get() = compilerArguments?.skipMetadataVersionCheck == true
set(value) {
compilerArguments!!.skipMetadataVersionCheck = value
}
}
fun TargetPlatformKind<*>.createCompilerArguments(init: CommonCompilerArguments.() -> Unit = {}): CommonCompilerArguments {
@@ -163,8 +163,7 @@ public class JsConfig {
Set<String> modules = new HashSet<>();
boolean skipMetadataVersionCheck =
getLanguageVersionSettings(configuration).isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck());
boolean skipMetadataVersionCheck = getLanguageVersionSettings(configuration).getFlag(AnalysisFlag.getSkipMetadataVersionCheck());
for (String path : libraries) {
if (librariesToSkip != null && librariesToSkip.contains(path)) continue;
@@ -312,7 +311,7 @@ public class JsConfig {
return factoryMap.computeIfAbsent(metadata, m -> {
LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(configuration);
assert m.getVersion().isCompatible() ||
languageVersionSettings.isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck()) :
languageVersionSettings.getFlag(AnalysisFlag.getSkipMetadataVersionCheck()) :
"Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + m.getVersion();
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
@@ -71,8 +71,8 @@ class KotlinJsr223JvmLocalScriptEngine(
addJvmClasspathRoots(PathUtil.getJdkClassesRootsFromCurrentJre())
addJvmClasspathRoots(templateClasspath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
languageVersionSettings = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE).apply {
switchFlag(AnalysisFlags.skipMetadataVersionCheck, true)
}
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.skipMetadataVersionCheck to true)
)
}
}