Add some validation for Experimental/UseExperimental usages
#KT-22759 In Progress
This commit is contained in:
@@ -229,6 +229,12 @@ public interface Errors {
|
||||
DiagnosticFactory2<PsiElement, FqName, Boolean> EXPERIMENTAL_API_USAGE = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, FqName, Boolean> EXPERIMENTAL_API_USAGE_ERROR = DiagnosticFactory2.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, FqName> USE_EXPERIMENTAL_ARGUMENT_HAS_NON_COMPILATION_IMPACT = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> EXPERIMENTAL_ANNOTATION_WITH_NO_IMPACT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
// Const
|
||||
DiagnosticFactory0<PsiElement> CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> CONST_VAL_WITH_GETTER = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+7
@@ -151,6 +151,13 @@ public class DefaultErrorMessages {
|
||||
MAP.put(EXPERIMENTAL_API_USAGE, "This declaration is experimental and its usage should be marked with ''@{0}''{1}", TO_STRING, renderUseExperimental);
|
||||
MAP.put(EXPERIMENTAL_API_USAGE_ERROR, "This declaration is experimental and its usage must be marked with ''@{0}''{1}", TO_STRING, renderUseExperimental);
|
||||
|
||||
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(USE_EXPERIMENTAL_ARGUMENT_HAS_NON_COMPILATION_IMPACT,
|
||||
"Experimental annotation ''{0}'' has impact other than COMPILATION, therefore its usage in @UseExperimental is forbidden", TO_STRING);
|
||||
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_NO_IMPACT, "Experimental annotation with changesMayBreak = [] is not allowed");
|
||||
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Experimental annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING);
|
||||
|
||||
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
|
||||
MAP.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members");
|
||||
MAP.put(REDUNDANT_MODIFIER_IN_GETTER, "Visibility modifiers are redundant in getter");
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
@@ -193,6 +194,8 @@ class AnnotationChecker(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TARGET_ALLOWED_TARGETS = Name.identifier("allowedTargets")
|
||||
|
||||
private fun applicableTargetSet(entry: KtAnnotationEntry, trace: BindingTrace): Set<KotlinTarget> {
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET
|
||||
// For descriptor with error type, all targets are considered as possible
|
||||
@@ -207,10 +210,12 @@ class AnnotationChecker(
|
||||
}
|
||||
|
||||
fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
|
||||
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
|
||||
?: return null
|
||||
val valueArguments = targetEntryDescriptor.allValueArguments
|
||||
val valueArgument = valueArguments.entries.firstOrNull()?.value as? ArrayValue ?: return null
|
||||
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target) ?: return null
|
||||
return loadAnnotationTargets(targetEntryDescriptor)
|
||||
}
|
||||
|
||||
fun loadAnnotationTargets(targetEntryDescriptor: AnnotationDescriptor): Set<KotlinTarget>? {
|
||||
val valueArgument = targetEntryDescriptor.allValueArguments[TARGET_ALLOWED_TARGETS] as? ArrayValue ?: return null
|
||||
return valueArgument.value.filterIsInstance<EnumValue>().mapNotNull {
|
||||
KotlinTarget.valueOrNull(it.enumEntryName.asString())
|
||||
}.toSet()
|
||||
|
||||
@@ -98,7 +98,9 @@ private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage,
|
||||
ExperimentalUsageChecker.ClassifierUsage
|
||||
)
|
||||
private val DEFAULT_ANNOTATION_CHECKERS = emptyList<AdditionalAnnotationChecker>()
|
||||
private val DEFAULT_ANNOTATION_CHECKERS = listOf<AdditionalAnnotationChecker>(
|
||||
ExperimentalMarkerDeclarationAnnotationChecker
|
||||
)
|
||||
|
||||
|
||||
abstract class PlatformConfigurator(
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.resolve.AdditionalAnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
object ExperimentalMarkerDeclarationAnnotationChecker : AdditionalAnnotationChecker {
|
||||
private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE)
|
||||
|
||||
override fun checkEntries(entries: List<KtAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
|
||||
var isAnnotatedWithExperimental = false
|
||||
|
||||
for (entry in entries) {
|
||||
val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry)
|
||||
when (annotation?.fqName) {
|
||||
ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME -> {
|
||||
val annotationClasses =
|
||||
(annotation.allValueArguments[ExperimentalUsageChecker.USE_EXPERIMENTAL_ANNOTATION_CLASS] as? ArrayValue)?.value.orEmpty()
|
||||
checkUseExperimentalUsage(annotationClasses, trace, entry)
|
||||
}
|
||||
ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAME -> {
|
||||
val impact = (annotation.allValueArguments[ExperimentalUsageChecker.IMPACT] as? ArrayValue)?.value
|
||||
checkExperimentalUsage(impact, trace, entry)
|
||||
isAnnotatedWithExperimental = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAnnotatedWithExperimental) {
|
||||
checkMarkerTargets(entries, trace)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUseExperimentalUsage(annotationClasses: List<ConstantValue<*>>, trace: BindingTrace, entry: KtAnnotationEntry) {
|
||||
if (annotationClasses.isEmpty()) {
|
||||
trace.report(Errors.USE_EXPERIMENTAL_WITHOUT_ARGUMENTS.on(entry))
|
||||
return
|
||||
}
|
||||
|
||||
for (annotationClass in annotationClasses) {
|
||||
val classDescriptor =
|
||||
(annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
?: continue
|
||||
val experimentality = with(ExperimentalUsageChecker) {
|
||||
classDescriptor.loadExperimentalityForMarkerAnnotation()
|
||||
}
|
||||
if (experimentality == null) {
|
||||
trace.report(Errors.USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER.on(entry, classDescriptor.fqNameSafe))
|
||||
} else if (!experimentality.isCompilationOnly) {
|
||||
trace.report(Errors.USE_EXPERIMENTAL_ARGUMENT_HAS_NON_COMPILATION_IMPACT.on(entry, experimentality.annotationFqName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkExperimentalUsage(impact: List<ConstantValue<*>>?, trace: BindingTrace, entry: KtAnnotationEntry) {
|
||||
if (impact != null && impact.isEmpty()) {
|
||||
trace.report(Errors.EXPERIMENTAL_ANNOTATION_WITH_NO_IMPACT.on(entry))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMarkerTargets(entries: List<KtAnnotationEntry>, trace: BindingTrace) {
|
||||
val targetEntry =
|
||||
entries.associate { entry -> entry to trace.bindingContext.get(BindingContext.ANNOTATION, entry) }
|
||||
.entries
|
||||
.firstOrNull { (_, descriptor) -> descriptor != null && descriptor.fqName == KotlinBuiltIns.FQ_NAMES.target }
|
||||
?: return
|
||||
val (entry, descriptor) = targetEntry
|
||||
val allowedTargets = AnnotationChecker.loadAnnotationTargets(descriptor!!) ?: return
|
||||
val wrongTargets = allowedTargets.intersect(WRONG_TARGETS_FOR_MARKER)
|
||||
if (wrongTargets.isNotEmpty()) {
|
||||
trace.report(
|
||||
Errors.EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET.on(entry, wrongTargets.joinToString(transform = KotlinTarget::description))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -41,20 +41,20 @@ import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
object ExperimentalUsageChecker : CallChecker {
|
||||
private val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
||||
private val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
||||
private val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||
internal val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
||||
internal val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
||||
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||
|
||||
private val LEVEL = Name.identifier("level")
|
||||
private val WARNING_LEVEL = Name.identifier("WARNING")
|
||||
private val ERROR_LEVEL = Name.identifier("ERROR")
|
||||
|
||||
private val IMPACT = Name.identifier("changesMayBreak")
|
||||
internal val IMPACT = Name.identifier("changesMayBreak")
|
||||
private val COMPILATION_IMPACT = Name.identifier("COMPILATION")
|
||||
private val LINKAGE_IMPACT = Name.identifier("LINKAGE")
|
||||
private val RUNTIME_IMPACT = Name.identifier("RUNTIME")
|
||||
|
||||
private data class Experimentality(val annotationFqName: FqName, val severity: Severity, val impact: List<Impact>) {
|
||||
internal data class Experimentality(val annotationFqName: FqName, val severity: Severity, private val impact: List<Impact>) {
|
||||
val isCompilationOnly: Boolean get() = impact.all(Impact.COMPILATION::equals)
|
||||
|
||||
enum class Severity { WARNING, ERROR }
|
||||
@@ -72,7 +72,7 @@ object ExperimentalUsageChecker : CallChecker {
|
||||
|
||||
private fun checkExperimental(descriptor: DeclarationDescriptor, element: PsiElement, trace: BindingTrace) {
|
||||
for (experimentality in descriptor.loadExperimentalities()) {
|
||||
val (annotationFqName, severity, impact) = experimentality
|
||||
val (annotationFqName, severity) = experimentality
|
||||
val isBodyUsageOfCompilationExperimentality =
|
||||
experimentality.isCompilationOnly && element.isBodyUsage()
|
||||
|
||||
@@ -95,22 +95,21 @@ object ExperimentalUsageChecker : CallChecker {
|
||||
val result = SmartSet.create<Experimentality>()
|
||||
|
||||
for (annotation in annotations) {
|
||||
result.addIfNotNull(annotation.loadExperimentalityForMarkerAnnotation())
|
||||
result.addIfNotNull(annotation.annotationClass?.loadExperimentalityForMarkerAnnotation())
|
||||
}
|
||||
|
||||
val container = containingDeclaration
|
||||
if (container is ClassDescriptor && this !is ConstructorDescriptor) {
|
||||
for (annotation in container.annotations) {
|
||||
result.addIfNotNull(annotation.loadExperimentalityForMarkerAnnotation())
|
||||
result.addIfNotNull(annotation.annotationClass?.loadExperimentalityForMarkerAnnotation())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun AnnotationDescriptor.loadExperimentalityForMarkerAnnotation(): Experimentality? {
|
||||
val experimental = annotationClass?.annotations?.findAnnotation(EXPERIMENTAL_FQ_NAME) ?: return null
|
||||
val annotationFqName = fqName ?: return null
|
||||
internal fun ClassDescriptor.loadExperimentalityForMarkerAnnotation(): Experimentality? {
|
||||
val experimental = annotations.findAnnotation(EXPERIMENTAL_FQ_NAME) ?: return null
|
||||
|
||||
val severity = when ((experimental.allValueArguments[LEVEL] as? EnumValue)?.enumEntryName) {
|
||||
WARNING_LEVEL -> Experimentality.Severity.WARNING
|
||||
@@ -126,7 +125,7 @@ object ExperimentalUsageChecker : CallChecker {
|
||||
}
|
||||
} ?: Experimentality.DEFAULT_IMPACT
|
||||
|
||||
return Experimentality(annotationFqName, severity, impact)
|
||||
return Experimentality(fqNameSafe, severity, impact)
|
||||
}
|
||||
|
||||
// Returns true if this element appears in the body of some function and is not visible in any non-local declaration signature.
|
||||
@@ -189,4 +188,5 @@ object ExperimentalUsageChecker : CallChecker {
|
||||
checkExperimental(targetDescriptor, element, context.trace)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package api
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION])
|
||||
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS,
|
||||
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
|
||||
AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class ExperimentalAPI
|
||||
|
||||
@ExperimentalAPI
|
||||
|
||||
@@ -9,7 +9,7 @@ package api {
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION}) public final annotation class ExperimentalAPI : kotlin.Annotation {
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, AnnotationTarget.VALUE_PARAMETER}) public final annotation class ExperimentalAPI : kotlin.Annotation {
|
||||
public constructor ExperimentalAPI()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// !API_VERSION: 1.3
|
||||
|
||||
<!EXPERIMENTAL_ANNOTATION_WITH_NO_IMPACT!>@Experimental(Experimental.Level.WARNING, [])<!>
|
||||
annotation class ExperimentalAPI
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {}, level = Level.WARNING) public final annotation class ExperimentalAPI : kotlin.Annotation {
|
||||
public constructor ExperimentalAPI()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// !API_VERSION: 1.3
|
||||
// FILE: api.kt
|
||||
|
||||
package api
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME])
|
||||
@Target(CLASS, ANNOTATION_CLASS, TYPE_PARAMETER, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION,
|
||||
PROPERTY_GETTER, PROPERTY_SETTER, TYPE, TYPEALIAS)
|
||||
annotation class E1
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME])
|
||||
<!EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET!>@Target(FILE)<!>
|
||||
annotation class E2
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME])
|
||||
<!EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET!>@Target(EXPRESSION)<!>
|
||||
annotation class E3
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME])
|
||||
<!EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET!>@Target(FILE, EXPRESSION)<!>
|
||||
annotation class E4
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package
|
||||
|
||||
package api {
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.RUNTIME}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPE, AnnotationTarget.TYPEALIAS}) public final annotation class E1 : kotlin.Annotation {
|
||||
public constructor E1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.RUNTIME}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FILE}) public final annotation class E2 : kotlin.Annotation {
|
||||
public constructor E2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.RUNTIME}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.EXPRESSION}) public final annotation class E3 : kotlin.Annotation {
|
||||
public constructor E3()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.RUNTIME}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FILE, AnnotationTarget.EXPRESSION}) public final annotation class E4 : kotlin.Annotation {
|
||||
public constructor E4()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// !API_VERSION: 1.3
|
||||
// FILE: api.kt
|
||||
|
||||
package api
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME])
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
annotation class BinaryExperimental
|
||||
|
||||
@BinaryExperimental
|
||||
val x = ""
|
||||
|
||||
// FILE: usage.kt
|
||||
|
||||
import api.*
|
||||
|
||||
<!USE_EXPERIMENTAL_WITHOUT_ARGUMENTS!>@UseExperimental<!>
|
||||
fun use1(): String {
|
||||
return <!EXPERIMENTAL_API_USAGE!>x<!>
|
||||
}
|
||||
|
||||
<!USE_EXPERIMENTAL_ARGUMENT_HAS_NON_COMPILATION_IMPACT!>@UseExperimental(BinaryExperimental::class)<!>
|
||||
fun use2(): String {
|
||||
return <!EXPERIMENTAL_API_USAGE!>x<!>
|
||||
}
|
||||
|
||||
<!USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER!>@UseExperimental(UseExperimental::class)<!>
|
||||
fun use3(): String {
|
||||
return <!EXPERIMENTAL_API_USAGE!>x<!>
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
@kotlin.UseExperimental(annotationClass = {}) public fun use1(): kotlin.String
|
||||
@kotlin.UseExperimental(annotationClass = {api.BinaryExperimental::class}) public fun use2(): kotlin.String
|
||||
@kotlin.UseExperimental(annotationClass = {kotlin.UseExperimental::class}) public fun use3(): kotlin.String
|
||||
|
||||
package api {
|
||||
@api.BinaryExperimental public val x: kotlin.String = ""
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.RUNTIME}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY}) public final annotation class BinaryExperimental : kotlin.Annotation {
|
||||
public constructor BinaryExperimental()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ package api
|
||||
|
||||
@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION])
|
||||
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS,
|
||||
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
|
||||
AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class ExperimentalAPI
|
||||
|
||||
@ExperimentalAPI
|
||||
|
||||
@@ -4,7 +4,7 @@ package api {
|
||||
@api.ExperimentalAPI public val property: kotlin.String = ""
|
||||
@api.ExperimentalAPI public fun function(): kotlin.String
|
||||
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION}) public final annotation class ExperimentalAPI : kotlin.Annotation {
|
||||
@kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, AnnotationTarget.VALUE_PARAMETER}) public final annotation class ExperimentalAPI : kotlin.Annotation {
|
||||
public constructor ExperimentalAPI()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
|
||||
+18
@@ -1833,6 +1833,24 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("experimentalWithNoImpact.kt")
|
||||
public void testExperimentalWithNoImpact() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/experimentalWithNoImpact.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectTargetsForExperimentalAnnotation.kt")
|
||||
public void testIncorrectTargetsForExperimentalAnnotation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectUseExperimental.kt")
|
||||
public void testIncorrectUseExperimental() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectUseExperimental.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt");
|
||||
|
||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+18
@@ -1833,6 +1833,24 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("experimentalWithNoImpact.kt")
|
||||
public void testExperimentalWithNoImpact() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/experimentalWithNoImpact.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectTargetsForExperimentalAnnotation.kt")
|
||||
public void testIncorrectTargetsForExperimentalAnnotation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectTargetsForExperimentalAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectUseExperimental.kt")
|
||||
public void testIncorrectUseExperimental() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/incorrectUseExperimental.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt");
|
||||
|
||||
Reference in New Issue
Block a user