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 }