Add applicability checks & tests for SubclassOptInRequired
This commit is contained in:
committed by
teamcity
parent
66e710704a
commit
80a9f22052
@@ -11,7 +11,6 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import kotlin.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DeclarationWithDiagnosticComponents;
|
||||
@@ -27,7 +26,6 @@ import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo;
|
||||
@@ -43,7 +41,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.config.LanguageFeature.ReportTypeVarianceConflictOnQualifierArguments;
|
||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.ACTUAL_DECLARATION_NAME;
|
||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.INCOMPATIBLE_DECLARATION;
|
||||
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
|
||||
@@ -339,6 +336,8 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtAnnotationEntry> OPT_IN_MARKER_ON_OVERRIDE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> OPT_IN_MARKER_ON_OVERRIDE_WARNING = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> SUBCLASS_OPT_IN_INAPPLICABLE = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> EXPERIMENTAL_UNSIGNED_LITERALS = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory1<PsiElement, String> EXPERIMENTAL_UNSIGNED_LITERALS_ERROR = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
|
||||
+2
@@ -180,6 +180,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(OPT_IN_MARKER_ON_OVERRIDE, "Opt-in requirement marker annotation on override requires the same marker on base declaration");
|
||||
MAP.put(OPT_IN_MARKER_ON_OVERRIDE_WARNING, "Opt-in requirement marker annotation on override makes no sense without the same marker on base declaration");
|
||||
|
||||
MAP.put(SUBCLASS_OPT_IN_INAPPLICABLE, "@SubclassOptInRequired is inapplicable on {0}", STRING);
|
||||
|
||||
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "{0}", STRING);
|
||||
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "{0}", STRING);
|
||||
|
||||
|
||||
+54
-2
@@ -8,14 +8,15 @@ package org.jetbrains.kotlin.resolve.checkers
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.AdditionalAnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -47,6 +48,11 @@ class OptInMarkerDeclarationAnnotationChecker(private val module: ModuleDescript
|
||||
.safeAs<ArrayValue>()?.value.orEmpty()
|
||||
checkOptInUsage(annotationClasses, trace, entry)
|
||||
}
|
||||
OptInNames.SUBCLASS_OPT_IN_REQUIRED_FQ_NAME -> {
|
||||
val annotationClass =
|
||||
annotation.allValueArguments[OptInNames.USE_EXPERIMENTAL_ANNOTATION_CLASS]
|
||||
checkSubclassOptInUsage(annotated, listOfNotNull(annotationClass), trace, entry)
|
||||
}
|
||||
in OptInNames.REQUIRES_OPT_IN_FQ_NAMES -> {
|
||||
hasOptIn = true
|
||||
}
|
||||
@@ -89,7 +95,53 @@ class OptInMarkerDeclarationAnnotationChecker(private val module: ModuleDescript
|
||||
trace.report(Errors.OPT_IN_WITHOUT_ARGUMENTS.on(entry))
|
||||
return
|
||||
}
|
||||
checkArgumentsAreMarkers(annotationClasses, trace, entry)
|
||||
}
|
||||
|
||||
private fun checkSubclassOptInUsage(
|
||||
annotated: KtAnnotated?,
|
||||
annotationClasses: List<ConstantValue<*>>,
|
||||
trace: BindingTrace,
|
||||
entry: KtAnnotationEntry
|
||||
) {
|
||||
when (annotated) {
|
||||
is KtAnnotatedExpression -> {
|
||||
if (annotated.baseExpression is KtObjectLiteralExpression) {
|
||||
trace.report(Errors.SUBCLASS_OPT_IN_INAPPLICABLE.on(entry, "object"))
|
||||
}
|
||||
return
|
||||
}
|
||||
is KtClassOrObject -> {
|
||||
val descriptor = trace[BindingContext.CLASS, annotated]
|
||||
if (descriptor != null) {
|
||||
val kind = descriptor.kind
|
||||
if (kind == ClassKind.OBJECT || kind == ClassKind.ENUM_CLASS || kind == ClassKind.ANNOTATION_CLASS) {
|
||||
trace.report(Errors.SUBCLASS_OPT_IN_INAPPLICABLE.on(entry, kind.toString()))
|
||||
return
|
||||
}
|
||||
if (kind != ClassKind.ENUM_ENTRY) {
|
||||
// ^ We don't report anything on enum entries because it's anyway inapplicable target
|
||||
val modality = descriptor.modality
|
||||
if (modality != Modality.ABSTRACT && modality != Modality.OPEN) {
|
||||
trace.report(Errors.SUBCLASS_OPT_IN_INAPPLICABLE.on(entry, "$modality $kind"))
|
||||
return
|
||||
}
|
||||
if (descriptor.isFun) {
|
||||
trace.report(Errors.SUBCLASS_OPT_IN_INAPPLICABLE.on(entry, "fun interface"))
|
||||
return
|
||||
}
|
||||
if (annotated.isLocal) {
|
||||
trace.report(Errors.SUBCLASS_OPT_IN_INAPPLICABLE.on(entry, "local $kind"))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
checkArgumentsAreMarkers(annotationClasses, trace, entry)
|
||||
}
|
||||
|
||||
private fun checkArgumentsAreMarkers(annotationClasses: List<ConstantValue<*>>, trace: BindingTrace, entry: KtAnnotationEntry) {
|
||||
for (annotationClass in annotationClasses) {
|
||||
val classDescriptor =
|
||||
(annotationClass as? KClassValue)?.getArgumentType(module)?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
|
||||
Reference in New Issue
Block a user