[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
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
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.ControlFlowGraph
@@ -15,6 +16,7 @@ abstract class AbstractFirPropertyInitializationChecker {
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol>
properties: Set<FirPropertySymbol>,
context: CheckerContext
)
}
}
@@ -43,7 +43,7 @@ import kotlin.contracts.contract
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
if (function !is FirContractDescriptionOwner) return
if (function.contractDescription.coneEffects?.any { it is ConeCallsEffectDeclaration } != true) return
@@ -73,10 +73,10 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
for ((symbol, leakedPlaces) in leakedSymbols) {
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 {
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 pathAwareInfo = invocationData.getValue(node)
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.
break
}
@@ -105,12 +105,13 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
symbol: AbstractFirBasedSymbol<*>,
requiredRange: EventOccurrencesRange,
function: FirContractDescriptionOwner,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
): Boolean {
val foundRange = info[symbol] ?: EventOccurrencesRange.ZERO
if (foundRange !in requiredRange) {
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
}
}
@@ -29,27 +29,32 @@ class FirControlFlowAnalyzer(session: FirSession) {
cfaCheckers.forEach { it.analyze(graph, reporter, context) }
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) {
if (graph.owner != null) return
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
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)
if (properties.isEmpty()) return
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.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.FirErrors
import org.jetbrains.kotlin.fir.declarations.isLateInit
@@ -23,7 +24,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol>
properties: Set<FirPropertySymbol>,
context: CheckerContext
) {
val localData = data.filter {
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 reporterVisitor = UninitializedPropertyReporter(localData, localProperties, reporter)
val reporterVisitor = UninitializedPropertyReporter(localData, localProperties, reporter, context)
graph.traverse(TraverseDirection.Forward, reporterVisitor)
}
private class UninitializedPropertyReporter(
val data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
val localProperties: Set<FirPropertySymbol>,
val reporter: DiagnosticReporter
val reporter: DiagnosticReporter,
val context: CheckerContext
) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {}
@@ -61,7 +64,7 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
val kind = info[symbol] ?: EventOccurrencesRange.ZERO
if (!kind.isDefinitelyVisited()) {
node.fir.source?.let {
reporter.report(FirErrors.UNINITIALIZED_VARIABLE.on(it, symbol))
reporter.report(FirErrors.UNINITIALIZED_VARIABLE.on(it, symbol), context)
return true
}
}
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
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 graphRef = function.controlFlowGraphReference as FirControlFlowGraphReferenceImpl
val dataFlowInfo = graphRef.dataFlowInfo
@@ -62,7 +62,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
if (wrongCondition) {
function.contractDescription.source?.let {
reporter.report(FirErrors.WRONG_IMPLIES_CONDITION.on(it))
reporter.report(FirErrors.WRONG_IMPLIES_CONDITION.on(it), context)
}
}
}
@@ -215,4 +215,4 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
private fun FirFunction<*>.getParameterSymbol(index: Int): AbstractFirBasedSymbol<*> {
return if (index == -1) this.symbol else this.valueParameters[index].symbol
}
}
}
@@ -10,5 +10,5 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
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
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind
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.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.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.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
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.types.*
import org.jetbrains.kotlin.name.Name
@@ -36,8 +39,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
for ((arg, _) in declarationOfAnnotation.argumentMapping ?: continue) {
val expression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
checkAnnotationArgumentWithSubElements(expression, context.session, reporter)
?.let { reporter.report(expression.source, it) }
checkAnnotationArgumentWithSubElements(expression, context.session, reporter, context)
?.let { reporter.reportOn(expression.source, it, context) }
}
}
}
@@ -45,7 +48,8 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
private fun checkAnnotationArgumentWithSubElements(
expression: FirExpression,
session: FirSession,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
): FirDiagnosticFactory0<FirSourceElement, KtExpression>? {
when (expression) {
is FirArrayOfCall -> {
@@ -54,13 +58,13 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
for (arg in expression.argumentList.arguments) {
val sourceForReport = arg.source
when (val err = checkAnnotationArgumentWithSubElements(arg, session, reporter)) {
when (val err = checkAnnotationArgumentWithSubElements(arg, session, reporter, context)) {
null -> {
//DO NOTHING
}
else -> {
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 -> {
for (arg in expression.arguments)
checkAnnotationArgumentWithSubElements(arg, session, reporter)
?.let { reporter.report(arg.source, it) }
checkAnnotationArgumentWithSubElements(arg, session, reporter, context)
?.let { reporter.reportOn(arg.source, it, context) }
}
else ->
return checkAnnotationArgument(expression, session)
@@ -224,14 +228,7 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
?.toSymbol(session)
?.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(
"toInt", "toLong", "toShort", "toByte", "toFloat", "toDouble", "toChar", "toBoolean"
).mapTo(hashSetOf()) { Name.identifier(it) }
}
}
@@ -5,28 +5,26 @@
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.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.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.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveArrayTypeByElementType
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.primitiveTypes
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.unsignedTypes
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
object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
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) {
when {
@@ -34,9 +32,9 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
for (parameter in it.valueParameters) {
val source = parameter.source ?: continue
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()) {
reporter.report(source, FirErrors.VAR_ANNOTATION_PARAMETER)
reporter.reportOn(source, FirErrors.VAR_ANNOTATION_PARAMETER, context)
}
val typeRef = parameter.returnTypeRef
@@ -48,7 +46,7 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
// TODO: replace with UNRESOLVED_REFERENCE check
}
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 -> {
// DO NOTHING: primitives are allowed as annotation class parameter
@@ -67,13 +65,13 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
}
classId == StandardClassIds.Array -> {
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) -> {
// DO NOTHING: annotation or enum classes are allowed
}
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
}
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
}
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
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.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -47,9 +47,9 @@ object FirCommonConstructorDelegationIssuesChecker : FirRegularClassChecker() {
for (it in otherConstructors) {
if (it.delegatedConstructor?.isThis != true) {
if (it.delegatedConstructor?.source != null) {
reporter.reportPrimaryConstructorDelegationCallExpected(it.delegatedConstructor?.source)
reporter.reportOn(it.delegatedConstructor?.source, FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, context)
} 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 &&
it.delegatedConstructor?.source?.kind is FirFakeSourceElementKind
) {
reporter.reportExplicitDelegationCallRequired(it.source)
reporter.reportOn(it.source, FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED, context)
}
}
}
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>()
?.resolvedSymbol
?.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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.*
@@ -35,7 +35,7 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
is FirTypeAlias -> {
for (it in declaration.typeParameters) {
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)
@@ -70,17 +70,9 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_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
}
}
}
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
@@ -25,11 +25,11 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
}
inspector.functionDeclarations.forEachNonSingle { it, hint ->
reporter.reportConflictingOverloads(it.source, hint)
reporter.reportOn(it.source, FirErrors.CONFLICTING_OVERLOADS, hint, context)
}
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)
}
}
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
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
object FirConstructorAllowedChecker : FirConstructorChecker() {
@@ -26,27 +24,20 @@ object FirConstructorAllowedChecker : FirConstructorChecker() {
return
}
when (containingClass.classKind) {
ClassKind.OBJECT -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT)
ClassKind.INTERFACE -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_INTERFACE)
ClassKind.ENUM_ENTRY -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT)
ClassKind.OBJECT -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_OBJECT, context)
ClassKind.INTERFACE -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_INTERFACE, context)
ClassKind.ENUM_ENTRY -> reporter.reportOn(source, FirErrors.CONSTRUCTOR_IN_OBJECT, context)
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 &&
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 -> {
// 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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
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.isInterface
@@ -20,11 +20,7 @@ object FirConstructorInInterfaceChecker : FirRegularClassChecker() {
}
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.fir.FirSourceElement
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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
@@ -25,14 +25,15 @@ internal fun checkExpectDeclarationVisibilityAndBody(
declaration: FirMemberDeclaration,
source: FirSourceElement,
modifierList: FirModifierList?,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
) {
if (declaration.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true) {
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) {
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(
containingClass: FirRegularClass?,
property: FirProperty,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
) {
val inInterface = containingClass?.isInterface == true
// 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 (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) {
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
@@ -61,7 +63,7 @@ internal fun checkPropertyInitializer(
val backingFieldRequired = property.hasBackingField
if (inInterface && backingFieldRequired && property.hasAccessorImplementation) {
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 {
when {
inInterface -> {
reporter.report(it, FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE)
reporter.reportOn(it, FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE, context)
}
isExpect -> {
reporter.report(it, FirErrors.EXPECTED_PROPERTY_INITIALIZER)
reporter.reportOn(it, FirErrors.EXPECTED_PROPERTY_INITIALIZER, context)
}
!backingFieldRequired -> {
// reporter.report(it, FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD)
// reporter.reportOn(it, FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD, context)
}
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 {
when {
inInterface -> {
reporter.report(it, FirErrors.DELEGATED_PROPERTY_IN_INTERFACE)
reporter.reportOn(it, FirErrors.DELEGATED_PROPERTY_IN_INTERFACE, context)
}
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) {
property.source?.let {
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 {
if (containingClass != null || property.hasAccessorImplementation) {
// reporter.report(it, FirErrors.MUST_BE_INITIALIZED)
// reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED, context)
} 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
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.diagnostics.DiagnosticReporter
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.isInterface
@@ -22,12 +22,8 @@ object FirDelegationInInterfaceChecker : FirRegularClassChecker() {
for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue
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
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.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isEnumClass
@@ -26,12 +26,8 @@ object FirDelegationSuperCallInEnumConstructorChecker : FirRegularClassChecker()
it.delegatedConstructor?.isThis == false &&
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.fir.FirSourceElement
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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
@@ -36,7 +36,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
assert(declaration.name.isSpecial && declaration.name.asString() == "<destruct>") {
"Unexpected name: ${declaration.name.asString()} for destructuring declaration"
}
checkInitializer(source, declaration.initializer, reporter)
checkInitializer(source, declaration.initializer, reporter, context)
return
}
@@ -82,7 +82,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
originalDestructuringDeclarationOrInitializerSource,
diagnostic.name,
originalDestructuringDeclarationType
)
),
context
)
}
is ConeAmbiguityError -> {
@@ -91,7 +92,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
originalDestructuringDeclarationOrInitializerSource,
diagnostic.name,
diagnostic.candidates
)
),
context
)
}
is ConeInapplicableCandidateError -> {
@@ -100,7 +102,8 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
FirErrors.COMPONENT_FUNCTION_ON_NULLABLE.on(
originalDestructuringDeclarationOrInitializerSource,
(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 =
when (initializer) {
null -> true
@@ -116,7 +124,7 @@ object FirDestructuringDeclarationChecker : FirPropertyChecker() {
else -> false
}
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.isEnumClass
@@ -20,19 +20,11 @@ object FirEnumClassSimpleChecker : FirRegularClassChecker() {
}
declaration.findNonInterfaceSupertype(context)?.let {
reporter.reportClassInSupertypeForEnum(it.source)
reporter.reportOn(it.source, FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM, context)
}
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
import com.intellij.psi.PsiElement
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.toRegularClass
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.reportOn
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.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved
@@ -51,12 +52,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
}
val restricting = supertype.findVisibilityExposure(context, classVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
supertypeRef.source ?: declaration.source,
if (isInterface) FirErrors.EXPOSED_SUPER_INTERFACE else FirErrors.EXPOSED_SUPER_CLASS,
restricting,
classVisibility,
restricting,
restricting.getEffectiveVisibility(context),
supertypeRef.source ?: declaration.source
context
)
}
}
@@ -70,12 +72,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
for (bound in parameter.symbol.fir.bounds) {
val restricting = bound.coneType.findVisibilityExposure(context, classVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
bound.source,
FirErrors.EXPOSED_TYPE_PARAMETER_BOUND,
restricting,
classVisibility,
restricting,
restricting.getEffectiveVisibility(context),
bound.source
context
)
}
}
@@ -89,12 +92,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
if (typeAliasVisibility == FirEffectiveVisibilityImpl.Local) return
val restricting = expandedType?.findVisibilityExposure(context, typeAliasVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE,
restricting,
typeAliasVisibility,
restricting,
restricting.getEffectiveVisibility(context),
declaration.source
context
)
}
}
@@ -107,12 +111,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
val restricting = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, functionVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_FUNCTION_RETURN_TYPE,
restricting,
functionVisibility,
restricting,
restricting.getEffectiveVisibility(context),
declaration.source
context
)
}
}
@@ -122,12 +127,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
valueParameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, functionVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
valueParameter.source,
FirErrors.EXPOSED_PARAMETER_TYPE,
restricting,
functionVisibility,
restricting,
restricting.getEffectiveVisibility(context),
valueParameter.source
context
)
}
}
@@ -143,12 +149,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.findVisibilityExposure(context, propertyVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
declaration.source,
FirErrors.EXPOSED_PROPERTY_TYPE,
restricting,
propertyVisibility,
restricting,
restricting.getEffectiveVisibility(context),
declaration.source
context
)
}
checkMemberReceiver(declaration.receiverTypeRef, declaration, reporter, context)
@@ -167,12 +174,13 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
if (memberVisibility == FirEffectiveVisibilityImpl.Local) return
val restricting = receiverParameterType.findVisibilityExposure(context, memberVisibility)
if (restricting != null) {
reporter.reportExposure(
reporter.reportOn(
typeRef.source,
FirErrors.EXPOSED_RECEIVER_TYPE,
restricting,
memberVisibility,
restricting,
restricting.getEffectiveVisibility(context),
typeRef.source
context
)
}
}
@@ -207,25 +215,6 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() {
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) =
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.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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction
@@ -23,7 +23,7 @@ object FirFunctionNameChecker : FirFunctionChecker() {
val containingDeclaration = context.containingDeclarations.lastOrNull()
val isNonLocal = containingDeclaration is FirFile || containingDeclaration is FirClass<*>
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.diagnostics.DiagnosticReporter
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.ConeTypeParameterType
import org.jetbrains.kotlin.fir.types.coneType
@@ -40,28 +41,28 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
when {
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) {
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 {
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 ->
reporter.report(declaration.source, "is not allowed on delegated properties")
reporter.reportOn(declaration.source, "is not allowed on delegated properties", context)
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) {
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 {
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() ->
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.hasSetter() = setter != null && setter?.source != null && setter?.source?.kind !is FirFakeSourceElementKind
private fun DiagnosticReporter.report(source: FirSourceElement?, target: String) {
source?.let { report(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER.on(it, target)) }
private fun DiagnosticReporter.reportOn(source: FirSourceElement?, target: String, context: CheckerContext) {
source?.let { report(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER.on(it, target), context) }
}
}
}
@@ -5,10 +5,10 @@
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.diagnostics.DiagnosticReporter
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.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
@@ -18,12 +18,12 @@ object FirInfixFunctionDeclarationChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirSimpleFunction && declaration.isInfix) {
if (declaration.valueParameters.size != 1 || !hasExtensionOrDispatchReceiver(declaration, context)) {
reporter.report(declaration.source)
reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_INFIX_MODIFIER, context)
}
return
}
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
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findNonInterfaceSupertype
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.isInterface
@@ -20,11 +20,7 @@ object FirInterfaceWithSuperclassChecker : FirRegularClassChecker() {
}
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
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion
import org.jetbrains.kotlin.fir.declarations.visibility
import org.jetbrains.kotlin.name.Name
object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -24,19 +23,11 @@ object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
when {
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 ->
reporter.reportLocalInterfaceNotAllowed(declaration.source, declaration.name)
reporter.reportOn(declaration.source, FirErrors.LOCAL_INTERFACE_NOT_ALLOWED, declaration.name, context)
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isCompanion
@@ -19,14 +19,10 @@ object FirManyCompanionObjectsChecker : FirRegularClassChecker() {
for (it in declaration.declarations) {
if (it is FirRegularClass && it.isCompanion) {
if (hasCompanion) {
reporter.report(it.source)
reporter.reportOn(it.source, FirErrors.MANY_COMPANION_OBJECTS, context)
}
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.fir.FirFakeSourceElementKind
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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtTokens
@@ -39,10 +39,13 @@ object FirMemberFunctionChecker : FirRegularClassChecker() {
val isAbstract = function.isAbstract || hasAbstractModifier
if (isAbstract) {
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) {
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)
@@ -51,17 +54,16 @@ object FirMemberFunctionChecker : FirRegularClassChecker() {
if (!function.hasBody) {
if (containingDeclaration.isInterface) {
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) {
reporter.report(source, FirErrors.REDUNDANT_OPEN_IN_INTERFACE)
reporter.reportOn(source, FirErrors.REDUNDANT_OPEN_IN_INTERFACE, context)
}
} 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.FirSourceElement
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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -47,37 +47,43 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
(property.getter == null || property.getter is FirDefaultPropertyAccessor)
) {
property.source?.let {
reporter.report(it, FirErrors.PRIVATE_PROPERTY_IN_INTERFACE)
reporter.reportOn(it, FirErrors.PRIVATE_PROPERTY_IN_INTERFACE, context)
}
}
if (isAbstract) {
if (!containingDeclaration.canHaveAbstractDeclaration) {
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
}
}
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 {
reporter.report(it, FirErrors.ABSTRACT_DELEGATED_PROPERTY)
reporter.reportOn(it, FirErrors.ABSTRACT_DELEGATED_PROPERTY, context)
}
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 ->
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 {
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
if (hasOpenModifier &&
@@ -87,19 +93,19 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
!isInsideExpectClass(containingDeclaration, context)
) {
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
if (isOpen) {
checkAccessor(property.setter, property.delegate) { src, symbol ->
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(
@@ -5,12 +5,12 @@
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.FirDeclarationPresenter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -64,12 +64,8 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirRegularClassChecker(), F
val inspector = getInspector(context)
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
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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -103,7 +103,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
secondModifier: FirModifier<*>,
reporter: DiagnosticReporter,
reportedNodes: MutableSet<FirModifier<*>>,
owner: FirDeclaration?
owner: FirDeclaration?,
context: CheckerContext
) {
val firstToken = firstModifier.token
val secondToken = secondModifier.token
@@ -111,21 +112,21 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
CompatibilityType.COMPATIBLE -> {
}
CompatibilityType.REPEATED ->
if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken)
if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken, context)
CompatibilityType.REDUNDANT_2_TO_1 ->
reporter.reportRedundantModifier(secondModifier, secondToken, firstToken)
reporter.reportRedundantModifier(secondModifier, secondToken, firstToken, context)
CompatibilityType.REDUNDANT_1_TO_2 ->
reporter.reportRedundantModifier(firstModifier, firstToken, secondToken)
reporter.reportRedundantModifier(firstModifier, firstToken, secondToken, context)
CompatibilityType.DEPRECATED -> {
reporter.reportDeprecatedModifierPair(firstModifier, firstToken, secondToken)
reporter.reportDeprecatedModifierPair(secondModifier, secondToken, firstToken)
reporter.reportDeprecatedModifierPair(firstModifier, firstToken, secondToken, context)
reporter.reportDeprecatedModifierPair(secondModifier, secondToken, firstToken, context)
}
CompatibilityType.INCOMPATIBLE, CompatibilityType.COMPATIBLE_FOR_CLASSES -> {
if (compatibilityType == CompatibilityType.COMPATIBLE_FOR_CLASSES && owner is FirClass<*>) {
return
}
if (reportedNodes.add(firstModifier)) reporter.reportIncompatibleModifiers(firstModifier, firstToken, secondToken)
if (reportedNodes.add(secondModifier)) reporter.reportIncompatibleModifiers(secondModifier, secondToken, firstToken)
if (reportedNodes.add(firstModifier)) reporter.reportIncompatibleModifiers(firstModifier, firstToken, secondToken, context)
if (reportedNodes.add(secondModifier)) reporter.reportIncompatibleModifiers(secondModifier, secondToken, firstToken, context)
}
}
}
@@ -133,7 +134,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
private fun checkModifiers(
list: FirModifierList,
owner: FirDeclaration,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
) {
// 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
@@ -145,7 +147,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
if (firstModifier == secondModifier) {
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
val modifierList = with(FirModifierList) { source.getModifierList() }
modifierList?.let { checkModifiers(it, declaration, reporter) }
modifierList?.let { checkModifiers(it, declaration, reporter, context) }
}
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(
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(
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(
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.diagnostics.DiagnosticReporter
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.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
@@ -106,6 +107,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
private fun FirCallableMemberDeclaration<*>.checkVisibility(
reporter: DiagnosticReporter,
overriddenSymbols: List<FirCallableSymbol<*>>,
context: CheckerContext
) {
val visibilities = overriddenSymbols.mapNotNull {
if (it.fir !is FirMemberDeclaration) return@mapNotNull null
@@ -122,7 +124,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
// reporter.reportCannotChangeAccessPrivilege(this, overridden.fir)
return
} else if (compare < 0) {
reporter.reportCannotWeakenAccessPrivilege(this, overridden.fir)
reporter.reportCannotWeakenAccessPrivilege(this, overridden.fir, context)
return
}
}
@@ -169,15 +171,15 @@ object FirOverrideChecker : FirRegularClassChecker() {
val overriddenFunctionSymbols = firTypeScope.retrieveDirectOverriddenOf(function)
if (overriddenFunctionSymbols.isEmpty()) {
reporter.reportNothingToOverride(function)
reporter.reportNothingToOverride(function, context)
return
}
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(
overriddenSymbols = overriddenFunctionSymbols,
@@ -186,7 +188,7 @@ object FirOverrideChecker : FirRegularClassChecker() {
)
restriction?.let {
reporter.reportReturnTypeMismatchOnFunction(function, it)
reporter.reportReturnTypeMismatchOnFunction(function, it, context)
}
}
@@ -204,19 +206,19 @@ object FirOverrideChecker : FirRegularClassChecker() {
val overriddenPropertySymbols = firTypeScope.retrieveDirectOverriddenOf(property)
if (overriddenPropertySymbols.isEmpty()) {
reporter.reportNothingToOverride(property)
reporter.reportNothingToOverride(property, context)
return
}
checkModality(overriddenPropertySymbols)?.let {
reporter.reportOverridingFinalMember(property, it)
reporter.reportOverridingFinalMember(property, it, context)
}
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(
overriddenSymbols = overriddenPropertySymbols,
@@ -226,76 +228,91 @@ object FirOverrideChecker : FirRegularClassChecker() {
restriction?.let {
if (property.isVar) {
reporter.reportTypeMismatchOnVariable(property, it)
reporter.reportTypeMismatchOnVariable(property, it, context)
} 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
// declaration.source?.let { report(FirErrors.NOTHING_TO_OVERRIDE.on(it, declaration)) }
// reportOn(declaration.source, FirErrors.NOTHING_TO_OVERRIDE, declaration, context)
}
private fun DiagnosticReporter.reportOverridingFinalMember(
overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>,
context: CheckerContext
) {
overriding.source?.let { source ->
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(
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(
overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>,
context: CheckerContext
) {
overriding.source?.let { source ->
overridden.containingClass()?.let { containingClass ->
report(FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(source, overriding.visibility, overridden, containingClass.name))
}
}
val containingClass = overridden.containingClass() ?: return
reportOn(
overriding.source,
FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE,
overriding.visibility,
overridden,
containingClass.name,
context
)
}
private fun DiagnosticReporter.reportCannotChangeAccessPrivilege(
overriding: FirMemberDeclaration,
overridden: FirCallableDeclaration<*>,
context: CheckerContext
) {
overriding.source?.let { source ->
overridden.containingClass()?.let { containingClass ->
report(FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE.on(source, overriding.visibility, overridden, containingClass.name))
}
}
val containingClass = overridden.containingClass() ?: return
reportOn(
overriding.source,
FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE,
overriding.visibility,
overridden,
containingClass.name,
context
)
}
private fun DiagnosticReporter.reportReturnTypeMismatchOnFunction(
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(
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(
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
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.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isData
@@ -23,11 +23,7 @@ object FirPrimaryConstructorRequiredForDataClassChecker : FirRegularClassChecker
val hasPrimaryConstructor = declaration.declarations.any { it is FirConstructor && it.isPrimary }
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
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.diagnostics.DiagnosticReporter
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.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
@@ -55,7 +55,7 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue
if (fir.status.modality == Modality.SEALED && classId.outerClassId != null) {
reporter.report(it.source)
reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE, context)
return
}
}
@@ -77,7 +77,7 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue
if (fir.status.modality == Modality.SEALED) {
reporter.reportInLocal(it.source)
reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS, context)
return
}
}
@@ -99,17 +99,9 @@ object FirSealedSupertypeChecker : FirMemberDeclarationChecker() {
?: continue
if (fir.status.modality == Modality.SEALED && !context.containingDeclarations.contains(fir)) {
reporter.report(it.source)
reporter.reportOn(it.source, FirErrors.SEALED_SUPERTYPE, context)
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
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.diagnostics.DiagnosticReporter
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.isInterface
@@ -22,12 +22,8 @@ object FirSupertypeInitializedInInterfaceChecker : FirRegularClassChecker() {
for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue
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
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.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.isInterface
@@ -27,12 +27,8 @@ object FirSupertypeInitializedWithoutPrimaryConstructor : FirRegularClassChecker
for (superTypeRef in declaration.superTypeRefs) {
val source = superTypeRef.source ?: continue
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.diagnostics.DiagnosticReporter
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.lexer.KtTokens
@@ -17,12 +18,12 @@ object FirTopLevelFunctionChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
for (topLevelDeclaration in declaration.declarations) {
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
if (source.kind is FirFakeSourceElementKind) return
// 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
val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true
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) {
for (topLevelDeclaration in declaration.declarations) {
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
if (source.kind is FirFakeSourceElementKind) return
val modifierList = with(FirModifierList) { source.getModifierList() }
checkPropertyInitializer(null, property, reporter)
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter)
checkPropertyInitializer(null, property, reporter, context)
checkExpectDeclarationVisibilityAndBody(property, source, modifierList, reporter, context)
}
}
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
object FirTypeParametersInObjectChecker : FirRegularClassChecker() {
@@ -19,11 +19,7 @@ object FirTypeParametersInObjectChecker : FirRegularClassChecker() {
}
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.Modality
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.checkers.getDeclaration
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.modality
@@ -42,14 +42,8 @@ object FirAbstractSuperCallChecker : FirQualifiedAccessChecker() {
declaration.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
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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -20,10 +20,10 @@ object FirAnonymousFunctionChecker : FirExpressionChecker<FirStatement>() {
for (valueParameter in expression.valueParameters) {
val source = valueParameter.source ?: continue
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) {
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
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
if (typeRef !is FirResolvedTypeRef) return
@@ -38,17 +38,17 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
val isReified = coneType.lookupTag.typeParameterSymbol.fir.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 {
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))
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) }
}
}
private fun ConeKotlinType.isThrowable(session: FirSession) =
throwable.isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session))
}
}
@@ -5,12 +5,12 @@
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.isSupertypeOf
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
@@ -29,7 +29,7 @@ object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
val surrounding = context.findClosestClass(superReference.labelName) ?: return
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
}
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.types.FirStarProjection
import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance
@@ -18,19 +18,13 @@ object FirProjectionsOnNonClassTypeArgumentChecker : FirQualifiedAccessChecker()
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
for (it in expression.typeArguments) {
when (it) {
is FirStarProjection -> reporter.report(it.source)
is FirStarProjection -> reporter.reportOn(it.source, FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, context)
is FirTypeProjectionWithVariance -> {
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject
import org.jetbrains.kotlin.fir.analysis.checkers.followAllAlias
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
@@ -61,13 +61,12 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess
}
if (count >= 2 && candidate != null) {
reporter.report(superReference.superTypeRef.source, candidate)
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?, candidate: FirClass<*>) {
source?.let {
report(FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE.on(it, candidate))
reporter.reportOn(
superReference.superTypeRef.source,
FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE,
candidate,
context
)
}
}
}
@@ -6,10 +6,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
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.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
@@ -33,11 +33,7 @@ object FirSealedClassConstructorCallChecker : FirQualifiedAccessChecker() {
?: return
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
@@ -23,13 +23,7 @@ object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() {
}
if (!isInsideClass) {
reporter.report(expression.source)
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let {
report(FirErrors.SUPER_NOT_AVAILABLE.on(it))
reporter.reportOn(expression.source, FirErrors.SUPER_NOT_AVAILABLE, context)
}
}
}
@@ -6,11 +6,11 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
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.getContainingClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
@@ -34,7 +34,7 @@ object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecke
?: return
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<*>? {
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
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
@@ -20,15 +20,9 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker()
if (explicitReceiver is FirResolvedQualifier && explicitReceiver.symbol == null) {
if (explicitReceiver.typeArguments.isNotEmpty()) {
reporter.report(explicitReceiver.source)
reporter.reportOn(explicitReceiver.source, FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED, context)
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.diagnostics.DiagnosticReporter
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.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
@@ -74,7 +75,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
}
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
reporter.report(actual.source, proto, actual.type)
reporter.reportOn(actual.source, proto, actual.type, context)
return
}
@@ -98,7 +99,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
// typealias A<G> = B<List<G>>
// val a = A<Int>()
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,
callSiteSubstitutor: ConeSubstitutor,
typeCheckerContext: AbstractTypeCheckerContext,
reporter: DiagnosticReporter
reporter: DiagnosticReporter,
context: CheckerContext
) {
// holds Collection<Number> bound.
// note that if B used another type parameter here,
@@ -168,7 +170,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
if (!satisfiesBounds) {
reporter.report(functionCall.source, proto, actual)
reporter.reportOn(functionCall.source, proto, actual, context)
return
}
}
@@ -218,7 +220,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
parameterPairs.forEach { (proto, actual) ->
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
// should report on the parameter instead!
reporter.report(reportTarget, proto, actual)
reporter.reportOn(reportTarget, proto, actual, context)
return true
}
@@ -250,9 +252,12 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
}
private fun DiagnosticReporter.report(source: FirSourceElement?, proto: FirTypeParameterSymbol, actual: ConeKotlinType) {
source?.let {
report(FirErrors.UPPER_BOUND_VIOLATED.on(it, proto, actual))
}
private fun DiagnosticReporter.reportOn(
source: FirSourceElement?,
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.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.reportOn
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -27,6 +28,6 @@ object ArrayEqualityCanBeReplacedWithEquals : FirBasicExpressionChecker() {
if (left.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.diagnostics.DiagnosticReporter
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.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
@@ -58,7 +59,7 @@ object CanBeReplacedWithOperatorAssignmentChecker : FirVariableAssignmentChecker
}
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.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.cfa.*
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.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.diagnostics.DiagnosticReporter
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.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
@@ -21,7 +27,8 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PathAwarePropertyInitializationInfo>,
properties: Set<FirPropertySymbol>
properties: Set<FirPropertySymbol>,
context: CheckerContext
) {
val unprocessedProperties = mutableSetOf<FirPropertySymbol>()
val propertiesCharacteristics = mutableMapOf<FirPropertySymbol, EventOccurrencesRange>()
@@ -51,14 +58,14 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
if (lastDestructuringSource != null) {
// if this is the last variable in destructuring declaration and destructuringCanBeVal == true and it can be val
if (lastDestructuredVariables == 1 && destructuringCanBeVal && canBeVal(symbol, value)) {
reporter.report(lastDestructuringSource, FirErrors.CAN_BE_VAL)
reporter.reportOn(lastDestructuringSource, FirErrors.CAN_BE_VAL, context)
lastDestructuringSource = null
} else if (!canBeVal(symbol, value)) {
destructuringCanBeVal = false
}
lastDestructuredVariables--
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null) {
reporter.report(source, FirErrors.CAN_BE_VAL)
reporter.reportOn(source, FirErrors.CAN_BE_VAL, context)
}
}
}
@@ -110,4 +117,4 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
EventOccurrencesRange.AT_MOST_ONCE,
EventOccurrencesRange.ZERO
)
}
}
@@ -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.diagnostics.DiagnosticReporter
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.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -36,8 +37,7 @@ object EmptyRangeChecker : FirBasicExpressionChecker() {
}
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.diagnostics.DiagnosticReporter
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.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -31,7 +32,7 @@ object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() {
val qualifiedType = targetClassMap[functionName] ?: return
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)
}
}
@@ -64,4 +65,4 @@ object RedundantCallOfConversionMethod : FirQualifiedAccessChecker() {
"toUShort" to StandardClassIds.UShort,
"toUByte" to StandardClassIds.UByte
)
}
}
@@ -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.diagnostics.DiagnosticReporter
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.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
@@ -84,7 +85,7 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
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 {
@@ -95,4 +96,4 @@ object RedundantExplicitTypeChecker : FirMemberDeclarationChecker() {
private fun ConeKotlinType.hasSameNameWithoutModifiers(name: Name): Boolean =
this is ConeClassLikeType && lookupTag.name == name && typeArguments.isEmpty() && !isMarkedNullable
}
}
@@ -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.FirErrors.REDUNDANT_MODALITY_MODIFIER
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.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.modality
@@ -33,6 +34,6 @@ object RedundantModalityModifierChecker : FirMemberDeclarationChecker() {
val implicitModality = declaration.implicitModality(context)
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.diagnostics.DiagnosticReporter
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.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
@@ -25,8 +26,8 @@ object RedundantReturnUnitType : FirBasicDeclarationChecker() {
if (returnType.annotations.isNotEmpty()) return
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.diagnostics.DiagnosticReporter
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.FirProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
@@ -23,7 +24,7 @@ object RedundantSetterParameterTypeChecker : FirMemberDeclarationChecker() {
val setterParameterTypeSource = valueParameter.returnTypeRef.source ?: return
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.diagnostics.DiagnosticReporter
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.FirStatement
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
@@ -32,7 +33,7 @@ object RedundantSingleExpressionStringTemplateChecker : FirBasicExpressionChecke
expression.explicitReceiver?.typeRef?.coneType?.classId == StandardClassIds.String
&& 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.Modality
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.Visibilities
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.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
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.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
@@ -53,7 +50,7 @@ object RedundantVisibilityModifierChecker : FirBasicDeclarationChecker() {
&& declaration.setter?.visibility == Visibilities.Public
) return
reporter.report(source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER)
reporter.reportOn(source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER, context)
}
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.diagnostics.DiagnosticReporter
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.FirFunctionCall
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
object UnusedChecker : FirControlFlowChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) {
if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(checkerContext)?.takeIf {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, context: CheckerContext) {
if ((graph.declaration as? FirSymbolOwner<*>)?.getContainingClass(context)?.takeIf {
!it.symbol.classId.isLocal
} != null
) return
val properties = LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return
val data = ValueWritesWithoutReading(checkerContext.session, properties).getData(graph)
graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter))
val data = ValueWritesWithoutReading(context.session, properties).getData(graph)
graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter, context))
}
class CfaVisitor(
val data: Map<CFGNode<*>, PathAwareVariableStatusInfo>,
val reporter: DiagnosticReporter
val reporter: DiagnosticReporter,
val context: CheckerContext
) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {}
@@ -56,7 +58,7 @@ object UnusedChecker : FirControlFlowChecker() {
if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) {
// todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea)
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.
break
}
@@ -74,17 +76,17 @@ object UnusedChecker : FirControlFlowChecker() {
when {
data == VariableStatus.UNUSED -> {
if ((node.fir.initializer as? FirFunctionCall)?.isIterator != true) {
reporter.report(variableSource, FirErrors.UNUSED_VARIABLE)
reporter.reportOn(variableSource, FirErrors.UNUSED_VARIABLE, context)
break
}
}
data.isRedundantInit -> {
val source = variableSymbol.fir.initializer?.source
reporter.report(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT)
reporter.reportOn(source, FirErrors.VARIABLE_INITIALIZER_IS_REDUNDANT, context)
break
}
data == VariableStatus.ONLY_WRITTEN_NEVER_READ -> {
reporter.report(variableSource, FirErrors.VARIABLE_NEVER_READ)
reporter.reportOn(variableSource, FirErrors.VARIABLE_NEVER_READ, context)
break
}
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.diagnostics.DiagnosticReporter
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.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
@@ -28,7 +29,7 @@ object UselessCallOnNotNullChecker : FirQualifiedAccessChecker() {
if ("$calleePackageName.$calleeName" !in triggerOn) return
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)
}
}
@@ -53,4 +54,4 @@ object UselessCallOnNotNullChecker : FirQualifiedAccessChecker() {
"kotlin.orEmpty"
)
}
}
@@ -10,7 +10,10 @@ 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.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.diagnostics.*
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind.*
@@ -27,37 +30,42 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
val source = errorLoop.source ?: return
reportFirDiagnostic(errorLoop.diagnostic, source, reporter)
reportFirDiagnostic(errorLoop.diagnostic, source, reporter, data)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
val source = errorTypeRef.source ?: return
reportFirDiagnostic(errorTypeRef.diagnostic, source, reporter)
reportFirDiagnostic(errorTypeRef.diagnostic, source, reporter, data)
}
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) {
val source = errorNamedReference.source ?: return
// 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
reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter)
reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data)
}
override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) {
val source = errorExpression.source ?: return
reportFirDiagnostic(errorExpression.diagnostic, source, reporter)
reportFirDiagnostic(errorExpression.diagnostic, source, reporter, data)
}
override fun visitErrorFunction(errorFunction: FirErrorFunction, data: CheckerContext) {
val source = errorFunction.source ?: return
reportFirDiagnostic(errorFunction.diagnostic, source, reporter)
reportFirDiagnostic(errorFunction.diagnostic, source, reporter, data)
}
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier, data: CheckerContext) {
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]
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.
@@ -97,7 +105,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
is ConeIntermediateDiagnostic -> null
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}")
}
reporter.report(coneDiagnostic)
reporter.report(coneDiagnostic, context)
}
private fun ConeKotlinType.isEffectivelyNotNull(): Boolean {
@@ -5,15 +5,57 @@
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 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() {
val diagnostics: MutableList<FirDiagnostic<*>> = mutableListOf()
override fun report(diagnostic: FirDiagnostic<*>?) {
override fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext) {
if (diagnostic == null) return
diagnostics += diagnostic
}
}
}
@@ -288,7 +288,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
)
// 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(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)
@@ -15,7 +15,9 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
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.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.Name
@@ -104,7 +106,7 @@ object FirErrors {
val EXPOSED_TYPE_PARAMETER_BOUND by error3<FirSourceElement, KtTypeReference, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
// 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 REDUNDANT_MODIFIER 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 org.jetbrains.kotlin.diagnostics.Diagnostic
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.registerAllComponents
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
@@ -39,7 +40,7 @@ internal abstract class AbstractFirIdeDiagnosticsCollector(
private inner class Reporter : DiagnosticReporter() {
override fun report(diagnostic: FirDiagnostic<*>?) {
override fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext) {
if (diagnostic !is FirPsiDiagnostic<*>) return
if (diagnostic.element.psi !is KtElement) return
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.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
@@ -16,7 +15,7 @@ object DummyNameChecker : FirMemberDeclarationChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirSimpleFunction) return
if (declaration.name.asString() == "dummy") {
declaration.source?.let { reporter.report(FirErrors.SYNTAX.on(it)) }
reporter.reportOn(declaration.source, FirErrors.SYNTAX, context)
}
}
}