Require "-Xuse-experimental=kotlin.Experimental" on usages of Experimental
Since we're not yet sure of the design of Experimental/UseExperimental, we're making them "experimental" themselves in some sense, in that the user is required to provide the magic argument "-Xuse-experimental=kotlin.Experimental" to be allowed to use either Experimental or UseExperimental. This is more convenient than the previous approach of "-language-version 1.3 -Xskip-metadata-version-check" because it's simpler and does not cause pre-release binaries to be produced
This commit is contained in:
@@ -240,6 +240,7 @@ public interface Errors {
|
||||
DiagnosticFactory2<PsiElement, FqName, DeclarationDescriptor> EXPERIMENTAL_OVERRIDE = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, FqName, DeclarationDescriptor> EXPERIMENTAL_OVERRIDE_ERROR = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<PsiElement> EXPERIMENTAL_IS_NOT_ENABLED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> USE_EXPERIMENTAL_WITHOUT_ARGUMENTS = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory1<KtAnnotationEntry, FqName> USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
@@ -146,6 +146,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(EXPERIMENTAL_OVERRIDE, "This declaration overrides experimental member of supertype ''{1}'' and should be annotated with ''@{0}''", TO_STRING, NAME);
|
||||
MAP.put(EXPERIMENTAL_OVERRIDE_ERROR, "This declaration overrides experimental member of supertype ''{1}'' and must be annotated with ''@{0}''", TO_STRING, NAME);
|
||||
|
||||
MAP.put(EXPERIMENTAL_IS_NOT_ENABLED, "This class can only be used with the compiler argument '-Xuse-experimental=kotlin.Experimental'");
|
||||
MAP.put(USE_EXPERIMENTAL_WITHOUT_ARGUMENTS, "@UseExperimental without any arguments has no effect");
|
||||
MAP.put(USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER, "Annotation ''{0}'' is not an experimental API marker, therefore its usage in @UseExperimental is ignored", TO_STRING);
|
||||
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Experimental annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING);
|
||||
|
||||
+22
-1
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
@@ -67,6 +68,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
private val WARNING_LEVEL = Name.identifier("WARNING")
|
||||
private val ERROR_LEVEL = Name.identifier("ERROR")
|
||||
|
||||
private val EXPERIMENTAL_SHORT_NAME = EXPERIMENTAL_FQ_NAME.shortName()
|
||||
private val USE_EXPERIMENTAL_SHORT_NAME = USE_EXPERIMENTAL_FQ_NAME.shortName()
|
||||
|
||||
private fun reportNotAcceptedExperimentalities(
|
||||
experimentalities: Collection<Experimentality>, element: PsiElement, context: CheckerContext
|
||||
) {
|
||||
@@ -196,7 +200,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
|
||||
val validExperimental = languageVersionSettings.getFlag(AnalysisFlag.experimental).filter(::checkAnnotation)
|
||||
val validUseExperimental = languageVersionSettings.getFlag(AnalysisFlag.useExperimental).filter(::checkAnnotation)
|
||||
val validUseExperimental = languageVersionSettings.getFlag(AnalysisFlag.useExperimental).filter { fqName ->
|
||||
fqName == EXPERIMENTAL_FQ_NAME.asString() || checkAnnotation(fqName)
|
||||
}
|
||||
|
||||
for (fqName in validExperimental.intersect(validUseExperimental)) {
|
||||
reportError("'-Xuse-experimental=$fqName' has no effect because '-Xexperimental=$fqName' is used")
|
||||
@@ -208,9 +214,24 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
private val moduleAnnotationsResolver = ModuleAnnotationsResolver.getInstance(project)
|
||||
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
val name = targetDescriptor.name
|
||||
if (name == EXPERIMENTAL_SHORT_NAME || name == USE_EXPERIMENTAL_SHORT_NAME) {
|
||||
val fqName = targetDescriptor.fqNameUnsafe
|
||||
if (fqName == EXPERIMENTAL_FQ_NAME.toUnsafe() || fqName == USE_EXPERIMENTAL_FQ_NAME.toUnsafe()) {
|
||||
checkUsageOfKotlinExperimentalOrUseExperimental(element, context)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val experimentalities = targetDescriptor.loadExperimentalities(moduleAnnotationsResolver)
|
||||
reportNotAcceptedExperimentalities(experimentalities, element, context)
|
||||
}
|
||||
|
||||
private fun checkUsageOfKotlinExperimentalOrUseExperimental(element: PsiElement, context: CheckerContext) {
|
||||
if (EXPERIMENTAL_FQ_NAME.asString() !in context.languageVersionSettings.getFlag(AnalysisFlag.useExperimental)) {
|
||||
context.trace.report(Errors.EXPERIMENTAL_IS_NOT_ENABLED.on(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Overrides(project: Project) : DeclarationChecker {
|
||||
|
||||
Reference in New Issue
Block a user