FIR: distinguish qualified access / qualified access expression checkers

This commit is contained in:
Mikhail Glukhikh
2021-05-25 18:17:03 +03:00
parent 6b6ba77869
commit f0453d2f5c
22 changed files with 34 additions and 26 deletions
@@ -27,7 +27,8 @@ fun main(args: Array<String>) {
val expressionPackage = "$basePackage.checkers.expression"
generateCheckersComponents(generationPath, expressionPackage, "FirExpressionChecker") {
alias<FirStatement>("BasicExpressionChecker")
alias<FirQualifiedAccessExpression>("QualifiedAccessChecker")
alias<FirQualifiedAccess>("QualifiedAccessChecker")
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
alias<FirFunctionCall>("FunctionCallChecker")
alias<FirVariableAssignment>("VariableAssignmentChecker")
alias<FirTryExpression>("TryExpressionChecker")
@@ -17,6 +17,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _basicExpressionCheckers
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
get() = _qualifiedAccessCheckers
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = _qualifiedAccessExpressionCheckers
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = _functionCallCheckers
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
@@ -56,6 +58,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
@@ -79,6 +82,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
fun register(checkers: ExpressionCheckers) {
_basicExpressionCheckers += checkers.basicExpressionCheckers
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
_functionCallCheckers += checkers.functionCallCheckers
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
_tryExpressionCheckers += checkers.tryExpressionCheckers
@@ -19,6 +19,7 @@ abstract class ExpressionCheckers {
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
@@ -40,8 +41,9 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> get() = basicExpressionCheckers
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> get() = qualifiedAccessCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> get() = functionCallCheckers + qualifiedAccessCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> get() = variableAssignmentCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> get() = qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> get() = functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> get() = variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> get() = tryExpressionCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> get() = whenExpressionCheckers + basicExpressionCheckers
@CheckersComponentInternal internal val allLoopExpressionCheckers: Set<FirLoopExpressionChecker> get() = loopExpressionCheckers + basicExpressionCheckers
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.expressions.FirLoop
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
@@ -32,7 +33,8 @@ import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
@@ -20,7 +20,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirExpressionAnnotationChecker,
)
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = setOf(
FirCallableReferenceChecker,
FirSuperNotAvailableChecker,
@@ -19,7 +19,7 @@ object ExtendedExpressionCheckers : ExpressionCheckers() {
CanBeReplacedWithOperatorAssignmentChecker,
)
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = setOf(
RedundantCallOfConversionMethod,
UselessCallOnNotNullChecker,
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirAbstractSuperCallChecker : FirQualifiedAccessChecker() {
object FirAbstractSuperCallChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
// require the receiver to be the super reference
expression.explicitReceiver.safeAs<FirQualifiedAccessExpression>()
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.getContainingClass
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
object FirCallableReferenceChecker : FirQualifiedAccessChecker() {
object FirCallableReferenceChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression !is FirCallableReferenceAccess) return
// [FirGetClassCallChecker] will check [FirGetClassCall].
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.isFun
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
object FirFunInterfaceConstructorReferenceChecker : FirQualifiedAccessChecker() {
object FirFunInterfaceConstructorReferenceChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression !is FirCallableReferenceAccess || expression is FirGetClassCall) return
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
object FirNotASupertypeChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val superReference = expression.calleeReference.safeAs<FirSuperReference>()?.takeIf { it.hadExplicitTypeInSource() }
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.types.FirStarProjection
import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance
import org.jetbrains.kotlin.types.Variance
object FirProjectionsOnNonClassTypeArgumentChecker : FirQualifiedAccessChecker() {
object FirProjectionsOnNonClassTypeArgumentChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in expression.typeArguments) {
when (it) {
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccessChecker() {
object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
// require to be called over a super reference
val superReference = expression.calleeReference.safeAs<FirSuperReference>()
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSealedClassConstructorCallChecker : FirQualifiedAccessChecker() {
object FirSealedClassConstructorCallChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val constructorFir = expression.calleeReference.safeAs<FirResolvedNamedReference>()
?.resolvedSymbol
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() {
object FirSuperNotAvailableChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression.calleeReference.safeAs<FirSuperReference>()?.hadExplicitTypeInSource() != true) return
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecker() {
object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
expression.explicitReceiver.safeAs<FirQualifiedAccessExpression>()
?.calleeReference.safeAs<FirSuperReference>()
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker() {
object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
// analyze type parameters near
// package names
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualified
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
object FirTypeParameterInQualifiedAccessChecker : FirQualifiedAccessChecker() {
object FirTypeParameterInQualifiedAccessChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
checkExplicitReceiver(expression, context, reporter)
checkExpressionItself(expression, context, reporter)
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
object FirUninitializedEnumChecker : FirQualifiedAccessChecker() {
object FirUninitializedEnumChecker : FirQualifiedAccessExpressionChecker() {
// Initialization order: member property initializers, enum entries, companion object (including members in it).
//
// When JVM loads a class, the corresponding class initializer, a.k.a. <clinit>, is executed first.
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
object FirUpperBoundViolatedChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
// something that contains the type parameters
// declarations with their declared bounds.
@@ -5,9 +5,8 @@
package org.jetbrains.kotlin.fir.analysis.checkers.extended
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
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.FirQualifiedAccessExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -24,7 +23,7 @@ import org.jetbrains.kotlin.fir.types.isMarkedNullable
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() {
object RedundantCallOfConversionMethod : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression !is FirFunctionCall) return
val functionName = expression.calleeReference.name.asString()
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.extended
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.FirQualifiedAccessExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
object UselessCallOnNotNullChecker : FirQualifiedAccessChecker() {
object UselessCallOnNotNullChecker : FirQualifiedAccessExpressionChecker() {
// todo: add 'call may be reduced' in cases like 's?.isNullOrEmpty()' where 's: String? = ""'
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val method = expression.getCallableId() ?: return
@@ -39,7 +39,7 @@ class ExpressionCheckersDiagnosticComponent(
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: CheckerContext) {
checkers.allQualifiedAccessCheckers.check(qualifiedAccessExpression, data, reporter)
checkers.allQualifiedAccessExpressionCheckers.check(qualifiedAccessExpression, data, reporter)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) {
@@ -47,7 +47,7 @@ class ExpressionCheckersDiagnosticComponent(
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: CheckerContext) {
checkers.allQualifiedAccessCheckers.check(callableReferenceAccess, data, reporter)
checkers.allQualifiedAccessExpressionCheckers.check(callableReferenceAccess, data, reporter)
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: CheckerContext) {