Explicit Api mode: Renamings after design discussions

Change CLI flag to -Xexplicit-api=strict|warning. 'Disable' state and 'mode' suffix are left out as implementation details.

Change intention title to 'make X public explicitly'

Do not report 'no explicit visibility' on property accessors

Set DECLARATION_SIGNATURE as a range for report

Rename internal diagnostic from _MIGRATION to _WARNING
This commit is contained in:
Leonid Startsev
2019-10-14 18:09:52 +03:00
parent 7fada51c42
commit ebb7e434c8
15 changed files with 69 additions and 71 deletions
@@ -317,12 +317,12 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
var disableDefaultScriptingPlugin: Boolean by FreezableVar(false)
@Argument(
value = "-Xapi-mode",
valueDescription = "{enable|disable|migration}",
description = "Enable api mode, force compiler to report errors an all public API declarations without explicit visibility.\n" +
"Use 'migration' level to issue warnings instead of errors."
value = "-Xexplicit-api",
valueDescription = "{strict|warning|disable}",
description = "Force compiler to report errors an all public API declarations without explicit visibility.\n" +
"Use 'warning' level to issue warnings instead of errors."
)
var apiMode: String by FreezableVar(ApiMode.DISABLED.state)
var explicitApi: String by FreezableVar(ExplicitApiMode.DISABLED.state)
open fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
return HashMap<AnalysisFlag<*>, Any>().apply {
@@ -332,9 +332,9 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
put(AnalysisFlags.useExperimental, useExperimental?.toList().orEmpty())
put(AnalysisFlags.explicitApiVersion, apiVersion != null)
put(AnalysisFlags.allowResultReturnType, allowResultReturnType)
ApiMode.fromString(apiMode)?.also { put(AnalysisFlags.apiMode, it) } ?: collector.report(
ExplicitApiMode.fromString(explicitApi)?.also { put(AnalysisFlags.explicitApiMode, it) } ?: collector.report(
CompilerMessageSeverity.ERROR,
"Unknown value for parameter -Xapi-mode: '$apiMode'. Value should be one of ${ApiMode.availableValues()}"
"Unknown value for parameter -Xexplicit-api: '$explicitApi'. Value should be one of ${ExplicitApiMode.availableValues()}"
)
}
}
@@ -28,7 +28,7 @@ object AnalysisFlags {
val allowResultReturnType by AnalysisFlag.Delegates.Boolean
@JvmStatic
val apiMode by AnalysisFlag.Delegates.ApiModeDisabledByDefault
val explicitApiMode by AnalysisFlag.Delegates.ApiModeDisabledByDefault
@JvmStatic
val constraintSystemForOverloadResolution by AnalysisFlag.Delegates.ConstraintSystemForOverloadResolution
@@ -207,10 +207,10 @@ public interface Errors {
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<PsiElement, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE_MIGRATION = DiagnosticFactory1.create(WARNING);
DiagnosticFactory0<PsiElement> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_MIGRATION = DiagnosticFactory0.create(WARNING);
DiagnosticFactory1<KtDeclaration, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory1<KtDeclaration, DeclarationDescriptor> NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING = DiagnosticFactory1.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<PsiElement, KtModifierKeywordToken> ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR);
@@ -121,8 +121,8 @@ public class DefaultErrorMessages {
MAP.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, TO_STRING);
MAP.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE, "Declaration ''{0}'' is effectively public API and API mode is on, but no visibility is specified", NAME);
MAP.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE, "This declaration is effectively public API and API mode is on, but no explicit return type is specified");
MAP.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE_MIGRATION, "Declaration ''{0}'' is effectively public API and API mode is on, but no visibility is specified", NAME);
MAP.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_MIGRATION, "This declaration is effectively public API and API mode is on, but no explicit return type is specified");
MAP.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING, "Declaration ''{0}'' is effectively public API and API mode is on, but no visibility is specified", NAME);
MAP.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING, "This declaration is effectively public API and API mode is on, but no explicit return type is specified");
MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING);
@@ -32,7 +32,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
ReservedMembersAndConstructsForInlineClass(),
ResultClassInReturnTypeChecker(),
LocalVariableTypeParametersChecker(),
ApiModeDeclarationChecker(),
ExplicitApiDeclarationChecker(),
TailrecFunctionChecker,
TrailingCommaDeclarationChecker
)
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.ApiMode
import org.jetbrains.kotlin.config.ExplicitApiMode
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
@@ -15,13 +15,12 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi
class ApiModeDeclarationChecker : DeclarationChecker {
class ExplicitApiDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val state = isEnabled(context.languageVersionSettings)
if (state == ApiMode.DISABLED) return
if (state == ExplicitApiMode.DISABLED) return
val isApi = (descriptor as? DeclarationDescriptorWithVisibility)?.isEffectivelyPublicApi ?: return
if (!isApi) return
@@ -31,7 +30,7 @@ class ApiModeDeclarationChecker : DeclarationChecker {
}
private fun checkVisibilityModifier(
state: ApiMode,
state: ExplicitApiMode,
declaration: KtDeclaration,
descriptor: DeclarationDescriptorWithVisibility,
context: DeclarationCheckerContext
@@ -41,15 +40,15 @@ class ApiModeDeclarationChecker : DeclarationChecker {
if (excludeForDiagnostic(descriptor)) return
val diagnostic =
if (state == ApiMode.ENABLED)
if (state == ExplicitApiMode.STRICT)
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE.on(declaration, descriptor)
else
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_MIGRATION.on(declaration, descriptor)
Errors.NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING.on(declaration, descriptor)
context.trace.reportDiagnosticOnce(diagnostic)
}
private fun checkExplicitReturnType(
state: ApiMode,
state: ExplicitApiMode,
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
context: DeclarationCheckerContext
@@ -65,10 +64,10 @@ class ApiModeDeclarationChecker : DeclarationChecker {
)
if (shouldReport) {
val diagnostic =
if (state == ApiMode.ENABLED)
if (state == ExplicitApiMode.STRICT)
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE.on(declaration)
else
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_MIGRATION
Errors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING
.on(declaration)
context.trace.reportDiagnosticOnce(diagnostic)
}
@@ -77,8 +76,9 @@ class ApiModeDeclarationChecker : DeclarationChecker {
/**
* Exclusion list:
* 1. Primary constructors of public API classes
* 3. Members of public API interfaces
* 4. do not report overrides of public API? effectively, this means 'no report on overrides at all'
* 2. Members of public API interfaces
* 3. do not report overrides of public API? effectively, this means 'no report on overrides at all'
* 4. Getters and setters (because getters can't change visibility and setter-only explicit visibility looks ugly)
*
* Do we need something like @PublicApiFile to disable (or invert) this inspection per-file?
*/
@@ -86,14 +86,15 @@ class ApiModeDeclarationChecker : DeclarationChecker {
/* 1. */ if ((descriptor as? ClassConstructorDescriptor)?.isPrimary == true) return true
val isMemberOfPublicInterface =
(descriptor.containingDeclaration as? ClassDescriptor)?.let { DescriptorUtils.isInterface(it) && it.effectiveVisibility().publicApi }
/* 3. */ if (descriptor is CallableDescriptor && isMemberOfPublicInterface == true) return true
/* 4. */ if ((descriptor as? CallableDescriptor)?.overriddenDescriptors?.isNotEmpty() == true) return true
/* 2. */ if (descriptor is CallableDescriptor && isMemberOfPublicInterface == true) return true
/* 3. */ if ((descriptor as? CallableDescriptor)?.overriddenDescriptors?.isNotEmpty() == true) return true
/* 4. */ if (descriptor is PropertyAccessorDescriptor) return true
return false
}
companion object {
fun isEnabled(settings: LanguageVersionSettings): ApiMode {
return settings.getFlag(AnalysisFlags.apiMode)
fun isEnabled(settings: LanguageVersionSettings): ExplicitApiMode {
return settings.getFlag(AnalysisFlags.explicitApiMode)
}
fun returnTypeRequired(
+3 -3
View File
@@ -11,9 +11,6 @@ where advanced options include:
-Xtyped-arrays Translate primitive arrays to JS typed arrays
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
-Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type
-Xapi-mode={enable|disable|migration}
Enable api mode, force compiler to report errors an all public API declarations without explicit visibility.
Use 'migration' level to issue warnings instead of errors.
-Xcheck-phase-conditions Check pre- and postconditions on phases
-Xcheck-sticky-phase-conditions
Run sticky condition checks on subsequent phases as well. Implies -Xcheck-phase-conditions
@@ -29,6 +26,9 @@ where advanced options include:
-Xdump-perf=<path> Dump detailed performance statistics to the specified file
-Xeffect-system Enable experimental language feature: effect system
-Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name
-Xexplicit-api={strict|warning|disable}
Force compiler to report errors an all public API declarations without explicit visibility.
Use 'warning' level to issue warnings instead of errors.
-Xinline-classes Enable experimental inline classes
-Xintellij-plugin-root=<path> Path to the kotlin-compiler.jar or directory where IntelliJ configuration files can be found
-Xlegacy-smart-cast-after-try Allow var smart casts despite assignment in try block
+3 -3
View File
@@ -70,9 +70,6 @@ where advanced options include:
-Xuse-type-table Use type table in metadata serialization
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
-Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type
-Xapi-mode={enable|disable|migration}
Enable api mode, force compiler to report errors an all public API declarations without explicit visibility.
Use 'migration' level to issue warnings instead of errors.
-Xcheck-phase-conditions Check pre- and postconditions on phases
-Xcheck-sticky-phase-conditions
Run sticky condition checks on subsequent phases as well. Implies -Xcheck-phase-conditions
@@ -88,6 +85,9 @@ where advanced options include:
-Xdump-perf=<path> Dump detailed performance statistics to the specified file
-Xeffect-system Enable experimental language feature: effect system
-Xexperimental=<fq.name> Enable and propagate usages of experimental API for marker annotation with the given fully qualified name
-Xexplicit-api={strict|warning|disable}
Force compiler to report errors an all public API declarations without explicit visibility.
Use 'warning' level to issue warnings instead of errors.
-Xinline-classes Enable experimental inline classes
-Xintellij-plugin-root=<path> Path to the kotlin-compiler.jar or directory where IntelliJ configuration files can be found
-Xlegacy-smart-cast-after-try Allow var smart casts despite assignment in try block
@@ -39,7 +39,7 @@ class AnalysisFlag<out T> internal constructor(
}
object ApiModeDisabledByDefault {
operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Delegate(property.name, ApiMode.DISABLED)
operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Delegate(property.name, ExplicitApiMode.DISABLED)
}
object ListOfStrings {
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.config
enum class ApiMode(val state: String) {
enum class ExplicitApiMode(val state: String) {
DISABLED("disable"),
ENABLED("enable"),
MIGRATION("migration");
STRICT("strict"),
WARNING("warning");
companion object {
fun fromString(string: String): ApiMode? = values().find { it.state == string }
fun fromString(string: String): ExplicitApiMode? = values().find { it.state == string }
fun availableValues() = values().joinToString(prefix = "{", postfix = "}") { it.state }
}