Remove Experimental and UseExperimental from compiler OptIn usage checkers

This commit is contained in:
Abduqodiri Qurbonzoda
2022-09-13 17:12:42 +03:00
committed by Space
parent bc684b8d36
commit f2b0c30cba
5 changed files with 26 additions and 54 deletions
@@ -42,23 +42,23 @@ class OptInMarkerDeclarationAnnotationChecker(private val module: ModuleDescript
for (entry in entries) {
val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry) ?: continue
when (annotation.fqName) {
in OptInNames.OPT_IN_FQ_NAMES -> {
OptInNames.OPT_IN_FQ_NAME -> {
val annotationClasses =
annotation.allValueArguments[OptInNames.USE_EXPERIMENTAL_ANNOTATION_CLASS]
annotation.allValueArguments[OptInNames.OPT_IN_ANNOTATION_CLASS]
.safeAs<ArrayValue>()?.value.orEmpty()
checkOptInUsage(annotationClasses, trace, entry)
}
OptInNames.SUBCLASS_OPT_IN_REQUIRED_FQ_NAME -> {
val annotationClass =
annotation.allValueArguments[OptInNames.USE_EXPERIMENTAL_ANNOTATION_CLASS]
annotation.allValueArguments[OptInNames.OPT_IN_ANNOTATION_CLASS]
checkSubclassOptInUsage(annotated, listOfNotNull(annotationClass), trace, entry)
}
in OptInNames.REQUIRES_OPT_IN_FQ_NAMES -> {
OptInNames.REQUIRES_OPT_IN_FQ_NAME -> {
hasOptIn = true
}
}
val annotationClass = annotation.annotationClass ?: continue
if (annotationClass.annotations.any { it.fqName in OptInNames.REQUIRES_OPT_IN_FQ_NAMES }) {
if (annotationClass.annotations.any { it.fqName == OptInNames.REQUIRES_OPT_IN_FQ_NAME }) {
val applicableTargets = AnnotationChecker.applicableTargetSet(annotationClass)
val possibleTargets = applicableTargets.intersect(actualTargets)
val annotationUseSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
@@ -36,14 +36,10 @@ import org.jetbrains.kotlin.resolve.*
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.checkers.OptInNames.OLD_EXPERIMENTAL_FQ_NAME
import org.jetbrains.kotlin.resolve.checkers.OptInNames.OLD_USE_EXPERIMENTAL_FQ_NAME
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.OPT_IN_ANNOTATION_CLASS
import org.jetbrains.kotlin.resolve.checkers.OptInNames.WAS_EXPERIMENTAL_FQ_NAME
import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
@@ -286,9 +282,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
subclassesOnly: Boolean = false
): OptInDescription? {
val optInAnnotationDescriptor =
annotations.findAnnotation(REQUIRES_OPT_IN_FQ_NAME)
?: annotations.findAnnotation(OLD_EXPERIMENTAL_FQ_NAME)
?: return null
annotations.findAnnotation(REQUIRES_OPT_IN_FQ_NAME) ?: return null
val arguments = optInAnnotationDescriptor.allValueArguments
val severity = when ((arguments[LEVEL] as? EnumValue)?.enumEntryName) {
@@ -308,7 +302,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
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]
val markerClass = allValueArguments[OPT_IN_ANNOTATION_CLASS]
if (markerClass !is KClassValue) return null
val value = markerClass.value
if (value !is KClassValue.Value.NormalClass) return null
@@ -320,7 +314,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
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
* Checks whether there's an element lexically above in the tree, annotated with `@OptIn(X::class)`, or a declaration
* annotated with `@X` where [annotationFqName] is the FQ name of X
*/
fun PsiElement.isOptInAllowed(
@@ -354,8 +348,8 @@ class OptInUsageChecker(project: Project) : CallChecker {
private fun PsiElement.isElementAnnotatedWithOptIn(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
return this is KtAnnotated && annotationEntries.any { entry ->
val descriptor = bindingContext.get(BindingContext.ANNOTATION, entry)
if (descriptor != null && descriptor.fqName in OPT_IN_FQ_NAMES) {
val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS]
if (descriptor != null && descriptor.fqName == OPT_IN_FQ_NAME) {
val annotationClasses = descriptor.allValueArguments[OPT_IN_ANNOTATION_CLASS]
annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass ->
annotationClass is KClassValue && annotationClass.value.let { value ->
value is KClassValue.Value.NormalClass &&
@@ -373,7 +367,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
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]
val annotationClass = descriptor.allValueArguments[OPT_IN_ANNOTATION_CLASS]
annotationClass is KClassValue && annotationClass.value.let { value ->
value is KClassValue.Value.NormalClass &&
value.classId.asSingleFqName() == annotationFqName && value.arrayDimensions == 0
@@ -429,7 +423,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
}
languageVersionSettings.getFlag(AnalysisFlags.optIn).forEach { fqName ->
if (fqName != REQUIRES_OPT_IN_FQ_NAME.asString() && fqName != OLD_EXPERIMENTAL_FQ_NAME.asString()) {
if (fqName != REQUIRES_OPT_IN_FQ_NAME.asString()) {
checkAnnotation(fqName)
}
}
@@ -441,12 +435,10 @@ class OptInUsageChecker(project: Project) : CallChecker {
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
val name = targetDescriptor.name
if (name == OLD_EXPERIMENTAL_FQ_NAME.shortName() || name == REQUIRES_OPT_IN_FQ_NAME.shortName() ||
name == OLD_USE_EXPERIMENTAL_FQ_NAME.shortName() || name == OPT_IN_FQ_NAME.shortName()
) {
if (name == REQUIRES_OPT_IN_FQ_NAME.shortName() || name == OPT_IN_FQ_NAME.shortName()) {
val fqName = targetDescriptor.fqNameSafe
if (fqName in REQUIRES_OPT_IN_FQ_NAMES || fqName in OPT_IN_FQ_NAMES) {
checkUsageOfKotlinExperimentalOrOptIn(element, context)
if (fqName == REQUIRES_OPT_IN_FQ_NAME || fqName == OPT_IN_FQ_NAME) {
checkUsageOfKotlinRequiresOptInOrOptIn(element, context)
return
}
}
@@ -481,11 +473,10 @@ class OptInUsageChecker(project: Project) : CallChecker {
}
}
private fun checkUsageOfKotlinExperimentalOrOptIn(element: PsiElement, context: CheckerContext) {
private fun checkUsageOfKotlinRequiresOptInOrOptIn(element: PsiElement, context: CheckerContext) {
val optInFqNames = context.languageVersionSettings.getFlag(AnalysisFlags.optIn)
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.OptInRelease) &&
REQUIRES_OPT_IN_FQ_NAME.asString() !in optInFqNames &&
OLD_EXPERIMENTAL_FQ_NAME.asString() !in optInFqNames
REQUIRES_OPT_IN_FQ_NAME.asString() !in optInFqNames
) {
context.trace.report(Errors.OPT_IN_IS_NOT_ENABLED.on(element))
}
@@ -515,7 +506,7 @@ 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 == OPT_IN_FQ_NAME || annotation.fqName == WAS_EXPERIMENTAL_FQ_NAME ||
annotation.fqName == SUBCLASS_OPT_IN_REQUIRED_FQ_NAME
} == true
}