FIR: report ANNOTATION_CLASS_CONSTRUCTOR_CALL diagnostic

This commit is contained in:
Mikhail Glukhikh
2021-05-11 16:14:40 +03:00
parent 3663884db2
commit 0d6bc7e7b2
15 changed files with 54 additions and 38 deletions
@@ -153,6 +153,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val LOCAL_ANNOTATION_CLASS_ERROR by error<KtClassOrObject>() val LOCAL_ANNOTATION_CLASS_ERROR by error<KtClassOrObject>()
val MISSING_VAL_ON_ANNOTATION_PARAMETER by error<KtParameter>() val MISSING_VAL_ON_ANNOTATION_PARAMETER by error<KtParameter>()
val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by error<KtExpression>() val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by error<KtExpression>()
val ANNOTATION_CLASS_CONSTRUCTOR_CALL by error<KtCallExpression>()
val NOT_AN_ANNOTATION_CLASS by error<PsiElement> { val NOT_AN_ANNOTATION_CLASS by error<PsiElement> {
parameter<String>("annotationName") parameter<String>("annotationName")
} }
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.psi.KtAnnotation
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -162,6 +163,7 @@ object FirErrors {
val LOCAL_ANNOTATION_CLASS_ERROR by error0<KtClassOrObject>() val LOCAL_ANNOTATION_CLASS_ERROR by error0<KtClassOrObject>()
val MISSING_VAL_ON_ANNOTATION_PARAMETER by error0<KtParameter>() val MISSING_VAL_ON_ANNOTATION_PARAMETER by error0<KtParameter>()
val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by error0<KtExpression>() val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by error0<KtExpression>()
val ANNOTATION_CLASS_CONSTRUCTOR_CALL by error0<KtCallExpression>()
val NOT_AN_ANNOTATION_CLASS by error1<PsiElement, String>() val NOT_AN_ANNOTATION_CLASS by error1<PsiElement, String>()
val NULLABLE_TYPE_OF_ANNOTATION_MEMBER by error0<KtTypeReference>() val NULLABLE_TYPE_OF_ANNOTATION_MEMBER by error0<KtTypeReference>()
val VAR_ANNOTATION_PARAMETER by error0<KtParameter>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) val VAR_ANNOTATION_PARAMETER by error0<KtParameter>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isAbstract import org.jetbrains.kotlin.fir.declarations.isAbstract
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
@@ -23,8 +25,20 @@ object FirConstructorCallChecker : FirFunctionCallChecker() {
(expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol ?: return (expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol ?: return
val declarationClass = constructorSymbol.fir.returnTypeRef.coneType.toRegularClass(context.session) val declarationClass = constructorSymbol.fir.returnTypeRef.coneType.toRegularClass(context.session)
if (declarationClass != null && declarationClass.isAbstract && declarationClass.classKind == ClassKind.CLASS) { if (declarationClass != null) {
reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context) if (declarationClass.isAbstract && declarationClass.classKind == ClassKind.CLASS) {
reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context)
}
if (declarationClass.classKind == ClassKind.ANNOTATION_CLASS &&
context.qualifiedAccessOrAnnotationCalls.all { call ->
call !is FirAnnotationCall
} &&
context.containingDeclarations.all { klass ->
klass !is FirRegularClass || klass.classKind != ClassKind.ANNOTATION_CLASS
}
) {
reporter.reportOn(expression.source, FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL, context)
}
} }
} }
} }
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT
@@ -445,6 +446,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(NULLABLE_TYPE_OF_ANNOTATION_MEMBER, "An annotation parameter cannot be nullable") map.put(NULLABLE_TYPE_OF_ANNOTATION_MEMBER, "An annotation parameter cannot be nullable")
map.put(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member") map.put(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member")
map.put(VAR_ANNOTATION_PARAMETER, "An annotation parameter cannot be 'var'") map.put(VAR_ANNOTATION_PARAMETER, "An annotation parameter cannot be 'var'")
map.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated");
map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING) map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING)
map.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes") map.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes")
map.put( map.put(
@@ -13,19 +13,19 @@ annotation class Ann4(val value: String)
@Ann4("a") class MyClass @Ann4("a") class MyClass
fun foo() { fun foo() {
Ann() <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>
val a = Ann() val a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>
Ann1(<!NO_VALUE_FOR_PARAMETER!>)<!> Ann1(<!NO_VALUE_FOR_PARAMETER!>)<!>
Ann1(1) <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann1(1)<!>
bar(Ann()) bar(<!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>)
bar(a = Ann()) bar(a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>)
val ann = javaClass<MyClass>().getAnnotation(javaClass<Ann4>()) val ann = javaClass<MyClass>().getAnnotation(javaClass<Ann4>())
ann!!.value() ann!!.value()
} }
fun bar(a: Ann = Ann()) { fun bar(a: Ann = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>) {
if (<!USELESS_IS_CHECK!>a is Ann<!>) {} if (<!USELESS_IS_CHECK!>a is Ann<!>) {}
} }
@@ -7,8 +7,8 @@ val test1a = <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>AbstractClass()<!>
annotation class AnnotationClass annotation class AnnotationClass
typealias Test2 = AnnotationClass typealias Test2 = AnnotationClass
val test2 = Test2() val test2 = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Test2()<!>
val test2a = AnnotationClass() val test2a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>AnnotationClass()<!>
enum class EnumClass { VALUE1, VALUE2 } enum class EnumClass { VALUE1, VALUE2 }
typealias Test3 = EnumClass typealias Test3 = EnumClass
@@ -21,4 +21,4 @@ annotation class AnnAnn(val i: Array<Ann>)
@AnnAnn(arrayOf(Ann(intArrayOf(1)))) @AnnAnn(arrayOf(Ann(intArrayOf(1))))
@AnnAnn(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>iAnn<!>)<!>) @AnnAnn(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>iAnn<!>)<!>)
class TestAnn class TestAnn
val iAnn = Ann(intArrayOf(1)) val iAnn = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann(intArrayOf(1))<!>
@@ -1,27 +0,0 @@
@Retention(AnnotationRetention.SOURCE)
@Repeatable
annotation class Ann(vararg val i: Int)
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>)
@Ann(i2)
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)
@Ann(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>)<!>)
@Ann(*intArrayOf(i2))
@Ann(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
@Ann(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
class Test
var i = 1
const val i2 = 1
val i3 = foo()
fun foo(): Int = 1
@Retention(AnnotationRetention.SOURCE)
@Repeatable
annotation class AnnAnn(vararg val i: Ann)
@AnnAnn(*arrayOf(Ann(1)))
@AnnAnn(*<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>arrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>iAnn<!>)<!>)
class TestAnn
val iAnn = Ann(1)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
@Repeatable @Repeatable
annotation class Ann(vararg val i: Int) annotation class Ann(vararg val i: Int)
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package Test.SubTest.AnotherTest package Test.SubTest.AnotherTest
open class TestClass { open class TestClass {
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package some package some
annotation class AnnComplete annotation class AnnComplete
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package some package some
annotation class AnnComplete annotation class AnnComplete
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.psi.KtAnnotation
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -519,6 +520,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL) { firDiagnostic ->
AnnotationClassConstructorCallImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.NOT_AN_ANNOTATION_CLASS) { firDiagnostic -> add(FirErrors.NOT_AN_ANNOTATION_CLASS) { firDiagnostic ->
NotAnAnnotationClassImpl( NotAnAnnotationClassImpl(
firDiagnostic.a, firDiagnostic.a,
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.psi.KtAnnotation
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -374,6 +375,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = NonConstValUsedInConstantExpression::class override val diagnosticClass get() = NonConstValUsedInConstantExpression::class
} }
abstract class AnnotationClassConstructorCall : KtFirDiagnostic<KtCallExpression>() {
override val diagnosticClass get() = AnnotationClassConstructorCall::class
}
abstract class NotAnAnnotationClass : KtFirDiagnostic<PsiElement>() { abstract class NotAnAnnotationClass : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = NotAnAnnotationClass::class override val diagnosticClass get() = NotAnAnnotationClass::class
abstract val annotationName: String abstract val annotationName: String
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.KtAnnotation
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -603,6 +604,13 @@ internal class NonConstValUsedInConstantExpressionImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class AnnotationClassConstructorCallImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.AnnotationClassConstructorCall(), KtAbstractFirDiagnostic<KtCallExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NotAnAnnotationClassImpl( internal class NotAnAnnotationClassImpl(
override val annotationName: String, override val annotationName: String,
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,