FirAnnotationArgumentChecker: handle conversion calls properly

This commit is contained in:
Mikhail Glukhikh
2020-10-05 15:14:22 +03:00
parent 6f432ea5dd
commit f6b49a2c9a
2 changed files with 25 additions and 7 deletions
@@ -19,5 +19,5 @@ val depth: Int = 42
annotation class KotlinMagicConstant(val intValues: LongArray) annotation class KotlinMagicConstant(val intValues: LongArray)
@KotlinMagicConstant(intValues = <!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>[StepRequest.STEP_INTO.<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>toLong()<!>, StepRequest.STEP_OVER.<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>toLong()<!>, StepRequest.STEP_OUT.<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>toLong()<!>]<!>) @KotlinMagicConstant(intValues = [StepRequest.STEP_INTO.toLong(), StepRequest.STEP_OVER.toLong(), StepRequest.STEP_OUT.toLong()])
val kotlinDepth: Int = 42 val kotlinDepth: Int = 42
@@ -19,7 +19,10 @@ import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES
import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS
@@ -140,18 +143,19 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
} }
expression is FirFunctionCall -> { expression is FirFunctionCall -> {
val calleeReference = expression.calleeReference val calleeReference = expression.calleeReference
if (calleeReference is FirErrorNamedReference) if (calleeReference is FirErrorNamedReference) {
return null return null
if (expression.typeRef.coneType.classId == StandardClassIds.KClass) }
if (expression.typeRef.coneType.classId == StandardClassIds.KClass) {
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
}
//TODO: UNRESOLVED REFERENCE //TODO: UNRESOLVED REFERENCE
if (expression.dispatchReceiver is FirThisReceiverExpression) if (expression.dispatchReceiver is FirThisReceiverExpression) {
return null return null
}
when (calleeReference.name) { when (calleeReference.name) {
TO_STRING ->
return checkAnnotationArgument(expression.dispatchReceiver, session)
in BINARY_OPERATION_NAMES, in UNARY_OPERATION_NAMES -> { in BINARY_OPERATION_NAMES, in UNARY_OPERATION_NAMES -> {
val receiverClassId = expression.dispatchReceiver.typeRef.coneType.classId val receiverClassId = expression.dispatchReceiver.typeRef.coneType.classId
@@ -167,8 +171,18 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
checkAnnotationArgument(exp, session)?.let { return it } checkAnnotationArgument(exp, session)?.let { return it }
} }
} }
else -> else -> {
if (expression.arguments.isNotEmpty() || calleeReference !is FirResolvedNamedReference) {
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
}
val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
if (calleeReference.name == TO_STRING ||
calleeReference.name in CONVERSION_NAMES && symbol?.callableId?.packageName?.asString() == "kotlin"
) {
return checkAnnotationArgument(expression.dispatchReceiver, session)
}
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
}
} }
} }
expression is FirQualifiedAccessExpression -> { expression is FirQualifiedAccessExpression -> {
@@ -242,4 +256,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
) { ) {
source?.let { report(factory.on(it)) } source?.let { report(factory.on(it)) }
} }
private val CONVERSION_NAMES = listOf(
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
).mapTo(hashSetOf()) { Name.identifier(it) }
} }