FIR: Make LHS of FirVariableAssignment a FirExpression
This way references can even be resolved for erroneous assignments (e.g. function call, if expression, ... on LHS) ^KT-54648 Fixed
This commit is contained in:
committed by
Space Team
parent
e9b8d6db80
commit
ace47c06a5
-1
@@ -31,7 +31,6 @@ fun main(args: Array<String>) {
|
||||
val expressionPackage = "$basePackage.checkers.expression"
|
||||
generateCheckersComponents(generationPath, expressionPackage, "FirExpressionChecker") {
|
||||
alias<FirStatement>("BasicExpressionChecker")
|
||||
alias<FirQualifiedAccess>("QualifiedAccessChecker")
|
||||
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
|
||||
alias<FirCall>("CallChecker")
|
||||
alias<FirFunctionCall>("FunctionCallChecker")
|
||||
|
||||
+5
-5
@@ -64,7 +64,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val BREAK_OR_CONTINUE_OUTSIDE_A_LOOP by error<PsiElement>()
|
||||
val NOT_A_LOOP_LABEL by error<PsiElement>()
|
||||
val BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY by error<KtExpressionWithLabel>()
|
||||
val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS)
|
||||
val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.SELECTOR_BY_QUALIFIED)
|
||||
val DELEGATION_IN_INTERFACE by error<PsiElement>()
|
||||
val DELEGATION_NOT_TO_INTERFACE by error<PsiElement>()
|
||||
val NESTED_CLASS_NOT_ALLOWED by error<KtNamedDeclaration>(PositioningStrategy.DECLARATION_NAME) {
|
||||
@@ -91,7 +91,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE) {
|
||||
parameter<KtKeywordToken>("valOrVar")
|
||||
}
|
||||
val INVISIBLE_SETTER by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS) {
|
||||
val INVISIBLE_SETTER by error<PsiElement>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
parameter<Visibility>("visibility")
|
||||
parameter<CallableId>("callableId")
|
||||
@@ -1135,10 +1135,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val UNINITIALIZED_ENUM_COMPANION by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<FirRegularClassSymbol>("enumClass")
|
||||
}
|
||||
val VAL_REASSIGNMENT by error<KtExpression> {
|
||||
val VAL_REASSIGNMENT by error<KtExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<FirVariableSymbol<*>>("variable")
|
||||
}
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError<KtExpression>(LanguageFeature.RestrictionOfValReassignmentViaBackingField) {
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError<KtExpression>(LanguageFeature.RestrictionOfValReassignmentViaBackingField, PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<FirBackingFieldSymbol>("property")
|
||||
}
|
||||
val CAPTURED_VAL_INITIALIZATION by error<KtExpression> {
|
||||
@@ -1147,7 +1147,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CAPTURED_MEMBER_VAL_INITIALIZATION by error<KtExpression> {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
}
|
||||
val SETTER_PROJECTED_OUT by error<KtBinaryExpression>(PositioningStrategy.ASSIGNMENT_LHS) {
|
||||
val SETTER_PROJECTED_OUT by error<KtBinaryExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
}
|
||||
val WRONG_INVOCATION_KIND by warning<PsiElement> {
|
||||
|
||||
-1
@@ -90,7 +90,6 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
NAME_IDENTIFIER,
|
||||
QUESTION_MARK_BY_TYPE,
|
||||
ANNOTATION_USE_SITE,
|
||||
ASSIGNMENT_LHS,
|
||||
IMPORT_LAST_NAME,
|
||||
DATA_MODIFIER,
|
||||
SPREAD_OPERATOR,
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ object JsExpressionCheckers : ExpressionCheckers() {
|
||||
FirJsQualifierChecker,
|
||||
)
|
||||
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
|
||||
get() = setOf(
|
||||
FirJsDefinedExternallyCallChecker,
|
||||
FirJsDefinedExternallyCallChecker
|
||||
)
|
||||
}
|
||||
|
||||
+9
-6
@@ -9,17 +9,20 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.closestNonLocal
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isNativeObject
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isPredefinedObject
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
object FirJsDefinedExternallyCallChecker : FirQualifiedAccessChecker() {
|
||||
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val symbol = expression.calleeReference.toResolvedCallableSymbol() ?: return
|
||||
object FirJsDefinedExternallyCallChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val symbol = expression.calleeReference?.toResolvedCallableSymbol() ?: return
|
||||
|
||||
if (symbol.callableId !in JsStandardClassIds.Callables.definedExternallyPropertyNames) {
|
||||
return
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.*
|
||||
|
||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
|
||||
get() = setOf(
|
||||
FirJvmProtectedInSuperClassCompanionCallChecker
|
||||
)
|
||||
|
||||
+15
-10
@@ -6,20 +6,19 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
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.context.findClosest
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
@@ -29,12 +28,18 @@ import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_CLASS_ID
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
object FirJvmProtectedInSuperClassCompanionCallChecker : FirQualifiedAccessChecker() {
|
||||
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val dispatchReceiver = expression.dispatchReceiver
|
||||
object FirJvmProtectedInSuperClassCompanionCallChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val dispatchReceiver = when (expression) {
|
||||
is FirQualifiedAccessExpression -> expression.dispatchReceiver
|
||||
is FirVariableAssignment -> expression.dispatchReceiver
|
||||
else -> null
|
||||
} ?: return
|
||||
|
||||
if (dispatchReceiver is FirNoReceiverExpression) return
|
||||
val dispatchClassSymbol = dispatchReceiver.typeRef.toRegularClassSymbol(context.session) ?: return
|
||||
val resolvedSymbol = expression.calleeReference.toResolvedCallableSymbol() ?: return
|
||||
val calleeReference = expression.calleeReference
|
||||
val resolvedSymbol = calleeReference?.toResolvedCallableSymbol() ?: return
|
||||
|
||||
val visibility = if (resolvedSymbol is FirPropertySymbol) {
|
||||
if (expression is FirVariableAssignment)
|
||||
@@ -64,7 +69,7 @@ object FirJvmProtectedInSuperClassCompanionCallChecker : FirQualifiedAccessCheck
|
||||
it.symbol == dispatchClassSymbol || it.symbol == companionContainingClassSymbol
|
||||
} == null
|
||||
) {
|
||||
reporter.reportOn(expression.calleeReference.source, FirJvmErrors.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, context)
|
||||
reporter.reportOn(calleeReference.source, FirJvmErrors.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ object FirJvmSuspensionPointInsideMutexLockChecker : FirFunctionCallChecker() {
|
||||
if (!symbol.isSuspend) return
|
||||
val closestAnonymousFunction = context.findClosest<FirAnonymousFunction>() ?: return
|
||||
|
||||
for (call in context.qualifiedAccessOrAnnotationCalls.asReversed()) {
|
||||
for (call in context.qualifiedAccessOrAssignmentsOrAnnotationCalls.asReversed()) {
|
||||
if (call is FirFunctionCall) {
|
||||
val callableSymbol = call.calleeReference.toResolvedCallableSymbol() ?: continue
|
||||
if (callableSymbol.callableId == synchronizedCallableId) {
|
||||
|
||||
-4
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
|
||||
class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
|
||||
get() = _basicExpressionCheckers
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
get() = _qualifiedAccessCheckers
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = _qualifiedAccessExpressionCheckers
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
@@ -81,7 +79,6 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _classReferenceExpressionCheckers
|
||||
|
||||
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
|
||||
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
|
||||
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
|
||||
@@ -117,7 +114,6 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
@CheckersComponentInternal
|
||||
fun register(checkers: ExpressionCheckers) {
|
||||
_basicExpressionCheckers += checkers.basicExpressionCheckers
|
||||
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
|
||||
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
|
||||
_callCheckers += checkers.callCheckers
|
||||
_functionCallCheckers += checkers.functionCallCheckers
|
||||
|
||||
+7
-9
@@ -18,7 +18,6 @@ abstract class ExpressionCheckers {
|
||||
}
|
||||
|
||||
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
|
||||
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
|
||||
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
|
||||
open val callCheckers: Set<FirCallChecker> = emptySet()
|
||||
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
|
||||
@@ -52,13 +51,12 @@ abstract class ExpressionCheckers {
|
||||
open val classReferenceExpressionCheckers: Set<FirClassReferenceExpressionChecker> = emptySet()
|
||||
|
||||
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> by lazy { basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> by lazy { qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allPropertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker> by lazy { propertyAccessExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allIntegerLiteralOperatorCallCheckers: Set<FirIntegerLiteralOperatorCallChecker> by lazy { integerLiteralOperatorCallCheckers + functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allPropertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker> by lazy { propertyAccessExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allIntegerLiteralOperatorCallCheckers: Set<FirIntegerLiteralOperatorCallChecker> by lazy { integerLiteralOperatorCallCheckers + functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allLoopExpressionCheckers: Set<FirLoopExpressionChecker> by lazy { loopExpressionCheckers + basicExpressionCheckers }
|
||||
@@ -77,8 +75,8 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> by lazy { resolvedQualifierCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allConstExpressionCheckers: Set<FirConstExpressionChecker> by lazy { constExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allWhileLoopCheckers: Set<FirWhileLoopChecker> by lazy { whileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allThrowExpressionCheckers: Set<FirThrowExpressionChecker> by lazy { throwExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allDoWhileLoopCheckers: Set<FirDoWhileLoopChecker> by lazy { doWhileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
|
||||
-2
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirLoop
|
||||
import org.jetbrains.kotlin.fir.expressions.FirLoopJump
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
@@ -45,7 +44,6 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
|
||||
|
||||
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
|
||||
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
|
||||
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
|
||||
typealias FirCallChecker = FirExpressionChecker<FirCall>
|
||||
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
|
||||
|
||||
+5
-5
@@ -123,7 +123,7 @@ object FirErrors {
|
||||
val BREAK_OR_CONTINUE_OUTSIDE_A_LOOP by error0<PsiElement>()
|
||||
val NOT_A_LOOP_LABEL by error0<PsiElement>()
|
||||
val BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY by error0<KtExpressionWithLabel>()
|
||||
val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val DELEGATION_IN_INTERFACE by error0<PsiElement>()
|
||||
val DELEGATION_NOT_TO_INTERFACE by error0<PsiElement>()
|
||||
val NESTED_CLASS_NOT_ALLOWED by error1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
@@ -140,7 +140,7 @@ object FirErrors {
|
||||
val VAL_OR_VAR_ON_FUN_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val VAL_OR_VAR_ON_CATCH_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
|
||||
// Unresolved
|
||||
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -607,11 +607,11 @@ object FirErrors {
|
||||
val UNINITIALIZED_PARAMETER by error1<KtSimpleNameExpression, FirValueParameterSymbol>()
|
||||
val UNINITIALIZED_ENUM_ENTRY by error1<KtSimpleNameExpression, FirEnumEntrySymbol>()
|
||||
val UNINITIALIZED_ENUM_COMPANION by error1<KtExpression, FirRegularClassSymbol>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val VAL_REASSIGNMENT by error1<KtExpression, FirVariableSymbol<*>>()
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError1<KtExpression, FirBackingFieldSymbol>(RestrictionOfValReassignmentViaBackingField)
|
||||
val VAL_REASSIGNMENT by error1<KtExpression, FirVariableSymbol<*>>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError1<KtExpression, FirBackingFieldSymbol>(RestrictionOfValReassignmentViaBackingField, SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val CAPTURED_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val CAPTURED_MEMBER_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val SETTER_PROJECTED_OUT by error1<KtBinaryExpression, FirPropertySymbol>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
val SETTER_PROJECTED_OUT by error1<KtBinaryExpression, FirPropertySymbol>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val WRONG_INVOCATION_KIND by warning3<PsiElement, FirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>()
|
||||
val LEAKED_IN_PLACE_LAMBDA by warning1<PsiElement, FirBasedSymbol<*>>()
|
||||
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
||||
|
||||
+2
-5
@@ -22,11 +22,8 @@ import org.jetbrains.kotlin.fir.contracts.effects
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||
@@ -309,7 +306,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
|
||||
return this is FirAnonymousFunction && this.isLambda && this.invocationKind != null
|
||||
}
|
||||
|
||||
private fun FirExpression?.toQualifiedReference(): FirReference? = (this as? FirQualifiedAccess)?.calleeReference
|
||||
private fun FirExpression?.toQualifiedReference(): FirReference? = (this as? FirQualifiedAccessExpression)?.calleeReference
|
||||
|
||||
private fun referenceToSymbol(reference: FirReference?): FirBasedSymbol<*>? = when (reference) {
|
||||
is FirResolvedNamedReference -> reference.resolvedSymbol
|
||||
|
||||
+9
-7
@@ -18,8 +18,10 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.expressions.unwrapLValue
|
||||
import org.jetbrains.kotlin.fir.isCatchParameter
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
@@ -65,7 +67,7 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
||||
scope: FirDeclaration?,
|
||||
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>,
|
||||
) {
|
||||
fun FirQualifiedAccess.hasCorrectReceiver() =
|
||||
fun FirQualifiedAccessExpression.hasCorrectReceiver() =
|
||||
(dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
|
||||
|
||||
for (node in graph.nodes) {
|
||||
@@ -83,17 +85,17 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
||||
}
|
||||
|
||||
node is VariableAssignmentNode -> {
|
||||
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: continue
|
||||
if (!symbol.fir.isVal || !node.fir.hasCorrectReceiver() || symbol !in properties) continue
|
||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: continue
|
||||
if (!symbol.fir.isVal || node.fir.unwrapLValue()?.hasCorrectReceiver() != true || symbol !in properties) continue
|
||||
|
||||
if (scope != scopes[symbol]) {
|
||||
if (getValue(node).values.any { it[symbol]?.canBeRevisited() == true }) {
|
||||
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
||||
} else if (scope != scopes[symbol]) {
|
||||
val error = if (receiver != null)
|
||||
FirErrors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
||||
else
|
||||
FirErrors.CAPTURED_VAL_INITIALIZATION
|
||||
reporter.reportOn(node.fir.lValue.source, error, symbol, context)
|
||||
} else if (getValue(node).values.any { it[symbol]?.canBeRevisited() == true }) {
|
||||
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.analysis.cfa.util
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.expressions.dispatchReceiver
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -51,7 +53,7 @@ class PropertyInitializationInfoCollector(
|
||||
val dataForNode = visitNode(node, data)
|
||||
val receiver = (node.fir.dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol
|
||||
if (receiver != expectedReceiver) return dataForNode
|
||||
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: return dataForNode
|
||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return dataForNode
|
||||
if (symbol !in localProperties) return dataForNode
|
||||
return addRange(dataForNode, symbol, EventOccurrencesRange.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
+3
-7
@@ -22,7 +22,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirUnderscoreChecker,
|
||||
FirExpressionAnnotationChecker,
|
||||
FirDeprecationChecker,
|
||||
FirRecursiveProblemChecker
|
||||
FirRecursiveProblemChecker,
|
||||
FirOptInUsageAccessChecker,
|
||||
)
|
||||
|
||||
override val throwExpressionCheckers: Set<FirThrowExpressionChecker>
|
||||
@@ -30,11 +31,6 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirThrowExpressionTypeChecker,
|
||||
)
|
||||
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
get() = setOf(
|
||||
FirOptInUsageAccessChecker,
|
||||
)
|
||||
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = setOf(
|
||||
FirCallableReferenceChecker,
|
||||
@@ -83,7 +79,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
get() = setOf(
|
||||
FirReassignmentAndInvisibleSetterChecker,
|
||||
FirAssignmentTypeMismatchChecker
|
||||
FirAssignmentTypeMismatchChecker,
|
||||
)
|
||||
|
||||
override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
|
||||
|
||||
@@ -655,7 +655,7 @@ fun getActualTargetList(annotated: FirDeclaration): AnnotationTargetList {
|
||||
|
||||
private typealias TargetLists = AnnotationTargetLists
|
||||
|
||||
fun FirQualifiedAccess.explicitReceiverIsNotSuperReference(): Boolean {
|
||||
fun FirQualifiedAccessExpression.explicitReceiverIsNotSuperReference(): Boolean {
|
||||
return (this.explicitReceiver as? FirQualifiedAccessExpression)?.calleeReference !is FirSuperReference
|
||||
}
|
||||
|
||||
@@ -728,3 +728,9 @@ fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: Fi
|
||||
val expression = annotation?.argumentMapping?.mapping?.values?.firstOrNull() as? FirConstExpression<*>
|
||||
return expression?.value as? String
|
||||
}
|
||||
|
||||
fun FirElement.isLhsOfAssignment(context: CheckerContext): Boolean {
|
||||
if (this !is FirQualifiedAccessExpression) return false
|
||||
val lastQualified = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull { it != this } ?: return false
|
||||
return lastQualified is FirVariableAssignment && lastQualified.lValue == this
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ abstract class CheckerContext : MutableDiagnosticContext() {
|
||||
// Context
|
||||
abstract val implicitReceiverStack: ImplicitReceiverStack
|
||||
abstract val containingDeclarations: List<FirDeclaration>
|
||||
abstract val qualifiedAccessOrAnnotationCalls: List<FirStatement>
|
||||
abstract val qualifiedAccessOrAssignmentsOrAnnotationCalls: List<FirStatement>
|
||||
abstract val getClassCalls: List<FirGetClassCall>
|
||||
abstract val annotationContainers: List<FirAnnotationContainer>
|
||||
abstract val isContractBody: Boolean
|
||||
|
||||
+5
-5
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
class MutableCheckerContext private constructor(
|
||||
override val implicitReceiverStack: PersistentImplicitReceiverStack,
|
||||
override val containingDeclarations: MutableList<FirDeclaration>,
|
||||
override val qualifiedAccessOrAnnotationCalls: MutableList<FirStatement>,
|
||||
override val qualifiedAccessOrAssignmentsOrAnnotationCalls: MutableList<FirStatement>,
|
||||
override val getClassCalls: MutableList<FirGetClassCall>,
|
||||
override val annotationContainers: MutableList<FirAnnotationContainer>,
|
||||
override var isContractBody: Boolean,
|
||||
@@ -50,7 +50,7 @@ class MutableCheckerContext private constructor(
|
||||
return MutableCheckerContext(
|
||||
implicitReceiverStack.add(name, value),
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -73,12 +73,12 @@ class MutableCheckerContext private constructor(
|
||||
}
|
||||
|
||||
override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): MutableCheckerContext {
|
||||
qualifiedAccessOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall)
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun dropQualifiedAccessOrAnnotationCall() {
|
||||
qualifiedAccessOrAnnotationCalls.removeAt(qualifiedAccessOrAnnotationCalls.size - 1)
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls.removeAt(qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 1)
|
||||
}
|
||||
|
||||
override fun addGetClassCall(getClassCall: FirGetClassCall): MutableCheckerContext {
|
||||
@@ -109,7 +109,7 @@ class MutableCheckerContext private constructor(
|
||||
return MutableCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
|
||||
+8
-8
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
class PersistentCheckerContext private constructor(
|
||||
override val implicitReceiverStack: PersistentImplicitReceiverStack,
|
||||
override val containingDeclarations: PersistentList<FirDeclaration>,
|
||||
override val qualifiedAccessOrAnnotationCalls: PersistentList<FirStatement>,
|
||||
override val qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement>,
|
||||
override val getClassCalls: PersistentList<FirGetClassCall>,
|
||||
override val annotationContainers: PersistentList<FirAnnotationContainer>,
|
||||
override val isContractBody: Boolean,
|
||||
@@ -52,7 +52,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack.add(name, value),
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -69,7 +69,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations.add(declaration),
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -89,7 +89,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
this.qualifiedAccessOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall),
|
||||
this.qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall),
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -109,7 +109,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls.add(getClassCall),
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -129,7 +129,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers.add(annotationContainer),
|
||||
isContractBody,
|
||||
@@ -155,7 +155,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody,
|
||||
@@ -174,7 +174,7 @@ class PersistentCheckerContext private constructor(
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
containingDeclarations,
|
||||
qualifiedAccessOrAnnotationCalls,
|
||||
qualifiedAccessOrAssignmentsOrAnnotationCalls,
|
||||
getClassCalls,
|
||||
annotationContainers,
|
||||
isContractBody = newValue,
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
|
||||
}
|
||||
|
||||
private val FirExpression.explicitReceiverOfQualifiedAccess: FirQualifiedAccessExpression?
|
||||
get() = (this as? FirQualifiedAccess)?.explicitReceiver?.unwrapped as? FirQualifiedAccessExpression
|
||||
get() = (this as? FirQualifiedAccessExpression)?.explicitReceiver?.unwrapped as? FirQualifiedAccessExpression
|
||||
|
||||
private val FirExpression.unwrapped: FirExpression
|
||||
get() =
|
||||
|
||||
+15
-10
@@ -111,7 +111,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: CheckerContext) {}
|
||||
|
||||
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) {
|
||||
val propertySymbol = variableAssignment.calleeReference.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
|
||||
val propertySymbol = variableAssignment.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
|
||||
val setterSymbol = propertySymbol.setterSymbol ?: return
|
||||
checkQualifiedAccess(variableAssignment, setterSymbol, data)
|
||||
}
|
||||
@@ -237,7 +237,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
}
|
||||
|
||||
private fun checkQualifiedAccess(
|
||||
qualifiedAccess: FirQualifiedAccess,
|
||||
qualifiedAccess: FirStatement,
|
||||
targetSymbol: FirBasedSymbol<*>?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
@@ -253,18 +253,18 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
checkRecursion(targetSymbol, source, context)
|
||||
}
|
||||
|
||||
private fun FirQualifiedAccess.partOfCall(context: CheckerContext): Boolean {
|
||||
private fun FirStatement.partOfCall(context: CheckerContext): Boolean {
|
||||
if (this !is FirExpression) return false
|
||||
val containingQualifiedAccess = context.qualifiedAccessOrAnnotationCalls.getOrNull(
|
||||
context.qualifiedAccessOrAnnotationCalls.size - 2
|
||||
val containingQualifiedAccess = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.getOrNull(
|
||||
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 2
|
||||
) ?: return false
|
||||
if (this == (containingQualifiedAccess as? FirQualifiedAccess)?.explicitReceiver) return true
|
||||
if (this == (containingQualifiedAccess as? FirQualifiedAccessExpression)?.explicitReceiver) return true
|
||||
val call = containingQualifiedAccess as? FirCall ?: return false
|
||||
return call.arguments.any { it.unwrapArgument() == this }
|
||||
}
|
||||
|
||||
private fun checkVisibilityAndAccess(
|
||||
accessExpression: FirQualifiedAccess,
|
||||
accessExpression: FirStatement,
|
||||
calledDeclaration: FirCallableSymbol<*>?,
|
||||
source: KtSourceElement,
|
||||
context: CheckerContext
|
||||
@@ -321,16 +321,21 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
|
||||
private fun checkSuperCalls(
|
||||
calledDeclaration: FirCallableSymbol<*>,
|
||||
callExpression: FirQualifiedAccess,
|
||||
callExpression: FirStatement,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val receiver = callExpression.dispatchReceiver as? FirQualifiedAccessExpression ?: return
|
||||
val receiver = when (callExpression) {
|
||||
is FirQualifiedAccessExpression -> callExpression.dispatchReceiver
|
||||
is FirVariableAssignment -> callExpression.dispatchReceiver
|
||||
else -> null
|
||||
} as? FirQualifiedAccessExpression ?: return
|
||||
|
||||
if (receiver.calleeReference is FirSuperReference) {
|
||||
val dispatchReceiverType = receiver.dispatchReceiver.typeRef.coneType
|
||||
val classSymbol = dispatchReceiverType.toSymbol(session) ?: return
|
||||
if (!classSymbol.isDefinedInInlineFunction()) {
|
||||
reporter.reportOn(
|
||||
callExpression.dispatchReceiver.source,
|
||||
receiver.source,
|
||||
FirErrors.SUPER_CALL_FROM_PUBLIC_INLINE,
|
||||
calledDeclaration,
|
||||
context
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
@@ -38,7 +39,7 @@ object FirPropertyInitializationChecker : FirRegularClassChecker() {
|
||||
|
||||
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment) {
|
||||
variableAssignment.acceptChildren(this)
|
||||
val propertySymbol = variableAssignment.lValue.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
|
||||
val propertySymbol = variableAssignment.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
|
||||
if (propertySymbol !in declaredLater) return
|
||||
reporter.reportOn(variableAssignment.lValue.source, FirErrors.INITIALIZATION_BEFORE_DECLARATION, propertySymbol, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.types.coneType
|
||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = expression.rValue.source ?: return
|
||||
val coneType = expression.lValueTypeRef.coneType
|
||||
val coneType = expression.lValue.typeRef.coneType
|
||||
checkTypeMismatch(
|
||||
coneType,
|
||||
expression,
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ object FirConstructorCallChecker : FirFunctionCallChecker() {
|
||||
reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context)
|
||||
}
|
||||
if (declarationClass.classKind == ClassKind.ANNOTATION_CLASS &&
|
||||
context.qualifiedAccessOrAnnotationCalls.all { call ->
|
||||
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.all { call ->
|
||||
call !is FirAnnotation
|
||||
} &&
|
||||
context.containingDeclarations.all { klass ->
|
||||
|
||||
+8
-8
@@ -15,11 +15,9 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.FutureApiDeprecationInfo
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
|
||||
import org.jetbrains.kotlin.fir.declarations.getDeprecation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvable
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.resolved
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
@@ -36,11 +34,13 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!allowedSourceKinds.contains(expression.source?.kind)) return
|
||||
if (expression is FirAnnotation || expression is FirDelegatedConstructorCall) return //checked by FirDeprecatedTypeChecker
|
||||
val resolvable = expression as? FirResolvable ?: return
|
||||
val reference = resolvable.calleeReference.resolved ?: return
|
||||
val referencedSymbol = reference.resolvedSymbol
|
||||
if (expression.isLhsOfAssignment(context)) return
|
||||
|
||||
reportApiStatusIfNeeded(reference.source, referencedSymbol, expression, context, reporter)
|
||||
val calleeReference = expression.calleeReference ?: return
|
||||
val resolvedReference = calleeReference.resolved ?: return
|
||||
val referencedSymbol = resolvedReference.resolvedSymbol
|
||||
|
||||
reportApiStatusIfNeeded(resolvedReference.source, referencedSymbol, expression, context, reporter)
|
||||
}
|
||||
|
||||
internal fun reportApiStatusIfNeeded(
|
||||
|
||||
+19
-15
@@ -8,33 +8,37 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() {
|
||||
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
object FirOptInUsageAccessChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val sourceKind = expression.source?.kind
|
||||
if (sourceKind is KtFakeSourceElementKind.DataClassGeneratedMembers ||
|
||||
sourceKind is KtFakeSourceElementKind.PropertyFromParameter
|
||||
) return
|
||||
val resolvedSymbol = expression.calleeReference.toResolvedBaseSymbol() ?: return
|
||||
val dispatchReceiverType =
|
||||
expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }?.typeRef?.coneType?.fullyExpandedType(context.session)
|
||||
|
||||
if (expression.isLhsOfAssignment(context)) return
|
||||
|
||||
val resolvedSymbol = expression.calleeReference?.toResolvedBaseSymbol() ?: return
|
||||
|
||||
with(FirOptInUsageBaseChecker) {
|
||||
if (expression is FirVariableAssignment && resolvedSymbol is FirPropertySymbol) {
|
||||
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true, dispatchReceiverType) +
|
||||
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
|
||||
if (expression is FirVariableAssignment) {
|
||||
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true, null) +
|
||||
loadExperimentalitiesFromTypeArguments(context, emptyList())
|
||||
reportNotAcceptedExperimentalities(experimentalities, expression.lValue, context, reporter)
|
||||
return
|
||||
} else if (expression is FirQualifiedAccessExpression) {
|
||||
val dispatchReceiverType =
|
||||
expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }?.typeRef?.coneType?.fullyExpandedType(context.session)
|
||||
|
||||
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) +
|
||||
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
|
||||
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
|
||||
}
|
||||
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) +
|
||||
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
|
||||
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-17
@@ -16,17 +16,14 @@ import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||
import org.jetbrains.kotlin.fir.references.FirBackingFieldReference
|
||||
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.references.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithCandidates
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.visibilityChecker
|
||||
@@ -36,7 +33,7 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
checkInvisibleSetter(expression, context, reporter)
|
||||
checkValReassignmentViaBackingField(expression, context, reporter)
|
||||
checkValReassignmentOnValueParameter(expression, context, reporter)
|
||||
checkAssignmentToThis(expression, context, reporter)
|
||||
checkVariableExpected(expression, context, reporter)
|
||||
checkValReassignment(expression, context, reporter)
|
||||
}
|
||||
|
||||
@@ -61,7 +58,7 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
return false
|
||||
}
|
||||
|
||||
val callableSymbol = expression.calleeReference.toResolvedCallableSymbol()
|
||||
val callableSymbol = expression.calleeReference?.toResolvedCallableSymbol()
|
||||
if (callableSymbol is FirPropertySymbol && shouldInvisibleSetterBeReported(callableSymbol)) {
|
||||
val explicitReceiver = expression.explicitReceiver
|
||||
// Try to get type from smartcast
|
||||
@@ -78,7 +75,7 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
}
|
||||
}
|
||||
reporter.reportOn(
|
||||
expression.source,
|
||||
expression.lValue.source,
|
||||
FirErrors.INVISIBLE_SETTER,
|
||||
callableSymbol,
|
||||
callableSymbol.setterSymbol?.visibility ?: Visibilities.Private,
|
||||
@@ -93,7 +90,7 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val backingFieldReference = expression.lValue as? FirBackingFieldReference ?: return
|
||||
val backingFieldReference = expression.calleeReference as? FirBackingFieldReference ?: return
|
||||
val propertySymbol = backingFieldReference.resolvedSymbol
|
||||
if (propertySymbol.isVar) return
|
||||
val closestGetter = context.findClosest<FirPropertyAccessor> { it.isGetter }?.symbol ?: return
|
||||
@@ -107,22 +104,37 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val valueParameter = expression.lValue.toResolvedValueParameterSymbol() ?: return
|
||||
val valueParameter = expression.calleeReference?.toResolvedValueParameterSymbol() ?: return
|
||||
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, valueParameter, context)
|
||||
}
|
||||
|
||||
private fun checkAssignmentToThis(
|
||||
private fun checkVariableExpected(
|
||||
expression: FirVariableAssignment,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
if (expression.lValue is FirThisReference) {
|
||||
val calleeReference = expression.calleeReference
|
||||
|
||||
if (expression.unwrapLValue() !is FirPropertyAccessExpression ||
|
||||
(calleeReference?.isConflictingError() != true && calleeReference?.toResolvedVariableSymbol() == null)
|
||||
) {
|
||||
reporter.reportOn(expression.lValue.source, FirErrors.VARIABLE_EXPECTED, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirReference.isConflictingError(): Boolean {
|
||||
if (!isError()) return false
|
||||
|
||||
return when (val it = diagnostic) {
|
||||
is ConeSimpleDiagnostic -> it.kind == DiagnosticKind.VariableExpected
|
||||
is ConeUnresolvedNameError -> true
|
||||
is ConeDiagnosticWithCandidates -> it.candidates.any { it.symbol is FirPropertySymbol }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkValReassignment(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val property = expression.lValue.toResolvedPropertySymbol() ?: return
|
||||
val property = expression.calleeReference?.toResolvedPropertySymbol() ?: return
|
||||
if (property.isVar) return
|
||||
// Assignments of uninitialized `val`s must be checked via CFG, since the first one is OK.
|
||||
// See `FirPropertyInitializationAnalyzer` for locals and `FirMemberPropertiesChecker` for backing fields in initializers.
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ object FirReturnSyntaxAndLabelChecker : FirReturnExpressionChecker() {
|
||||
if (targetSymbol is FirAnonymousFunctionSymbol) {
|
||||
val label = targetSymbol.label
|
||||
if (label?.source?.kind !is KtRealSourceElementKind) {
|
||||
val functionCall = context.qualifiedAccessOrAnnotationCalls.asReversed().find {
|
||||
val functionCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.asReversed().find {
|
||||
it is FirFunctionCall &&
|
||||
(it.calleeReference.toResolvedFunctionSymbol())?.callableId ==
|
||||
FirSuspendCallChecker.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.types.isUnit
|
||||
|
||||
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
|
||||
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lastQualifiedAccess = context.qualifiedAccessOrAnnotationCalls.lastOrNull() as? FirQualifiedAccess
|
||||
val lastQualifiedAccess = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull() as? FirQualifiedAccessExpression
|
||||
// Note: qualifier isn't standalone when it's in receiver (SomeClass.foo) or getClass (SomeClass::class) position
|
||||
if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return
|
||||
val lastGetClass = context.getClassCalls.lastOrNull()
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ object FirTypeParameterInQualifiedAccessChecker : FirQualifiedAccessExpressionCh
|
||||
// Make sure the current expression is not the receiver of a qualified access expression.
|
||||
// E.g., for `T::toString`, which is a callable reference (a subtype of qualified access), type parameter T is checked once as an
|
||||
// explicit receiver. When we visit `T` (as a qualified access expression), we should not regard it as an expression here.
|
||||
val secondLast = context.qualifiedAccessOrAnnotationCalls.elementAtOrNull(context.qualifiedAccessOrAnnotationCalls.size - 2)
|
||||
val secondLast = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.elementAtOrNull(context.qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 2)
|
||||
if (secondLast is FirQualifiedAccessExpression && secondLast.explicitReceiver == expression) return
|
||||
|
||||
val diagnostic = expression.typeRef.coneTypeParameterInQualifiedAccess ?: return
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.expressions.*
|
||||
object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() {
|
||||
override fun check(expression: FirArrayOfCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!isInsideAnnotationCall(expression, context) &&
|
||||
(context.qualifiedAccessOrAnnotationCalls.isNotEmpty() || !isInsideAnnotationClass(context))
|
||||
(context.qualifiedAccessOrAssignmentsOrAnnotationCalls.isNotEmpty() || !isInsideAnnotationClass(context))
|
||||
) {
|
||||
reporter.reportOn(
|
||||
expression.source,
|
||||
@@ -32,7 +32,7 @@ object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() {
|
||||
}
|
||||
|
||||
private fun isInsideAnnotationCall(expression: FirArrayOfCall, context: CheckerContext): Boolean {
|
||||
context.qualifiedAccessOrAnnotationCalls.lastOrNull()?.let {
|
||||
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.let {
|
||||
val arguments = when (it) {
|
||||
is FirFunctionCall ->
|
||||
if (it.typeRef.toRegularClassSymbol(context.session)?.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
@@ -87,4 +87,4 @@ object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() {
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.dispatchReceiverClassTypeOrNull
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
@@ -32,7 +33,7 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
|
||||
object CanBeReplacedWithOperatorAssignmentChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lValue = expression.lValue
|
||||
val lValue = expression.calleeReference
|
||||
if (lValue !is FirResolvedNamedReference) return
|
||||
if (expression.source?.kind is KtFakeSourceElementKind) return
|
||||
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.util.PropertyInitializationInfoData
|
||||
import org.jetbrains.kotlin.fir.expressions.calleeReference
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
@@ -48,7 +49,7 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
||||
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: return
|
||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return
|
||||
if (symbol.isVar && symbol.source?.kind !is KtFakeSourceElementKind && symbol in data.properties &&
|
||||
(!symbol.requiresInitialization || data.getValue(node).values.any { it[symbol]?.canBeRevisited() == true })
|
||||
) {
|
||||
|
||||
+5
-5
@@ -44,7 +44,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
|
||||
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
||||
val variableSymbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: return
|
||||
val variableSymbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return
|
||||
val dataPerNode = data[node] ?: return
|
||||
for (dataPerLabel in dataPerNode.values) {
|
||||
val data = dataPerLabel[variableSymbol] ?: continue
|
||||
@@ -210,7 +210,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
data: PathAwareVariableStatusInfo
|
||||
): PathAwareVariableStatusInfo {
|
||||
val dataForNode = visitNode(node, data)
|
||||
val symbol = node.fir.lValue.toResolvedPropertySymbol() ?: return dataForNode
|
||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return dataForNode
|
||||
return update(dataForNode, symbol) update@{ prev ->
|
||||
val toPut = when {
|
||||
symbol !in localProperties -> {
|
||||
@@ -247,7 +247,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
annotation: FirAnnotation,
|
||||
): PathAwareVariableStatusInfo {
|
||||
return if (annotation is FirAnnotationCall) {
|
||||
val qualifiedAccesses = annotation.argumentList.arguments.mapNotNull { it as? FirQualifiedAccess }.toTypedArray()
|
||||
val qualifiedAccesses = annotation.argumentList.arguments.mapNotNull { it as? FirQualifiedAccessExpression }.toTypedArray()
|
||||
visitQualifiedAccesses(dataForNode, *qualifiedAccesses)
|
||||
} else {
|
||||
dataForNode
|
||||
@@ -256,9 +256,9 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
|
||||
|
||||
private fun visitQualifiedAccesses(
|
||||
dataForNode: PathAwareVariableStatusInfo,
|
||||
vararg qualifiedAccesses: FirQualifiedAccess,
|
||||
vararg qualifiedAccesses: FirQualifiedAccessExpression,
|
||||
): PathAwareVariableStatusInfo {
|
||||
fun retrieveSymbol(qualifiedAccess: FirQualifiedAccess): FirPropertySymbol? {
|
||||
fun retrieveSymbol(qualifiedAccess: FirQualifiedAccessExpression): FirPropertySymbol? {
|
||||
return qualifiedAccess.calleeReference.toResolvedPropertySymbol()?.takeIf { it in localProperties }
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
|
||||
val symbol = coneType.lookupTag.toSymbol(context.session) ?: return
|
||||
symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
val classId = symbol.classId
|
||||
val lastAnnotationCall = context.qualifiedAccessOrAnnotationCalls.lastOrNull() as? FirAnnotation
|
||||
val lastAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull() as? FirAnnotation
|
||||
if (lastAnnotationCall == null || lastAnnotationCall.annotationTypeRef !== typeRef) {
|
||||
if (classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID) {
|
||||
reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context)
|
||||
|
||||
+5
-1
@@ -36,9 +36,13 @@ abstract class AbstractDiagnosticCollectorVisitor(
|
||||
|
||||
override fun visitElement(element: FirElement, data: Nothing?) {
|
||||
if (element is FirAnnotationContainer) {
|
||||
visitAnnotationContainer(element, data)
|
||||
withAnnotationContainer(element) {
|
||||
checkElement(element)
|
||||
visitNestedElements(element)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
checkElement(element)
|
||||
visitNestedElements(element)
|
||||
}
|
||||
|
||||
+4
-11
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.renderForDebugging
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
|
||||
class ErrorNodeDiagnosticCollectorComponent(
|
||||
session: FirSession,
|
||||
@@ -63,13 +60,9 @@ class ErrorNodeDiagnosticCollectorComponent(
|
||||
|
||||
private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) {
|
||||
val source = reference.source ?: return
|
||||
val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAnnotationCalls.lastOrNull()?.takeIf {
|
||||
val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.takeIf {
|
||||
// Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee.
|
||||
when (it) {
|
||||
is FirQualifiedAccess -> it.calleeReference == reference
|
||||
is FirAnnotationCall -> it.calleeReference == reference
|
||||
else -> false
|
||||
}
|
||||
it.calleeReference == reference
|
||||
}
|
||||
// Don't report duplicated unresolved reference on annotation entry (already reported on its type)
|
||||
if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && diagnostic is ConeUnresolvedNameError) return
|
||||
@@ -79,7 +72,7 @@ class ErrorNodeDiagnosticCollectorComponent(
|
||||
) return
|
||||
|
||||
// If the receiver cannot be resolved, we skip reporting any further problems for this call.
|
||||
if (qualifiedAccessOrAnnotationCall is FirQualifiedAccess) {
|
||||
if (qualifiedAccessOrAnnotationCall is FirQualifiedAccessExpression) {
|
||||
if (qualifiedAccessOrAnnotationCall.dispatchReceiver.cannotBeResolved() ||
|
||||
qualifiedAccessOrAnnotationCall.extensionReceiver.cannotBeResolved() ||
|
||||
qualifiedAccessOrAnnotationCall.explicitReceiver.cannotBeResolved()
|
||||
|
||||
-4
@@ -91,10 +91,6 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
||||
|
||||
is ConeOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.createOn(source, this.candidateSymbols)
|
||||
is ConeVariableExpectedError -> FirErrors.VARIABLE_EXPECTED.createOn(source)
|
||||
is ConeValReassignmentError -> when (val symbol = this.variable) {
|
||||
is FirBackingFieldSymbol -> FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD.errorFactory.createOn(source, symbol)
|
||||
else -> FirErrors.VAL_REASSIGNMENT.createOn(source, symbol)
|
||||
}
|
||||
|
||||
is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.createOn(this.source ?: source)
|
||||
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.createOn(source, this.name.asString())
|
||||
|
||||
Reference in New Issue
Block a user