FIR: introduce three diagnostics for const val
This commit is contained in:
committed by
Mikhail Glukhikh
parent
cc106085e2
commit
334d0a8b5a
+5
@@ -946,6 +946,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("const.kt")
|
||||
public void testConst() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/constVal/const.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("constValNotTopLevelOrObject.kt")
|
||||
public void testConstValNotTopLevelOrObject() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt");
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
FILE: const.kt
|
||||
public final const val a: R|kotlin/String| = String(something)
|
||||
public get(): R|kotlin/String|
|
||||
public final const val b: <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
|
||||
public get(): <ERROR TYPE REF: Cannot infer variable type without initializer / getter / delegate>
|
||||
public final const val c: R|kotlin/Nothing?| = Null(null)
|
||||
public get(): R|kotlin/Nothing?|
|
||||
public final const val d: R|ForConst.Companion| = Q|ForConst|
|
||||
public get(): R|ForConst.Companion|
|
||||
public final const val e: R|kotlin/String| = Q|ForConst|.R|/ForConst.Companion.one|()
|
||||
public get(): R|kotlin/String|
|
||||
public final const val f: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(2)).R|kotlin/Int.times|(Int(3)).R|kotlin/Int.div|(Int(4)).R|kotlin/Int.rem|(Int(5)).R|kotlin/Int.minus|(Int(1))
|
||||
public get(): R|kotlin/Int|
|
||||
public final const val g: R|kotlin/String| = <strcat>(String(string ), R|/f|.R|kotlin/Any.toString|())
|
||||
public get(): R|kotlin/String|
|
||||
public final const val h: R|kotlin/String| = String(string).R|kotlin/String.plus|(R|/g|)
|
||||
public get(): R|kotlin/String|
|
||||
public final const val i: R|kotlin/String| = Q|ForConst|.R|/ForConst.Companion.one|().R|kotlin/String.plus|(String(one))
|
||||
public get(): R|kotlin/String|
|
||||
public final const val j: R|kotlin/Int| = Int(4).R|kotlin/Int.times|(Q|ForConst|.R|/ForConst.Companion.two|())
|
||||
public get(): R|kotlin/Int|
|
||||
public final val k: R|kotlin/Int| = Int(3).R|kotlin/Int.minus|(Q|ForConst|.R|/ForConst.Companion.two|())
|
||||
public get(): R|kotlin/Int|
|
||||
public final const val l: R|kotlin/Int| = R|/k|
|
||||
public get(): R|kotlin/Int|
|
||||
public final class ForConst : R|kotlin/Any| {
|
||||
public constructor(): R|ForConst| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final companion object Companion : R|kotlin/Any| {
|
||||
private constructor(): R|ForConst.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun one(): R|kotlin/String| {
|
||||
^one String(1)
|
||||
}
|
||||
|
||||
public final fun two(): R|kotlin/Int| {
|
||||
^two Int(2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private final const val MAJOR_BITS: R|kotlin/Int| = Int(3)
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val MINOR_BITS: R|kotlin/Int| = Int(4)
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val PATCH_BITS: R|kotlin/Int| = Int(7)
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val MAJOR_MASK: R|kotlin/Int| = Int(1).R|kotlin/Int.shl|(R|/MAJOR_BITS|).R|kotlin/Int.minus|(Int(1))
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val MINOR_MASK: R|kotlin/Int| = Int(1).R|kotlin/Int.shl|(R|/MINOR_BITS|).R|kotlin/Int.minus|(Int(1))
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val PATCH_MASK: R|kotlin/Int| = Int(1).R|kotlin/Int.shl|(R|/PATCH_BITS|).R|kotlin/Int.minus|(Int(1))
|
||||
private get(): R|kotlin/Int|
|
||||
private final const val stringFromJava: R|kotlin/String| = Q|Constants|.R|/Constants.FIRST|.R|kotlin/String.plus|(String(+)).R|kotlin/String.plus|(Q|Constants|.R|/Constants.SECOND|)
|
||||
private get(): R|kotlin/String|
|
||||
@@ -0,0 +1,36 @@
|
||||
// FILE: Constants.java
|
||||
|
||||
public class Constants {
|
||||
public static final String FIRST = "1st";
|
||||
public static final String SECOND = "2nd";
|
||||
}
|
||||
|
||||
// FILE: const.kt
|
||||
const val a = "something"
|
||||
<!MUST_BE_INITIALIZED!><!CONST_VAL_WITHOUT_INITIALIZER!>const<!> val b<!>
|
||||
<!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val c = null
|
||||
<!TYPE_CANT_BE_USED_FOR_CONST_VAL!>const<!> val d = ForConst
|
||||
const val e = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>ForConst.one()<!>
|
||||
const val f = ((1 + 2) * 3) / 4 % 5 - 1
|
||||
const val g = "string $f"
|
||||
const val h = "string" + g
|
||||
const val i = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>ForConst.one() + "one"<!>
|
||||
const val j = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>4 * ForConst.two()<!>
|
||||
val k = 3 - ForConst.two()
|
||||
const val l = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>k<!>
|
||||
|
||||
class ForConst{
|
||||
companion object {
|
||||
fun one(): String = "1"
|
||||
fun two(): Int = 2
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAJOR_BITS = 3
|
||||
private const val MINOR_BITS = 4
|
||||
private const val PATCH_BITS = 7
|
||||
private const val MAJOR_MASK = (1 shl MAJOR_BITS) - 1 // False positive error
|
||||
private const val MINOR_MASK = (1 shl MINOR_BITS) - 1 // False positive error
|
||||
private const val PATCH_MASK = (1 shl PATCH_BITS) - 1 // False positive error
|
||||
|
||||
private const val stringFromJava = Constants.FIRST + "+" + Constants.SECOND
|
||||
+6
@@ -1093,6 +1093,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("const.kt")
|
||||
public void testConst() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/constVal/const.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constValNotTopLevelOrObject.kt")
|
||||
public void testConstValNotTopLevelOrObject() throws Exception {
|
||||
|
||||
+6
@@ -1102,6 +1102,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("const.kt")
|
||||
public void testConst() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/constVal/const.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constValNotTopLevelOrObject.kt")
|
||||
public void testConstValNotTopLevelOrObject() throws Exception {
|
||||
|
||||
+5
@@ -496,6 +496,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error<FirSourceElement, KtProperty>(PositioningStrategy.CONST_MODIFIER)
|
||||
val CONST_VAL_WITH_GETTER by error<FirSourceElement, KtProperty>()
|
||||
val CONST_VAL_WITH_DELEGATE by error<FirSourceElement, KtPropertyDelegate>()
|
||||
val TYPE_CANT_BE_USED_FOR_CONST_VAL by error<FirSourceElement, KtProperty>(PositioningStrategy.CONST_MODIFIER) {
|
||||
parameter<ConeKotlinType>("constValType")
|
||||
}
|
||||
val CONST_VAL_WITHOUT_INITIALIZER by error<FirSourceElement, KtProperty>(PositioningStrategy.CONST_MODIFIER)
|
||||
val CONST_VAL_WITH_NON_CONST_INITIALIZER by error<FirSourceElement, KtExpression>()
|
||||
val WRONG_SETTER_PARAMETER_TYPE by error<FirSourceElement, KtTypeReference> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
|
||||
@@ -312,6 +312,9 @@ object FirErrors {
|
||||
val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.CONST_MODIFIER)
|
||||
val CONST_VAL_WITH_GETTER by error0<FirSourceElement, KtProperty>()
|
||||
val CONST_VAL_WITH_DELEGATE by error0<FirSourceElement, KtPropertyDelegate>()
|
||||
val TYPE_CANT_BE_USED_FOR_CONST_VAL by error1<FirSourceElement, KtProperty, ConeKotlinType>(SourceElementPositioningStrategies.CONST_MODIFIER)
|
||||
val CONST_VAL_WITHOUT_INITIALIZER by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.CONST_MODIFIER)
|
||||
val CONST_VAL_WITH_NON_CONST_INITIALIZER by error0<FirSourceElement, KtExpression>()
|
||||
val WRONG_SETTER_PARAMETER_TYPE by error2<FirSourceElement, KtTypeReference, ConeKotlinType, ConeKotlinType>()
|
||||
val INITIALIZER_TYPE_MISMATCH by error2<FirSourceElement, KtProperty, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.ASSIGNMENT_VALUE)
|
||||
|
||||
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun ConeKotlinType.canBeUsedForConstVal(): Boolean {
|
||||
val classId = if (this is ConeFlexibleType) {
|
||||
val lb = this.lowerBoundIfFlexible()
|
||||
if (lb is ConeClassLikeType) lb.lookupTag.classId
|
||||
else this.classId
|
||||
} else this.classId
|
||||
return (classId in StandardClassIds.primitiveTypes || classId in StandardClassIds.unsignedTypes) && !this.isNullable ||
|
||||
classId == StandardClassIds.String
|
||||
}
|
||||
|
||||
internal fun checkConstantArguments(
|
||||
expression: FirExpression,
|
||||
session: FirSession,
|
||||
): ConstantArgumentKind? {
|
||||
val expressionSymbol = expression.toResolvedCallableSymbol()
|
||||
?.fir
|
||||
val classKindOfParent = (expressionSymbol
|
||||
?.getReferencedClass(session) as? FirRegularClass)
|
||||
?.classKind
|
||||
|
||||
when {
|
||||
expression is FirTypeOperatorCall -> {
|
||||
if (expression.operation == FirOperation.AS) return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
expression is FirConstExpression<*>
|
||||
|| expressionSymbol is FirEnumEntry
|
||||
|| (expressionSymbol as? FirMemberDeclaration)?.isConst == true
|
||||
|| expressionSymbol is FirConstructor && classKindOfParent == ClassKind.ANNOTATION_CLASS -> {
|
||||
//DO NOTHING
|
||||
}
|
||||
classKindOfParent == ClassKind.ENUM_CLASS -> {
|
||||
return ConstantArgumentKind.ENUM_NOT_CONST
|
||||
}
|
||||
expression is FirComparisonExpression -> {
|
||||
return checkConstantArguments(expression.compareToCall, session)
|
||||
}
|
||||
expression is FirIntegerOperatorCall -> {
|
||||
for (exp in (expression as FirCall).arguments.plus(expression.dispatchReceiver))
|
||||
checkConstantArguments(exp, session).let { return it }
|
||||
}
|
||||
expression is FirStringConcatenationCall || expression is FirEqualityOperatorCall -> {
|
||||
for (exp in (expression as FirCall).arguments)
|
||||
checkConstantArguments(exp, session).let { return it }
|
||||
}
|
||||
(expression is FirGetClassCall) -> {
|
||||
var coneType = (expression as? FirCall)
|
||||
?.argument
|
||||
?.typeRef
|
||||
?.coneType
|
||||
|
||||
if (coneType is ConeClassErrorType)
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
|
||||
while (coneType?.classId == StandardClassIds.Array)
|
||||
coneType = (coneType.lowerBoundIfFlexible().typeArguments.first() as? ConeKotlinTypeProjection)?.type ?: break
|
||||
|
||||
return when {
|
||||
coneType is ConeTypeParameterType ->
|
||||
ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
|
||||
(expression as FirCall).argument !is FirResolvedQualifier ->
|
||||
ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
expressionSymbol == null -> {
|
||||
//DO NOTHING
|
||||
}
|
||||
expressionSymbol is FirField -> {
|
||||
//TODO: fix checking of Java fields initializer
|
||||
if (
|
||||
!(expressionSymbol as FirMemberDeclaration).status.isStatic
|
||||
|| (expressionSymbol as FirMemberDeclaration).status.modality != Modality.FINAL
|
||||
)
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
expression is FirFunctionCall -> {
|
||||
val calleeReference = expression.calleeReference
|
||||
if (calleeReference is FirErrorNamedReference) {
|
||||
return null
|
||||
}
|
||||
if (expression.typeRef.coneType.classId == StandardClassIds.KClass) {
|
||||
return ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
}
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
if (expression.dispatchReceiver is FirThisReceiverExpression) {
|
||||
return null
|
||||
}
|
||||
|
||||
when (calleeReference.name) {
|
||||
in OperatorNameConventions.BINARY_OPERATION_NAMES, in OperatorNameConventions.UNARY_OPERATION_NAMES,
|
||||
OperatorNameConventions.SHL, OperatorNameConventions.SHR, OperatorNameConventions.USHR,
|
||||
OperatorNameConventions.OR, OperatorNameConventions.AND -> {
|
||||
val coneType =
|
||||
expression.dispatchReceiver.typeRef.coneTypeSafe<ConeKotlinType>() ?: return ConstantArgumentKind.NOT_CONST
|
||||
val receiverClassId = coneType.lowerBoundIfFlexible().classId
|
||||
|
||||
|
||||
if ((calleeReference.name == OperatorNameConventions.DIV || calleeReference.name == OperatorNameConventions.REM)
|
||||
&& expression.typeRef.coneType.classId == StandardClassIds.Int
|
||||
) {
|
||||
val value = expression.arguments.first() as? FirConstExpression<*>
|
||||
if (value?.value == 0L) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
}
|
||||
|
||||
for (exp in (expression as FirCall).arguments.plus(expression.dispatchReceiver)) {
|
||||
val expClassId = exp.typeRef.coneType.lowerBoundIfFlexible().classId
|
||||
|
||||
if (calleeReference.name == OperatorNameConventions.PLUS
|
||||
&& expClassId != receiverClassId
|
||||
&& (expClassId !in StandardClassIds.primitiveTypesAndString || receiverClassId !in StandardClassIds.primitiveTypesAndString)
|
||||
) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
checkConstantArguments(exp, session)?.let { return it }
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if (expression.arguments.isNotEmpty() || calleeReference !is FirResolvedNamedReference) {
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
|
||||
if (calleeReference.name == OperatorNameConventions.TO_STRING ||
|
||||
calleeReference.name in CONVERSION_NAMES && symbol?.callableId?.packageName?.asString() == "kotlin"
|
||||
) {
|
||||
return checkConstantArguments(expression.dispatchReceiver, session)
|
||||
}
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
}
|
||||
}
|
||||
expression is FirQualifiedAccessExpression -> {
|
||||
|
||||
when {
|
||||
(expressionSymbol as FirProperty).isLocal || expressionSymbol.symbol.callableId.className?.isRoot == false ->
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
expression.typeRef.coneType.classId == StandardClassIds.KClass ->
|
||||
return ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
expression.dispatchReceiver is FirThisReceiverExpression ->
|
||||
return null
|
||||
}
|
||||
|
||||
return when ((expressionSymbol as? FirProperty)?.initializer) {
|
||||
is FirConstExpression<*> -> {
|
||||
if ((expressionSymbol as? FirVariable)?.isVal == true)
|
||||
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION
|
||||
else
|
||||
ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
is FirGetClassCall ->
|
||||
ConstantArgumentKind.NOT_KCLASS_LITERAL
|
||||
else ->
|
||||
ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
}
|
||||
else ->
|
||||
return ConstantArgumentKind.NOT_CONST
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun FirTypedDeclaration?.getReferencedClass(session: FirSession): FirSymbolOwner<*>? =
|
||||
this?.returnTypeRef
|
||||
?.coneTypeSafe<ConeLookupTagBasedType>()
|
||||
?.lookupTag
|
||||
?.toSymbol(session)
|
||||
?.fir
|
||||
|
||||
private val CONVERSION_NAMES = listOf(
|
||||
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
|
||||
).mapTo(hashSetOf()) { Name.identifier(it) }
|
||||
|
||||
internal enum class ConstantArgumentKind {
|
||||
NOT_CONST,
|
||||
ENUM_NOT_CONST,
|
||||
NOT_KCLASS_LITERAL,
|
||||
NOT_CONST_VAL_IN_CONST_EXPRESSION,
|
||||
KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
|
||||
}
|
||||
+10
-151
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
|
||||
@@ -78,158 +80,15 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
|
||||
?.let { reporter.reportOn(arg.source, it, context) }
|
||||
}
|
||||
else ->
|
||||
return checkAnnotationArgument(expression, session)
|
||||
return when (checkConstantArguments(expression, session)) {
|
||||
ConstantArgumentKind.NOT_CONST -> FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
ConstantArgumentKind.ENUM_NOT_CONST -> FirErrors.ANNOTATION_ARGUMENT_MUST_BE_ENUM_CONST
|
||||
ConstantArgumentKind.NOT_KCLASS_LITERAL -> FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
|
||||
ConstantArgumentKind.KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR -> FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
|
||||
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION -> FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkAnnotationArgument(
|
||||
expression: FirExpression,
|
||||
session: FirSession,
|
||||
): FirDiagnosticFactory0<FirSourceElement, KtExpression>? {
|
||||
val expressionSymbol = expression.toResolvedCallableSymbol()
|
||||
?.fir
|
||||
val classKindOfParent = (expressionSymbol
|
||||
?.getReferencedClass(session) as? FirRegularClass)
|
||||
?.classKind
|
||||
|
||||
when {
|
||||
expression is FirConstExpression<*>
|
||||
|| expressionSymbol is FirEnumEntry
|
||||
|| (expressionSymbol as? FirMemberDeclaration)?.isConst == true
|
||||
|| expressionSymbol is FirConstructor && classKindOfParent == ClassKind.ANNOTATION_CLASS -> {
|
||||
//DO NOTHING
|
||||
}
|
||||
classKindOfParent == ClassKind.ENUM_CLASS -> {
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_ENUM_CONST
|
||||
}
|
||||
expression is FirComparisonExpression -> {
|
||||
return checkAnnotationArgument(expression.compareToCall, session)
|
||||
}
|
||||
expression is FirIntegerOperatorCall -> {
|
||||
for (exp in (expression as FirCall).arguments.plus(expression.dispatchReceiver))
|
||||
checkAnnotationArgument(exp, session).let { return it }
|
||||
}
|
||||
expression is FirStringConcatenationCall || expression is FirEqualityOperatorCall -> {
|
||||
for (exp in (expression as FirCall).arguments)
|
||||
checkAnnotationArgument(exp, session).let { return it }
|
||||
}
|
||||
(expression is FirGetClassCall) -> {
|
||||
var coneType = (expression as? FirCall)
|
||||
?.argument
|
||||
?.typeRef
|
||||
?.coneType
|
||||
|
||||
if (coneType is ConeClassErrorType)
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
|
||||
while (coneType?.classId == StandardClassIds.Array)
|
||||
coneType = (coneType.lowerBoundIfFlexible().typeArguments.first() as? ConeKotlinTypeProjection)?.type ?: break
|
||||
|
||||
return when {
|
||||
coneType is ConeTypeParameterType ->
|
||||
FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
|
||||
(expression as FirCall).argument !is FirResolvedQualifier ->
|
||||
FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
expressionSymbol == null -> {
|
||||
//DO NOTHING
|
||||
}
|
||||
expressionSymbol is FirField -> {
|
||||
//TODO: fix checking of Java fields initializer
|
||||
if (
|
||||
!(expressionSymbol as FirMemberDeclaration).status.isStatic
|
||||
|| (expressionSymbol as FirMemberDeclaration).status.modality != Modality.FINAL
|
||||
)
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
}
|
||||
expression is FirFunctionCall -> {
|
||||
val calleeReference = expression.calleeReference
|
||||
if (calleeReference is FirErrorNamedReference) {
|
||||
return null
|
||||
}
|
||||
if (expression.typeRef.coneType.classId == StandardClassIds.KClass) {
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
|
||||
}
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
if (expression.dispatchReceiver is FirThisReceiverExpression) {
|
||||
return null
|
||||
}
|
||||
|
||||
when (calleeReference.name) {
|
||||
in BINARY_OPERATION_NAMES, in UNARY_OPERATION_NAMES -> {
|
||||
val receiverClassId = expression.dispatchReceiver.typeRef.coneType.classId
|
||||
|
||||
for (exp in (expression as FirCall).arguments.plus(expression.dispatchReceiver)) {
|
||||
val expClassId = exp.typeRef.coneType.classId
|
||||
|
||||
if (calleeReference.name == PLUS
|
||||
&& expClassId != receiverClassId
|
||||
&& (expClassId !in primitiveTypesAndString || receiverClassId !in primitiveTypesAndString)
|
||||
)
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
|
||||
checkAnnotationArgument(exp, session)?.let { return it }
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
expression is FirQualifiedAccessExpression -> {
|
||||
|
||||
when {
|
||||
(expressionSymbol as FirProperty).isLocal || expressionSymbol.symbol.callableId.className?.isRoot == false ->
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
expression.typeRef.coneType.classId == StandardClassIds.KClass ->
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
|
||||
|
||||
//TODO: UNRESOLVED REFERENCE
|
||||
expression.dispatchReceiver is FirThisReceiverExpression ->
|
||||
return null
|
||||
}
|
||||
|
||||
return when ((expressionSymbol as? FirProperty)?.initializer) {
|
||||
is FirConstExpression<*> -> {
|
||||
if ((expressionSymbol as? FirVariable)?.isVal == true)
|
||||
FirErrors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION
|
||||
else
|
||||
FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
}
|
||||
is FirGetClassCall ->
|
||||
FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
|
||||
else ->
|
||||
FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
}
|
||||
}
|
||||
else ->
|
||||
return FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun FirTypedDeclaration?.getReferencedClass(session: FirSession): FirSymbolOwner<*>? =
|
||||
this?.returnTypeRef
|
||||
?.coneTypeSafe<ConeLookupTagBasedType>()
|
||||
?.lookupTag
|
||||
?.toSymbol(session)
|
||||
?.fir
|
||||
|
||||
private val CONVERSION_NAMES = listOf(
|
||||
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
|
||||
).mapTo(hashSetOf()) { Name.identifier(it) }
|
||||
}
|
||||
|
||||
+25
-6
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.canBeUsedForConstVal
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
@@ -14,6 +16,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.isConst
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
object FirConstPropertyChecker : FirPropertyChecker() {
|
||||
@@ -30,19 +34,34 @@ object FirConstPropertyChecker : FirPropertyChecker() {
|
||||
val classKind = (context.containingDeclarations.lastOrNull() as? FirRegularClass)?.classKind
|
||||
if (classKind != ClassKind.OBJECT && context.containingDeclarations.size > 1) {
|
||||
reporter.reportOn(declaration.source, FirErrors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, context)
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.getter?.source?.kind !is FirFakeSourceElementKind) {
|
||||
reporter.reportOn(declaration.getter?.source, FirErrors.CONST_VAL_WITH_GETTER, context)
|
||||
val source = declaration.getter?.source
|
||||
if (source != null && source.kind !is FirFakeSourceElementKind) {
|
||||
reporter.reportOn(source, FirErrors.CONST_VAL_WITH_GETTER, context)
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.delegate != null) {
|
||||
reporter.reportOn(declaration.delegate?.source, FirErrors.CONST_VAL_WITH_DELEGATE, context)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Implement checkers for these errors (see ConstModifierChecker in FE1.0):
|
||||
// - TYPE_CANT_BE_USED_FOR_CONST_VAL
|
||||
// - CONST_VAL_WITHOUT_INITIALIZER
|
||||
// - CONST_VAL_WITH_NON_CONST_INITIALIZER
|
||||
val initializer = declaration.initializer
|
||||
if (initializer == null) {
|
||||
reporter.reportOn(declaration.source, FirErrors.CONST_VAL_WITHOUT_INITIALIZER, context)
|
||||
return
|
||||
}
|
||||
|
||||
val type = declaration.returnTypeRef.coneType
|
||||
if ((type !is ConeClassErrorType) && !type.canBeUsedForConstVal()) {
|
||||
reporter.reportOn(declaration.source, FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL, declaration.returnTypeRef.coneType, context)
|
||||
return
|
||||
}
|
||||
|
||||
if (checkConstantArguments(initializer, context.session) != null) {
|
||||
reporter.reportOn(initializer.source, FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -63,6 +63,11 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_UPPER_BOUNDS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITHOUT_INITIALIZER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_DELEGATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_GETTER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PROPERTY_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER
|
||||
@@ -214,6 +219,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT
|
||||
@@ -693,6 +699,13 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
)
|
||||
map.put(INITIALIZER_TYPE_MISMATCH, "Initializer type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
|
||||
|
||||
map.put(CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, "Const 'val' are only allowed on top level or in objects")
|
||||
map.put(CONST_VAL_WITH_GETTER, "Const 'val' should not have a getter")
|
||||
map.put(CONST_VAL_WITH_DELEGATE, "Const 'val' should not have a delegate")
|
||||
map.put(TYPE_CANT_BE_USED_FOR_CONST_VAL, "Const ''val'' has type ''{0}''. Only primitives and String are allowed", RENDER_TYPE)
|
||||
map.put(CONST_VAL_WITHOUT_INITIALIZER, "Const 'val' should have an initializer")
|
||||
map.put(CONST_VAL_WITH_NON_CONST_INITIALIZER, "Const 'val' initializer should be a constant value")
|
||||
|
||||
// Multi-platform projects
|
||||
map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body")
|
||||
map.put(EXPECTED_PROPERTY_INITIALIZER, "Expected property cannot have an initializer")
|
||||
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER
|
||||
|
||||
fun Int.mod(other: Int) = 10
|
||||
fun Int.floorDiv(other: Int): Int = 20
|
||||
|
||||
const val a1 = (-5).mod(2)
|
||||
const val b1 = 5.floorDiv(3)
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER
|
||||
|
||||
fun Int.mod(other: Int) = 10
|
||||
|
||||
@@ -17,6 +17,6 @@ val a11 = <!DIVISION_BY_ZERO!>1 / 0.0<!>
|
||||
val a12 = <!DIVISION_BY_ZERO!>1L / 0<!>
|
||||
|
||||
val b1: Byte = <!DIVISION_BY_ZERO!>1 / 0<!>
|
||||
@Ann(<!DIVISION_BY_ZERO!>1 / 0<!>) val b2 = 1
|
||||
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, DIVISION_BY_ZERO!>1 / 0<!>) val b2 = 1
|
||||
|
||||
annotation class Ann(val i : Int)
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class C {
|
||||
|
||||
final const val final = 11
|
||||
|
||||
const val withoutInitializer: Int
|
||||
<!CONST_VAL_WITHOUT_INITIALIZER!>const<!> val withoutInitializer: Int
|
||||
|
||||
init {
|
||||
withoutInitializer = 12
|
||||
@@ -70,20 +70,20 @@ class Outer {
|
||||
const val defaultGetter = 19
|
||||
<!CONST_VAL_WITH_GETTER!>get<!>
|
||||
|
||||
const val nonConstInitializer1 = foo()
|
||||
const val nonConstInitializer2 = 1 as String
|
||||
const val nonConstInitializer3 = 1.0 as String
|
||||
const val nonConstInitializer4 = 1 as Double
|
||||
const val nonConstInitializer5 = "2" as Int
|
||||
const val nonConstInitializer6 = 1/0
|
||||
const val nonConstInitializer7 = -1/0
|
||||
const val nonConstInitializer8 = 1/0 - 1/0
|
||||
const val nonConstInitializer9 = 1.0/0.0 - 1/0
|
||||
const val nonConstInitializer10 = 0/0
|
||||
const val nonConstInitializer11 = 1 % 0
|
||||
const val nonConstInitializer12 = 0 % 0
|
||||
const val nonConstInitializer14 = 0.rem(0)
|
||||
const val nonConstInitializer15 = 0.div(0)
|
||||
const val nonConstInitializer1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>foo()<!>
|
||||
const val nonConstInitializer2 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 as String<!>
|
||||
const val nonConstInitializer3 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1.0 as String<!>
|
||||
const val nonConstInitializer4 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 as Double<!>
|
||||
const val nonConstInitializer5 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>"2" as Int<!>
|
||||
const val nonConstInitializer6 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1/0<!>
|
||||
const val nonConstInitializer7 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>-1/0<!>
|
||||
const val nonConstInitializer8 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1/0 - 1/0<!>
|
||||
const val nonConstInitializer9 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1.0/0.0 - 1/0<!>
|
||||
const val nonConstInitializer10 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>0/0<!>
|
||||
const val nonConstInitializer11 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 % 0<!>
|
||||
const val nonConstInitializer12 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>0 % 0<!>
|
||||
const val nonConstInitializer14 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>0.rem(0)<!>
|
||||
const val nonConstInitializer15 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>0.div(0)<!>
|
||||
|
||||
const val constInitializer1 = 1.0/0
|
||||
const val constInitializer2 = 1/0.0
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ const val e = 0.0 % 0
|
||||
const val g = 0.0.rem(0)
|
||||
const val h = 0.0.div(0)
|
||||
|
||||
const val i = 1 / 0
|
||||
const val i = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 / 0<!>
|
||||
|
||||
val nonConst1 = 1.0 / 0
|
||||
val nonConst2 = 1 / 0
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
const val intConst = 1
|
||||
const val longConst: Long = 1
|
||||
const val boolConst = true
|
||||
const val stringConst = "empty"
|
||||
|
||||
enum class MyEnum { A }
|
||||
|
||||
const val enumConst: MyEnum = MyEnum.A
|
||||
const val arrayConst: Array<String> = arrayOf("1")
|
||||
const val intArrayConst: IntArray = intArrayOf()
|
||||
|
||||
const val unresolvedConst1 = <!UNRESOLVED_REFERENCE!>Unresolved<!>
|
||||
<!WRONG_MODIFIER_TARGET!>const<!> var unresolvedConst2 = <!UNRESOLVED_REFERENCE!>Unresolved<!>
|
||||
const val unresolvedConst3 = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD, UNRESOLVED_REFERENCE!>Unresolved<!>
|
||||
<!CONST_VAL_WITH_GETTER!>get() = 10<!>
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
const val intConst = 1
|
||||
|
||||
compiler/testData/diagnostics/tests/multiplatform/topLevelProperty/differentKindsOfProperties.fir.kt
Vendored
+1
-1
@@ -26,7 +26,7 @@ expect var customAccessorVar: String
|
||||
get() = "no"
|
||||
set(value) {}
|
||||
|
||||
expect const val constVal: Int
|
||||
expect <!CONST_VAL_WITHOUT_INITIALIZER!>const<!> val constVal: Int
|
||||
|
||||
expect <!EXPECTED_LATEINIT_PROPERTY!>lateinit<!> var lateinitVar: String
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
val nonConst = 1
|
||||
|
||||
const val constConst = nonConst * nonConst + 2
|
||||
const val constConst = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>nonConst * nonConst + 2<!>
|
||||
|
||||
annotation class Ann(val x: Int, val y: String)
|
||||
|
||||
|
||||
+19
@@ -1430,6 +1430,25 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL) { firDiagnostic ->
|
||||
TypeCantBeUsedForConstValImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.CONST_VAL_WITHOUT_INITIALIZER) { firDiagnostic ->
|
||||
ConstValWithoutInitializerImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER) { firDiagnostic ->
|
||||
ConstValWithNonConstInitializerImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.WRONG_SETTER_PARAMETER_TYPE) { firDiagnostic ->
|
||||
WrongSetterParameterTypeImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
|
||||
+13
@@ -1011,6 +1011,19 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = ConstValWithDelegate::class
|
||||
}
|
||||
|
||||
abstract class TypeCantBeUsedForConstVal : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = TypeCantBeUsedForConstVal::class
|
||||
abstract val constValType: KtType
|
||||
}
|
||||
|
||||
abstract class ConstValWithoutInitializer : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = ConstValWithoutInitializer::class
|
||||
}
|
||||
|
||||
abstract class ConstValWithNonConstInitializer : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ConstValWithNonConstInitializer::class
|
||||
}
|
||||
|
||||
abstract class WrongSetterParameterType : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = WrongSetterParameterType::class
|
||||
abstract val expectedType: KtType
|
||||
|
||||
+22
@@ -1636,6 +1636,28 @@ internal class ConstValWithDelegateImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TypeCantBeUsedForConstValImpl(
|
||||
override val constValType: KtType,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TypeCantBeUsedForConstVal(), KtAbstractFirDiagnostic<KtProperty> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ConstValWithoutInitializerImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ConstValWithoutInitializer(), KtAbstractFirDiagnostic<KtProperty> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ConstValWithNonConstInitializerImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ConstValWithNonConstInitializer(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class WrongSetterParameterTypeImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
|
||||
Reference in New Issue
Block a user