Introduce EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION diagnostic
#KT-22941 Fixed
This commit is contained in:
committed by
teamcityserver
parent
7393465696
commit
d8d38862d9
@@ -284,6 +284,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtAnnotationEntry> USE_EXPERIMENTAL_WITHOUT_ARGUMENTS = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory1<KtAnnotationEntry, FqName> USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> EXPERIMENTAL_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory1<PsiElement, String> EXPERIMENTAL_UNSIGNED_LITERALS_ERROR = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
@@ -168,6 +168,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(USE_EXPERIMENTAL_WITHOUT_ARGUMENTS, "@OptIn without any arguments has no effect");
|
||||
MAP.put(USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER, "Annotation ''{0}'' is not an opt-in requirement marker, therefore its usage in @OptIn is ignored", TO_STRING);
|
||||
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Opt-in requirement marker annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING);
|
||||
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION, "Opt-in requirement marker annotation cannot be used with SOURCE retention. Please replace retention with BINARY");
|
||||
|
||||
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "{0}", STRING);
|
||||
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "{0}", STRING);
|
||||
|
||||
+37
-15
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.checkers
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
@@ -19,12 +20,17 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleDescriptor) : AdditionalAnnotationChecker {
|
||||
private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE)
|
||||
|
||||
override fun checkEntries(entries: List<KtAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
|
||||
override fun checkEntries(
|
||||
entries: List<KtAnnotationEntry>,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
var isAnnotatedWithExperimental = false
|
||||
|
||||
for (entry in entries) {
|
||||
@@ -43,7 +49,7 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD
|
||||
}
|
||||
|
||||
if (isAnnotatedWithExperimental) {
|
||||
checkMarkerTargets(entries, trace)
|
||||
checkMarkerTargetsAndRetention(entries, trace)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,19 +72,35 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMarkerTargets(entries: List<KtAnnotationEntry>, trace: BindingTrace) {
|
||||
val targetEntry =
|
||||
entries.associate { entry -> entry to trace.bindingContext.get(BindingContext.ANNOTATION, entry) }
|
||||
.entries
|
||||
.firstOrNull { (_, descriptor) -> descriptor != null && descriptor.fqName == StandardNames.FqNames.target }
|
||||
?: return
|
||||
val (entry, descriptor) = targetEntry
|
||||
val allowedTargets = AnnotationChecker.loadAnnotationTargets(descriptor!!) ?: return
|
||||
val wrongTargets = allowedTargets.intersect(WRONG_TARGETS_FOR_MARKER)
|
||||
if (wrongTargets.isNotEmpty()) {
|
||||
trace.report(
|
||||
Errors.EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET.on(entry, wrongTargets.joinToString(transform = KotlinTarget::description))
|
||||
)
|
||||
private fun checkMarkerTargetsAndRetention(
|
||||
entries: List<KtAnnotationEntry>,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val associatedEntries = entries.associateWith { entry -> trace.bindingContext.get(BindingContext.ANNOTATION, entry) }.entries
|
||||
val targetEntry = associatedEntries.firstOrNull { (_, descriptor) ->
|
||||
descriptor?.fqName == StandardNames.FqNames.target
|
||||
}
|
||||
if (targetEntry != null) {
|
||||
val (entry, descriptor) = targetEntry
|
||||
val allowedTargets = AnnotationChecker.loadAnnotationTargets(descriptor!!) ?: return
|
||||
val wrongTargets = allowedTargets.intersect(WRONG_TARGETS_FOR_MARKER)
|
||||
if (wrongTargets.isNotEmpty()) {
|
||||
trace.report(
|
||||
Errors.EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET.on(
|
||||
entry,
|
||||
wrongTargets.joinToString(transform = KotlinTarget::description)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
val retentionEntry = associatedEntries.firstOrNull { (_, descriptor) ->
|
||||
descriptor?.fqName == StandardNames.FqNames.retention
|
||||
}
|
||||
if (retentionEntry != null) {
|
||||
val (entry, descriptor) = retentionEntry
|
||||
if (descriptor?.getAnnotationRetention() == KotlinRetention.SOURCE) {
|
||||
trace.report(Errors.EXPERIMENTAL_ANNOTATION_WITH_WRONG_RETENTION.on(entry))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user