[FIR] Make Volatile diagnostics applicable to kotlin.concurrent.Volatile

#KT-55628 Fixed
This commit is contained in:
Kirill Rakhman
2023-04-03 17:58:23 +02:00
committed by Space Team
parent 91adb88eff
commit 085df96afe
18 changed files with 96 additions and 153 deletions
@@ -321,6 +321,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val AMBIGUOUS_ANNOTATION_ARGUMENT by error<PsiElement> {
parameter<List<FirBasedSymbol<*>>>("symbols")
}
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
}
val OPT_IN by object : DiagnosticGroup("OptIn") {
@@ -55,8 +55,6 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val ANNOTATIONS by object : DiagnosticGroup("annotations") {
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
@@ -54,8 +54,6 @@ object FirJvmErrors {
// annotations
val STRICTFP_ON_CLASS by error0<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error0<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning0<KtAnnotationEntry>()
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
import org.jetbrains.kotlin.fir.analysis.diagnostics.checkMissingMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONCURRENT_HASH_MAP_CONTAINS_OPERATOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET
@@ -87,8 +86,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZ
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_SUSPEND
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_VALUE
object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
@@ -97,8 +94,6 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
map.put(UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of a type parameter cannot be an array")
map.put(STRICTFP_ON_CLASS, "'@Strictfp' annotation on classes is unsupported yet")
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
map.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions")
map.put(SYNCHRONIZED_ON_INLINE, "'@Synchronized' annotation has no effect on inline functions")
map.put(SYNCHRONIZED_ON_SUSPEND, "@Synchronized annotation is not applicable to suspend functions and lambdas")
@@ -302,4 +297,4 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING,
)
}
}
}
@@ -35,7 +35,6 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val propertyCheckers: Set<FirPropertyChecker>
get() = setOf(
FirVolatileAnnotationChecker,
FirJvmFieldApplicabilityChecker,
FirJvmSyntheticApplicabilityChecker,
FirJvmInlinePropertyChecker,
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.name.JvmNames.VOLATILE_ANNOTATION_CLASS_ID
object FirVolatileAnnotationChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind != KtRealSourceElementKind) return
val fieldAnnotation = declaration.getAnnotationByClassId(VOLATILE_ANNOTATION_CLASS_ID, context.session)
if (fieldAnnotation != null && !declaration.isVar) {
reporter.reportOn(fieldAnnotation.source, FirJvmErrors.VOLATILE_ON_VALUE, context)
}
val delegateAnnotation = declaration.delegateFieldSymbol?.getAnnotationByClassId(VOLATILE_ANNOTATION_CLASS_ID, context.session)
if (delegateAnnotation != null) {
reporter.reportOn(delegateAnnotation.source, FirJvmErrors.VOLATILE_ON_DELEGATE, context)
}
}
}
@@ -268,6 +268,8 @@ object FirErrors {
val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error0<KtAnnotationEntry>()
val PLUGIN_ANNOTATION_AMBIGUITY by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val AMBIGUOUS_ANNOTATION_ARGUMENT by error1<PsiElement, List<FirBasedSymbol<*>>>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
// OptIn
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -76,6 +76,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirTopLevelPropertiesChecker,
FirLocalExtensionPropertyChecker,
ContractSyntaxV2PropertyChecker,
FirVolatileAnnotationChecker,
)
override val backingFieldCheckers: Set<FirBackingFieldChecker>
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassIds
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.name.StandardClassIds
object FirVolatileAnnotationChecker : FirPropertyChecker() {
private val VOLATILE_CLASS_IDS = listOf(StandardClassIds.Annotations.Volatile, StandardClassIds.Annotations.JvmVolatile)
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind != KtRealSourceElementKind) return
val fieldAnnotation = declaration.annotations.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
?: declaration.backingField?.annotations?.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
?: return
if (!declaration.isVar) {
reporter.reportOn(fieldAnnotation.source, FirErrors.VOLATILE_ON_VALUE, context)
}
if (declaration.delegateFieldSymbol != null) {
reporter.reportOn(fieldAnnotation.source, FirErrors.VOLATILE_ON_DELEGATE, context)
}
}
}
@@ -608,6 +608,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_INHERITANCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HIDDEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VOLATILE_ON_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VOLATILE_ON_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_EXTENSION_FUNCTION_TYPE
@@ -891,6 +893,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(REPEATED_ANNOTATION, "This annotation is not repeatable")
map.put(REPEATED_ANNOTATION_WARNING, "This annotation is not repeatable")
map.put(NON_INTERNAL_PUBLISHED_API, "@PublishedApi annotation is only applicable to internal declaration")
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
// OptIn
map.put(OPT_IN_USAGE, "{1}", TO_STRING, STRING)
@@ -178,6 +178,12 @@ fun List<FirAnnotation>.getAnnotationsByClassId(classId: ClassId, session: FirSe
}
}
fun List<FirAnnotation>.getAnnotationByClassIds(classIds: Collection<ClassId>, session: FirSession): FirAnnotation? {
return firstOrNull {
it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session)?.lookupTag?.classId in classIds
}
}
inline fun <T> List<FirAnnotation>.mapAnnotationsWithClassIdTo(
classId: ClassId,
destination: MutableCollection<T>,