[FIR] Add CheckerContext to DiagnosticReporter and refactor diagnostic reporting

Refactoring includes replacing `Diagnostic.report` extensions in
  checkers with `DiagnosticReporter.reportOn` extension declared
  in DiagnosticReporter.kt
This commit is contained in:
Dmitriy Novozhilov
2021-02-01 17:01:45 +03:00
parent 923a4427c5
commit 459a2886a0
68 changed files with 486 additions and 552 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.cfa package org.jetbrains.kotlin.fir.analysis.cfa
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
@@ -15,6 +16,7 @@ abstract class AbstractFirPropertyInitializationChecker {
graph: ControlFlowGraph, graph: ControlFlowGraph,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>, data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol> properties: Set<FirPropertySymbol>,
context: CheckerContext
) )
} }
@@ -43,7 +43,7 @@ import kotlin.contracts.contract
object FirCallsEffectAnalyzer : FirControlFlowChecker() { object FirCallsEffectAnalyzer : FirControlFlowChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) { override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
val function = (graph.declaration as? FirFunction<*>) ?: return val function = (graph.declaration as? FirFunction<*>) ?: return
if (function !is FirContractDescriptionOwner) return if (function !is FirContractDescriptionOwner) return
if (function.contractDescription.coneEffects?.any { it is ConeCallsEffectDeclaration } != true) return if (function.contractDescription.coneEffects?.any { it is ConeCallsEffectDeclaration } != true) return
@@ -73,10 +73,10 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
for ((symbol, leakedPlaces) in leakedSymbols) { for ((symbol, leakedPlaces) in leakedSymbols) {
function.contractDescription.source?.let { function.contractDescription.source?.let {
reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol)) reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol), context)
} }
leakedPlaces.forEach { leakedPlaces.forEach {
reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol)) reporter.report(FirErrors.LEAKED_IN_PLACE_LAMBDA.on(it, symbol), context)
} }
} }
@@ -91,7 +91,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
val requiredRange = effectDeclaration.kind val requiredRange = effectDeclaration.kind
val pathAwareInfo = invocationData.getValue(node) val pathAwareInfo = invocationData.getValue(node)
for (info in pathAwareInfo.values) { for (info in pathAwareInfo.values) {
if (investigate(info, symbol, requiredRange, function, reporter)) { if (investigate(info, symbol, requiredRange, function, reporter, context)) {
// To avoid duplicate reports, stop investigating remaining paths once reported. // To avoid duplicate reports, stop investigating remaining paths once reported.
break break
} }
@@ -105,12 +105,13 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
symbol: AbstractFirBasedSymbol<*>, symbol: AbstractFirBasedSymbol<*>,
requiredRange: EventOccurrencesRange, requiredRange: EventOccurrencesRange,
function: FirContractDescriptionOwner, function: FirContractDescriptionOwner,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
): Boolean { ): Boolean {
val foundRange = info[symbol] ?: EventOccurrencesRange.ZERO val foundRange = info[symbol] ?: EventOccurrencesRange.ZERO
if (foundRange !in requiredRange) { if (foundRange !in requiredRange) {
function.contractDescription.source?.let { function.contractDescription.source?.let {
reporter.report(FirErrors.WRONG_INVOCATION_KIND.on(it, symbol, requiredRange, foundRange)) reporter.report(FirErrors.WRONG_INVOCATION_KIND.on(it, symbol, requiredRange, foundRange), context)
return true return true
} }
} }
@@ -29,27 +29,32 @@ class FirControlFlowAnalyzer(session: FirSession) {
cfaCheckers.forEach { it.analyze(graph, reporter, context) } cfaCheckers.forEach { it.analyze(graph, reporter, context) }
if (context.containingDeclarations.any { it is FirProperty || it is FirFunction<*> }) return if (context.containingDeclarations.any { it is FirProperty || it is FirFunction<*> }) return
runAssignmentCfaCheckers(graph, reporter) runAssignmentCfaCheckers(graph, reporter, context)
} }
fun analyzePropertyInitializer(property: FirProperty, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) { fun analyzePropertyInitializer(property: FirProperty, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return if (graph.owner != null) return
cfaCheckers.forEach { it.analyze(graph, reporter, context) } cfaCheckers.forEach { it.analyze(graph, reporter, context) }
runAssignmentCfaCheckers(graph, reporter) runAssignmentCfaCheckers(graph, reporter, context)
} }
fun analyzePropertyAccessor(accessor: FirPropertyAccessor, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) { fun analyzePropertyAccessor(
accessor: FirPropertyAccessor,
graph: ControlFlowGraph,
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (graph.owner != null) return if (graph.owner != null) return
cfaCheckers.forEach { it.analyze(graph, reporter, context) } cfaCheckers.forEach { it.analyze(graph, reporter, context) }
runAssignmentCfaCheckers(graph, reporter) runAssignmentCfaCheckers(graph, reporter, context)
} }
private fun runAssignmentCfaCheckers(graph: ControlFlowGraph, reporter: DiagnosticReporter) { private fun runAssignmentCfaCheckers(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
val properties = LocalPropertyCollector.collect(graph) val properties = LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return if (properties.isEmpty()) return
val data = PropertyInitializationInfoCollector(properties).getData(graph) val data = PropertyInitializationInfoCollector(properties).getData(graph)
variableAssignmentCheckers.forEach { it.analyze(graph, reporter, data, properties) } variableAssignmentCheckers.forEach { it.analyze(graph, reporter, data, properties, context) }
} }
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.cfa
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.isLateInit import org.jetbrains.kotlin.fir.declarations.isLateInit
@@ -23,7 +24,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
graph: ControlFlowGraph, graph: ControlFlowGraph,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>, data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol> properties: Set<FirPropertySymbol>,
context: CheckerContext
) { ) {
val localData = data.filter { val localData = data.filter {
val symbolFir = (it.key.fir as? FirVariableSymbol<*>)?.fir val symbolFir = (it.key.fir as? FirVariableSymbol<*>)?.fir
@@ -32,14 +34,15 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
val localProperties = properties.filter { it.fir.initializer == null && it.fir.delegate == null }.toSet() val localProperties = properties.filter { it.fir.initializer == null && it.fir.delegate == null }.toSet()
val reporterVisitor = UninitializedPropertyReporter(localData, localProperties, reporter) val reporterVisitor = UninitializedPropertyReporter(localData, localProperties, reporter, context)
graph.traverse(TraverseDirection.Forward, reporterVisitor) graph.traverse(TraverseDirection.Forward, reporterVisitor)
} }
private class UninitializedPropertyReporter( private class UninitializedPropertyReporter(
val data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>, val data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
val localProperties: Set<FirPropertySymbol>, val localProperties: Set<FirPropertySymbol>,
val reporter: DiagnosticReporter val reporter: DiagnosticReporter,
val context: CheckerContext
) : ControlFlowGraphVisitorVoid() { ) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {} override fun visitNode(node: CFGNode<*>) {}
@@ -61,7 +64,7 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
val kind = info[symbol] ?: EventOccurrencesRange.ZERO val kind = info[symbol] ?: EventOccurrencesRange.ZERO
if (!kind.isDefinitelyVisited()) { if (!kind.isDefinitelyVisited()) {
node.fir.source?.let { node.fir.source?.let {
reporter.report(FirErrors.UNINITIALIZED_VARIABLE.on(it, symbol)) reporter.report(FirErrors.UNINITIALIZED_VARIABLE.on(it, symbol), context)
return true return true
} }
} }
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
object FirReturnsImpliesAnalyzer : FirControlFlowChecker() { object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) { override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
val function = graph.declaration as? FirFunction<*> ?: return val function = graph.declaration as? FirFunction<*> ?: return
val graphRef = function.controlFlowGraphReference as FirControlFlowGraphReferenceImpl val graphRef = function.controlFlowGraphReference as FirControlFlowGraphReferenceImpl
val dataFlowInfo = graphRef.dataFlowInfo val dataFlowInfo = graphRef.dataFlowInfo
@@ -62,7 +62,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
if (wrongCondition) { if (wrongCondition) {
function.contractDescription.source?.let { function.contractDescription.source?.let {
reporter.report(FirErrors.WRONG_IMPLIES_CONDITION.on(it)) reporter.report(FirErrors.WRONG_IMPLIES_CONDITION.on(it), context)
} }
} }
} }
@@ -10,5 +10,5 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
abstract class FirControlFlowChecker { abstract class FirControlFlowChecker {
abstract fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) abstract fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext)
} }
@@ -5,21 +5,24 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -36,8 +39,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
for ((arg, _) in declarationOfAnnotation.argumentMapping ?: continue) { for ((arg, _) in declarationOfAnnotation.argumentMapping ?: continue) {
val expression = (arg as? FirNamedArgumentExpression)?.expression ?: arg val expression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
checkAnnotationArgumentWithSubElements(expression, context.session, reporter) checkAnnotationArgumentWithSubElements(expression, context.session, reporter, context)
?.let { reporter.report(expression.source, it) } ?.let { reporter.reportOn(expression.source, it, context) }
} }
} }
} }
@@ -45,7 +48,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
private fun checkAnnotationArgumentWithSubElements( private fun checkAnnotationArgumentWithSubElements(
expression: FirExpression, expression: FirExpression,
session: FirSession, session: FirSession,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
): FirDiagnosticFactory0<FirSourceElement, KtExpression>? { ): FirDiagnosticFactory0<FirSourceElement, KtExpression>? {
when (expression) { when (expression) {
is FirArrayOfCall -> { is FirArrayOfCall -> {
@@ -54,13 +58,13 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
for (arg in expression.argumentList.arguments) { for (arg in expression.argumentList.arguments) {
val sourceForReport = arg.source val sourceForReport = arg.source
when (val err = checkAnnotationArgumentWithSubElements(arg, session, reporter)) { when (val err = checkAnnotationArgumentWithSubElements(arg, session, reporter, context)) {
null -> { null -> {
//DO NOTHING //DO NOTHING
} }
else -> { else -> {
if (err != FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL) usedNonConst = true if (err != FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL) usedNonConst = true
reporter.report(sourceForReport, err) reporter.reportOn(sourceForReport, err, context)
} }
} }
} }
@@ -69,8 +73,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
} }
is FirVarargArgumentsExpression -> { is FirVarargArgumentsExpression -> {
for (arg in expression.arguments) for (arg in expression.arguments)
checkAnnotationArgumentWithSubElements(arg, session, reporter) checkAnnotationArgumentWithSubElements(arg, session, reporter, context)
?.let { reporter.report(arg.source, it) } ?.let { reporter.reportOn(arg.source, it, context) }
} }
else -> else ->
return checkAnnotationArgument(expression, session) return checkAnnotationArgument(expression, session)
@@ -224,13 +228,6 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
?.toSymbol(session) ?.toSymbol(session)
?.fir ?.fir
private inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.report(
source: T?,
factory: FirDiagnosticFactory0<T, P>
) {
source?.let { report(factory.on(it)) }
}
private val CONVERSION_NAMES = listOf( private val CONVERSION_NAMES = listOf(
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean" "toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
).mapTo(hashSetOf()) { Name.identifier(it) } ).mapTo(hashSetOf()) { Name.identifier(it) }
@@ -5,28 +5,26 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes.FUN
import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER
import org.jetbrains.kotlin.descriptors.ClassKind.ANNOTATION_CLASS import org.jetbrains.kotlin.descriptors.ClassKind.ANNOTATION_CLASS
import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS import org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveArrayTypeByElementType import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveArrayTypeByElementType
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveTypes import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveTypes
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.unsignedTypes import org.jetbrains.kotlin.fir.symbols.StandardClassIds.unsignedTypes
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.KtNodeTypes.FUN
import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() { object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.classKind != ANNOTATION_CLASS) return if (declaration.classKind != ANNOTATION_CLASS) return
if (declaration.isLocal) reporter.report(declaration.source, FirErrors.LOCAL_ANNOTATION_CLASS_ERROR) if (declaration.isLocal) reporter.reportOn(declaration.source, FirErrors.LOCAL_ANNOTATION_CLASS_ERROR, context)
for (it in declaration.declarations) { for (it in declaration.declarations) {
when { when {
@@ -34,9 +32,9 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
for (parameter in it.valueParameters) { for (parameter in it.valueParameters) {
val source = parameter.source ?: continue val source = parameter.source ?: continue
if (!source.hasValOrVar()) { if (!source.hasValOrVar()) {
reporter.report(source, FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER) reporter.reportOn(source, FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER, context)
} else if (source.hasVar()) { } else if (source.hasVar()) {
reporter.report(source, FirErrors.VAR_ANNOTATION_PARAMETER) reporter.reportOn(source, FirErrors.VAR_ANNOTATION_PARAMETER, context)
} }
val typeRef = parameter.returnTypeRef val typeRef = parameter.returnTypeRef
@@ -48,7 +46,7 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
// TODO: replace with UNRESOLVED_REFERENCE check // TODO: replace with UNRESOLVED_REFERENCE check
} }
coneType.isNullable -> { coneType.isNullable -> {
reporter.report(typeRef.source, FirErrors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER) reporter.reportOn(typeRef.source, FirErrors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER, context)
} }
classId in primitiveTypes -> { classId in primitiveTypes -> {
// DO NOTHING: primitives are allowed as annotation class parameter // DO NOTHING: primitives are allowed as annotation class parameter
@@ -67,13 +65,13 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
} }
classId == StandardClassIds.Array -> { classId == StandardClassIds.Array -> {
if (!isAllowedArray(typeRef, context.session)) if (!isAllowedArray(typeRef, context.session))
reporter.report(typeRef.source, FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER) reporter.reportOn(typeRef.source, FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER, context)
} }
isAllowedClassKind(coneType, context.session) -> { isAllowedClassKind(coneType, context.session) -> {
// DO NOTHING: annotation or enum classes are allowed // DO NOTHING: annotation or enum classes are allowed
} }
else -> { else -> {
reporter.report(typeRef.source, FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER) reporter.reportOn(typeRef.source, FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER, context)
} }
} }
} }
@@ -89,7 +87,7 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
// TODO: replace with origin check // TODO: replace with origin check
} }
else -> { else -> {
reporter.report(it.source, FirErrors.ANNOTATION_CLASS_MEMBER) reporter.reportOn(it.source, FirErrors.ANNOTATION_CLASS_MEMBER, context)
} }
} }
} }
@@ -134,11 +132,4 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
return false return false
} }
private inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.report(
source: T?,
factory: FirDiagnosticFactory0<T, P>
) {
source?.let { report(factory.on(it)) }
}
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -47,9 +47,9 @@ object FirCommonConstructorDelegationIssuesChecker : FirRegularClassChecker() {
for (it in otherConstructors) { for (it in otherConstructors) {
if (it.delegatedConstructor?.isThis != true) { if (it.delegatedConstructor?.isThis != true) {
if (it.delegatedConstructor?.source != null) { if (it.delegatedConstructor?.source != null) {
reporter.reportPrimaryConstructorDelegationCallExpected(it.delegatedConstructor?.source) reporter.reportOn(it.delegatedConstructor?.source, FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, context)
} else { } else {
reporter.reportPrimaryConstructorDelegationCallExpected(it.source) reporter.reportOn(it.source, FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, context)
} }
} }
} }
@@ -62,13 +62,13 @@ object FirCommonConstructorDelegationIssuesChecker : FirRegularClassChecker() {
callee is FirErrorNamedReference && callee.diagnostic is ConeAmbiguityError && callee is FirErrorNamedReference && callee.diagnostic is ConeAmbiguityError &&
it.delegatedConstructor?.source?.kind is FirFakeSourceElementKind it.delegatedConstructor?.source?.kind is FirFakeSourceElementKind
) { ) {
reporter.reportExplicitDelegationCallRequired(it.source) reporter.reportOn(it.source, FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED, context)
} }
} }
} }
cyclicConstructors.forEach { cyclicConstructors.forEach {
reporter.reportCyclicConstructorDelegationCall(it.delegatedConstructor?.source) reporter.reportOn(it.delegatedConstructor?.source, FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL, context)
} }
} }
@@ -95,16 +95,4 @@ object FirCommonConstructorDelegationIssuesChecker : FirRegularClassChecker() {
?.calleeReference.safeAs<FirResolvedNamedReference>() ?.calleeReference.safeAs<FirResolvedNamedReference>()
?.resolvedSymbol ?.resolvedSymbol
?.fir.safeAs() ?.fir.safeAs()
private fun DiagnosticReporter.reportCyclicConstructorDelegationCall(source: FirSourceElement?) {
source?.let { report(FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(it)) }
}
private fun DiagnosticReporter.reportPrimaryConstructorDelegationCallExpected(source: FirSourceElement?) {
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(it)) }
}
private fun DiagnosticReporter.reportExplicitDelegationCallRequired(source: FirSourceElement?) {
source?.let { report(FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED.on(it)) }
}
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -35,7 +35,7 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
is FirTypeAlias -> { is FirTypeAlias -> {
for (it in declaration.typeParameters) { for (it in declaration.typeParameters) {
if (it.variance != Variance.INVARIANT) { if (it.variance != Variance.INVARIANT) {
reporter.reportVarianceNotAllowed(it.source) reporter.reportOn(it.source, FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, context)
} }
} }
checkTypeRef(declaration.expandedTypeRef, context, reporter) checkTypeRef(declaration.expandedTypeRef, context, reporter)
@@ -70,17 +70,9 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE || actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE
) { ) {
reporter.reportConflictingProjections(typeRef.source, typeRef.coneType.toString()) reporter.reportOn(typeRef.source, FirErrors.CONFLICTING_PROJECTION, typeRef.coneType.toString(), context)
return return
} }
} }
} }
private fun DiagnosticReporter.reportConflictingProjections(source: FirSourceElement?, desiredProjection: String) {
source?.let { report(FirErrors.CONFLICTING_PROJECTION.on(it, desiredProjection)) }
}
private fun DiagnosticReporter.reportVarianceNotAllowed(source: FirSourceElement?) {
source?.let { report(FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED.on(it)) }
}
} }
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
@@ -25,11 +25,11 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
} }
inspector.functionDeclarations.forEachNonSingle { it, hint -> inspector.functionDeclarations.forEachNonSingle { it, hint ->
reporter.reportConflictingOverloads(it.source, hint) reporter.reportOn(it.source, FirErrors.CONFLICTING_OVERLOADS, hint, context)
} }
inspector.otherDeclarations.forEachNonSingle { it, hint -> inspector.otherDeclarations.forEachNonSingle { it, hint ->
reporter.reportConflictingDeclarations(it.source, hint) reporter.reportOn(it.source, FirErrors.REDECLARATION, hint, context)
} }
} }
@@ -56,12 +56,4 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
inspector.collect(it) inspector.collect(it)
} }
} }
private fun DiagnosticReporter.reportConflictingOverloads(source: FirSourceElement?, declarations: String) {
source?.let { report(FirErrors.CONFLICTING_OVERLOADS.on(it, declarations)) }
}
private fun DiagnosticReporter.reportConflictingDeclarations(source: FirSourceElement?, declarations: String) {
source?.let { report(FirErrors.REDECLARATION.on(it, declarations)) }
}
} }
@@ -5,16 +5,14 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
object FirConstructorAllowedChecker : FirConstructorChecker() { object FirConstructorAllowedChecker : FirConstructorChecker() {
@@ -26,27 +24,20 @@ object FirConstructorAllowedChecker : FirConstructorChecker() {
return return
} }
when (containingClass.classKind) { when (containingClass.classKind) {
ClassKind.OBJECT -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT) ClassKind.OBJECT -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_OBJECT, context)
ClassKind.INTERFACE -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_INTERFACE) ClassKind.INTERFACE -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_INTERFACE, context)
ClassKind.ENUM_ENTRY -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT) ClassKind.ENUM_ENTRY -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_OBJECT, context)
ClassKind.ENUM_CLASS -> if (declaration.visibility != Visibilities.Private) { ClassKind.ENUM_CLASS -> if (declaration.visibility != Visibilities.Private) {
reporter.report(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM) reporter.reportOn(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM, context)
} }
ClassKind.CLASS -> if (containingClass is FirRegularClass && containingClass.modality == Modality.SEALED && ClassKind.CLASS -> if (containingClass is FirRegularClass && containingClass.modality == Modality.SEALED &&
declaration.visibility != Visibilities.Private declaration.visibility != Visibilities.Private
) { ) {
reporter.report(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED) reporter.reportOn(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED, context)
} }
ClassKind.ANNOTATION_CLASS -> { ClassKind.ANNOTATION_CLASS -> {
// DO NOTHING // DO NOTHING
} }
} }
} }
private inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.report(
source: T?,
factory: FirDiagnosticFactory0<T, P>
) {
source?.let { report(factory.on(it)) }
}
} }
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.hasPrimaryConstructor import org.jetbrains.kotlin.fir.analysis.diagnostics.hasPrimaryConstructor
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -20,11 +20,7 @@ object FirConstructorInInterfaceChecker : FirRegularClassChecker() {
} }
if (declaration.source?.hasPrimaryConstructor() == true) { if (declaration.source?.hasPrimaryConstructor() == true) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.CONSTRUCTOR_IN_INTERFACE, context)
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.CONSTRUCTOR_IN_INTERFACE.on(it)) }
}
} }
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
@@ -25,14 +25,15 @@ internal fun checkExpectDeclarationVisibilityAndBody(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
source: FirSourceElement, source: FirSourceElement,
modifierList: FirModifierList?, modifierList: FirModifierList?,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
) { ) {
if (declaration.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true) { if (declaration.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true) {
if (Visibilities.isPrivate(declaration.visibility)) { if (Visibilities.isPrivate(declaration.visibility)) {
reporter.report(source, FirErrors.EXPECTED_PRIVATE_DECLARATION) reporter.reportOn(source, FirErrors.EXPECTED_PRIVATE_DECLARATION, context)
} }
if (declaration is FirSimpleFunction && declaration.hasBody) { if (declaration is FirSimpleFunction && declaration.hasBody) {
reporter.report(source, FirErrors.EXPECTED_DECLARATION_WITH_BODY) reporter.reportOn(source, FirErrors.EXPECTED_DECLARATION_WITH_BODY, context)
} }
} }
} }
@@ -40,7 +41,8 @@ internal fun checkExpectDeclarationVisibilityAndBody(
internal fun checkPropertyInitializer( internal fun checkPropertyInitializer(
containingClass: FirRegularClass?, containingClass: FirRegularClass?,
property: FirProperty, property: FirProperty,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
) { ) {
val inInterface = containingClass?.isInterface == true val inInterface = containingClass?.isInterface == true
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`. // If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
@@ -51,7 +53,7 @@ internal fun checkPropertyInitializer(
if (isAbstract) { if (isAbstract) {
if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) { if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) {
property.source?.let { property.source?.let {
reporter.report(it, FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER) reporter.reportOn(it, FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, context)
} }
} }
return return
@@ -61,7 +63,7 @@ internal fun checkPropertyInitializer(
val backingFieldRequired = property.hasBackingField val backingFieldRequired = property.hasBackingField
if (inInterface && backingFieldRequired && property.hasAccessorImplementation) { if (inInterface && backingFieldRequired && property.hasAccessorImplementation) {
property.source?.let { property.source?.let {
// reporter.report(it, FirErrors.BACKING_FIELD_IN_INTERFACE) // reporter.reportOn(it, FirErrors.BACKING_FIELD_IN_INTERFACE, context)
} }
} }
@@ -72,16 +74,16 @@ internal fun checkPropertyInitializer(
property.initializer?.source?.let { property.initializer?.source?.let {
when { when {
inInterface -> { inInterface -> {
reporter.report(it, FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE) reporter.reportOn(it, FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE, context)
} }
isExpect -> { isExpect -> {
reporter.report(it, FirErrors.EXPECTED_PROPERTY_INITIALIZER) reporter.reportOn(it, FirErrors.EXPECTED_PROPERTY_INITIALIZER, context)
} }
!backingFieldRequired -> { !backingFieldRequired -> {
// reporter.report(it, FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD) // reporter.reportOn(it, FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD, context)
} }
property.receiverTypeRef != null -> { property.receiverTypeRef != null -> {
// reporter.report(it, FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD) // reporter.reportOn(it, FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD, context)
} }
} }
} }
@@ -90,10 +92,10 @@ internal fun checkPropertyInitializer(
property.delegate?.source?.let { property.delegate?.source?.let {
when { when {
inInterface -> { inInterface -> {
reporter.report(it, FirErrors.DELEGATED_PROPERTY_IN_INTERFACE) reporter.reportOn(it, FirErrors.DELEGATED_PROPERTY_IN_INTERFACE, context)
} }
isExpect -> { isExpect -> {
reporter.report(it, FirErrors.EXPECTED_DELEGATED_PROPERTY) reporter.reportOn(it, FirErrors.EXPECTED_DELEGATED_PROPERTY, context)
} }
} }
} }
@@ -105,12 +107,12 @@ internal fun checkPropertyInitializer(
if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && isUninitialized && !isExternal) { if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && isUninitialized && !isExternal) {
property.source?.let { property.source?.let {
if (property.receiverTypeRef != null && !property.hasAccessorImplementation) { if (property.receiverTypeRef != null && !property.hasAccessorImplementation) {
// reporter.report(it, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT) // reporter.reportOn(it, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context)
} else { } else {
if (containingClass != null || property.hasAccessorImplementation) { if (containingClass != null || property.hasAccessorImplementation) {
// reporter.report(it, FirErrors.MUST_BE_INITIALIZED) // reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED, context)
} else { } else {
// reporter.report(it, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT) // reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context)
} }
} }
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -22,12 +22,8 @@ object FirDelegationInInterfaceChecker : FirRegularClassChecker() {
for (superTypeRef in declaration.superTypeRefs) { for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY) { if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY) {
reporter.report(source) reporter.reportOn(source, FirErrors.DELEGATION_IN_INTERFACE, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.DELEGATION_IN_INTERFACE.on(it)) }
}
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isEnumClass import org.jetbrains.kotlin.fir.declarations.isEnumClass
@@ -26,12 +26,8 @@ object FirDelegationSuperCallInEnumConstructorChecker : FirRegularClassChecker()
it.delegatedConstructor?.isThis == false && it.delegatedConstructor?.isThis == false &&
it.delegatedConstructor?.source?.kind !is FirFakeSourceElementKind it.delegatedConstructor?.source?.kind !is FirFakeSourceElementKind
) { ) {
reporter.report(it.delegatedConstructor?.source) reporter.reportOn(it.delegatedConstructor?.source, FirErrors.DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR.on(it)) }
}
} }
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
@@ -36,7 +36,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
assert(declaration.name.isSpecial && declaration.name.asString() == "<destruct>") { assert(declaration.name.isSpecial && declaration.name.asString() == "<destruct>") {
"Unexpected name: ${declaration.name.asString()} for destructuring declaration" "Unexpected name: ${declaration.name.asString()} for destructuring declaration"
} }
checkInitializer(source, declaration.initializer, reporter) checkInitializer(source, declaration.initializer, reporter, context)
return return
} }
@@ -82,7 +82,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
originalDestructuringDeclarationOrInitializerSource, originalDestructuringDeclarationOrInitializerSource,
diagnostic.name, diagnostic.name,
originalDestructuringDeclarationType originalDestructuringDeclarationType
) ),
context
) )
} }
is ConeAmbiguityError -> { is ConeAmbiguityError -> {
@@ -91,7 +92,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
originalDestructuringDeclarationOrInitializerSource, originalDestructuringDeclarationOrInitializerSource,
diagnostic.name, diagnostic.name,
diagnostic.candidates diagnostic.candidates
) ),
context
) )
} }
is ConeInapplicableCandidateError -> { is ConeInapplicableCandidateError -> {
@@ -100,7 +102,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
FirErrors.COMPONENT_FUNCTION_ON_NULLABLE.on( FirErrors.COMPONENT_FUNCTION_ON_NULLABLE.on(
originalDestructuringDeclarationOrInitializerSource, originalDestructuringDeclarationOrInitializerSource,
(diagnostic.candidateSymbol.fir as FirSimpleFunction).name (diagnostic.candidateSymbol.fir as FirSimpleFunction).name
) ),
context
) )
} }
} }
@@ -108,7 +111,12 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
} }
} }
private fun checkInitializer(source: FirSourceElement, initializer: FirExpression?, reporter: DiagnosticReporter) { private fun checkInitializer(
source: FirSourceElement,
initializer: FirExpression?,
reporter: DiagnosticReporter,
context: CheckerContext
) {
val needToReport = val needToReport =
when (initializer) { when (initializer) {
null -> true null -> true
@@ -116,7 +124,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
else -> false else -> false
} }
if (needToReport) { if (needToReport) {
reporter.report(source, FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) reporter.reportOn(source, FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, context)
} }
} }
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isEnumClass import org.jetbrains.kotlin.fir.declarations.isEnumClass
@@ -20,19 +20,11 @@ object FirEnumClassSimpleChecker : FirRegularClassChecker() {
} }
declaration.findNonInterfaceSupertype(context)?.let { declaration.findNonInterfaceSupertype(context)?.let {
reporter.reportClassInSupertypeForEnum(it.source) reporter.reportOn(it.source, FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM, context)
} }
if (declaration.typeParameters.isNotEmpty()) { if (declaration.typeParameters.isNotEmpty()) {
reporter.reportTypeParametersInEnum(declaration.typeParameters.firstOrNull()?.source) reporter.reportOn(declaration.typeParameters.firstOrNull()?.source, FirErrors.TYPE_PARAMETERS_IN_ENUM, context)
} }
} }
private fun DiagnosticReporter.reportClassInSupertypeForEnum(source: FirSourceElement?) {
source?.let { report(FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM.on(it)) }
}
private fun DiagnosticReporter.reportTypeParametersInEnum(source: FirSourceElement?) {
source?.let { report(FirErrors.TYPE_PARAMETERS_IN_ENUM.on(it)) }
}
} }
@@ -5,15 +5,16 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.FirEffectiveVisibility
import org.jetbrains.kotlin.fir.FirEffectiveVisibilityImpl
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory3
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.getEffectiveVisibility
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved
@@ -51,12 +52,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
} }
val restricting = supertype.findVisibilityExposure(context, classVisibility) val restricting = supertype.findVisibilityExposure(context, classVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
supertypeRef.source ?: declaration.source,
if (isInterface) FirErrors.EXPOSED_SUPER_INTERFACE else FirErrors.EXPOSED_SUPER_CLASS, if (isInterface) FirErrors.EXPOSED_SUPER_INTERFACE else FirErrors.EXPOSED_SUPER_CLASS,
restricting,
classVisibility, classVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
supertypeRef.source ?: declaration.source context
) )
} }
} }
@@ -70,12 +72,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
for (bound in parameter.symbol.fir.bounds) { for (bound in parameter.symbol.fir.bounds) {
val restricting = bound.coneType.findVisibilityExposure(context, classVisibility) val restricting = bound.coneType.findVisibilityExposure(context, classVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
bound.source,
FirErrors.EXPOSED_TYPE_PARAMETER_BOUND, FirErrors.EXPOSED_TYPE_PARAMETER_BOUND,
restricting,
classVisibility, classVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
bound.source context
) )
} }
} }
@@ -89,12 +92,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
if (typeAliasVisibility == FirEffectiveVisibilityImpl.Local) return if (typeAliasVisibility == FirEffectiveVisibilityImpl.Local) return
val restricting = expandedType?.findVisibilityExposure(context, typeAliasVisibility) val restricting = expandedType?.findVisibilityExposure(context, typeAliasVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE, FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE,
restricting,
typeAliasVisibility, typeAliasVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
declaration.source context
) )
} }
} }
@@ -107,12 +111,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
val restricting = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>() val restricting = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, functionVisibility) ?.findVisibilityExposure(context, functionVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_FUNCTION_RETURN_TYPE, FirErrors.EXPOSED_FUNCTION_RETURN_TYPE,
restricting,
functionVisibility, functionVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
declaration.source context
) )
} }
} }
@@ -122,12 +127,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
valueParameter.returnTypeRef.coneTypeSafe<ConeKotlinType>() valueParameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, functionVisibility) ?.findVisibilityExposure(context, functionVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
valueParameter.source,
FirErrors.EXPOSED_PARAMETER_TYPE, FirErrors.EXPOSED_PARAMETER_TYPE,
restricting,
functionVisibility, functionVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
valueParameter.source context
) )
} }
} }
@@ -143,12 +149,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>() declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, propertyVisibility) ?.findVisibilityExposure(context, propertyVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_PROPERTY_TYPE, FirErrors.EXPOSED_PROPERTY_TYPE,
restricting,
propertyVisibility, propertyVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
declaration.source context
) )
} }
checkMemberReceiver(declaration.receiverTypeRef, declaration, reporter, context) checkMemberReceiver(declaration.receiverTypeRef, declaration, reporter, context)
@@ -167,12 +174,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
if (memberVisibility == FirEffectiveVisibilityImpl.Local) return if (memberVisibility == FirEffectiveVisibilityImpl.Local) return
val restricting = receiverParameterType.findVisibilityExposure(context, memberVisibility) val restricting = receiverParameterType.findVisibilityExposure(context, memberVisibility)
if (restricting != null) { if (restricting != null) {
reporter.reportExposure( reporter.reportOn(
typeRef.source,
FirErrors.EXPOSED_RECEIVER_TYPE, FirErrors.EXPOSED_RECEIVER_TYPE,
restricting,
memberVisibility, memberVisibility,
restricting,
restricting.getEffectiveVisibility(context), restricting.getEffectiveVisibility(context),
typeRef.source context
) )
} }
} }
@@ -207,25 +215,6 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
return null return null
} }
private inline fun <reified E : FirSourceElement, P : PsiElement> DiagnosticReporter.reportExposure(
error: FirDiagnosticFactory3<E, P, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>,
restrictingDeclaration: FirMemberDeclaration,
elementVisibility: FirEffectiveVisibility,
restrictingVisibility: FirEffectiveVisibility,
source: FirSourceElement?
) {
source?.let {
report(
error.on(
it as E,
elementVisibility,
restrictingDeclaration,
restrictingVisibility
)
)
}
}
private fun FirMemberDeclaration.getEffectiveVisibility(context: CheckerContext) = private fun FirMemberDeclaration.getEffectiveVisibility(context: CheckerContext) =
getEffectiveVisibility(context.session, context.containingDeclarations, context.sessionHolder.scopeSession) getEffectiveVisibility(context.session, context.containingDeclarations, context.sessionHolder.scopeSession)
} }
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirFunction
@@ -23,7 +23,7 @@ object FirFunctionNameChecker : FirFunctionChecker() {
val containingDeclaration = context.containingDeclarations.lastOrNull() val containingDeclaration = context.containingDeclarations.lastOrNull()
val isNonLocal = containingDeclaration is FirFile || containingDeclaration is FirClass<*> val isNonLocal = containingDeclaration is FirFile || containingDeclaration is FirClass<*>
if (declaration is FirSimpleFunction && declaration.name == SpecialNames.NO_NAME_PROVIDED && isNonLocal) { if (declaration is FirSimpleFunction && declaration.name == SpecialNames.NO_NAME_PROVIDED && isNonLocal) {
reporter.report(source, FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME) reporter.reportOn(source, FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME, context)
} }
} }
} }
@@ -10,7 +10,8 @@ import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.isLateInit
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
@@ -40,28 +41,28 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
when { when {
declaration.isVal -> declaration.isVal ->
reporter.report(declaration.source, "is allowed only on mutable properties") reporter.reportOn(declaration.source, "is allowed only on mutable properties", context)
declaration.initializer != null -> if (declaration.isLocal) { declaration.initializer != null -> if (declaration.isLocal) {
reporter.report(declaration.source, "is not allowed on local variables with initializer") reporter.reportOn(declaration.source, "is not allowed on local variables with initializer", context)
} else { } else {
reporter.report(declaration.source, "is not allowed on properties with initializer") reporter.reportOn(declaration.source, "is not allowed on properties with initializer", context)
} }
declaration.delegate != null -> declaration.delegate != null ->
reporter.report(declaration.source, "is not allowed on delegated properties") reporter.reportOn(declaration.source, "is not allowed on delegated properties", context)
declaration.isNullable() -> declaration.isNullable() ->
reporter.report(declaration.source, "is not allowed on properties of a type with nullable upper bound") reporter.reportOn(declaration.source, "is not allowed on properties of a type with nullable upper bound", context)
declaration.returnTypeRef.coneType in getPrimitiveTypes(context) -> if (declaration.isLocal) { declaration.returnTypeRef.coneType in getPrimitiveTypes(context) -> if (declaration.isLocal) {
reporter.report(declaration.source, "is not allowed on local variables of primitive types") reporter.reportOn(declaration.source, "is not allowed on local variables of primitive types", context)
} else { } else {
reporter.report(declaration.source, "is not allowed on properties of primitive types") reporter.reportOn(declaration.source, "is not allowed on properties of primitive types", context)
} }
declaration.hasGetter() || declaration.hasSetter() -> declaration.hasGetter() || declaration.hasSetter() ->
reporter.report(declaration.source, "is not allowed on properties with a custom getter or setter") reporter.reportOn(declaration.source, "is not allowed on properties with a custom getter or setter", context)
} }
} }
@@ -73,7 +74,7 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
private fun FirProperty.hasGetter() = getter != null && getter?.source != null && getter?.source?.kind !is FirFakeSourceElementKind private fun FirProperty.hasGetter() = getter != null && getter?.source != null && getter?.source?.kind !is FirFakeSourceElementKind
private fun FirProperty.hasSetter() = setter != null && setter?.source != null && setter?.source?.kind !is FirFakeSourceElementKind private fun FirProperty.hasSetter() = setter != null && setter?.source != null && setter?.source?.kind !is FirFakeSourceElementKind
private fun DiagnosticReporter.report(source: FirSourceElement?, target: String) { private fun DiagnosticReporter.reportOn(source: FirSourceElement?, target: String, context: CheckerContext) {
source?.let { report(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER.on(it, target)) } source?.let { report(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER.on(it, target), context) }
} }
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
@@ -18,12 +18,12 @@ object FirInfixFunctionDeclarationChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirSimpleFunction && declaration.isInfix) { if (declaration is FirSimpleFunction && declaration.isInfix) {
if (declaration.valueParameters.size != 1 || !hasExtensionOrDispatchReceiver(declaration, context)) { if (declaration.valueParameters.size != 1 || !hasExtensionOrDispatchReceiver(declaration, context)) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_INFIX_MODIFIER, context)
} }
return return
} }
if (declaration.isInfix) { if (declaration.isInfix) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_INFIX_MODIFIER, context)
} }
} }
@@ -34,8 +34,4 @@ object FirInfixFunctionDeclarationChecker : FirMemberDeclarationChecker() {
if (function.receiverTypeRef != null) return true if (function.receiverTypeRef != null) return true
return context.containingDeclarations.lastOrNull() is FirClass<*> return context.containingDeclarations.lastOrNull() is FirClass<*>
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) }
}
} }
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -20,11 +20,7 @@ object FirInterfaceWithSuperclassChecker : FirRegularClassChecker() {
} }
declaration.findNonInterfaceSupertype(context)?.let { declaration.findNonInterfaceSupertype(context)?.let {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.INTERFACE_WITH_SUPERCLASS, context)
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.INTERFACE_WITH_SUPERCLASS.on(it)) }
}
} }
@@ -6,15 +6,14 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion import org.jetbrains.kotlin.fir.declarations.isCompanion
import org.jetbrains.kotlin.fir.declarations.visibility import org.jetbrains.kotlin.fir.declarations.visibility
import org.jetbrains.kotlin.name.Name
object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() { object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -24,19 +23,11 @@ object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
when { when {
declaration.classKind == ClassKind.OBJECT && !declaration.isCompanion -> declaration.classKind == ClassKind.OBJECT && !declaration.isCompanion ->
reporter.reportLocalObjectNotAllowed(declaration.source, declaration.name) reporter.reportOn(declaration.source, FirErrors.LOCAL_OBJECT_NOT_ALLOWED, declaration.name, context)
declaration.classKind == ClassKind.INTERFACE -> declaration.classKind == ClassKind.INTERFACE ->
reporter.reportLocalInterfaceNotAllowed(declaration.source, declaration.name) reporter.reportOn(declaration.source, FirErrors.LOCAL_INTERFACE_NOT_ALLOWED, declaration.name, context)
else -> { else -> {
} }
} }
} }
private fun DiagnosticReporter.reportLocalObjectNotAllowed(source: FirSourceElement?, name: Name) {
source?.let { report(FirErrors.LOCAL_OBJECT_NOT_ALLOWED.on(it, name)) }
}
private fun DiagnosticReporter.reportLocalInterfaceNotAllowed(source: FirSourceElement?, name: Name) {
source?.let { report(FirErrors.LOCAL_INTERFACE_NOT_ALLOWED.on(it, name)) }
}
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion import org.jetbrains.kotlin.fir.declarations.isCompanion
@@ -19,14 +19,10 @@ object FirManyCompanionObjectsChecker : FirRegularClassChecker() {
for (it in declaration.declarations) { for (it in declaration.declarations) {
if (it is FirRegularClass && it.isCompanion) { if (it is FirRegularClass && it.isCompanion) {
if (hasCompanion) { if (hasCompanion) {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.MANY_COMPANION_OBJECTS, context)
} }
hasCompanion = true hasCompanion = true
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.MANY_COMPANION_OBJECTS.on(it)) }
}
} }
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -39,10 +39,13 @@ object FirMemberFunctionChecker : FirRegularClassChecker() {
val isAbstract = function.isAbstract || hasAbstractModifier val isAbstract = function.isAbstract || hasAbstractModifier
if (isAbstract) { if (isAbstract) {
if (!containingDeclaration.canHaveAbstractDeclaration) { if (!containingDeclaration.canHaveAbstractDeclaration) {
reporter.report(FirErrors.ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(source, function, containingDeclaration)) reporter.report(
FirErrors.ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(source, function, containingDeclaration),
context
)
} }
if (function.hasBody) { if (function.hasBody) {
reporter.report(FirErrors.ABSTRACT_FUNCTION_WITH_BODY.on(source, function)) reporter.report(FirErrors.ABSTRACT_FUNCTION_WITH_BODY.on(source, function), context)
} }
} }
val isInsideExpectClass = isInsideExpectClass(containingDeclaration, context) val isInsideExpectClass = isInsideExpectClass(containingDeclaration, context)
@@ -51,17 +54,16 @@ object FirMemberFunctionChecker : FirRegularClassChecker() {
if (!function.hasBody) { if (!function.hasBody) {
if (containingDeclaration.isInterface) { if (containingDeclaration.isInterface) {
if (Visibilities.isPrivate(function.visibility)) { if (Visibilities.isPrivate(function.visibility)) {
reporter.report(FirErrors.PRIVATE_FUNCTION_WITH_NO_BODY.on(source, function)) reporter.reportOn(source, FirErrors.PRIVATE_FUNCTION_WITH_NO_BODY, function, context)
} }
if (!isInsideExpectClass && !hasAbstractModifier && hasOpenModifier) { if (!isInsideExpectClass && !hasAbstractModifier && hasOpenModifier) {
reporter.report(source, FirErrors.REDUNDANT_OPEN_IN_INTERFACE) reporter.reportOn(source, FirErrors.REDUNDANT_OPEN_IN_INTERFACE, context)
} }
} else if (!isInsideExpectClass && !hasAbstractModifier && !isExternal) { } else if (!isInsideExpectClass && !hasAbstractModifier && !isExternal) {
reporter.report(FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(source, function)) reporter.reportOn(source, FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY, function, context)
} }
} }
checkExpectDeclarationVisibilityAndBody(function, source, modifierList, reporter) checkExpectDeclarationVisibilityAndBody(function, source, modifierList, reporter, context)
} }
} }
@@ -9,9 +9,9 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -47,37 +47,43 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
(property.getter == null || property.getter is FirDefaultPropertyAccessor) (property.getter == null || property.getter is FirDefaultPropertyAccessor)
) { ) {
property.source?.let { property.source?.let {
reporter.report(it, FirErrors.PRIVATE_PROPERTY_IN_INTERFACE) reporter.reportOn(it, FirErrors.PRIVATE_PROPERTY_IN_INTERFACE, context)
} }
} }
if (isAbstract) { if (isAbstract) {
if (!containingDeclaration.canHaveAbstractDeclaration) { if (!containingDeclaration.canHaveAbstractDeclaration) {
property.source?.let { property.source?.let {
reporter.report(FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(it, property, containingDeclaration)) reporter.reportOn(
it,
FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS,
property,
containingDeclaration,
context
)
return return
} }
} }
property.initializer?.source?.let { property.initializer?.source?.let {
reporter.report(it, FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER) reporter.reportOn(it, FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER, context)
} }
property.delegate?.source?.let { property.delegate?.source?.let {
reporter.report(it, FirErrors.ABSTRACT_DELEGATED_PROPERTY) reporter.reportOn(it, FirErrors.ABSTRACT_DELEGATED_PROPERTY, context)
} }
checkAccessor(property.getter, property.delegate) { src, _ -> checkAccessor(property.getter, property.delegate) { src, _ ->
reporter.report(src, FirErrors.ABSTRACT_PROPERTY_WITH_GETTER) reporter.reportOn(src, FirErrors.ABSTRACT_PROPERTY_WITH_GETTER, context)
} }
checkAccessor(property.setter, property.delegate) { src, symbol -> checkAccessor(property.setter, property.delegate) { src, symbol ->
if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) { if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) {
reporter.report(src, FirErrors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY) reporter.reportOn(src, FirErrors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY, context)
} else { } else {
reporter.report(src, FirErrors.ABSTRACT_PROPERTY_WITH_SETTER) reporter.reportOn(src, FirErrors.ABSTRACT_PROPERTY_WITH_SETTER, context)
} }
} }
} }
checkPropertyInitializer(containingDeclaration, property, reporter) checkPropertyInitializer(containingDeclaration, property, reporter, context)
val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true val hasOpenModifier = modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
if (hasOpenModifier && if (hasOpenModifier &&
@@ -87,19 +93,19 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
!isInsideExpectClass(containingDeclaration, context) !isInsideExpectClass(containingDeclaration, context)
) { ) {
property.source?.let { property.source?.let {
reporter.report(it, FirErrors.REDUNDANT_OPEN_IN_INTERFACE) reporter.reportOn(it, FirErrors.REDUNDANT_OPEN_IN_INTERFACE, context)
} }
} }
val isOpen = property.isOpen || hasOpenModifier val isOpen = property.isOpen || hasOpenModifier
if (isOpen) { if (isOpen) {
checkAccessor(property.setter, property.delegate) { src, symbol -> checkAccessor(property.setter, property.delegate) { src, symbol ->
if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) { if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) {
reporter.report(src, FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY) reporter.reportOn(src, FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY, context)
} }
} }
} }
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter) checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
} }
private fun checkAccessor( private fun checkAccessor(
@@ -5,12 +5,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -64,12 +64,8 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirRegularClassChecker(), F
val inspector = getInspector(context) val inspector = getInspector(context)
if (it is FirSimpleFunction && inspector.contains(it) && it.body != null && it.isOverride) { if (it is FirSimpleFunction && inspector.contains(it) && it.body != null && it.isOverride) {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.ANY_METHOD_IMPLEMENTED_IN_INTERFACE, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.ANY_METHOD_IMPLEMENTED_IN_INTERFACE.on(it)) }
}
} }
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -103,7 +103,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
secondModifier: FirModifier<*>, secondModifier: FirModifier<*>,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
reportedNodes: MutableSet<FirModifier<*>>, reportedNodes: MutableSet<FirModifier<*>>,
owner: FirDeclaration? owner: FirDeclaration?,
context: CheckerContext
) { ) {
val firstToken = firstModifier.token val firstToken = firstModifier.token
val secondToken = secondModifier.token val secondToken = secondModifier.token
@@ -111,21 +112,21 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
CompatibilityType.COMPATIBLE -> { CompatibilityType.COMPATIBLE -> {
} }
CompatibilityType.REPEATED -> CompatibilityType.REPEATED ->
if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken) if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken, context)
CompatibilityType.REDUNDANT_2_TO_1 -> CompatibilityType.REDUNDANT_2_TO_1 ->
reporter.reportRedundantModifier(secondModifier, secondToken, firstToken) reporter.reportRedundantModifier(secondModifier, secondToken, firstToken, context)
CompatibilityType.REDUNDANT_1_TO_2 -> CompatibilityType.REDUNDANT_1_TO_2 ->
reporter.reportRedundantModifier(firstModifier, firstToken, secondToken) reporter.reportRedundantModifier(firstModifier, firstToken, secondToken, context)
CompatibilityType.DEPRECATED -> { CompatibilityType.DEPRECATED -> {
reporter.reportDeprecatedModifierPair(firstModifier, firstToken, secondToken) reporter.reportDeprecatedModifierPair(firstModifier, firstToken, secondToken, context)
reporter.reportDeprecatedModifierPair(secondModifier, secondToken, firstToken) reporter.reportDeprecatedModifierPair(secondModifier, secondToken, firstToken, context)
} }
CompatibilityType.INCOMPATIBLE, CompatibilityType.COMPATIBLE_FOR_CLASSES -> { CompatibilityType.INCOMPATIBLE, CompatibilityType.COMPATIBLE_FOR_CLASSES -> {
if (compatibilityType == CompatibilityType.COMPATIBLE_FOR_CLASSES && owner is FirClass<*>) { if (compatibilityType == CompatibilityType.COMPATIBLE_FOR_CLASSES && owner is FirClass<*>) {
return return
} }
if (reportedNodes.add(firstModifier)) reporter.reportIncompatibleModifiers(firstModifier, firstToken, secondToken) if (reportedNodes.add(firstModifier)) reporter.reportIncompatibleModifiers(firstModifier, firstToken, secondToken, context)
if (reportedNodes.add(secondModifier)) reporter.reportIncompatibleModifiers(secondModifier, secondToken, firstToken) if (reportedNodes.add(secondModifier)) reporter.reportIncompatibleModifiers(secondModifier, secondToken, firstToken, context)
} }
} }
} }
@@ -133,7 +134,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
private fun checkModifiers( private fun checkModifiers(
list: FirModifierList, list: FirModifierList,
owner: FirDeclaration, owner: FirDeclaration,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
) { ) {
// general strategy: report no more than one error and any number of warnings // general strategy: report no more than one error and any number of warnings
// therefore, a track of nodes with already reported errors should be kept // therefore, a track of nodes with already reported errors should be kept
@@ -145,7 +147,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
if (firstModifier == secondModifier) { if (firstModifier == secondModifier) {
break break
} }
checkCompatibilityType(firstModifier, secondModifier, reporter, reportedNodes, owner) checkCompatibilityType(firstModifier, secondModifier, reporter, reportedNodes, owner, context)
} }
} }
} }
@@ -168,30 +170,30 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
if (context.containingDeclarations.last() is FirDefaultPropertyAccessor) return if (context.containingDeclarations.last() is FirDefaultPropertyAccessor) return
val modifierList = with(FirModifierList) { source.getModifierList() } val modifierList = with(FirModifierList) { source.getModifierList() }
modifierList?.let { checkModifiers(it, declaration, reporter) } modifierList?.let { checkModifiers(it, declaration, reporter, context) }
} }
private fun DiagnosticReporter.reportRepeatedModifier( private fun DiagnosticReporter.reportRepeatedModifier(
modifier: FirModifier<*>, keyword: KtModifierKeywordToken modifier: FirModifier<*>, keyword: KtModifierKeywordToken, context: CheckerContext
) { ) {
report(FirErrors.REPEATED_MODIFIER.on(modifier.source, keyword)) report(FirErrors.REPEATED_MODIFIER.on(modifier.source, keyword), context)
} }
private fun DiagnosticReporter.reportRedundantModifier( private fun DiagnosticReporter.reportRedundantModifier(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken, context: CheckerContext
) { ) {
report(FirErrors.REDUNDANT_MODIFIER.on(modifier.source, firstKeyword, secondKeyword)) report(FirErrors.REDUNDANT_MODIFIER.on(modifier.source, firstKeyword, secondKeyword), context)
} }
private fun DiagnosticReporter.reportDeprecatedModifierPair( private fun DiagnosticReporter.reportDeprecatedModifierPair(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken, context: CheckerContext
) { ) {
report(FirErrors.DEPRECATED_MODIFIER_PAIR.on(modifier.source, firstKeyword, secondKeyword)) report(FirErrors.DEPRECATED_MODIFIER_PAIR.on(modifier.source, firstKeyword, secondKeyword), context)
} }
private fun DiagnosticReporter.reportIncompatibleModifiers( private fun DiagnosticReporter.reportIncompatibleModifiers(
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken, context: CheckerContext
) { ) {
report(FirErrors.INCOMPATIBLE_MODIFIERS.on(modifier.source, firstKeyword, secondKeyword)) report(FirErrors.INCOMPATIBLE_MODIFIERS.on(modifier.source, firstKeyword, secondKeyword), context)
} }
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.containingClass import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
@@ -106,6 +107,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
private fun FirCallableMemberDeclaration<*>.checkVisibility( private fun FirCallableMemberDeclaration<*>.checkVisibility(
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
overriddenSymbols: List<FirCallableSymbol<*>>, overriddenSymbols: List<FirCallableSymbol<*>>,
context: CheckerContext
) { ) {
val visibilities = overriddenSymbols.mapNotNull { val visibilities = overriddenSymbols.mapNotNull {
if (it.fir !is FirMemberDeclaration) return@mapNotNull null if (it.fir !is FirMemberDeclaration) return@mapNotNull null
@@ -122,7 +124,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
// reporter.reportCannotChangeAccessPrivilege(this, overridden.fir) // reporter.reportCannotChangeAccessPrivilege(this, overridden.fir)
return return
} else if (compare < 0) { } else if (compare < 0) {
reporter.reportCannotWeakenAccessPrivilege(this, overridden.fir) reporter.reportCannotWeakenAccessPrivilege(this, overridden.fir, context)
return return
} }
} }
@@ -169,15 +171,15 @@ object FirOverrideChecker : FirRegularClassChecker() {
val overriddenFunctionSymbols = firTypeScope.retrieveDirectOverriddenOf(function) val overriddenFunctionSymbols = firTypeScope.retrieveDirectOverriddenOf(function)
if (overriddenFunctionSymbols.isEmpty()) { if (overriddenFunctionSymbols.isEmpty()) {
reporter.reportNothingToOverride(function) reporter.reportNothingToOverride(function, context)
return return
} }
checkModality(overriddenFunctionSymbols)?.let { checkModality(overriddenFunctionSymbols)?.let {
reporter.reportOverridingFinalMember(function, it) reporter.reportOverridingFinalMember(function, it, context)
} }
function.checkVisibility(reporter, overriddenFunctionSymbols) function.checkVisibility(reporter, overriddenFunctionSymbols, context)
val restriction = function.checkReturnType( val restriction = function.checkReturnType(
overriddenSymbols = overriddenFunctionSymbols, overriddenSymbols = overriddenFunctionSymbols,
@@ -186,7 +188,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
) )
restriction?.let { restriction?.let {
reporter.reportReturnTypeMismatchOnFunction(function, it) reporter.reportReturnTypeMismatchOnFunction(function, it, context)
} }
} }
@@ -204,19 +206,19 @@ object FirOverrideChecker : FirRegularClassChecker() {
val overriddenPropertySymbols = firTypeScope.retrieveDirectOverriddenOf(property) val overriddenPropertySymbols = firTypeScope.retrieveDirectOverriddenOf(property)
if (overriddenPropertySymbols.isEmpty()) { if (overriddenPropertySymbols.isEmpty()) {
reporter.reportNothingToOverride(property) reporter.reportNothingToOverride(property, context)
return return
} }
checkModality(overriddenPropertySymbols)?.let { checkModality(overriddenPropertySymbols)?.let {
reporter.reportOverridingFinalMember(property, it) reporter.reportOverridingFinalMember(property, it, context)
} }
property.checkMutability(overriddenPropertySymbols)?.let { property.checkMutability(overriddenPropertySymbols)?.let {
reporter.reportVarOverriddenByVal(property, it) reporter.reportVarOverriddenByVal(property, it, context)
} }
property.checkVisibility(reporter, overriddenPropertySymbols) property.checkVisibility(reporter, overriddenPropertySymbols, context)
val restriction = property.checkReturnType( val restriction = property.checkReturnType(
overriddenSymbols = overriddenPropertySymbols, overriddenSymbols = overriddenPropertySymbols,
@@ -226,76 +228,91 @@ object FirOverrideChecker : FirRegularClassChecker() {
restriction?.let { restriction?.let {
if (property.isVar) { if (property.isVar) {
reporter.reportTypeMismatchOnVariable(property, it) reporter.reportTypeMismatchOnVariable(property, it, context)
} else { } else {
reporter.reportTypeMismatchOnProperty(property, it) reporter.reportTypeMismatchOnProperty(property, it, context)
} }
} }
} }
private fun DiagnosticReporter.reportNothingToOverride(declaration: FirMemberDeclaration) { private fun DiagnosticReporter.reportNothingToOverride(declaration: FirMemberDeclaration, context: CheckerContext) {
// TODO: not ready yet, e.g., Collections // TODO: not ready yet, e.g., Collections
// declaration.source?.let { report(FirErrors.NOTHING_TO_OVERRIDE.on(it, declaration)) } // reportOn(declaration.source, FirErrors.NOTHING_TO_OVERRIDE, declaration, context)
} }
private fun DiagnosticReporter.reportOverridingFinalMember( private fun DiagnosticReporter.reportOverridingFinalMember(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>, overridden: FirCallableDeclaration<*>,
context: CheckerContext
) { ) {
overriding.source?.let { source -> overriding.source?.let { source ->
overridden.containingClass()?.let { containingClass -> overridden.containingClass()?.let { containingClass ->
report(FirErrors.OVERRIDING_FINAL_MEMBER.on(source, overridden, containingClass.name)) report(FirErrors.OVERRIDING_FINAL_MEMBER.on(source, overridden, containingClass.name), context)
} }
} }
} }
private fun DiagnosticReporter.reportVarOverriddenByVal( private fun DiagnosticReporter.reportVarOverriddenByVal(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirMemberDeclaration overridden: FirMemberDeclaration,
context: CheckerContext
) { ) {
overriding.source?.let { report(FirErrors.VAR_OVERRIDDEN_BY_VAL.on(it, overriding, overridden)) } overriding.source?.let { report(FirErrors.VAR_OVERRIDDEN_BY_VAL.on(it, overriding, overridden), context) }
} }
private fun DiagnosticReporter.reportCannotWeakenAccessPrivilege( private fun DiagnosticReporter.reportCannotWeakenAccessPrivilege(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>, overridden: FirCallableDeclaration<*>,
context: CheckerContext
) { ) {
overriding.source?.let { source -> val containingClass = overridden.containingClass() ?: return
overridden.containingClass()?.let { containingClass -> reportOn(
report(FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(source, overriding.visibility, overridden, containingClass.name)) overriding.source,
} FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE,
} overriding.visibility,
overridden,
containingClass.name,
context
)
} }
private fun DiagnosticReporter.reportCannotChangeAccessPrivilege( private fun DiagnosticReporter.reportCannotChangeAccessPrivilege(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>, overridden: FirCallableDeclaration<*>,
context: CheckerContext
) { ) {
overriding.source?.let { source -> val containingClass = overridden.containingClass() ?: return
overridden.containingClass()?.let { containingClass -> reportOn(
report(FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE.on(source, overriding.visibility, overridden, containingClass.name)) overriding.source,
} FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE,
} overriding.visibility,
overridden,
containingClass.name,
context
)
} }
private fun DiagnosticReporter.reportReturnTypeMismatchOnFunction( private fun DiagnosticReporter.reportReturnTypeMismatchOnFunction(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirMemberDeclaration overridden: FirMemberDeclaration,
context: CheckerContext
) { ) {
overriding.source?.let { report(FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(it, overriding, overridden)) } reportOn(overriding.source, FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE, overriding, overridden, context)
} }
private fun DiagnosticReporter.reportTypeMismatchOnProperty( private fun DiagnosticReporter.reportTypeMismatchOnProperty(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirMemberDeclaration overridden: FirMemberDeclaration,
context: CheckerContext
) { ) {
overriding.source?.let { report(FirErrors.PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(it, overriding, overridden)) } reportOn(overriding.source, FirErrors.PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, overriding, overridden, context)
} }
private fun DiagnosticReporter.reportTypeMismatchOnVariable( private fun DiagnosticReporter.reportTypeMismatchOnVariable(
overriding: FirMemberDeclaration, overriding: FirMemberDeclaration,
overridden: FirMemberDeclaration overridden: FirMemberDeclaration,
context: CheckerContext
) { ) {
overriding.source?.let { report(FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE.on(it, overriding, overridden)) } reportOn(overriding.source, FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE, overriding, overridden, context)
} }
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isData import org.jetbrains.kotlin.fir.declarations.isData
@@ -23,11 +23,7 @@ object FirPrimaryConstructorRequiredForDataClassChecker : FirRegularClassChecker
val hasPrimaryConstructor = declaration.declarations.any { it is FirConstructor && it.isPrimary } val hasPrimaryConstructor = declaration.declarations.any { it is FirConstructor && it.isPrimary }
if (!hasPrimaryConstructor) { if (!hasPrimaryConstructor) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, context)
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) }
}
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeClassLikeType
@@ -55,7 +55,7 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue ?: continue
if (fir.status.modality == Modality.SEALED && classId.outerClassId != null) { if (fir.status.modality == Modality.SEALED && classId.outerClassId != null) {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE, context)
return return
} }
} }
@@ -77,7 +77,7 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue ?: continue
if (fir.status.modality == Modality.SEALED) { if (fir.status.modality == Modality.SEALED) {
reporter.reportInLocal(it.source) reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS, context)
return return
} }
} }
@@ -99,17 +99,9 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue ?: continue
if (fir.status.modality == Modality.SEALED && !context.containingDeclarations.contains(fir)) { if (fir.status.modality == Modality.SEALED && !context.containingDeclarations.contains(fir)) {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE, context)
return return
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_SUPERTYPE.on(it)) }
}
private fun DiagnosticReporter.reportInLocal(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(it)) }
}
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -22,12 +22,8 @@ object FirSupertypeInitializedInInterfaceChecker : FirRegularClassChecker() {
for (superTypeRef in declaration.superTypeRefs) { for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) { if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
reporter.report(source) reporter.reportOn(source, FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE.on(it)) }
}
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -27,12 +27,8 @@ object FirSupertypeInitializedWithoutPrimaryConstructor : FirRegularClassChecker
for (superTypeRef in declaration.superTypeRefs) { for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue val source = superTypeRef.source ?: continue
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) { if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR.on(it)) }
}
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -17,12 +18,12 @@ object FirTopLevelFunctionChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
for (topLevelDeclaration in declaration.declarations) { for (topLevelDeclaration in declaration.declarations) {
if (topLevelDeclaration is FirSimpleFunction) { if (topLevelDeclaration is FirSimpleFunction) {
checkFunction(topLevelDeclaration, reporter) checkFunction(topLevelDeclaration, reporter, context)
} }
} }
} }
private fun checkFunction(function: FirSimpleFunction, reporter: DiagnosticReporter) { private fun checkFunction(function: FirSimpleFunction, reporter: DiagnosticReporter, context: CheckerContext) {
val source = function.source ?: return val source = function.source ?: return
if (source.kind is FirFakeSourceElementKind) return if (source.kind is FirFakeSourceElementKind) return
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`. // If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
@@ -32,9 +33,9 @@ object FirTopLevelFunctionChecker : FirFileChecker() {
if (function.isExternal || modifierList?.modifiers?.any { it.token == KtTokens.EXTERNAL_KEYWORD } == true) return if (function.isExternal || modifierList?.modifiers?.any { it.token == KtTokens.EXTERNAL_KEYWORD } == true) return
val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true
if (!function.hasBody && !isExpect) { if (!function.hasBody && !isExpect) {
reporter.report(FirErrors.NON_MEMBER_FUNCTION_NO_BODY.on(source, function)) reporter.reportOn(source, FirErrors.NON_MEMBER_FUNCTION_NO_BODY, function, context)
} }
checkExpectDeclarationVisibilityAndBody(function, source, modifierList, reporter) checkExpectDeclarationVisibilityAndBody(function, source, modifierList, reporter, context)
} }
} }
@@ -16,17 +16,17 @@ object FirTopLevelPropertyChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
for (topLevelDeclaration in declaration.declarations) { for (topLevelDeclaration in declaration.declarations) {
if (topLevelDeclaration is FirProperty) { if (topLevelDeclaration is FirProperty) {
checkProperty(topLevelDeclaration, reporter) checkProperty(topLevelDeclaration, reporter, context)
} }
} }
} }
private fun checkProperty(property: FirProperty, reporter: DiagnosticReporter) { private fun checkProperty(property: FirProperty, reporter: DiagnosticReporter, context: CheckerContext) {
val source = property.source ?: return val source = property.source ?: return
if (source.kind is FirFakeSourceElementKind) return if (source.kind is FirFakeSourceElementKind) return
val modifierList = with(FirModifierList) { source.getModifierList() } val modifierList = with(FirModifierList) { source.getModifierList() }
checkPropertyInitializer(null, property, reporter) checkPropertyInitializer(null, property, reporter, context)
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter) checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
} }
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
object FirTypeParametersInObjectChecker : FirRegularClassChecker() { object FirTypeParametersInObjectChecker : FirRegularClassChecker() {
@@ -19,11 +19,7 @@ object FirTypeParametersInObjectChecker : FirRegularClassChecker() {
} }
if (declaration.typeParameters.isNotEmpty()) { if (declaration.typeParameters.isNotEmpty()) {
reporter.report(declaration.source) reporter.reportOn(declaration.source, FirErrors.TYPE_PARAMETERS_IN_OBJECT, context)
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.TYPE_PARAMETERS_IN_OBJECT.on(it)) }
}
} }
@@ -7,12 +7,12 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.checkers.getDeclaration import org.jetbrains.kotlin.fir.analysis.checkers.getDeclaration
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.modality import org.jetbrains.kotlin.fir.declarations.modality
@@ -42,14 +42,8 @@ object FirAbstractSuperCallChecker : FirQualifiedAccessChecker() {
declaration.modality == Modality.ABSTRACT && declaration.modality == Modality.ABSTRACT &&
item.modality == Modality.ABSTRACT item.modality == Modality.ABSTRACT
) { ) {
reporter.report(expression.calleeReference.source) reporter.reportOn(expression.calleeReference.source, FirErrors.ABSTRACT_SUPER_CALL, context)
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.ABSTRACT_SUPER_CALL.on(it))
}
}
} }
@@ -6,9 +6,9 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -20,10 +20,10 @@ object FirAnonymousFunctionChecker : FirExpressionChecker<FirStatement>() {
for (valueParameter in expression.valueParameters) { for (valueParameter in expression.valueParameters) {
val source = valueParameter.source ?: continue val source = valueParameter.source ?: continue
if (valueParameter.defaultValue != null) { if (valueParameter.defaultValue != null) {
reporter.report(source, FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE) reporter.reportOn(source, FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE, context)
} }
if (valueParameter.isVararg) { if (valueParameter.isVararg) {
reporter.report(source, FirErrors.USELESS_VARARG_ON_PARAMETER) reporter.reportOn(source, FirErrors.USELESS_VARARG_ON_PARAMETER, context)
} }
} }
} }
@@ -28,7 +28,7 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
val catchParameter = catchEntry.parameter val catchParameter = catchEntry.parameter
if (catchParameter.defaultValue != null) if (catchParameter.defaultValue != null)
catchParameter.source?.let { reporter.report(FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it)) } catchParameter.source?.let { reporter.report(FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it), context) }
val typeRef = catchParameter.returnTypeRef val typeRef = catchParameter.returnTypeRef
if (typeRef !is FirResolvedTypeRef) return if (typeRef !is FirResolvedTypeRef) return
@@ -38,14 +38,14 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified
if (isReified) { if (isReified) {
catchParameter.source?.let { reporter.report(FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it)) } catchParameter.source?.let { reporter.report(FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it), context) }
} else { } else {
catchParameter.source?.let { reporter.report(FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it)) } catchParameter.source?.let { reporter.report(FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it), context) }
} }
} }
if (!coneType.isThrowable(context.session)) if (!coneType.isThrowable(context.session))
catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwable, coneType)) } catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwable, coneType), context) }
} }
} }
@@ -5,12 +5,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
@@ -29,7 +29,7 @@ object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
val surrounding = context.findClosestClass(superReference.labelName) ?: return val surrounding = context.findClosestClass(superReference.labelName) ?: return
if (!targetClass.isSupertypeOf(surrounding)) { if (!targetClass.isSupertypeOf(surrounding)) {
reporter.report(expression.source) reporter.reportOn(expression.source, FirErrors.NOT_A_SUPERTYPE, context)
} }
} }
@@ -51,10 +51,4 @@ object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
return null return null
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.NOT_A_SUPERTYPE.on(it))
}
}
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.types.FirStarProjection import org.jetbrains.kotlin.fir.types.FirStarProjection
import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance
@@ -18,19 +18,13 @@ object FirProjectionsOnNonClassTypeArgumentChecker : FirQualifiedAccessChecker()
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in expression.typeArguments) { for (it in expression.typeArguments) {
when (it) { when (it) {
is FirStarProjection -> reporter.report(it.source) is FirStarProjection -> reporter.reportOn(it.source, FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, context)
is FirTypeProjectionWithVariance -> { is FirTypeProjectionWithVariance -> {
if (it.variance != Variance.INVARIANT) { if (it.variance != Variance.INVARIANT) {
reporter.report(it.source) reporter.reportOn(it.source, FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, context)
} }
} }
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(it))
}
}
} }
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject
import org.jetbrains.kotlin.fir.analysis.checkers.followAllAlias import org.jetbrains.kotlin.fir.analysis.checkers.followAllAlias
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.references.FirSuperReference
@@ -61,13 +61,12 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess
} }
if (count >= 2 && candidate != null) { if (count >= 2 && candidate != null) {
reporter.report(superReference.superTypeRef.source, candidate) reporter.reportOn(
} superReference.superTypeRef.source,
} FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE,
candidate,
private fun DiagnosticReporter.report(source: FirSourceElement?, candidate: FirClass<*>) { context
source?.let { )
report(FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE.on(it, candidate))
} }
} }
} }
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
@@ -33,11 +33,7 @@ object FirSealedClassConstructorCallChecker : FirQualifiedAccessChecker() {
?: return ?: return
if (typeFir.status.modality == Modality.SEALED) { if (typeFir.status.modality == Modality.SEALED) {
reporter.report(expression.calleeReference.source) reporter.reportOn(expression.calleeReference.source, FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL, context)
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL.on(it)) }
}
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.references.FirSuperReference
@@ -23,13 +23,7 @@ object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() {
} }
if (!isInsideClass) { if (!isInsideClass) {
reporter.report(expression.source) reporter.reportOn(expression.source, FirErrors.SUPER_NOT_AVAILABLE, context)
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.SUPER_NOT_AVAILABLE.on(it))
} }
} }
} }
@@ -6,11 +6,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
@@ -34,7 +34,7 @@ object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecke
?: return ?: return
if (origin.source != null && origin.classKind == ClassKind.CLASS) { if (origin.source != null && origin.classKind == ClassKind.CLASS) {
reporter.report(expression.explicitReceiver?.source) reporter.reportOn(expression.explicitReceiver?.source, FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE, context)
} }
} }
} }
@@ -46,10 +46,4 @@ object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecke
private fun getClassLikeDeclaration(functionCall: FirQualifiedAccessExpression, context: CheckerContext): FirClassLikeDeclaration<*>? { private fun getClassLikeDeclaration(functionCall: FirQualifiedAccessExpression, context: CheckerContext): FirClassLikeDeclaration<*>? {
return functionCall.calleeReference.safeAs<FirResolvedNamedReference>()?.resolvedSymbol?.fir?.getContainingClass(context) return functionCall.calleeReference.safeAs<FirResolvedNamedReference>()?.resolvedSymbol?.fir?.getContainingClass(context)
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE.on(it))
}
}
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
@@ -20,15 +20,9 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker()
if (explicitReceiver is FirResolvedQualifier && explicitReceiver.symbol == null) { if (explicitReceiver is FirResolvedQualifier && explicitReceiver.symbol == null) {
if (explicitReceiver.typeArguments.isNotEmpty()) { if (explicitReceiver.typeArguments.isNotEmpty()) {
reporter.report(explicitReceiver.source) reporter.reportOn(explicitReceiver.source, FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED, context)
return return
} }
} }
} }
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.on(it))
}
}
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
@@ -74,7 +75,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
} }
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) { if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
reporter.report(actual.source, proto, actual.type) reporter.reportOn(actual.source, proto, actual.type, context)
return return
} }
@@ -98,7 +99,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
// typealias A<G> = B<List<G>> // typealias A<G> = B<List<G>>
// val a = A<Int>() // val a = A<Int>()
when (calleeFir) { when (calleeFir) {
is FirConstructor -> analyzeConstructorCall(expression, substitutor, typeCheckerContext, reporter) is FirConstructor -> analyzeConstructorCall(expression, substitutor, typeCheckerContext, reporter, context)
} }
} }
@@ -106,7 +107,8 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
functionCall: FirQualifiedAccessExpression, functionCall: FirQualifiedAccessExpression,
callSiteSubstitutor: ConeSubstitutor, callSiteSubstitutor: ConeSubstitutor,
typeCheckerContext: AbstractTypeCheckerContext, typeCheckerContext: AbstractTypeCheckerContext,
reporter: DiagnosticReporter reporter: DiagnosticReporter,
context: CheckerContext
) { ) {
// holds Collection<Number> bound. // holds Collection<Number> bound.
// note that if B used another type parameter here, // note that if B used another type parameter here,
@@ -168,7 +170,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
if (!satisfiesBounds) { if (!satisfiesBounds) {
reporter.report(functionCall.source, proto, actual) reporter.reportOn(functionCall.source, proto, actual, context)
return return
} }
} }
@@ -218,7 +220,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
parameterPairs.forEach { (proto, actual) -> parameterPairs.forEach { (proto, actual) ->
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) { if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
// should report on the parameter instead! // should report on the parameter instead!
reporter.report(reportTarget, proto, actual) reporter.reportOn(reportTarget, proto, actual, context)
return true return true
} }
@@ -250,9 +252,12 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
} }
private fun DiagnosticReporter.report(source: FirSourceElement?, proto: FirTypeParameterSymbol, actual: ConeKotlinType) { private fun DiagnosticReporter.reportOn(
source?.let { source: FirSourceElement?,
report(FirErrors.UPPER_BOUND_VIOLATED.on(it, proto, actual)) proto: FirTypeParameterSymbol,
} actual: ConeKotlinType,
context: CheckerContext
) {
reportOn(source, FirErrors.UPPER_BOUND_VIOLATED, proto, actual, context)
} }
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirOperation import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -27,6 +28,6 @@ object ArrayEqualityCanBeReplacedWithEquals : FirBasicExpressionChecker() {
if (left.typeRef.coneType.classId != StandardClassIds.Array) return if (left.typeRef.coneType.classId != StandardClassIds.Array) return
if (right.typeRef.coneType.classId != StandardClassIds.Array) return if (right.typeRef.coneType.classId != StandardClassIds.Array) return
reporter.report(expression.source, ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS) reporter.reportOn(expression.source, ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS, context)
} }
} }
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirVariableAssignme
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
@@ -58,7 +59,7 @@ object CanBeReplacedWithOperatorAssignmentChecker : FirVariableAssignmentChecker
} }
if (needToReport) { if (needToReport) {
reporter.report(expression.source, FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT) reporter.reportOn(expression.source, FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT, context)
} }
} }
@@ -7,11 +7,17 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.* import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.PathAwarePropertyInitializationInfo
import org.jetbrains.kotlin.fir.analysis.cfa.TraverseDirection
import org.jetbrains.kotlin.fir.analysis.cfa.traverse
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
@@ -21,7 +27,8 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
graph: ControlFlowGraph, graph: ControlFlowGraph,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>, data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol> properties: Set<FirPropertySymbol>,
context: CheckerContext
) { ) {
val unprocessedProperties = mutableSetOf<FirPropertySymbol>() val unprocessedProperties = mutableSetOf<FirPropertySymbol>()
val propertiesCharacteristics = mutableMapOf<FirPropertySymbol, EventOccurrencesRange>() val propertiesCharacteristics = mutableMapOf<FirPropertySymbol, EventOccurrencesRange>()
@@ -51,14 +58,14 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
if (lastDestructuringSource != null) { if (lastDestructuringSource != null) {
// if this is the last variable in destructuring declaration and destructuringCanBeVal == true and it can be val // if this is the last variable in destructuring declaration and destructuringCanBeVal == true and it can be val
if (lastDestructuredVariables == 1 && destructuringCanBeVal && canBeVal(symbol, value)) { if (lastDestructuredVariables == 1 && destructuringCanBeVal && canBeVal(symbol, value)) {
reporter.report(lastDestructuringSource, FirErrors.CAN_BE_VAL) reporter.reportOn(lastDestructuringSource, FirErrors.CAN_BE_VAL, context)
lastDestructuringSource = null lastDestructuringSource = null
} else if (!canBeVal(symbol, value)) { } else if (!canBeVal(symbol, value)) {
destructuringCanBeVal = false destructuringCanBeVal = false
} }
lastDestructuredVariables-- 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) reporter.reportOn(source, FirErrors.CAN_BE_VAL, context)
} }
} }
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -36,8 +37,7 @@ object EmptyRangeChecker : FirBasicExpressionChecker() {
} }
if (needReport) { if (needReport) {
reporter.report(expression.source, FirErrors.EMPTY_RANGE) reporter.reportOn(expression.source, FirErrors.EMPTY_RANGE, context)
} }
} }
@@ -10,6 +10,7 @@ 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.FirQualifiedAccessChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -31,7 +32,7 @@ object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() {
val qualifiedType = targetClassMap[functionName] ?: return val qualifiedType = targetClassMap[functionName] ?: return
if (expression.explicitReceiver?.isRedundant(qualifiedType) == true) { if (expression.explicitReceiver?.isRedundant(qualifiedType) == true) {
reporter.report(expression.source, FirErrors.REDUNDANT_CALL_OF_CONVERSION_METHOD) reporter.reportOn(expression.source, FirErrors.REDUNDANT_CALL_OF_CONVERSION_METHOD, context)
} }
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
@@ -84,7 +85,7 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
else -> return else -> return
} }
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE) reporter.reportOn(declaration.returnTypeRef.source, FirErrors.REDUNDANT_EXPLICIT_TYPE, context)
} }
private fun ConeKotlinType.isSame(other: ClassId?): Boolean { private fun ConeKotlinType.isSame(other: ClassId?): Boolean {
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.implicitModality
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.modality import org.jetbrains.kotlin.fir.declarations.modality
@@ -33,6 +34,6 @@ object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
val implicitModality = declaration.implicitModality(context) val implicitModality = declaration.implicitModality(context)
if (modality != implicitModality) return if (modality != implicitModality) return
reporter.report(source, REDUNDANT_MODALITY_MODIFIER) reporter.reportOn(source, REDUNDANT_MODALITY_MODIFIER, context)
} }
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
@@ -25,7 +26,7 @@ object RedundantReturnUnitType : FirBasicDeclarationChecker() {
if (returnType.annotations.isNotEmpty()) return if (returnType.annotations.isNotEmpty()) return
if (returnType.isUnit) { if (returnType.isUnit) {
reporter.report(declaration.returnTypeRef.source, FirErrors.REDUNDANT_RETURN_UNIT_TYPE) reporter.reportOn(declaration.returnTypeRef.source, FirErrors.REDUNDANT_RETURN_UNIT_TYPE, context)
} }
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
@@ -23,7 +24,7 @@ object RedundantSetterParameterTypeChecker : FirMemberDeclarationChecker() {
val setterParameterTypeSource = valueParameter.returnTypeRef.source ?: return val setterParameterTypeSource = valueParameter.returnTypeRef.source ?: return
if (setterParameterTypeSource != propertyTypeSource) { if (setterParameterTypeSource != propertyTypeSource) {
reporter.report(setterParameterTypeSource, REDUNDANT_SETTER_PARAMETER_TYPE) reporter.reportOn(setterParameterTypeSource, REDUNDANT_SETTER_PARAMETER_TYPE, context)
} }
} }
} }
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirBasicExpressionC
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
@@ -32,7 +33,7 @@ object RedundantSingleExpressionStringTemplateChecker : FirBasicExpressionChecke
expression.explicitReceiver?.typeRef?.coneType?.classId == StandardClassIds.String expression.explicitReceiver?.typeRef?.coneType?.classId == StandardClassIds.String
&& expression.stringParentChildrenCount() == 1 // there is no more children in original string template && expression.stringParentChildrenCount() == 1 // there is no more children in original string template
) { ) {
reporter.report(expression.source, REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE) reporter.reportOn(expression.source, REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE, context)
} }
} }
@@ -7,17 +7,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.* import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
@@ -53,7 +50,7 @@ object RedundantVisibilityModifierChecker : FirBasicDeclarationChecker() {
&& declaration.setter?.visibility == Visibilities.Public && declaration.setter?.visibility == Visibilities.Public
) return ) return
reporter.report(source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER) reporter.reportOn(source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER, context)
} }
private fun FirDeclaration.implicitVisibility(context: CheckerContext): Visibility { private fun FirDeclaration.implicitVisibility(context: CheckerContext): Visibility {
@@ -1,18 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.extended
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.report(
source: T?,
factory: FirDiagnosticFactory0<T, P>
) {
source?.let { report(factory.on(it)) }
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.checkers.isIterator import org.jetbrains.kotlin.fir.analysis.checkers.isIterator
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
@@ -30,21 +31,22 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
object UnusedChecker : FirControlFlowChecker() { object UnusedChecker : FirControlFlowChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) { override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(checkerContext)?.takeIf { if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(context)?.takeIf {
!it.symbol.classId.isLocal !it.symbol.classId.isLocal
} != null } != null
) return ) return
val properties = LocalPropertyCollector.collect(graph) val properties = LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return if (properties.isEmpty()) return
val data = ValueWritesWithoutReading(checkerContext.session, properties).getData(graph) val data = ValueWritesWithoutReading(context.session, properties).getData(graph)
graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter)) graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter, context))
} }
class CfaVisitor( class CfaVisitor(
val data: Map<CFGNode<*>, PathAwareVariableStatusInfo>, val data: Map<CFGNode<*>, PathAwareVariableStatusInfo>,
val reporter: DiagnosticReporter val reporter: DiagnosticReporter,
val context: CheckerContext
) : ControlFlowGraphVisitorVoid() { ) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {} override fun visitNode(node: CFGNode<*>) {}
@@ -56,7 +58,7 @@ object UnusedChecker : FirControlFlowChecker() {
if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) { if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) {
// todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea) // todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
val source = node.fir.lValue.source val source = node.fir.lValue.source
reporter.report(source, FirErrors.ASSIGNED_VALUE_IS_NEVER_READ) reporter.reportOn(source, FirErrors.ASSIGNED_VALUE_IS_NEVER_READ, context)
// To avoid duplicate reports, stop investigating remaining paths once reported. // To avoid duplicate reports, stop investigating remaining paths once reported.
break break
} }
@@ -74,17 +76,17 @@ object UnusedChecker : FirControlFlowChecker() {
when { when {
data == VariableStatus.UNUSED -> { data == VariableStatus.UNUSED -> {
if ((node.fir.initializer as? FirFunctionCall)?.isIterator != true) { if ((node.fir.initializer as? FirFunctionCall)?.isIterator != true) {
reporter.report(variableSource, FirErrors.UNUSED_VARIABLE) reporter.reportOn(variableSource, FirErrors.UNUSED_VARIABLE, context)
break break
} }
} }
data.isRedundantInit -> { data.isRedundantInit -> {
val source = variableSymbol.fir.initializer?.source val source = variableSymbol.fir.initializer?.source
reporter.report(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT) reporter.reportOn(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT, context)
break break
} }
data == VariableStatus.ONLY_WRITTEN_NEVER_READ -> { data == VariableStatus.ONLY_WRITTEN_NEVER_READ -> {
reporter.report(variableSource, FirErrors.VARIABLE_NEVER_READ) reporter.reportOn(variableSource, FirErrors.VARIABLE_NEVER_READ, context)
break break
} }
else -> { else -> {
@@ -9,6 +9,7 @@ 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.FirQualifiedAccessChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
@@ -28,7 +29,7 @@ object UselessCallOnNotNullChecker : FirQualifiedAccessChecker() {
if ("$calleePackageName.$calleeName" !in triggerOn) return if ("$calleePackageName.$calleeName" !in triggerOn) return
if (calleeOn.getNullability() == ConeNullability.NOT_NULL) { if (calleeOn.getNullability() == ConeNullability.NOT_NULL) {
reporter.report(expression.source, FirErrors.USELESS_CALL_ON_NOT_NULL) reporter.reportOn(expression.source, FirErrors.USELESS_CALL_ON_NOT_NULL, context)
} }
} }
@@ -10,7 +10,10 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.* import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.diagnostics.* import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind.* import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind.*
@@ -27,37 +30,42 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) { class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) { override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
val source = errorLoop.source ?: return val source = errorLoop.source ?: return
reportFirDiagnostic(errorLoop.diagnostic, source, reporter) reportFirDiagnostic(errorLoop.diagnostic, source, reporter, data)
} }
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) { override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
val source = errorTypeRef.source ?: return val source = errorTypeRef.source ?: return
reportFirDiagnostic(errorTypeRef.diagnostic, source, reporter) reportFirDiagnostic(errorTypeRef.diagnostic, source, reporter, data)
} }
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) { override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) {
val source = errorNamedReference.source ?: return val source = errorNamedReference.source ?: return
// Don't report duplicated unresolved reference on annotation entry (already reported on its type) // Don't report duplicated unresolved reference on annotation entry (already reported on its type)
if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return
reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter) reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data)
} }
override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) { override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) {
val source = errorExpression.source ?: return val source = errorExpression.source ?: return
reportFirDiagnostic(errorExpression.diagnostic, source, reporter) reportFirDiagnostic(errorExpression.diagnostic, source, reporter, data)
} }
override fun visitErrorFunction(errorFunction: FirErrorFunction, data: CheckerContext) { override fun visitErrorFunction(errorFunction: FirErrorFunction, data: CheckerContext) {
val source = errorFunction.source ?: return val source = errorFunction.source ?: return
reportFirDiagnostic(errorFunction.diagnostic, source, reporter) reportFirDiagnostic(errorFunction.diagnostic, source, reporter, data)
} }
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier, data: CheckerContext) { override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier, data: CheckerContext) {
val source = errorResolvedQualifier.source ?: return val source = errorResolvedQualifier.source ?: return
reportFirDiagnostic(errorResolvedQualifier.diagnostic, source, reporter) reportFirDiagnostic(errorResolvedQualifier.diagnostic, source, reporter, data)
} }
private fun reportFirDiagnostic(diagnostic: ConeDiagnostic, source: FirSourceElement, reporter: DiagnosticReporter) { private fun reportFirDiagnostic(
diagnostic: ConeDiagnostic,
source: FirSourceElement,
reporter: DiagnosticReporter,
context: CheckerContext
) {
// Will be handled by [FirDestructuringDeclarationChecker] // Will be handled by [FirDestructuringDeclarationChecker]
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) { if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) {
// TODO: if all diagnostics are supported, we don't need the following check, and will bail out based on element type. // TODO: if all diagnostics are supported, we don't need the following check, and will bail out based on element type.
@@ -97,7 +105,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
is ConeIntermediateDiagnostic -> null is ConeIntermediateDiagnostic -> null
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}") else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}")
} }
reporter.report(coneDiagnostic) reporter.report(coneDiagnostic, context)
} }
private fun ConeKotlinType.isEffectivelyNotNull(): Boolean { private fun ConeKotlinType.isEffectivelyNotNull(): Boolean {
@@ -5,14 +5,56 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
abstract class DiagnosticReporter { abstract class DiagnosticReporter {
abstract fun report(diagnostic: FirDiagnostic<*>?) abstract fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext)
}
inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.reportOn(
source: T?,
factory: FirDiagnosticFactory0<T, P>,
context: CheckerContext
) {
source?.let { report(factory.on(it), context) }
}
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any> DiagnosticReporter.reportOn(
source: T?,
factory: FirDiagnosticFactory1<T, P, A>,
a: A,
context: CheckerContext
) {
source?.let { report(factory.on(it, a), context) }
}
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any, B : Any> DiagnosticReporter.reportOn(
source: T?,
factory: FirDiagnosticFactory2<T, P, A, B>,
a: A,
b: B,
context: CheckerContext
) {
source?.let { report(factory.on(it, a, b), context) }
}
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> DiagnosticReporter.reportOn(
source: T?,
factory: FirDiagnosticFactory3<T, P, A, B, C>,
a: A,
b: B,
c: C,
context: CheckerContext
) {
source?.let { report(factory.on(it, a, b, c), context) }
} }
class SimpleDiagnosticReporter : DiagnosticReporter() { class SimpleDiagnosticReporter : DiagnosticReporter() {
val diagnostics: MutableList<FirDiagnostic<*>> = mutableListOf() val diagnostics: MutableList<FirDiagnostic<*>> = mutableListOf()
override fun report(diagnostic: FirDiagnostic<*>?) { override fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext) {
if (diagnostic == null) return if (diagnostic == null) return
diagnostics += diagnostic diagnostics += diagnostic
} }
@@ -288,7 +288,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
) )
// Modifiers // Modifiers
map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable on this function: {0}", TO_STRING) map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable on this function")
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING) map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING)
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING) map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING)
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING) map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
@@ -15,7 +15,9 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -104,7 +106,7 @@ object FirErrors {
val EXPOSED_TYPE_PARAMETER_BOUND by error3<FirSourceElement, KtTypeReference, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>() val EXPOSED_TYPE_PARAMETER_BOUND by error3<FirSourceElement, KtTypeReference, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
// Modifiers // Modifiers
val INAPPLICABLE_INFIX_MODIFIER by existing1<FirSourceElement, PsiElement, String>() val INAPPLICABLE_INFIX_MODIFIER by error0<FirSourceElement, PsiElement>()
val REPEATED_MODIFIER by error1<FirSourceElement, PsiElement, KtModifierKeywordToken>() val REPEATED_MODIFIER by error1<FirSourceElement, PsiElement, KtModifierKeywordToken>()
val REDUNDANT_MODIFIER by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>() val REDUNDANT_MODIFIER by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>() val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.collectors.registerAllComponents import org.jetbrains.kotlin.fir.analysis.collectors.registerAllComponents
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
@@ -39,7 +40,7 @@ internal abstract class AbstractFirIdeDiagnosticsCollector(
private inner class Reporter : DiagnosticReporter() { private inner class Reporter : DiagnosticReporter() {
override fun report(diagnostic: FirDiagnostic<*>?) { override fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext) {
if (diagnostic !is FirPsiDiagnostic<*>) return if (diagnostic !is FirPsiDiagnostic<*>) return
if (diagnostic.element.psi !is KtElement) return if (diagnostic.element.psi !is KtElement) return
onDiagnostic(diagnostic) onDiagnostic(diagnostic)
@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.fir.plugin.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
@@ -16,7 +15,7 @@ object DummyNameChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirSimpleFunction) return if (declaration !is FirSimpleFunction) return
if (declaration.name.asString() == "dummy") { if (declaration.name.asString() == "dummy") {
declaration.source?.let { reporter.report(FirErrors.SYNTAX.on(it)) } reporter.reportOn(declaration.source, FirErrors.SYNTAX, context)
} }
} }
} }