[FIR][FE 1.0] KT-47933: Warn about redundant @Repeatable
Merge-request: KT-MR-7318 Merged-by: Nikolay Lunyak <Nikolay.Lunyak@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
6117cdc0c3
commit
b6f950ed75
@@ -6,7 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.analysis.api.fir
|
package org.jetbrains.kotlin.analysis.api.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
|
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.fullyExpandedClassId
|
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClassId
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.mapAnnotationParameters
|
import org.jetbrains.kotlin.analysis.api.fir.annotations.mapAnnotationParameters
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||||
|
|||||||
+1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotation
|
|||||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||||
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClassId
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
|||||||
+1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotation
|
|||||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||||
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClassId
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.customAnnotations
|
import org.jetbrains.kotlin.fir.types.customAnnotations
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|||||||
-3
@@ -90,6 +90,3 @@ internal fun mapAnnotationParameters(annotation: FirAnnotation, session: FirSess
|
|||||||
|
|
||||||
return resultMap
|
return resultMap
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FirAnnotation.fullyExpandedClassId(useSiteSession: FirSession): ClassId? =
|
|
||||||
coneClassLikeType?.fullyExpandedType(useSiteSession)?.classId
|
|
||||||
|
|||||||
+8
@@ -4178,6 +4178,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirJvmErrors.REDUNDANT_REPEATABLE_ANNOTATION) { firDiagnostic ->
|
||||||
|
RedundantRepeatableAnnotationImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic.b,
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirJvmErrors.LOCAL_JVM_RECORD) { firDiagnostic ->
|
add(FirJvmErrors.LOCAL_JVM_RECORD) { firDiagnostic ->
|
||||||
LocalJvmRecordImpl(
|
LocalJvmRecordImpl(
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
|||||||
+6
@@ -2908,6 +2908,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = PositionedValueArgumentForJavaAnnotation::class
|
override val diagnosticClass get() = PositionedValueArgumentForJavaAnnotation::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class RedundantRepeatableAnnotation : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||||
|
override val diagnosticClass get() = RedundantRepeatableAnnotation::class
|
||||||
|
abstract val kotlinRepeatable: FqName
|
||||||
|
abstract val javaRepeatable: FqName
|
||||||
|
}
|
||||||
|
|
||||||
abstract class LocalJvmRecord : KtFirDiagnostic<PsiElement>() {
|
abstract class LocalJvmRecord : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = LocalJvmRecord::class
|
override val diagnosticClass get() = LocalJvmRecord::class
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -3514,6 +3514,13 @@ internal class PositionedValueArgumentForJavaAnnotationImpl(
|
|||||||
override val token: KtLifetimeToken,
|
override val token: KtLifetimeToken,
|
||||||
) : KtFirDiagnostic.PositionedValueArgumentForJavaAnnotation(), KtAbstractFirDiagnostic<KtExpression>
|
) : KtFirDiagnostic.PositionedValueArgumentForJavaAnnotation(), KtAbstractFirDiagnostic<KtExpression>
|
||||||
|
|
||||||
|
internal class RedundantRepeatableAnnotationImpl(
|
||||||
|
override val kotlinRepeatable: FqName,
|
||||||
|
override val javaRepeatable: FqName,
|
||||||
|
override val firDiagnostic: KtPsiDiagnostic,
|
||||||
|
override val token: KtLifetimeToken,
|
||||||
|
) : KtFirDiagnostic.RedundantRepeatableAnnotation(), KtAbstractFirDiagnostic<KtAnnotationEntry>
|
||||||
|
|
||||||
internal class LocalJvmRecordImpl(
|
internal class LocalJvmRecordImpl(
|
||||||
override val firDiagnostic: KtPsiDiagnostic,
|
override val firDiagnostic: KtPsiDiagnostic,
|
||||||
override val token: KtLifetimeToken,
|
override val token: KtLifetimeToken,
|
||||||
|
|||||||
+6
@@ -34866,6 +34866,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleRepeatables.kt")
|
||||||
|
public void testMultipleRepeatables() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/multipleRepeatables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("qualifiedCallValue.kt")
|
@TestMetadata("qualifiedCallValue.kt")
|
||||||
public void testQualifiedCallValue() throws Exception {
|
public void testQualifiedCallValue() throws Exception {
|
||||||
|
|||||||
+6
@@ -34866,6 +34866,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleRepeatables.kt")
|
||||||
|
public void testMultipleRepeatables() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/multipleRepeatables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("qualifiedCallValue.kt")
|
@TestMetadata("qualifiedCallValue.kt")
|
||||||
public void testQualifiedCallValue() throws Exception {
|
public void testQualifiedCallValue() throws Exception {
|
||||||
|
|||||||
+6
@@ -34866,6 +34866,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleRepeatables.kt")
|
||||||
|
public void testMultipleRepeatables() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/multipleRepeatables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("qualifiedCallValue.kt")
|
@TestMetadata("qualifiedCallValue.kt")
|
||||||
public void testQualifiedCallValue() throws Exception {
|
public void testQualifiedCallValue() throws Exception {
|
||||||
|
|||||||
+5
@@ -79,6 +79,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
|||||||
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error<KtAnnotationEntry>()
|
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error<KtAnnotationEntry>()
|
||||||
|
|
||||||
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error<KtExpression>()
|
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error<KtExpression>()
|
||||||
|
|
||||||
|
val REDUNDANT_REPEATABLE_ANNOTATION by warning<KtAnnotationEntry> {
|
||||||
|
parameter<FqName>("kotlinRepeatable")
|
||||||
|
parameter<FqName>("javaRepeatable")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val SUPER by object : DiagnosticGroup("Super") {
|
val SUPER by object : DiagnosticGroup("Super") {
|
||||||
|
|||||||
+1
@@ -71,6 +71,7 @@ object FirJvmErrors {
|
|||||||
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0<KtAnnotationEntry>()
|
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0<KtAnnotationEntry>()
|
||||||
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0<KtAnnotationEntry>()
|
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0<KtAnnotationEntry>()
|
||||||
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error0<KtExpression>()
|
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error0<KtExpression>()
|
||||||
|
val REDUNDANT_REPEATABLE_ANNOTATION by warning2<KtAnnotationEntry, FqName, FqName>()
|
||||||
|
|
||||||
// Super
|
// Super
|
||||||
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1<PsiElement, String>()
|
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1<PsiElement, String>()
|
||||||
|
|||||||
+7
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REDUNDANT_REPEATABLE_ANNOTATION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION
|
||||||
@@ -285,6 +286,12 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
JAVA_SAM_INTERFACE_CONSTRUCTOR_REFERENCE,
|
JAVA_SAM_INTERFACE_CONSTRUCTOR_REFERENCE,
|
||||||
"Java SAM interface constructor references are prohibited"
|
"Java SAM interface constructor references are prohibited"
|
||||||
)
|
)
|
||||||
|
map.put(
|
||||||
|
REDUNDANT_REPEATABLE_ANNOTATION,
|
||||||
|
"Please, remove the ''{0}'' annotation, as ''{1}'' is already enough",
|
||||||
|
TO_STRING,
|
||||||
|
TO_STRING,
|
||||||
|
)
|
||||||
|
|
||||||
map.checkMissingMessages(FirJvmErrors)
|
map.checkMissingMessages(FirJvmErrors)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -18,6 +18,7 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
|
|||||||
FirJvmStaticChecker,
|
FirJvmStaticChecker,
|
||||||
FirRepeatableAnnotationChecker,
|
FirRepeatableAnnotationChecker,
|
||||||
FirJvmInvalidAndDangerousCharactersChecker,
|
FirJvmInvalidAndDangerousCharactersChecker,
|
||||||
|
FirJvmRedundantRepeatableChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val classCheckers: Set<FirClassChecker>
|
override val classCheckers: Set<FirClassChecker>
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.classId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Repeatable
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.JvmRepeatable
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Java
|
||||||
|
|
||||||
|
object FirJvmRedundantRepeatableChecker : FirBasicDeclarationChecker() {
|
||||||
|
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val kotlinRepeatable = declaration.annotations.find { it.fullyExpandedClassId(context.session) == Repeatable }
|
||||||
|
|
||||||
|
val javaRepeatable = declaration.annotations.find {
|
||||||
|
val expandedClassId = it.fullyExpandedClassId(context.session)
|
||||||
|
expandedClassId == JvmRepeatable || expandedClassId == Java.Repeatable
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kotlinRepeatable != null && javaRepeatable != null) {
|
||||||
|
reporter.reportOn(
|
||||||
|
kotlinRepeatable.source,
|
||||||
|
FirJvmErrors.REDUNDANT_REPEATABLE_ANNOTATION,
|
||||||
|
kotlinRepeatable.classId?.asSingleFqName() ?: FqName.ROOT,
|
||||||
|
javaRepeatable.classId?.asSingleFqName() ?: FqName.ROOT,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+4
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclaratio
|
|||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationRetention
|
import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationRetention
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.isJvm6
|
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.isJvm6
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.classId
|
|||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.scopes.getSingleClassifier
|
import org.jetbrains.kotlin.fir.scopes.getSingleClassifier
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
@@ -51,7 +53,8 @@ object FirRepeatableAnnotationChecker : FirBasicDeclarationChecker() {
|
|||||||
val annotationClass = session.symbolProvider.getClassLikeSymbolByClassId(annotationClassId) ?: continue
|
val annotationClass = session.symbolProvider.getClassLikeSymbolByClassId(annotationClassId) ?: continue
|
||||||
|
|
||||||
val useSiteTarget = annotation.useSiteTarget
|
val useSiteTarget = annotation.useSiteTarget
|
||||||
val existingTargetsForAnnotation = annotationsMap.getOrPut(annotation.annotationTypeRef.coneType) { arrayListOf() }
|
val expandedType = annotation.annotationTypeRef.coneType.fullyExpandedType(context.session)
|
||||||
|
val existingTargetsForAnnotation = annotationsMap.getOrPut(expandedType) { arrayListOf() }
|
||||||
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation ||
|
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation ||
|
||||||
existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) }
|
existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) }
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -185,7 +185,8 @@ fun checkRepeatedAnnotation(
|
|||||||
|
|
||||||
for (annotation in annotations) {
|
for (annotation in annotations) {
|
||||||
val useSiteTarget = annotation.useSiteTarget ?: annotationContainer?.getDefaultUseSiteTarget(annotation, context)
|
val useSiteTarget = annotation.useSiteTarget ?: annotationContainer?.getDefaultUseSiteTarget(annotation, context)
|
||||||
val existingTargetsForAnnotation = annotationsMap.getOrPut(annotation.annotationTypeRef.coneType) { arrayListOf() }
|
val expandedType = annotation.annotationTypeRef.coneType.fullyExpandedType(context.session)
|
||||||
|
val existingTargetsForAnnotation = annotationsMap.getOrPut(expandedType) { arrayListOf() }
|
||||||
|
|
||||||
checkRepeatedAnnotation(useSiteTarget, existingTargetsForAnnotation, annotation, context, reporter)
|
checkRepeatedAnnotation(useSiteTarget, existingTargetsForAnnotation, annotation, context, reporter)
|
||||||
existingTargetsForAnnotation.add(useSiteTarget)
|
existingTargetsForAnnotation.add(useSiteTarget)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolvedSymbol
|
import org.jetbrains.kotlin.fir.resolvedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||||
@@ -223,3 +224,6 @@ fun hasLowPriorityAnnotation(annotations: List<FirAnnotation>) = annotations.any
|
|||||||
val lookupTag = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return@any false
|
val lookupTag = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return@any false
|
||||||
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
|
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirAnnotation.fullyExpandedClassId(useSiteSession: FirSession): ClassId? =
|
||||||
|
coneClassLikeType?.fullyExpandedType(useSiteSession)?.classId
|
||||||
|
|||||||
+10
-4
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
|||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.*
|
||||||
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.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -73,6 +70,15 @@ class RepeatableAnnotationChecker(
|
|||||||
javaRepeatable != null -> checkJavaRepeatableAnnotationDeclaration(javaRepeatable, annotationClass, trace)
|
javaRepeatable != null -> checkJavaRepeatableAnnotationDeclaration(javaRepeatable, annotationClass, trace)
|
||||||
kotlinRepeatable != null -> checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, annotationClass, trace)
|
kotlinRepeatable != null -> checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, annotationClass, trace)
|
||||||
}
|
}
|
||||||
|
if (javaRepeatable != null && kotlinRepeatable != null) {
|
||||||
|
trace.report(
|
||||||
|
ErrorsJvm.REDUNDANT_REPEATABLE_ANNOTATION.on(
|
||||||
|
kotlinRepeatable.entry,
|
||||||
|
kotlinRepeatable.descriptor.abbreviationFqName ?: FqName.ROOT,
|
||||||
|
javaRepeatable.descriptor.abbreviationFqName ?: FqName.ROOT,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -232,6 +232,9 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
|||||||
|
|
||||||
MAP.put(JAVA_SAM_INTERFACE_CONSTRUCTOR_REFERENCE, "Java SAM interface constructor references are prohibited");
|
MAP.put(JAVA_SAM_INTERFACE_CONSTRUCTOR_REFERENCE, "Java SAM interface constructor references are prohibited");
|
||||||
MAP.put(ENUM_DECLARING_CLASS_DEPRECATED, "Enum.declaringClass is deprecated, use declaringJavaClass instead or cast receiver to java.lang.Enum explicitly");
|
MAP.put(ENUM_DECLARING_CLASS_DEPRECATED, "Enum.declaringClass is deprecated, use declaringJavaClass instead or cast receiver to java.lang.Enum explicitly");
|
||||||
|
|
||||||
|
MAP.put(REDUNDANT_REPEATABLE_ANNOTATION,
|
||||||
|
"Please, remove the ''{0}'' annotation, as ''{1}'' is already enough", TO_STRING, TO_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -210,6 +210,8 @@ public interface ErrorsJvm {
|
|||||||
DiagnosticFactoryForDeprecation0<PsiElement> ENUM_DECLARING_CLASS_DEPRECATED =
|
DiagnosticFactoryForDeprecation0<PsiElement> ENUM_DECLARING_CLASS_DEPRECATED =
|
||||||
DiagnosticFactoryForDeprecation0.create(LanguageFeature.ProhibitEnumDeclaringClass);
|
DiagnosticFactoryForDeprecation0.create(LanguageFeature.ProhibitEnumDeclaringClass);
|
||||||
|
|
||||||
|
DiagnosticFactory2<KtAnnotationEntry, FqName, FqName> REDUNDANT_REPEATABLE_ANNOTATION = DiagnosticFactory2.create(WARNING);
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
Object _initializer = new Object() {
|
Object _initializer = new Object() {
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ annotation class B1 {
|
|||||||
}
|
}
|
||||||
annotation class D1(val value: Array<B1>)
|
annotation class D1(val value: Array<B1>)
|
||||||
|
|
||||||
@Repeatable
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@Repeatable<!>
|
||||||
@java.lang.annotation.Repeatable(D2::class)
|
@java.lang.annotation.Repeatable(D2::class)
|
||||||
annotation class B2 {
|
annotation class B2 {
|
||||||
class Container
|
class Container
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ annotation class B1 {
|
|||||||
}
|
}
|
||||||
annotation class D1(val value: Array<B1>)
|
annotation class D1(val value: Array<B1>)
|
||||||
|
|
||||||
@Repeatable
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@Repeatable<!>
|
||||||
@java.lang.annotation.Repeatable(D2::class)
|
@java.lang.annotation.Repeatable(D2::class)
|
||||||
annotation class B2 {
|
annotation class B2 {
|
||||||
class Container
|
class Container
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@kotlin.annotation.Repeatable<!>
|
||||||
|
@java.lang.annotation.Repeatable(AContainer::class)
|
||||||
|
annotation class A
|
||||||
|
annotation class AContainer(val value: Array<A>)
|
||||||
|
|
||||||
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@kotlin.annotation.Repeatable<!>
|
||||||
|
@kotlin.jvm.JvmRepeatable(BContainer::class)
|
||||||
|
annotation class B
|
||||||
|
annotation class BContainer(val value: Array<B>)
|
||||||
|
|
||||||
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@kotlin.annotation.Repeatable<!>
|
||||||
|
<!REPEATED_ANNOTATION!>@kotlin.annotation.Repeatable<!>
|
||||||
|
@kotlin.jvm.JvmRepeatable(CContainer::class)
|
||||||
|
<!REPEATED_ANNOTATION!>@java.lang.annotation.Repeatable(CContainer::class)<!>
|
||||||
|
annotation class C
|
||||||
|
annotation class CContainer(val value: Array<C>)
|
||||||
|
|
||||||
|
typealias AlphaRepeatable = kotlin.annotation.Repeatable
|
||||||
|
typealias BetaRepeatable = kotlin.jvm.JvmRepeatable
|
||||||
|
|
||||||
|
<!REDUNDANT_REPEATABLE_ANNOTATION!>@AlphaRepeatable<!>
|
||||||
|
@BetaRepeatable(DContainer::class)
|
||||||
|
annotation class D
|
||||||
|
annotation class DContainer(val value: Array<D>)
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
@kotlin.annotation.Repeatable @java.lang.annotation.Repeatable(value = AContainer::class) public final annotation class A : kotlin.Annotation {
|
||||||
|
public constructor A()
|
||||||
|
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 annotation class AContainer : kotlin.Annotation {
|
||||||
|
public constructor AContainer(/*0*/ value: kotlin.Array<A>)
|
||||||
|
public final val value: kotlin.Array<A>
|
||||||
|
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.annotation.Repeatable @kotlin.jvm.JvmRepeatable /* = java.lang.annotation.Repeatable */(value = BContainer::class) public final annotation class B : kotlin.Annotation {
|
||||||
|
public constructor B()
|
||||||
|
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 annotation class BContainer : kotlin.Annotation {
|
||||||
|
public constructor BContainer(/*0*/ value: kotlin.Array<B>)
|
||||||
|
public final val value: kotlin.Array<B>
|
||||||
|
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.annotation.Repeatable @kotlin.annotation.Repeatable @kotlin.jvm.JvmRepeatable /* = java.lang.annotation.Repeatable */(value = CContainer::class) @java.lang.annotation.Repeatable(value = CContainer::class) public final annotation class C : kotlin.Annotation {
|
||||||
|
public constructor C()
|
||||||
|
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 annotation class CContainer : kotlin.Annotation {
|
||||||
|
public constructor CContainer(/*0*/ value: kotlin.Array<C>)
|
||||||
|
public final val value: kotlin.Array<C>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
@AlphaRepeatable /* = kotlin.annotation.Repeatable */ @BetaRepeatable /* = java.lang.annotation.Repeatable */(value = DContainer::class) public final annotation class D : kotlin.Annotation {
|
||||||
|
public constructor D()
|
||||||
|
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 annotation class DContainer : kotlin.Annotation {
|
||||||
|
public constructor DContainer(/*0*/ value: kotlin.Array<D>)
|
||||||
|
public final val value: kotlin.Array<D>
|
||||||
|
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 typealias AlphaRepeatable = kotlin.annotation.Repeatable
|
||||||
|
public typealias BetaRepeatable = kotlin.jvm.JvmRepeatable
|
||||||
|
|
||||||
Generated
+6
@@ -34956,6 +34956,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleRepeatables.kt")
|
||||||
|
public void testMultipleRepeatables() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/multipleRepeatables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("qualifiedCallValue.kt")
|
@TestMetadata("qualifiedCallValue.kt")
|
||||||
public void testQualifiedCallValue() throws Exception {
|
public void testQualifiedCallValue() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user