[FIR] Checkers performance improvement and some refactoring
This commit is contained in:
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
|
||||
@@ -70,6 +71,8 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
get() = _constructorCheckers
|
||||
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker>
|
||||
get() = _controlFlowAnalyserCheckers
|
||||
override val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker>
|
||||
get() = _variableAssignmentCfaBasedCheckers
|
||||
|
||||
private val _fileCheckers: MutableList<FirFileChecker> = mutableListOf()
|
||||
private val _declarationCheckers: MutableList<FirBasicDeclarationChecker> = mutableListOf()
|
||||
@@ -77,6 +80,7 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
private val _regularClassCheckers: MutableList<FirRegularClassChecker> = mutableListOf()
|
||||
private val _constructorCheckers: MutableList<FirConstructorChecker> = mutableListOf()
|
||||
private val _controlFlowAnalyserCheckers: MutableList<FirControlFlowChecker> = mutableListOf()
|
||||
private val _variableAssignmentCfaBasedCheckers: MutableList<AbstractFirCfaPropertyAssignmentChecker> = mutableListOf()
|
||||
|
||||
fun register(checkers: DeclarationCheckers) {
|
||||
_fileCheckers += checkers.allFileCheckers
|
||||
@@ -85,6 +89,7 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
_regularClassCheckers += checkers.allRegularClassCheckers
|
||||
_constructorCheckers += checkers.allConstructorCheckers
|
||||
_controlFlowAnalyserCheckers += checkers.controlFlowAnalyserCheckers
|
||||
_variableAssignmentCfaBasedCheckers += checkers.variableAssignmentCfaBasedCheckers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -8,14 +8,18 @@ package org.jetbrains.kotlin.fir.analysis.cfa
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
|
||||
abstract class AbstractFirPropertyInitializationChecker : FirControlFlowChecker() {
|
||||
abstract override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter)
|
||||
abstract class AbstractFirCfaPropertyAssignmentChecker {
|
||||
abstract fun analyze(
|
||||
graph: ControlFlowGraph,
|
||||
reporter: DiagnosticReporter,
|
||||
data: Map<CFGNode<*>, PropertyInitializationInfo>,
|
||||
properties: Set<FirPropertySymbol>
|
||||
)
|
||||
|
||||
class PropertyInitializationInfo(
|
||||
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
|
||||
|
||||
+10
-2
@@ -15,7 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
|
||||
|
||||
class FirControlFlowAnalyzer(session: FirSession) {
|
||||
private val checkers = session.checkersComponent.declarationCheckers.controlFlowAnalyserCheckers
|
||||
private val cfaCheckers = session.checkersComponent.declarationCheckers.controlFlowAnalyserCheckers
|
||||
private val variableAssignmentCheckers = session.checkersComponent.declarationCheckers.variableAssignmentCfaBasedCheckers
|
||||
|
||||
fun analyzeClassInitializer(klass: FirClass<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (graph.owner != null) return
|
||||
@@ -24,7 +25,14 @@ class FirControlFlowAnalyzer(session: FirSession) {
|
||||
|
||||
fun analyzeFunction(function: FirFunction<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (graph.owner != null) return
|
||||
checkers.forEach { it.analyze(graph, reporter) }
|
||||
|
||||
cfaCheckers.forEach { it.analyze(graph, reporter) }
|
||||
|
||||
val properties = AbstractFirCfaPropertyAssignmentChecker.LocalPropertyCollector.collect(graph)
|
||||
if (properties.isEmpty()) return
|
||||
val data = AbstractFirCfaPropertyAssignmentChecker.DataCollector(properties).getData(graph)
|
||||
|
||||
variableAssignmentCheckers.forEach { it.analyze(graph, reporter, data, properties) }
|
||||
}
|
||||
|
||||
fun analyzePropertyInitializer(property: FirProperty, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
|
||||
+17
-8
@@ -16,15 +16,24 @@ import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraphVisitorVoid
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.QualifiedAccessNode
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
|
||||
object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChecker() {
|
||||
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
|
||||
val localProperties = LocalPropertyCollector.collect(graph)
|
||||
// we want to analyze only properties without initializers
|
||||
localProperties.retainAll { it.fir.initializer == null && it.fir.delegate == null }
|
||||
if (localProperties.isEmpty()) return
|
||||
val data = DataCollector(localProperties).getData(graph)
|
||||
val reporterVisitor = UninitializedPropertyReporter(data, localProperties, reporter)
|
||||
object FirPropertyInitializationAnalyzer : AbstractFirCfaPropertyAssignmentChecker() {
|
||||
override fun analyze(
|
||||
graph: ControlFlowGraph,
|
||||
reporter: DiagnosticReporter,
|
||||
data: Map<CFGNode<*>, PropertyInitializationInfo>,
|
||||
properties: Set<FirPropertySymbol>
|
||||
) {
|
||||
// getting symbols of properties without initializers and non-variable symbols
|
||||
val localData = data.filter {
|
||||
val symbolFir = (it.key.fir as? FirVariableSymbol<*>)?.fir
|
||||
symbolFir == null || symbolFir.initializer == null && symbolFir.delegate == null
|
||||
}
|
||||
|
||||
val localProperties = properties.filter { it.fir.initializer == null && it.fir.delegate == null }.toSet()
|
||||
|
||||
val reporterVisitor = UninitializedPropertyReporter(localData, localProperties, reporter)
|
||||
graph.traverse(TraverseDirection.Forward, reporterVisitor)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.toVisibility
|
||||
@@ -185,7 +184,7 @@ fun FirClassLikeDeclaration<*>.followAllAlias(session: FirSession): FirClassLike
|
||||
* or null if no such item could be found.
|
||||
*/
|
||||
fun CheckerContext.findClosestClassOrObject(): FirClass<*>? {
|
||||
for (it in containingDeclarations.reversed()) {
|
||||
for (it in containingDeclarations.asReversed()) {
|
||||
if (
|
||||
it is FirRegularClass ||
|
||||
it is FirAnonymousObject
|
||||
@@ -237,20 +236,20 @@ fun FirClass<*>.modality(): Modality? {
|
||||
/**
|
||||
* returns implicit modality by FirMemberDeclaration
|
||||
*/
|
||||
fun FirMemberDeclaration.implicitModality(context: CheckerContext): KtModifierKeywordToken {
|
||||
fun FirMemberDeclaration.implicitModality(context: CheckerContext): Modality {
|
||||
if (this is FirRegularClass && (this.classKind == ClassKind.CLASS || this.classKind == ClassKind.OBJECT)) {
|
||||
if (this.classKind == ClassKind.INTERFACE) return KtTokens.ABSTRACT_KEYWORD
|
||||
return KtTokens.FINAL_KEYWORD
|
||||
if (this.classKind == ClassKind.INTERFACE) return Modality.ABSTRACT
|
||||
return Modality.FINAL
|
||||
}
|
||||
|
||||
val klass = context.findClosestClassOrObject() ?: return KtTokens.FINAL_KEYWORD
|
||||
val modifiers = this.modifierListOrNull() ?: return KtTokens.FINAL_KEYWORD
|
||||
val klass = context.findClosestClassOrObject() ?: return Modality.FINAL
|
||||
val modifiers = this.modifierListOrNull() ?: return Modality.FINAL
|
||||
if (modifiers.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
val klassModifiers = klass.modifierListOrNull()
|
||||
if (klassModifiers != null && klassModifiers.run {
|
||||
hasModifier(KtTokens.ABSTRACT_KEYWORD) || hasModifier(KtTokens.OPEN_KEYWORD) || hasModifier(KtTokens.SEALED_KEYWORD)
|
||||
}) {
|
||||
return KtTokens.OPEN_KEYWORD
|
||||
return Modality.OPEN
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,10 +258,10 @@ fun FirMemberDeclaration.implicitModality(context: CheckerContext): KtModifierKe
|
||||
&& klass.classKind == ClassKind.INTERFACE
|
||||
&& !modifiers.hasModifier(KtTokens.PRIVATE_KEYWORD)
|
||||
) {
|
||||
return if (this.hasBody()) KtTokens.OPEN_KEYWORD else KtTokens.ABSTRACT_KEYWORD
|
||||
return if (this.hasBody()) Modality.OPEN else Modality.ABSTRACT
|
||||
}
|
||||
|
||||
return KtTokens.FINAL_KEYWORD
|
||||
return Modality.FINAL
|
||||
}
|
||||
|
||||
private fun FirDeclaration.modifierListOrNull() = (this.source.getModifierList() as? FirPsiModifierList)?.modifierList
|
||||
|
||||
+2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||
|
||||
abstract class DeclarationCheckers {
|
||||
@@ -18,6 +19,7 @@ abstract class DeclarationCheckers {
|
||||
open val regularClassCheckers: List<FirRegularClassChecker> = emptyList()
|
||||
open val constructorCheckers: List<FirConstructorChecker> = emptyList()
|
||||
open val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = emptyList()
|
||||
open val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker> = emptyList()
|
||||
|
||||
internal val allFileCheckers: List<FirFileChecker> get() = fileCheckers + declarationCheckers
|
||||
internal val allMemberDeclarationCheckers: List<FirMemberDeclarationChecker> get() = memberDeclarationCheckers + declarationCheckers
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.*
|
||||
|
||||
object ExtendedDeclarationCheckers : DeclarationCheckers() {
|
||||
@@ -20,7 +20,7 @@ object ExtendedDeclarationCheckers : DeclarationCheckers() {
|
||||
RedundantSetterParameterTypeChecker
|
||||
)
|
||||
|
||||
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = listOf(
|
||||
override val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker> = listOf(
|
||||
VariableAssignmentChecker
|
||||
)
|
||||
}
|
||||
+12
-6
@@ -22,16 +22,19 @@ import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
|
||||
|
||||
object CanBeReplacedWithOperatorAssignmentChecker : FirExpressionChecker<FirVariableAssignment>() {
|
||||
override fun check(functionCall: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lValue = functionCall.lValue
|
||||
override fun check(assignment: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lValue = assignment.lValue
|
||||
if (lValue !is FirResolvedNamedReference) return
|
||||
val operator = functionCall.psi?.children?.getOrNull(1) ?: return
|
||||
if (operator.text != "=") return
|
||||
|
||||
val operator = assignment.psi?.children?.getOrNull(1) ?: return
|
||||
val operationSign = (operator as? KtOperationReferenceExpression)?.operationSignTokenType
|
||||
if (operationSign != KtTokens.EQ) return
|
||||
|
||||
val lValuePsi = lValue.psi as? KtNameReferenceExpression ?: return
|
||||
val rValue = functionCall.rValue as? FirFunctionCall ?: return
|
||||
val rValue = assignment.rValue as? FirFunctionCall ?: return
|
||||
val rValuePsi = rValue.psi as? KtBinaryExpression ?: return
|
||||
val rValueClassId = rValue.explicitReceiver?.typeRef?.coneType?.classId
|
||||
|
||||
@@ -56,9 +59,12 @@ object CanBeReplacedWithOperatorAssignmentChecker : FirExpressionChecker<FirVari
|
||||
|
||||
val isLeftMatch = isHierarchicallyTrue(operationToken, leftExpression?.operationToken)
|
||||
&& leftExpression?.matcher(variable) == true
|
||||
if (isLeftMatch) return true
|
||||
val isRightMatch = isHierarchicallyTrue(operationToken, rightExpression?.operationToken)
|
||||
&& rightExpression?.matcher(variable) == true
|
||||
isLeftMatch or isRightMatch
|
||||
if (isRightMatch) return true
|
||||
|
||||
false
|
||||
} else {
|
||||
val leftExpression = left as? KtBinaryExpression
|
||||
|
||||
|
||||
+28
-4
@@ -10,17 +10,17 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpresionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||
|
||||
object EmptyRangeChecker : FirBasicExpresionChecker() {
|
||||
override fun check(functionCall: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (functionCall.source is FirFakeSourceElement<*>) return
|
||||
if (functionCall !is FirFunctionCall) return
|
||||
val range = functionCall.psi ?: return
|
||||
val left = range.children.getOrNull(0)?.text?.toLongOrNull() ?: return
|
||||
val right = range.children.getOrNull(2)?.text?.toLongOrNull() ?: return
|
||||
val left = functionCall.rangeLeft ?: return
|
||||
val right = functionCall.rangeRight ?: return
|
||||
|
||||
val needReport = when (functionCall.calleeReference.name.asString()) {
|
||||
"rangeTo" -> {
|
||||
@@ -41,4 +41,28 @@ object EmptyRangeChecker : FirBasicExpresionChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private val FirFunctionCall.rangeLeft: Long?
|
||||
get() {
|
||||
return if (explicitReceiver is FirIntegerOperatorCall) {
|
||||
(explicitReceiver as? FirIntegerOperatorCall)?.asLong
|
||||
} else {
|
||||
(explicitReceiver as? FirConstExpression<*>)?.value as? Long
|
||||
}
|
||||
}
|
||||
|
||||
private val FirFunctionCall.rangeRight: Long?
|
||||
get() {
|
||||
val arg = argumentList.arguments.getOrNull(0)
|
||||
return if (arg is FirIntegerOperatorCall) arg.asLong
|
||||
else (arg as? FirConstExpression<*>)?.value as? Long
|
||||
}
|
||||
|
||||
private val FirIntegerOperatorCall.asLong: Long?
|
||||
get() {
|
||||
val value = (dispatchReceiver as? FirConstExpression<*>)?.value as Long? ?: return null
|
||||
if (this.calleeReference.name.asString() == "unaryMinus") {
|
||||
return -value
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private val targetClassMap = mapOf(
|
||||
private val targetClassMap = hashMapOf(
|
||||
"toString" to StandardClassIds.String,
|
||||
"toDouble" to StandardClassIds.Double,
|
||||
"toFloat" to StandardClassIds.Float,
|
||||
|
||||
+5
-6
@@ -5,8 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.extended
|
||||
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
|
||||
@@ -15,10 +15,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.modality
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.toFirPsiSourceElement
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
|
||||
|
||||
@@ -26,10 +25,9 @@ object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
|
||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.source is FirFakeSourceElement<*>) return
|
||||
|
||||
val modalityModifier = (declaration.psi as? KtDeclaration)?.modalityModifier() ?: return
|
||||
val modality = (modalityModifier as? LeafPsiElement)?.elementType as? KtModifierKeywordToken ?: return
|
||||
val modality = declaration.modality ?: return
|
||||
if (
|
||||
modality == KtTokens.FINAL_KEYWORD
|
||||
modality == Modality.FINAL
|
||||
&& (context.containingDeclarations.last() as? FirClass<*>)?.classKind == ClassKind.INTERFACE
|
||||
) return
|
||||
|
||||
@@ -37,6 +35,7 @@ object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
|
||||
|
||||
if (modality != implicitModality) return
|
||||
|
||||
val modalityModifier = (declaration.psi as? KtDeclaration)?.modalityModifier() ?: return
|
||||
reporter.report(modalityModifier.toFirPsiSourceElement(), REDUNDANT_MODALITY_MODIFIER)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -19,10 +19,9 @@ object RedundantReturnUnitType : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirSimpleFunction) return
|
||||
if (declaration.body is FirSingleExpressionBlock) return
|
||||
if (declaration.returnTypeRef.source == null) return
|
||||
if (declaration.source is FirFakeSourceElement<*>) return
|
||||
|
||||
val returnType = declaration.returnTypeRef
|
||||
if (returnType.source == null) return
|
||||
if (declaration.source is FirFakeSourceElement<*>) return
|
||||
if (returnType.annotations.isNotEmpty()) return
|
||||
|
||||
if (returnType.isUnit) {
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ object RedundantSetterParameterTypeChecker : FirMemberDeclarationChecker() {
|
||||
val valueParameter = setter.valueParameters.firstOrNull() ?: return
|
||||
val propertyTypeSource = declaration.returnTypeRef.source
|
||||
val setterParameterTypeSource = valueParameter.returnTypeRef.source ?: return
|
||||
|
||||
if (setterParameterTypeSource != propertyTypeSource) {
|
||||
reporter.report(setterParameterTypeSource, REDUNDANT_SETTER_PARAMETER_TYPE)
|
||||
}
|
||||
|
||||
+1
-2
@@ -33,7 +33,6 @@ object RedundantSingleExpressionStringTemplateChecker : FirBasicExpresionChecker
|
||||
|
||||
private fun PsiElement.findStringParent(): KtStringTemplateExpression? {
|
||||
if (this is KtStringTemplateExpression) return this
|
||||
return if (this.parent != null) this.parent.findStringParent()
|
||||
else null
|
||||
return this.parent?.findStringParent()
|
||||
}
|
||||
}
|
||||
|
||||
+10
-9
@@ -9,7 +9,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.TraverseDirection
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.traverse
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
@@ -22,16 +22,17 @@ import org.jetbrains.kotlin.fir.toFirPsiSourceElement
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
|
||||
|
||||
object VariableAssignmentChecker : AbstractFirPropertyInitializationChecker() {
|
||||
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
|
||||
object VariableAssignmentChecker : AbstractFirCfaPropertyAssignmentChecker() {
|
||||
override fun analyze(
|
||||
graph: ControlFlowGraph,
|
||||
reporter: DiagnosticReporter,
|
||||
data: Map<CFGNode<*>, PropertyInitializationInfo>,
|
||||
properties: Set<FirPropertySymbol>
|
||||
) {
|
||||
val unprocessedProperties = mutableSetOf<FirPropertySymbol>()
|
||||
val propertiesCharacteristics = mutableMapOf<FirPropertySymbol, EventOccurrencesRange>()
|
||||
|
||||
val localProperties = LocalPropertyCollector.collect(graph)
|
||||
if (localProperties.isEmpty()) return
|
||||
|
||||
val data = DataCollector(localProperties).getData(graph)
|
||||
val reporterVisitor = UninitializedPropertyReporter(data, localProperties, unprocessedProperties, propertiesCharacteristics)
|
||||
val reporterVisitor = UninitializedPropertyReporter(data, properties, unprocessedProperties, propertiesCharacteristics)
|
||||
graph.traverse(TraverseDirection.Forward, reporterVisitor)
|
||||
|
||||
for (property in unprocessedProperties) {
|
||||
@@ -63,7 +64,7 @@ object VariableAssignmentChecker : AbstractFirPropertyInitializationChecker() {
|
||||
destructuringCanBeVal = false
|
||||
}
|
||||
lastDestructuredVariables--
|
||||
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null ) {
|
||||
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null) {
|
||||
reporter.report(source, FirErrors.CAN_BE_VAL)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user