[FIR] Properly check constructor call in FirConstCheckVisitor
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// Should be something like TYPE_MISMATCH here
|
// Should be something like TYPE_MISMATCH here
|
||||||
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@file:Some(return x)<!>
|
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@file:Some(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>return x<!>)<!>
|
||||||
|
|
||||||
const val x = 42
|
const val x = 42
|
||||||
|
|
||||||
|
|||||||
+32
-33
@@ -44,36 +44,7 @@ internal fun checkConstantArguments(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
): ConstantArgumentKind {
|
): ConstantArgumentKind {
|
||||||
if (expression == null) return ConstantArgumentKind.VALID_CONST
|
if (expression == null) return ConstantArgumentKind.VALID_CONST
|
||||||
|
return expression.accept(FirConstCheckVisitor(session), null)
|
||||||
val firConstCheckVisitor = FirConstCheckVisitor(session)
|
|
||||||
|
|
||||||
val expressionSymbol = expression.toReference()?.toResolvedCallableSymbol(discardErrorReference = true)
|
|
||||||
val classKindOfParent = with(firConstCheckVisitor) {
|
|
||||||
(expressionSymbol?.getReferencedClassSymbol() as? FirRegularClassSymbol)?.classKind
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FirExpression.getExpandedType() = resolvedType.fullyExpandedType(session)
|
|
||||||
|
|
||||||
when {
|
|
||||||
expressionSymbol is FirConstructorSymbol && classKindOfParent == ClassKind.ANNOTATION_CLASS -> {
|
|
||||||
return ConstantArgumentKind.VALID_CONST
|
|
||||||
}
|
|
||||||
expressionSymbol == null -> {
|
|
||||||
return ConstantArgumentKind.VALID_CONST
|
|
||||||
}
|
|
||||||
expressionSymbol is FirConstructorSymbol -> {
|
|
||||||
if (expression is FirCallableReferenceAccess) return ConstantArgumentKind.VALID_CONST
|
|
||||||
if (expression.getExpandedType().isUnsignedType) {
|
|
||||||
(expression as FirFunctionCall).arguments.forEach { argumentExpression ->
|
|
||||||
checkConstantArguments(argumentExpression, session).ifNotValidConst { return it }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return ConstantArgumentKind.NOT_CONST
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> return expression.accept(firConstCheckVisitor, null)
|
|
||||||
}
|
|
||||||
return ConstantArgumentKind.VALID_CONST
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum class ConstantArgumentKind {
|
internal enum class ConstantArgumentKind {
|
||||||
@@ -276,8 +247,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
|
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
|
||||||
val symbol = calleeReference.resolvedSymbol as? FirNamedFunctionSymbol ?: return ConstantArgumentKind.NOT_CONST
|
return when (val symbol = calleeReference.resolvedSymbol) {
|
||||||
|
is FirNamedFunctionSymbol -> visitNamedFunction(functionCall, symbol)
|
||||||
|
is FirConstructorSymbol -> visitConstructorCall(functionCall, symbol)
|
||||||
|
else -> ConstantArgumentKind.NOT_CONST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitNamedFunction(functionCall: FirFunctionCall, symbol: FirNamedFunctionSymbol): ConstantArgumentKind {
|
||||||
if (!symbol.canBeEvaluated() && !functionCall.isCompileTimeBuiltinCall()) {
|
if (!symbol.canBeEvaluated() && !functionCall.isCompileTimeBuiltinCall()) {
|
||||||
return ConstantArgumentKind.NOT_CONST
|
return ConstantArgumentKind.NOT_CONST
|
||||||
}
|
}
|
||||||
@@ -290,12 +267,26 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
|
|||||||
return ConstantArgumentKind.NOT_CONST
|
return ConstantArgumentKind.NOT_CONST
|
||||||
}
|
}
|
||||||
|
|
||||||
exp.accept(this, data).ifNotValidConst { return it }
|
exp.accept(this, null).ifNotValidConst { return it }
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConstantArgumentKind.VALID_CONST
|
return ConstantArgumentKind.VALID_CONST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun visitConstructorCall(constructorCall: FirFunctionCall, symbol: FirConstructorSymbol): ConstantArgumentKind {
|
||||||
|
val classKindOfParent = (symbol.getReferencedClassSymbol() as? FirRegularClassSymbol)?.classKind
|
||||||
|
return when {
|
||||||
|
classKindOfParent == ClassKind.ANNOTATION_CLASS -> ConstantArgumentKind.VALID_CONST
|
||||||
|
constructorCall.getExpandedType().isUnsignedType -> {
|
||||||
|
constructorCall.arguments.forEach { argumentExpression ->
|
||||||
|
argumentExpression.accept(this, null).ifNotValidConst { return it }
|
||||||
|
}
|
||||||
|
ConstantArgumentKind.VALID_CONST
|
||||||
|
}
|
||||||
|
else -> ConstantArgumentKind.NOT_CONST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitQualifiedAccessExpression(
|
override fun visitQualifiedAccessExpression(
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?
|
qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?
|
||||||
): ConstantArgumentKind {
|
): ConstantArgumentKind {
|
||||||
@@ -307,6 +298,14 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
|
|||||||
return ConstantArgumentKind.VALID_CONST
|
return ConstantArgumentKind.VALID_CONST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: Nothing?): ConstantArgumentKind {
|
||||||
|
return ConstantArgumentKind.VALID_CONST
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Nothing?): ConstantArgumentKind {
|
||||||
|
return visitQualifiedAccessExpression(callableReferenceAccess, data)
|
||||||
|
}
|
||||||
|
|
||||||
// --- Utils ---
|
// --- Utils ---
|
||||||
private fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
|
private fun FirBasedSymbol<*>.canBeEvaluated(): Boolean {
|
||||||
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session)
|
return intrinsicConstEvaluation && this.hasAnnotation(StandardClassIds.Annotations.IntrinsicConstEvaluation, session)
|
||||||
@@ -352,7 +351,7 @@ private class FirConstCheckVisitor(private val session: FirSession) : FirVisitor
|
|||||||
return this?.callableId?.packageName?.asString() == "kotlin"
|
return this?.callableId?.packageName?.asString() == "kotlin"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? =
|
private fun FirCallableSymbol<*>?.getReferencedClassSymbol(): FirBasedSymbol<*>? =
|
||||||
this?.resolvedReturnTypeRef
|
this?.resolvedReturnTypeRef
|
||||||
?.coneTypeSafe<ConeLookupTagBasedType>()
|
?.coneTypeSafe<ConeLookupTagBasedType>()
|
||||||
?.lookupTag
|
?.lookupTag
|
||||||
|
|||||||
+2
-2
@@ -3,14 +3,14 @@
|
|||||||
@Target(AnnotationTarget.TYPE)
|
@Target(AnnotationTarget.TYPE)
|
||||||
annotation class Ann(val x: Int)
|
annotation class Ann(val x: Int)
|
||||||
|
|
||||||
class A<T: @Ann(<!ARGUMENT_TYPE_MISMATCH!>{
|
class A<T: @Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{
|
||||||
fun local() = 1
|
fun local() = 1
|
||||||
var result = local()
|
var result = local()
|
||||||
result += 1
|
result += 1
|
||||||
result
|
result
|
||||||
}<!>) Any>
|
}<!>) Any>
|
||||||
|
|
||||||
fun f(x: @Ann(<!ARGUMENT_TYPE_MISMATCH!>{
|
fun f(x: @Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{
|
||||||
fun local() = 1
|
fun local() = 1
|
||||||
var result = local()
|
var result = local()
|
||||||
result += 1
|
result += 1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ISSUE: KT-59110
|
// ISSUE: KT-59110
|
||||||
|
|
||||||
<!WRONG_ANNOTATION_TARGET!>@Target(<!ARGUMENT_TYPE_MISMATCH!>{}<!>)<!>
|
<!WRONG_ANNOTATION_TARGET!>@Target(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, ARGUMENT_TYPE_MISMATCH!>{}<!>)<!>
|
||||||
interface SomeInterface {
|
interface SomeInterface {
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user