K1: report errors related to SubClassOptInRequired annotation
Related to KT-41886
This commit is contained in:
committed by
teamcity
parent
84291181af
commit
c67c5cad27
+6
@@ -37548,6 +37548,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("subClassOptInRequired.kt")
|
||||
public void testSubClassOptInRequired() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/subClassOptInRequired.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
+6
@@ -37548,6 +37548,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("subClassOptInRequired.kt")
|
||||
public void testSubClassOptInRequired() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/subClassOptInRequired.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
+6
@@ -37548,6 +37548,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("subClassOptInRequired.kt")
|
||||
public void testSubClassOptInRequired() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/subClassOptInRequired.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.config.AnalysisFlags
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||
@@ -41,6 +42,7 @@ import org.jetbrains.kotlin.resolve.checkers.OptInNames.OPT_IN_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.OPT_IN_FQ_NAMES
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.REQUIRES_OPT_IN_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.REQUIRES_OPT_IN_FQ_NAMES
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.SUBCLASS_OPT_IN_REQUIRED_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.USE_EXPERIMENTAL_ANNOTATION_CLASS
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames.WAS_EXPERIMENTAL_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
@@ -84,7 +86,9 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
val optIns = resultingDescriptor.loadOptIns(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
val bindingContext = context.trace.bindingContext
|
||||
val languageVersionSettings = context.languageVersionSettings
|
||||
val optIns = resultingDescriptor.loadOptIns(moduleAnnotationsResolver, bindingContext, languageVersionSettings)
|
||||
if (resultingDescriptor is FunctionDescriptor &&
|
||||
resultingDescriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
) {
|
||||
@@ -92,7 +96,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
if (propertyDescriptor != null) {
|
||||
reportNotAllowedOptIns(
|
||||
optIns + propertyDescriptor.loadOptIns(
|
||||
moduleAnnotationsResolver, context.languageVersionSettings
|
||||
moduleAnnotationsResolver, bindingContext, languageVersionSettings
|
||||
), reportOn, context
|
||||
)
|
||||
return
|
||||
@@ -101,9 +105,9 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
if (resultingDescriptor is SamConstructorDescriptor) {
|
||||
// KT-47708 special case (warning only)
|
||||
val methodDescriptor = resultingDescriptor.getSingleAbstractMethod()
|
||||
val samOptIns = methodDescriptor.loadOptIns(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
val samOptIns = methodDescriptor.loadOptIns(moduleAnnotationsResolver, bindingContext, languageVersionSettings)
|
||||
.map { (fqName, _, message) ->
|
||||
OptInDescription(fqName, OptInDescription.Severity.WARNING, message)
|
||||
OptInDescription(fqName, OptInDescription.Severity.WARNING, message, subclassesOnly = false)
|
||||
}
|
||||
reportNotAllowedOptIns(samOptIns, reportOn, context)
|
||||
}
|
||||
@@ -162,8 +166,8 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
trace: BindingTrace,
|
||||
diagnostics: OptInReporterMultiplexer
|
||||
) {
|
||||
for ((annotationFqName, severity, message) in descriptions) {
|
||||
if (!element.isOptInAllowed(annotationFqName, languageVersionSettings, trace.bindingContext)) {
|
||||
for ((annotationFqName, severity, message, subclassesOnly) in descriptions) {
|
||||
if (!element.isOptInAllowed(annotationFqName, languageVersionSettings, trace.bindingContext, subclassesOnly)) {
|
||||
val diagnostic = when (severity) {
|
||||
OptInDescription.Severity.WARNING -> diagnostics.warning
|
||||
OptInDescription.Severity.ERROR -> diagnostics.error
|
||||
@@ -176,10 +180,12 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
|
||||
fun DeclarationDescriptor.loadOptIns(
|
||||
moduleAnnotationsResolver: ModuleAnnotationsResolver,
|
||||
context: BindingContext,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
visited: MutableSet<DeclarationDescriptor> = mutableSetOf(),
|
||||
useFutureError: Boolean = false,
|
||||
useMarkersFromContainer: Boolean = true,
|
||||
fromSupertype: Boolean = false,
|
||||
): Set<OptInDescription> {
|
||||
if (!visited.add(this)) return emptySet()
|
||||
val result = SmartSet.create<OptInDescription>()
|
||||
@@ -188,6 +194,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
result.addAll(
|
||||
overridden.loadOptIns(
|
||||
moduleAnnotationsResolver,
|
||||
context,
|
||||
languageVersionSettings,
|
||||
visited,
|
||||
useFutureError = !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures),
|
||||
@@ -197,7 +204,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
if (useMarkersFromContainer) {
|
||||
(containingDeclaration as? ClassDescriptor)?.let {
|
||||
result.addAll(
|
||||
it.loadOptIns(moduleAnnotationsResolver, languageVersionSettings, visited, useFutureError)
|
||||
it.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visited, useFutureError)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -206,23 +213,26 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
|
||||
for (annotation in annotations) {
|
||||
result.addIfNotNull(annotation.annotationClass?.loadOptInForMarkerAnnotation(useFutureError))
|
||||
result.addIfNotNull(
|
||||
annotation.annotationClass?.loadOptInForMarkerAnnotation(useFutureError)
|
||||
?: if (fromSupertype) annotation.loadSubclassOptInRequired(context) else null
|
||||
)
|
||||
}
|
||||
|
||||
if (this is CallableDescriptor && this !is ClassConstructorDescriptor) {
|
||||
result.addAll(
|
||||
returnType.loadOptIns(moduleAnnotationsResolver, languageVersionSettings, visited)
|
||||
returnType.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visited)
|
||||
)
|
||||
result.addAll(
|
||||
extensionReceiverParameter?.type.loadOptIns(
|
||||
moduleAnnotationsResolver, languageVersionSettings, visited
|
||||
moduleAnnotationsResolver, context, languageVersionSettings, visited
|
||||
)
|
||||
)
|
||||
if (this is FunctionDescriptor) {
|
||||
valueParameters.forEach {
|
||||
result.addAll(
|
||||
it.type.loadOptIns(
|
||||
moduleAnnotationsResolver, languageVersionSettings, visited
|
||||
moduleAnnotationsResolver, context, languageVersionSettings, visited
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -230,7 +240,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
|
||||
if (this is TypeAliasDescriptor) {
|
||||
result.addAll(expandedType.loadOptIns(moduleAnnotationsResolver, languageVersionSettings, visited))
|
||||
result.addAll(expandedType.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visited))
|
||||
}
|
||||
|
||||
if (annotations.any { it.fqName == WAS_EXPERIMENTAL_FQ_NAME }) {
|
||||
@@ -242,7 +252,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
|
||||
val container = containingDeclaration
|
||||
if (useMarkersFromContainer && container is ClassDescriptor && this !is ConstructorDescriptor) {
|
||||
result.addAll(container.loadOptIns(moduleAnnotationsResolver, languageVersionSettings, visited, useFutureError))
|
||||
result.addAll(container.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visited, useFutureError))
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -250,27 +260,31 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
|
||||
private fun KotlinType?.loadOptIns(
|
||||
moduleAnnotationsResolver: ModuleAnnotationsResolver,
|
||||
context: BindingContext,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
visitedClassifiers: MutableSet<DeclarationDescriptor>
|
||||
): Set<OptInDescription> =
|
||||
when {
|
||||
this?.isError != false -> emptySet()
|
||||
this is AbbreviatedType -> abbreviation.constructor.declarationDescriptor?.loadOptIns(
|
||||
moduleAnnotationsResolver, languageVersionSettings, visitedClassifiers,
|
||||
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers,
|
||||
useFutureError = !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
|
||||
).orEmpty() + expandedType.loadOptIns(
|
||||
moduleAnnotationsResolver, languageVersionSettings, visitedClassifiers
|
||||
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers
|
||||
)
|
||||
else -> constructor.declarationDescriptor?.loadOptIns(
|
||||
moduleAnnotationsResolver, languageVersionSettings, visitedClassifiers,
|
||||
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers,
|
||||
useFutureError = !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
|
||||
).orEmpty() + arguments.flatMap {
|
||||
if (it.isStarProjection) emptySet()
|
||||
else it.type.loadOptIns(moduleAnnotationsResolver, languageVersionSettings, visitedClassifiers)
|
||||
else it.type.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ClassDescriptor.loadOptInForMarkerAnnotation(useFutureError: Boolean = false): OptInDescription? {
|
||||
internal fun ClassDescriptor.loadOptInForMarkerAnnotation(
|
||||
useFutureError: Boolean = false,
|
||||
subclassesOnly: Boolean = false
|
||||
): OptInDescription? {
|
||||
val optInAnnotationDescriptor =
|
||||
annotations.findAnnotation(REQUIRES_OPT_IN_FQ_NAME)
|
||||
?: annotations.findAnnotation(OLD_EXPERIMENTAL_FQ_NAME)
|
||||
@@ -289,11 +303,21 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
|
||||
val message = (arguments[MESSAGE] as? StringValue)?.value
|
||||
|
||||
return OptInDescription(fqNameSafe, severity, message)
|
||||
return OptInDescription(fqNameSafe, severity, message, subclassesOnly)
|
||||
}
|
||||
|
||||
private fun PsiElement.isOptInAllowed(annotationFqName: FqName, context: CheckerContext): Boolean =
|
||||
isOptInAllowed(annotationFqName, context.languageVersionSettings, context.trace.bindingContext)
|
||||
private fun AnnotationDescriptor.loadSubclassOptInRequired(context: BindingContext?): OptInDescription? {
|
||||
if (this.fqName != SUBCLASS_OPT_IN_REQUIRED_FQ_NAME) return null
|
||||
val markerClass = allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS]
|
||||
if (markerClass !is KClassValue) return null
|
||||
val value = markerClass.value
|
||||
if (value !is KClassValue.Value.NormalClass) return null
|
||||
val markerDescriptor = context?.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, value.classId.asSingleFqName().toUnsafe())
|
||||
return markerDescriptor?.loadOptInForMarkerAnnotation(subclassesOnly = true)
|
||||
}
|
||||
|
||||
private fun PsiElement.isOptInAllowed(annotationFqName: FqName, context: CheckerContext, subclassesOnly: Boolean): Boolean =
|
||||
isOptInAllowed(annotationFqName, context.languageVersionSettings, context.trace.bindingContext, subclassesOnly)
|
||||
|
||||
/**
|
||||
* Checks whether there's an element lexically above in the tree, annotated with `@UseExperimental(X::class)`, or a declaration
|
||||
@@ -302,13 +326,17 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
fun PsiElement.isOptInAllowed(
|
||||
annotationFqName: FqName,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
bindingContext: BindingContext
|
||||
): Boolean =
|
||||
annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlags.optIn) ||
|
||||
anyParentMatches { element ->
|
||||
element.isDeclarationAnnotatedWith(annotationFqName, bindingContext) ||
|
||||
element.isElementAnnotatedWithOptIn(annotationFqName, bindingContext)
|
||||
}
|
||||
bindingContext: BindingContext,
|
||||
subclassesOnly: Boolean
|
||||
): Boolean {
|
||||
if (annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlags.optIn)) return true
|
||||
val isSubclass = subclassesOnly && getParentOfType<KtSuperTypeListEntry>(strict = true) != null
|
||||
return anyParentMatches { element ->
|
||||
element.isDeclarationAnnotatedWith(annotationFqName, bindingContext) ||
|
||||
element.isElementAnnotatedWithOptIn(annotationFqName, bindingContext) ||
|
||||
isSubclass && element.isElementAnnotatedWithSubclassOptInRequired(annotationFqName, bindingContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
|
||||
if (this !is KtDeclaration) return false
|
||||
@@ -332,6 +360,22 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isElementAnnotatedWithSubclassOptInRequired(
|
||||
annotationFqName: FqName,
|
||||
bindingContext: BindingContext
|
||||
): Boolean {
|
||||
return this is KtAnnotated && annotationEntries.any { entry ->
|
||||
val descriptor = bindingContext.get(BindingContext.ANNOTATION, entry)
|
||||
if (descriptor != null && descriptor.fqName == SUBCLASS_OPT_IN_REQUIRED_FQ_NAME) {
|
||||
val annotationClass = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS]
|
||||
annotationClass is KClassValue && annotationClass.value.let { value ->
|
||||
value is KClassValue.Value.NormalClass &&
|
||||
value.classId.asSingleFqName() == annotationFqName && value.arrayDimensions == 0
|
||||
}
|
||||
} else false
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun PsiElement.anyParentMatches(predicate: (element: PsiElement) -> Boolean): Boolean {
|
||||
var element = this
|
||||
while (true) {
|
||||
@@ -406,9 +450,10 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
is TypeAliasDescriptor -> targetDescriptor.classDescriptor
|
||||
else -> null
|
||||
}
|
||||
val bindingContext = context.trace.bindingContext
|
||||
if (targetClass != null && targetClass.loadOptInForMarkerAnnotation() != null) {
|
||||
if (!element.isUsageAsAnnotationOrImport() &&
|
||||
!element.isUsageAsOptInArgument(context.trace.bindingContext)
|
||||
!element.isUsageAsOptInArgument(bindingContext)
|
||||
) {
|
||||
context.trace.report(
|
||||
Errors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN.on(element)
|
||||
@@ -417,7 +462,12 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
|
||||
if (element.getParentOfType<KtImportDirective>(false) == null) {
|
||||
val descriptions = targetDescriptor.loadOptIns(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
val descriptions = targetDescriptor.loadOptIns(
|
||||
moduleAnnotationsResolver,
|
||||
bindingContext,
|
||||
context.languageVersionSettings,
|
||||
fromSupertype = element.getParentOfType<KtSuperTypeListEntry>(strict = true) != null
|
||||
)
|
||||
reportNotAllowedOptIns(descriptions, element, context)
|
||||
}
|
||||
}
|
||||
@@ -456,7 +506,8 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
parent.parent.parent is KtValueArgumentList &&
|
||||
parent.parent.parent.parent.let { entry ->
|
||||
entry is KtAnnotationEntry && bindingContext.get(BindingContext.ANNOTATION, entry)?.let { annotation ->
|
||||
annotation.fqName in OPT_IN_FQ_NAMES || annotation.fqName == WAS_EXPERIMENTAL_FQ_NAME
|
||||
annotation.fqName in OPT_IN_FQ_NAMES || annotation.fqName == WAS_EXPERIMENTAL_FQ_NAME ||
|
||||
annotation.fqName == SUBCLASS_OPT_IN_REQUIRED_FQ_NAME
|
||||
} == true
|
||||
}
|
||||
}
|
||||
@@ -469,12 +520,12 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
if (descriptor !is CallableMemberDescriptor) return
|
||||
|
||||
val optInOverriddenDescriptorMap = descriptor.overriddenDescriptors.flatMap { overriddenMember ->
|
||||
overriddenMember.loadOptIns(moduleAnnotationsResolver, context.languageVersionSettings)
|
||||
overriddenMember.loadOptIns(moduleAnnotationsResolver, context.trace.bindingContext, context.languageVersionSettings)
|
||||
.map { description -> description to overriddenMember }
|
||||
}.toMap()
|
||||
|
||||
for ((description, overriddenMember) in optInOverriddenDescriptorMap) {
|
||||
if (!declaration.isOptInAllowed(description.annotationFqName, context)) {
|
||||
if (!declaration.isOptInAllowed(description.annotationFqName, context, description.subclassesOnly)) {
|
||||
val reportOn = (declaration as? KtNamedDeclaration)?.nameIdentifier ?: declaration
|
||||
|
||||
val (diagnostic, defaultMessageVerb) = when (description.severity) {
|
||||
|
||||
+1
-1
@@ -324,7 +324,7 @@ class ConstantExpressionEvaluator(
|
||||
|
||||
with(OptInUsageChecker) {
|
||||
val descriptor = constantType.constructor.declarationDescriptor ?: return
|
||||
val optInDescriptions = descriptor.loadOptIns(moduleAnnotationsResolver, languageVersionSettings)
|
||||
val optInDescriptions = descriptor.loadOptIns(moduleAnnotationsResolver, trace.bindingContext, languageVersionSettings)
|
||||
|
||||
reportNotAllowedOptIns(
|
||||
optInDescriptions, expression, languageVersionSettings, trace, EXPERIMENTAL_UNSIGNED_LITERALS_DIAGNOSTICS
|
||||
|
||||
+3
-1
@@ -117,7 +117,9 @@ class DeprecationResolver(
|
||||
return if (callElement != null && bindingContext != null) {
|
||||
with(OptInUsageChecker) {
|
||||
sinceKotlinAccessibility.markerClasses.any { classDescriptor ->
|
||||
!callElement.isOptInAllowed(classDescriptor.fqNameSafe, languageVersionSettings, bindingContext)
|
||||
!callElement.isOptInAllowed(
|
||||
classDescriptor.fqNameSafe, languageVersionSettings, bindingContext, subclassesOnly = false
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
@RequiresOptIn
|
||||
annotation class Marker
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
open class Base
|
||||
|
||||
@Marker
|
||||
class DerivedFirst : Base()
|
||||
|
||||
@OptIn(Marker::class)
|
||||
class DerivedSecond : Base()
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
open class DerivedThird : Base()
|
||||
|
||||
open class DerivedFourth : Base()
|
||||
|
||||
class GrandDerivedThird : DerivedThird()
|
||||
|
||||
// Question: should we have an error also here?
|
||||
class GrandDerivedFourth : DerivedFourth()
|
||||
|
||||
@Marker
|
||||
open class Marked
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
class DerivedMarked : <!OPT_IN_USAGE_ERROR!>Marked<!>()
|
||||
|
||||
fun test() {
|
||||
val b = Base()
|
||||
val d1 = <!OPT_IN_USAGE_ERROR!>DerivedFirst<!>()
|
||||
val d2 = DerivedSecond()
|
||||
val d3 = DerivedThird()
|
||||
val d4 = DerivedFourth()
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
@RequiresOptIn
|
||||
annotation class Marker
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
open class Base
|
||||
|
||||
@Marker
|
||||
class DerivedFirst : Base()
|
||||
|
||||
@OptIn(Marker::class)
|
||||
class DerivedSecond : Base()
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
open class DerivedThird : Base()
|
||||
|
||||
open class DerivedFourth : <!OPT_IN_USAGE_ERROR!>Base<!>()
|
||||
|
||||
class GrandDerivedThird : <!OPT_IN_USAGE_ERROR!>DerivedThird<!>()
|
||||
|
||||
// Question: should we have an error also here?
|
||||
class GrandDerivedFourth : DerivedFourth()
|
||||
|
||||
@Marker
|
||||
open class Marked
|
||||
|
||||
@SubclassOptInRequired(Marker::class)
|
||||
class DerivedMarked : <!OPT_IN_USAGE_ERROR!>Marked<!>()
|
||||
|
||||
fun test() {
|
||||
val b = Base()
|
||||
val d1 = <!OPT_IN_USAGE_ERROR!>DerivedFirst<!>()
|
||||
val d2 = DerivedSecond()
|
||||
val d3 = DerivedThird()
|
||||
val d4 = DerivedFourth()
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
@kotlin.SubclassOptInRequired(markerClass = Marker::class) public open class Base {
|
||||
public constructor Base()
|
||||
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
|
||||
}
|
||||
|
||||
@Marker public final class DerivedFirst : Base {
|
||||
public constructor DerivedFirst()
|
||||
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 open class DerivedFourth : Base {
|
||||
public constructor DerivedFourth()
|
||||
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.SubclassOptInRequired(markerClass = Marker::class) public final class DerivedMarked : Marked {
|
||||
public constructor DerivedMarked()
|
||||
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.OptIn(markerClass = {Marker::class}) public final class DerivedSecond : Base {
|
||||
public constructor DerivedSecond()
|
||||
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.SubclassOptInRequired(markerClass = Marker::class) public open class DerivedThird : Base {
|
||||
public constructor DerivedThird()
|
||||
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 GrandDerivedFourth : DerivedFourth {
|
||||
public constructor GrandDerivedFourth()
|
||||
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 GrandDerivedThird : DerivedThird {
|
||||
public constructor GrandDerivedThird()
|
||||
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
|
||||
}
|
||||
|
||||
@Marker public open class Marked {
|
||||
public constructor Marked()
|
||||
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.RequiresOptIn public final annotation class Marker : kotlin.Annotation {
|
||||
public constructor Marker()
|
||||
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
|
||||
}
|
||||
Generated
+6
@@ -37638,6 +37638,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/overrideInAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("subClassOptInRequired.kt")
|
||||
public void testSubClassOptInRequired() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/subClassOptInRequired.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevel.kt")
|
||||
public void testTopLevel() throws Exception {
|
||||
|
||||
@@ -8,7 +8,12 @@ package org.jetbrains.kotlin.resolve.checkers
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
data class OptInDescription(val annotationFqName: FqName, val severity: Severity, val message: String?) {
|
||||
data class OptInDescription(
|
||||
val annotationFqName: FqName,
|
||||
val severity: Severity,
|
||||
val message: String?,
|
||||
val subclassesOnly: Boolean,
|
||||
) {
|
||||
enum class Severity { WARNING, ERROR, FUTURE_ERROR }
|
||||
|
||||
companion object {
|
||||
|
||||
Reference in New Issue
Block a user