diff --git a/.idea/dictionaries/dzharkov.xml b/.idea/dictionaries/dzharkov.xml index 91938406f8b..6a38863e835 100644 --- a/.idea/dictionaries/dzharkov.xml +++ b/.idea/dictionaries/dzharkov.xml @@ -3,6 +3,8 @@ checkcast coroutine + experimentalities + experimentality insn liveness diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index fb2c7275087..89785af9329 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -226,6 +226,9 @@ public interface Errors { DiagnosticFactory1 ILLEGAL_KOTLIN_VERSION_STRING_VALUE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 NEWER_VERSION_IN_SINCE_KOTLIN = DiagnosticFactory1.create(WARNING); + DiagnosticFactory2 EXPERIMENTAL_API_USAGE = DiagnosticFactory2.create(WARNING); + DiagnosticFactory2 EXPERIMENTAL_API_USAGE_ERROR = DiagnosticFactory2.create(ERROR); + // Const DiagnosticFactory0 CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 CONST_VAL_WITH_GETTER = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 145c47a3ffc..c280a0ee44f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.config.LanguageVersion; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.Errors; +import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData; import org.jetbrains.kotlin.serialization.deserialization.descriptors.VersionRequirement; import org.jetbrains.kotlin.types.KotlinTypeKt; @@ -22,6 +23,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.AddToStdlibKt; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.ServiceLoader; @@ -138,6 +140,17 @@ public class DefaultErrorMessages { MAP.put(ILLEGAL_KOTLIN_VERSION_STRING_VALUE, "Invalid @{0} annotation value (should be ''major.minor'' or ''major.minor.patch'')", TO_STRING); MAP.put(NEWER_VERSION_IN_SINCE_KOTLIN, "The version is greater than the specified API version {0}", STRING); + RenderingContext.Key getExperimentalFqName = new RenderingContext.Key("getExperimentalFqName") { + @Override + public FqName compute(@NotNull Collection objectsToRender) { + return (FqName) CollectionsKt.first(objectsToRender); + } + }; + DiagnosticParameterRenderer renderUseExperimental = (useExperimentalAllowed, c) -> + useExperimentalAllowed ? " or ''@UseExperimental(" + c.get(getExperimentalFqName) + "::class)''" : ""; + 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(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"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt index c946cc5625f..ff7304fa24d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt @@ -29,17 +29,12 @@ sealed class RenderingContext { class Impl(private val objectsToRender: Collection) : RenderingContext() { private val data = linkedMapOf, Any?>() + @Suppress("UNCHECKED_CAST") override fun get(key: Key): T { - if (!data.containsKey(key)) { - val result = key.compute(objectsToRender) - data[key] = result - return result - } - return data[key] as T + return data[key] as? T ?: key.compute(objectsToRender).also { data[key] = it } } } - object Empty : RenderingContext() { override fun get(key: Key): T { return key.compute(emptyList()) @@ -65,4 +60,4 @@ sealed class RenderingContext { return Impl(parameters) } } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 17f15357021..e1e6c409aef 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -91,12 +91,14 @@ private val DEFAULT_CALL_CHECKERS = listOf( CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker, CallableReferenceCompatibilityChecker(), LateinitIntrinsicApplicabilityChecker, UnderscoreUsageChecker, AssigningNamedArgumentToVarargChecker(), - PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker + PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker, ExperimentalUsageChecker ) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf( - DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage + DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage, + ExperimentalUsageChecker.ClassifierUsage ) +private val DEFAULT_ANNOTATION_CHECKERS = emptyList() abstract class PlatformConfigurator( @@ -105,7 +107,7 @@ abstract class PlatformConfigurator( additionalCallCheckers: List, additionalTypeCheckers: List, additionalClassifierUsageCheckers: List, - private val additionalAnnotationCheckers: List, + additionalAnnotationCheckers: List, private val identifierChecker: IdentifierChecker, private val overloadFilter: OverloadFilter, private val platformToKotlinClassMap: PlatformToKotlinClassMap, @@ -118,6 +120,7 @@ abstract class PlatformConfigurator( private val typeCheckers: List = DEFAULT_TYPE_CHECKERS + additionalTypeCheckers private val classifierUsageCheckers: List = DEFAULT_CLASSIFIER_USAGE_CHECKERS + additionalClassifierUsageCheckers + private val annotationCheckers: List = DEFAULT_ANNOTATION_CHECKERS + additionalAnnotationCheckers abstract fun configureModuleComponents(container: StorageComponentContainer) @@ -127,7 +130,7 @@ abstract class PlatformConfigurator( callCheckers.forEach { useInstance(it) } typeCheckers.forEach { useInstance(it) } classifierUsageCheckers.forEach { useInstance(it) } - additionalAnnotationCheckers.forEach { useInstance(it) } + annotationCheckers.forEach { useInstance(it) } useInstance(identifierChecker) useInstance(overloadFilter) useInstance(platformToKotlinClassMap) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt new file mode 100644 index 00000000000..ae471a7fba9 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -0,0 +1,192 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.constants.ArrayValue +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.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") + + 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") + 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) { + val isCompilationOnly: Boolean get() = impact.all(Impact.COMPILATION::equals) + + enum class Severity { WARNING, ERROR } + enum class Impact { COMPILATION, LINKAGE_OR_RUNTIME } + + companion object { + val DEFAULT_SEVERITY = Severity.ERROR + val DEFAULT_IMPACT = listOf(Impact.COMPILATION, Impact.LINKAGE_OR_RUNTIME) + } + } + + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + checkExperimental(resolvedCall.resultingDescriptor, reportOn, context.trace) + } + + private fun checkExperimental(descriptor: DeclarationDescriptor, element: PsiElement, trace: BindingTrace) { + for (experimentality in descriptor.loadExperimentalities()) { + val (annotationFqName, severity, impact) = experimentality + val isBodyUsageOfCompilationExperimentality = + experimentality.isCompilationOnly && element.isBodyUsage() + + val isExperimentalityAccepted = + (isBodyUsageOfCompilationExperimentality && + element.hasContainerAnnotatedWithUseExperimental(annotationFqName, trace.bindingContext)) || + element.propagates(annotationFqName, trace.bindingContext) + + if (!isExperimentalityAccepted) { + val diagnostic = when (severity) { + ExperimentalUsageChecker.Experimentality.Severity.WARNING -> Errors.EXPERIMENTAL_API_USAGE + ExperimentalUsageChecker.Experimentality.Severity.ERROR -> Errors.EXPERIMENTAL_API_USAGE_ERROR + } + trace.report(diagnostic.on(element, annotationFqName, isBodyUsageOfCompilationExperimentality)) + } + } + } + + private fun DeclarationDescriptor.loadExperimentalities(): Set { + val result = SmartSet.create() + + for (annotation in annotations) { + result.addIfNotNull(annotation.loadExperimentalityForMarkerAnnotation()) + } + + val container = containingDeclaration + if (container is ClassDescriptor && this !is ConstructorDescriptor) { + for (annotation in container.annotations) { + result.addIfNotNull(annotation.loadExperimentalityForMarkerAnnotation()) + } + } + + return result + } + + private fun AnnotationDescriptor.loadExperimentalityForMarkerAnnotation(): Experimentality? { + val experimental = annotationClass?.annotations?.findAnnotation(EXPERIMENTAL_FQ_NAME) ?: return null + val annotationFqName = fqName ?: return null + + val severity = when ((experimental.allValueArguments[LEVEL] as? EnumValue)?.enumEntryName) { + WARNING_LEVEL -> Experimentality.Severity.WARNING + ERROR_LEVEL -> Experimentality.Severity.ERROR + else -> Experimentality.DEFAULT_SEVERITY + } + + val impact = (experimental.allValueArguments[IMPACT] as? ArrayValue)?.value?.mapNotNull { impact -> + when ((impact as? EnumValue)?.enumEntryName) { + COMPILATION_IMPACT -> Experimentality.Impact.COMPILATION + LINKAGE_IMPACT, RUNTIME_IMPACT -> Experimentality.Impact.LINKAGE_OR_RUNTIME + else -> null + } + } ?: Experimentality.DEFAULT_IMPACT + + return Experimentality(annotationFqName, severity, impact) + } + + // Returns true if this element appears in the body of some function and is not visible in any non-local declaration signature. + // If that's the case, one can opt-in to using the corresponding experimental API by annotating this element (or any of its + // enclosing declarations) with @UseExperimental(X::class), not requiring propagation of the experimental annotation to the call sites. + // (Note that this is allowed only if X's impact is [COMPILATION].) + private fun PsiElement.isBodyUsage(): Boolean { + return anyParentMatches { element, parent -> + element == (parent as? KtDeclarationWithBody)?.bodyExpression || + element == (parent as? KtDeclarationWithInitializer)?.initializer || + element == (parent as? KtClassInitializer)?.body || + element == (parent as? KtParameter)?.defaultValue || + element == (parent as? KtSuperTypeCallEntry)?.valueArgumentList || + element == (parent as? KtDelegatedSuperTypeEntry)?.delegateExpression || + element == (parent as? KtPropertyDelegate)?.expression + } + } + + // Checks whether any of the non-local enclosing declarations is annotated with annotationFqName, effectively requiring + // propagation for the experimental annotation to the call sites + private fun PsiElement.propagates(annotationFqName: FqName, bindingContext: BindingContext): Boolean { + return anyParentMatches { element, _ -> + if (element is KtDeclaration) { + val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + descriptor != null && !DescriptorUtils.isLocal(descriptor) && descriptor.annotations.hasAnnotation(annotationFqName) + } else false + } + } + + // Checks whether there's an element lexically above the tree, that is annotated with `@UseExperimental(X::class)` + // where annotationFqName is the FQ name of X + private fun PsiElement.hasContainerAnnotatedWithUseExperimental(annotationFqName: FqName, bindingContext: BindingContext): Boolean { + return anyParentMatches { element, _ -> + element is KtAnnotated && element.annotationEntries.any { entry -> + bindingContext.get(BindingContext.ANNOTATION, entry)?.isUseExperimental(annotationFqName) == true + } + } + } + + private inline fun PsiElement.anyParentMatches(predicate: (element: PsiElement, parent: PsiElement?) -> Boolean): Boolean { + var element = this + while (true) { + val parent = element.parent + if (predicate(element, parent)) return true + element = parent ?: return false + } + } + + private fun AnnotationDescriptor.isUseExperimental(annotationFqName: FqName): Boolean { + if (fqName != USE_EXPERIMENTAL_FQ_NAME) return false + + val annotationClasses = allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS] + return annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass -> + (annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor?.fqNameSafe == annotationFqName + } + } + + object ClassifierUsage : ClassifierUsageChecker { + override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) { + checkExperimental(targetDescriptor, element, context.trace) + } + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.kt new file mode 100644 index 00000000000..2918dd74429 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.kt @@ -0,0 +1,136 @@ +// !API_VERSION: 1.3 +// !DIAGNOSTICS: -UNUSED_PARAMETER +// FILE: api.kt + +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) +annotation class ExperimentalAPI + +@ExperimentalAPI +@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, + AnnotationTarget.VALUE_PARAMETER) +annotation class EAnno + +// FILE: usage-propagate.kt + +package usage1 + +import api.* + +@ExperimentalAPI +@EAnno fun function() {} + +@ExperimentalAPI +fun parameter(@EAnno p: String) {} + +@ExperimentalAPI +fun parameterType(p: @EAnno String) {} + +@ExperimentalAPI +fun returnType(): @EAnno Unit {} + +@ExperimentalAPI +@EAnno val property = "" + +@ExperimentalAPI +@EAnno typealias Typealias = Unit + +@ExperimentalAPI +@EAnno class Klass + +@ExperimentalAPI +annotation class AnnotationArgument(val p: EAnno) + +@ExperimentalAPI +fun insideBody() { + @EAnno fun local() {} +} + +@ExperimentalAPI +fun inDefaultArgument(f: () -> Unit = @EAnno fun() {}) {} + +@ExperimentalAPI +val inProperty = @EAnno fun() {} + +@ExperimentalAPI +val inPropertyAccessor: () -> Unit + get() = @EAnno fun() {} + +// FILE: usage-use.kt + +package usage2 + +import api.* + +@UseExperimental(ExperimentalAPI::class) +@EAnno fun function() {} + +@UseExperimental(ExperimentalAPI::class) +fun parameter(@EAnno p: String) {} + +@UseExperimental(ExperimentalAPI::class) +fun parameterType(p: @EAnno String) {} + +@UseExperimental(ExperimentalAPI::class) +fun returnType(): @EAnno Unit {} + +@UseExperimental(ExperimentalAPI::class) +@EAnno val property = "" + +@UseExperimental(ExperimentalAPI::class) +@EAnno typealias Typealias = Unit + +@UseExperimental(ExperimentalAPI::class) +@EAnno class Klass + +@UseExperimental(ExperimentalAPI::class) +annotation class AnnotationArgument(val p: EAnno) + +fun insideBody() { + @UseExperimental(ExperimentalAPI::class) @EAnno fun local() {} +} + +fun inDefaultArgument(@UseExperimental(ExperimentalAPI::class) f: () -> Unit = @EAnno fun() {}) {} + +@UseExperimental(ExperimentalAPI::class) +val inProperty = @EAnno fun() {} + +val inPropertyAccessor: () -> Unit + @UseExperimental(ExperimentalAPI::class) + get() = @EAnno fun() {} + +// FILE: usage-none.kt + +package usage3 + +import api.* + +@EAnno fun function() {} + +fun parameter(@EAnno p: String) {} + +fun parameterType(p: @EAnno String) {} + +fun returnType(): @EAnno Unit {} + +@EAnno val property = "" + +@EAnno typealias Typealias = Unit + +@EAnno class Klass + +annotation class AnnotationArgument(val p: EAnno) + +fun insideBody() { + @EAnno fun local() {} +} + +fun inDefaultArgument(f: () -> Unit = @EAnno fun() {}) {} + +val inProperty = @EAnno fun() {} + +val inPropertyAccessor: () -> Unit + get() = @EAnno fun() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.txt new file mode 100644 index 00000000000..34f11bd2c47 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.txt @@ -0,0 +1,102 @@ +package + +package api { + + @api.ExperimentalAPI @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS, AnnotationTarget.VALUE_PARAMETER}) public final annotation class EAnno : kotlin.Annotation { + public constructor EAnno() + 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.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 { + 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 + } +} + +package usage1 { + @api.ExperimentalAPI public val inProperty: () -> kotlin.Unit + @api.ExperimentalAPI public val inPropertyAccessor: () -> kotlin.Unit + @api.ExperimentalAPI @api.EAnno public val property: kotlin.String = "" + @api.ExperimentalAPI @api.EAnno public fun function(): kotlin.Unit + @api.ExperimentalAPI public fun inDefaultArgument(/*0*/ f: () -> kotlin.Unit = ...): kotlin.Unit + @api.ExperimentalAPI public fun insideBody(): kotlin.Unit + @api.ExperimentalAPI public fun parameter(/*0*/ @api.EAnno p: kotlin.String): kotlin.Unit + @api.ExperimentalAPI public fun parameterType(/*0*/ p: @api.EAnno kotlin.String): kotlin.Unit + @api.ExperimentalAPI public fun returnType(): @api.EAnno kotlin.Unit + + @api.ExperimentalAPI public final annotation class AnnotationArgument : kotlin.Annotation { + public constructor AnnotationArgument(/*0*/ p: api.EAnno) + public final val p: api.EAnno + 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 + } + + @api.ExperimentalAPI @api.EAnno public final class Klass { + public constructor Klass() + 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 + } + @api.ExperimentalAPI @api.EAnno public typealias Typealias = kotlin.Unit +} + +package usage2 { + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public val inProperty: () -> kotlin.Unit + public val inPropertyAccessor: () -> kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) @api.EAnno public val property: kotlin.String = "" + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) @api.EAnno public fun function(): kotlin.Unit + public fun inDefaultArgument(/*0*/ @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) f: () -> kotlin.Unit = ...): kotlin.Unit + public fun insideBody(): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun parameter(/*0*/ @api.EAnno p: kotlin.String): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun parameterType(/*0*/ p: @api.EAnno kotlin.String): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun returnType(): @api.EAnno kotlin.Unit + + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public final annotation class AnnotationArgument : kotlin.Annotation { + public constructor AnnotationArgument(/*0*/ p: api.EAnno) + public final val p: api.EAnno + 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.UseExperimental(markerClass = {api.ExperimentalAPI::class}) @api.EAnno public final class Klass { + public constructor Klass() + 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.UseExperimental(markerClass = {api.ExperimentalAPI::class}) @api.EAnno public typealias Typealias = kotlin.Unit +} + +package usage3 { + public val inProperty: () -> kotlin.Unit + public val inPropertyAccessor: () -> kotlin.Unit + @api.EAnno public val property: kotlin.String = "" + @api.EAnno public fun function(): kotlin.Unit + public fun inDefaultArgument(/*0*/ f: () -> kotlin.Unit = ...): kotlin.Unit + public fun insideBody(): kotlin.Unit + public fun parameter(/*0*/ @api.EAnno p: kotlin.String): kotlin.Unit + public fun parameterType(/*0*/ p: @api.EAnno kotlin.String): kotlin.Unit + public fun returnType(): @api.EAnno kotlin.Unit + + public final annotation class AnnotationArgument : kotlin.Annotation { + public constructor AnnotationArgument(/*0*/ p: api.EAnno) + public final val p: api.EAnno + 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 + } + + @api.EAnno public final class Klass { + public constructor Klass() + 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 + } + @api.EAnno public typealias Typealias = kotlin.Unit +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.kt new file mode 100644 index 00000000000..f1a8a249a7e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.kt @@ -0,0 +1,30 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +annotation class ExperimentalCompilationAPI + +interface I + +@ExperimentalCompilationAPI +class Impl : I + +// FILE: usage.kt + +package usage + +import api.* + +open class Base(val i: I) + +@UseExperimental(ExperimentalCompilationAPI::class) +class Derived : Base(Impl()) + +@UseExperimental(ExperimentalCompilationAPI::class) +class Delegated : I by Impl() + +@UseExperimental(ExperimentalCompilationAPI::class) +val delegatedProperty by Impl() +operator fun I.getValue(x: Any?, y: Any?) = null diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.txt new file mode 100644 index 00000000000..1cd8553d863 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.txt @@ -0,0 +1,52 @@ +package + +package api { + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) public final annotation class ExperimentalCompilationAPI : kotlin.Annotation { + public constructor ExperimentalCompilationAPI() + 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 + } + + public interface I { + 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 + } + + @api.ExperimentalCompilationAPI public final class Impl : api.I { + public constructor Impl() + 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 + } +} + +package usage { + @kotlin.UseExperimental(markerClass = {api.ExperimentalCompilationAPI::class}) public val delegatedProperty: kotlin.Nothing? + public operator fun api.I.getValue(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Any?): kotlin.Nothing? + + public open class Base { + public constructor Base(/*0*/ i: api.I) + public final val i: api.I + 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.UseExperimental(markerClass = {api.ExperimentalCompilationAPI::class}) public final class Delegated : api.I { + public constructor Delegated() + 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.UseExperimental(markerClass = {api.ExperimentalCompilationAPI::class}) public final class Derived : usage.Base { + public constructor Derived() + public final override /*1*/ /*fake_override*/ val i: api.I + 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 + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.kt new file mode 100644 index 00000000000..528f8f00a10 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.kt @@ -0,0 +1,88 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +annotation class ExperimentalAPI + +@ExperimentalAPI +class C { + fun function(): String = "" + val property: String = "" + class Nested + inner class Inner +} + +@ExperimentalAPI +fun C.extension() {} + +// FILE: usage-propagate.kt + +package usage1 + +import api.* + +@ExperimentalAPI +fun useAll() { + val c: C = C() + c.function() + c.property + C.Nested() + c.Inner() + c.extension() +} + +@ExperimentalAPI +class Use { + fun useAll(c: C) { + c.function() + c.property + C.Nested() + c.Inner() + c.extension() + } +} + +// FILE: usage-use.kt + +package usage2 + +import api.* + +@UseExperimental(ExperimentalAPI::class) +fun useAll() { + val c: C = C() + c.function() + c.property + C.Nested() + c.Inner() + c.extension() +} + +@UseExperimental(ExperimentalAPI::class) +class Use { + fun useAll(c: C) { + c.function() + c.property + C.Nested() + c.Inner() + c.extension() + } +} + +// FILE: usage-none.kt + +package usage3 + +import api.* + +fun use() { + val c: C = C() + c.function() + c.property + C.Nested() + c.Inner() + c.extension() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.txt new file mode 100644 index 00000000000..8b754e9dd7c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.txt @@ -0,0 +1,63 @@ +package + +package api { + @api.ExperimentalAPI public fun api.C.extension(): kotlin.Unit + + @api.ExperimentalAPI public final class C { + public constructor C() + public final val property: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun function(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final inner class Inner { + public constructor Inner() + 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 + } + + public final class Nested { + public constructor Nested() + 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.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION}) 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 + } +} + +package usage1 { + @api.ExperimentalAPI public fun useAll(): kotlin.Unit + + @api.ExperimentalAPI public final class Use { + public constructor Use() + 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 + public final fun useAll(/*0*/ c: api.C): kotlin.Unit + } +} + +package usage2 { + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun useAll(): kotlin.Unit + + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public final class Use { + public constructor Use() + 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 + public final fun useAll(/*0*/ c: api.C): kotlin.Unit + } +} + +package usage3 { + public fun use(): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.kt new file mode 100644 index 00000000000..3e82f7c156d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.kt @@ -0,0 +1,36 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) +annotation class ExperimentalAPI + +@ExperimentalAPI +class C { + @ExperimentalAPI + fun function() {} + + @ExperimentalAPI + val property: String = "" + + @ExperimentalAPI + class Nested { + @ExperimentalAPI + fun nestedFunction() {} + } +} + +// FILE: usage.kt + +package usage + +import api.* + +fun use() { + val c: C = C() + c.function() + c.property + C.Nested().nestedFunction() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.txt new file mode 100644 index 00000000000..f8f3b3cc81f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.txt @@ -0,0 +1,32 @@ +package + +package api { + + @api.ExperimentalAPI public final class C { + public constructor C() + @api.ExperimentalAPI public final val property: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @api.ExperimentalAPI public final fun function(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + @api.ExperimentalAPI public final class Nested { + public constructor Nested() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + @api.ExperimentalAPI public final fun nestedFunction(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY}) 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 + } +} + +package usage { + public fun use(): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.kt new file mode 100644 index 00000000000..0a96a42bb52 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.kt @@ -0,0 +1,73 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +annotation class ExperimentalCompilationAPI + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.LINKAGE]) +annotation class ExperimentalLinkageAPI + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME]) +annotation class ExperimentalRuntimeAPI + +@ExperimentalCompilationAPI +fun compilation() {} + +@ExperimentalLinkageAPI +fun linkage() {} + +@ExperimentalRuntimeAPI +fun runtime() {} + +// FILE: usage.kt + +package usage1 + +import api.* + +@UseExperimental(ExperimentalCompilationAPI::class) +@ExperimentalLinkageAPI +@ExperimentalRuntimeAPI +fun use() { + compilation() + linkage() + runtime() +} + +@ExperimentalLinkageAPI +@ExperimentalRuntimeAPI +fun useUse() { + use() +} + +@ExperimentalCompilationAPI +@ExperimentalLinkageAPI +@ExperimentalRuntimeAPI +fun recursiveUse() { + compilation() + linkage() + runtime() + recursiveUse() +} + +// FILE: usage-no-annotation.txt + +package usage2 + +import api.* + +fun use1() { + usage1.use() +} + +@ExperimentalLinkageAPI +fun use2() { + usage1.use() +} + +@ExperimentalRuntimeAPI +fun use3() { + usage1.use() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.txt new file mode 100644 index 00000000000..ead6bb7ff73 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.txt @@ -0,0 +1,40 @@ +package + +package api { + @api.ExperimentalCompilationAPI public fun compilation(): kotlin.Unit + @api.ExperimentalLinkageAPI public fun linkage(): kotlin.Unit + @api.ExperimentalRuntimeAPI public fun runtime(): kotlin.Unit + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) public final annotation class ExperimentalCompilationAPI : kotlin.Annotation { + public constructor ExperimentalCompilationAPI() + 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.LINKAGE}, level = Level.WARNING) public final annotation class ExperimentalLinkageAPI : kotlin.Annotation { + public constructor ExperimentalLinkageAPI() + 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) public final annotation class ExperimentalRuntimeAPI : kotlin.Annotation { + public constructor ExperimentalRuntimeAPI() + 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 + } +} + +package usage1 { + @api.ExperimentalCompilationAPI @api.ExperimentalLinkageAPI @api.ExperimentalRuntimeAPI public fun recursiveUse(): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalCompilationAPI::class}) @api.ExperimentalLinkageAPI @api.ExperimentalRuntimeAPI public fun use(): kotlin.Unit + @api.ExperimentalLinkageAPI @api.ExperimentalRuntimeAPI public fun useUse(): kotlin.Unit +} + +package usage2 { + public fun use1(): kotlin.Unit + @api.ExperimentalLinkageAPI public fun use2(): kotlin.Unit + @api.ExperimentalRuntimeAPI public fun use3(): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt new file mode 100644 index 00000000000..8568cca1bae --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt @@ -0,0 +1,78 @@ +// !API_VERSION: 1.3 +// !DIAGNOSTICS: -UNUSED_VARIABLE +// FILE: api.kt + +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) +annotation class ExperimentalAPI + +@ExperimentalAPI +fun function(): String = "" + +@ExperimentalAPI +val property: String = "" + +@ExperimentalAPI +typealias Typealias = String + +// FILE: usage-propagate.kt + +package usage1 + +import api.* + +@ExperimentalAPI +fun useAll() { + function() + property + val s: Typealias = "" +} + +@ExperimentalAPI +class Use { + fun useAll() { + function() + property + val s: Typealias = "" + } +} + +// FILE: usage-use.kt + +package usage2 + +import api.* + +fun useAll() { + @UseExperimental(ExperimentalAPI::class) + { + function() + property + val s: Typealias = "" + }() +} + +@UseExperimental(ExperimentalAPI::class) +class Use { + fun useAll() { + function() + property + val s: Typealias = "" + } +} + +// FILE: usage-none.kt + +package usage3 + +import api.* + +fun use() { + function() + property + val s: Typealias = "" + s.hashCode() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.txt new file mode 100644 index 00000000000..671c5cf634f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.txt @@ -0,0 +1,42 @@ +package + +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 { + 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 + } + @api.ExperimentalAPI public typealias Typealias = kotlin.String +} + +package usage1 { + @api.ExperimentalAPI public fun useAll(): kotlin.Unit + + @api.ExperimentalAPI public final class Use { + public constructor Use() + 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 + public final fun useAll(): kotlin.Unit + } +} + +package usage2 { + public fun useAll(): kotlin.Unit + + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public final class Use { + public constructor Use() + 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 + public final fun useAll(): kotlin.Unit + } +} + +package usage3 { + public fun use(): kotlin.Unit +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.kt new file mode 100644 index 00000000000..a0ad16616da --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.kt @@ -0,0 +1,13 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental +@Target(AnnotationTarget.CLASS) +annotation class ExperimentalAPI + +@ExperimentalAPI +class Foo + +typealias Bar = Foo diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.txt new file mode 100644 index 00000000000..770d6360eab --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.txt @@ -0,0 +1,19 @@ +package + +package api { + + @kotlin.Experimental @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS}) 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 + } + + @api.ExperimentalAPI public final class Foo { + public constructor Foo() + 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 + } + public typealias Bar = api.Foo +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.kt new file mode 100644 index 00000000000..ba1b643b3db --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.kt @@ -0,0 +1,37 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.FUNCTION) +annotation class CompilationExperimentalAPI + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.RUNTIME]) +@Target(AnnotationTarget.FUNCTION) +annotation class RuntimeExperimentalAPI + +@CompilationExperimentalAPI +fun compilation() {} + +@RuntimeExperimentalAPI +fun runtime() {} + +// FILE: usage.kt + +@file:UseExperimental(CompilationExperimentalAPI::class) +package usage + +import api.* + +fun use() { + compilation() + runtime() +} + +class Use { + fun use() { + compilation() + runtime() + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.txt new file mode 100644 index 00000000000..f19ec327ceb --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.txt @@ -0,0 +1,32 @@ +package + +package api { + @api.CompilationExperimentalAPI public fun compilation(): kotlin.Unit + @api.RuntimeExperimentalAPI public fun runtime(): kotlin.Unit + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION}) public final annotation class CompilationExperimentalAPI : kotlin.Annotation { + public constructor CompilationExperimentalAPI() + 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.FUNCTION}) public final annotation class RuntimeExperimentalAPI : kotlin.Annotation { + public constructor RuntimeExperimentalAPI() + 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 + } +} + +package usage { + public fun use(): kotlin.Unit + + public final class Use { + public constructor Use() + 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 + public final fun use(): kotlin.Unit + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.kt new file mode 100644 index 00000000000..397945a4f15 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.kt @@ -0,0 +1,54 @@ +// !API_VERSION: 1.3 +// !DIAGNOSTICS: -UNUSED_PARAMETER +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.CLASS) +annotation class E + +@E +open class Foo(val s: String = "") + +// FILE: usage.kt + +import api.* + +@UseExperimental(E::class) +class Klass { + init { + Foo() + } +} + +class Constructor { + @UseExperimental(E::class) constructor() { + Foo() + } +} + +@UseExperimental(E::class) +val property = Foo().s + +@UseExperimental(E::class) +fun function() { + Foo() +} + +fun valueParameter(@UseExperimental(E::class) p: String = Foo().s): String { + @UseExperimental(E::class) + val localVariable: String = Foo().s + return localVariable +} + +var propertyAccessors: String + @UseExperimental(E::class) + get() = Foo().s + @UseExperimental(E::class) + set(value) { Foo() } + +fun expression(): String { + val s = @UseExperimental(E::class) Foo().s + return s +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.txt new file mode 100644 index 00000000000..dc75ed386f2 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.txt @@ -0,0 +1,39 @@ +package + +@kotlin.UseExperimental(markerClass = {api.E::class}) public val property: kotlin.String +public var propertyAccessors: kotlin.String +public fun expression(): kotlin.String +@kotlin.UseExperimental(markerClass = {api.E::class}) public fun function(): kotlin.Unit +public fun valueParameter(/*0*/ @kotlin.UseExperimental(markerClass = {api.E::class}) p: kotlin.String = ...): kotlin.String + +public final class Constructor { + @kotlin.UseExperimental(markerClass = {api.E::class}) public constructor Constructor() + 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.UseExperimental(markerClass = {api.E::class}) public final class Klass { + public constructor Klass() + 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 +} + +package api { + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS}) public final annotation class E : kotlin.Annotation { + public constructor E() + 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 + } + + @api.E public open class Foo { + public constructor Foo(/*0*/ s: kotlin.String = ...) + public final val s: kotlin.String + 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 + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt new file mode 100644 index 00000000000..0d56ce82407 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt @@ -0,0 +1,52 @@ +// !API_VERSION: 1.3 +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.FUNCTION) +annotation class E1 + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.FUNCTION) +annotation class E2 + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.FUNCTION) +annotation class E3 + +@E1 +fun e1() {} + +@E2 +fun e2() {} + +@E3 +fun e3() {} + +// FILE: usage.kt + +package usage + +import api.* + +@UseExperimental(E1::class, E2::class, E3::class) +fun use1() { + e1() + e2() + e3() +} + +@UseExperimental(E1::class, E3::class) +fun use2() { + e1() + @UseExperimental(E2::class) e2() + e3() +} + +@UseExperimental(E1::class, E2::class) +fun use3() { + e1() + e2() + e3() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.txt new file mode 100644 index 00000000000..a2be94a9946 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.txt @@ -0,0 +1,34 @@ +package + +package api { + @api.E1 public fun e1(): kotlin.Unit + @api.E2 public fun e2(): kotlin.Unit + @api.E3 public fun e3(): kotlin.Unit + + @kotlin.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION}) 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.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION}) 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.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION}) 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 + } +} + +package usage { + @kotlin.UseExperimental(markerClass = {api.E1::class, api.E2::class, api.E3::class}) public fun use1(): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.E1::class, api.E3::class}) public fun use2(): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.E1::class, api.E2::class}) public fun use3(): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index de27fce9e47..741a1571c16 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1795,6 +1795,75 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Experimental extends AbstractDiagnosticsTestWithStdLib { + public void testAllFilesPresentInExperimental() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/experimental"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.kt"); + doTest(fileName); + } + + @TestMetadata("bodyUsages.kt") + public void testBodyUsages() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.kt"); + doTest(fileName); + } + + @TestMetadata("classMembers.kt") + public void testClassMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.kt"); + doTest(fileName); + } + + @TestMetadata("classMembersOverlyExperimental.kt") + public void testClassMembersOverlyExperimental() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.kt"); + doTest(fileName); + } + + @TestMetadata("compilationVsLinkageVsRuntime.kt") + public void testCompilationVsLinkageVsRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt"); + doTest(fileName); + } + + @TestMetadata("typealias.kt") + public void testTypealias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalOnFile.kt") + public void testUseExperimentalOnFile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalTargets.kt") + public void testUseExperimentalTargets() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalWithSeveralAnnotations.kt") + public void testUseExperimentalWithSeveralAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index e65650545c5..9c18a301e18 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1795,6 +1795,75 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno } } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Experimental extends AbstractDiagnosticsTestWithStdLibUsingJavac { + public void testAllFilesPresentInExperimental() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/experimental"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/annotation.kt"); + doTest(fileName); + } + + @TestMetadata("bodyUsages.kt") + public void testBodyUsages() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/bodyUsages.kt"); + doTest(fileName); + } + + @TestMetadata("classMembers.kt") + public void testClassMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/classMembers.kt"); + doTest(fileName); + } + + @TestMetadata("classMembersOverlyExperimental.kt") + public void testClassMembersOverlyExperimental() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/classMembersOverlyExperimental.kt"); + doTest(fileName); + } + + @TestMetadata("compilationVsLinkageVsRuntime.kt") + public void testCompilationVsLinkageVsRuntime() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/compilationVsLinkageVsRuntime.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/topLevel.kt"); + doTest(fileName); + } + + @TestMetadata("typealias.kt") + public void testTypealias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/typealias.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalOnFile.kt") + public void testUseExperimentalOnFile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalOnFile.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalTargets.kt") + public void testUseExperimentalTargets() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalTargets.kt"); + doTest(fileName); + } + + @TestMetadata("useExperimentalWithSeveralAnnotations.kt") + public void testUseExperimentalWithSeveralAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/libraries/stdlib/src/kotlin/annotations/Experimental.kt b/libraries/stdlib/src/kotlin/annotations/Experimental.kt new file mode 100644 index 00000000000..70a01dc9c84 --- /dev/null +++ b/libraries/stdlib/src/kotlin/annotations/Experimental.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin + +import kotlin.annotation.AnnotationRetention.BINARY +import kotlin.annotation.AnnotationRetention.SOURCE +import kotlin.annotation.AnnotationTarget.* +import kotlin.reflect.KClass + +/** + * Signals that the annotated annotation class is a marker of an experimental API. Any declaration annotated with that marker is thus + * considered an experimental declaration and its call sites must accept the experimental aspect of it either by using [UseExperimental], + * or by being annotated with that marker themselves, effectively causing further propagation of that experimental aspect. + */ +@Target(ANNOTATION_CLASS) +@Retention(BINARY) +@SinceKotlin("1.3") +@Suppress("ANNOTATION_CLASS_WITH_BODY", "ANNOTATION_CLASS_MEMBER", "ReplaceArrayOfWithLiteral") +annotation class Experimental( + val level: Level = Level.ERROR, + val changesMayBreak: Array = arrayOf(Impact.COMPILATION, Impact.LINKAGE, Impact.RUNTIME) // arrayOf, not [] because of KT-22578 +) { + /** + * Severity of the diagnostic that should be reported on usages of experimental API which did not explicitly accept the experimental aspect + * of that API either by using [UseExperimental] or by being annotated with the corresponding marker annotation. + */ + enum class Level { + /** Specifies that a warning should be reported on incorrect usages of this experimental API. */ + WARNING, + /** Specifies that an error should be reported on incorrect usages of this experimental API. */ + ERROR, + } + + /** + * Impact of the experimental API specifies what aspects may break after that API is changed. + */ + enum class Impact { + /** + * Signifies that changes in this experimental API can cause compilation errors or warnings in the client code. + * + * Non-signature usages (inside a function body, variable initializer, default argument value, etc.) of compilation-affecting + * experimental API are allowed either if the containing declaration is annotated with the experimental annotation marker + * and thus propagates the experimental aspect to its clients, or if there's a [UseExperimental] annotation entry with + * the corresponding annotation marker somewhere above that usage in the parse tree. Signature usages of compilation-affecting + * experimental API always require propagation (as long as the experimental API is declared in another module). + */ + COMPILATION, + /** + * Signifies that changes in this experimental API can cause linkage errors, i.e. exceptions at runtime + * if the client code was not recompiled after the change. + * + * Any usage of a linkage-affecting experimental API requires its containing declaration to be annotated with + * the corresponding annotation marker (except non-signature usages in annotation marker's module). + */ + LINKAGE, + /** + * Signifies that changes in this experimental API can cause changes in runtime behavior, including exceptions at runtime. + * + * Any usage of a runtime-affecting experimental API requires its containing declaration to be annotated with + * the corresponding annotation marker (except non-signature usages in the annotation marker's module). + */ + RUNTIME, + } +} + +/** + * Allows to use experimental API denoted by the given markers in the annotated file, declaration, or expression. Each of the given markers + * must be an annotation class, whose impact ([Experimental.changesMayBreak]) is [Experimental.Impact.COMPILATION]. + * Any other given annotation classes have no effect and are ignored. + * + * Only allows non-signature usages of the experimental API, i.e. inside a function body, variable initializer, default argument value, etc. + * (Usages in declaration signatures must be propagated by annotating the affected signature with the marker annotation itself.) + */ +@Target(CLASS, PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, EXPRESSION, FILE) +@Retention(SOURCE) +@SinceKotlin("1.3") +annotation class UseExperimental( + vararg val markerClass: KClass +) diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 6d153e2b4f5..a190731f1a2 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -20,6 +20,26 @@ public final class kotlin/ExceptionsKt { public static final fun getStackTrace (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement; } +public abstract interface annotation class kotlin/Experimental : java/lang/annotation/Annotation { + public abstract fun changesMayBreak ()[Lkotlin/Experimental$Impact; + public abstract fun level ()Lkotlin/Experimental$Level; +} + +public final class kotlin/Experimental$Impact : java/lang/Enum { + public static final field COMPILATION Lkotlin/Experimental$Impact; + public static final field LINKAGE Lkotlin/Experimental$Impact; + public static final field RUNTIME Lkotlin/Experimental$Impact; + public static fun valueOf (Ljava/lang/String;)Lkotlin/Experimental$Impact; + public static fun values ()[Lkotlin/Experimental$Impact; +} + +public final class kotlin/Experimental$Level : java/lang/Enum { + public static final field ERROR Lkotlin/Experimental$Level; + public static final field WARNING Lkotlin/Experimental$Level; + public static fun valueOf (Ljava/lang/String;)Lkotlin/Experimental$Level; + public static fun values ()[Lkotlin/Experimental$Level; +} + public abstract interface annotation class kotlin/ExtensionFunctionType : java/lang/annotation/Annotation { } @@ -159,6 +179,10 @@ public final class kotlin/Unit { public abstract interface annotation class kotlin/UnsafeVariance : java/lang/annotation/Annotation { } +public abstract interface annotation class kotlin/UseExperimental : java/lang/annotation/Annotation { + public abstract fun markerClass ()[Ljava/lang/Class; +} + public final class kotlin/_Assertions { public static final field INSTANCE Lkotlin/_Assertions; } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt index 445b7b58177..2ae9c56e4f5 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt @@ -3,6 +3,26 @@ public final class kotlin/ExceptionsKt { public static final fun getStackTrace (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement; } +public abstract interface annotation class kotlin/Experimental : java/lang/annotation/Annotation { + public abstract fun changesMayBreak ()[Lkotlin/Experimental$Impact; + public abstract fun level ()Lkotlin/Experimental$Level; +} + +public final class kotlin/Experimental$Impact : java/lang/Enum { + public static final field COMPILATION Lkotlin/Experimental$Impact; + public static final field LINKAGE Lkotlin/Experimental$Impact; + public static final field RUNTIME Lkotlin/Experimental$Impact; + public static fun valueOf (Ljava/lang/String;)Lkotlin/Experimental$Impact; + public static fun values ()[Lkotlin/Experimental$Impact; +} + +public final class kotlin/Experimental$Level : java/lang/Enum { + public static final field ERROR Lkotlin/Experimental$Level; + public static final field WARNING Lkotlin/Experimental$Level; + public static fun valueOf (Ljava/lang/String;)Lkotlin/Experimental$Level; + public static fun values ()[Lkotlin/Experimental$Level; +} + public final class kotlin/KotlinVersion : java/lang/Comparable { public static final field CURRENT Lkotlin/KotlinVersion; public static final field Companion Lkotlin/KotlinVersion$Companion; @@ -84,6 +104,10 @@ public final class kotlin/TuplesKt { public static final fun toList (Lkotlin/Triple;)Ljava/util/List; } +public abstract interface annotation class kotlin/UseExperimental : java/lang/annotation/Annotation { + public abstract fun markerClass ()[Ljava/lang/Class; +} + public final class kotlin/_Assertions { public static final field INSTANCE Lkotlin/_Assertions; }