K2: add more accurate & more automatic control of diagnostic suppression

#KT-51363 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-07-20 16:46:23 +02:00
committed by Space
parent 179b267d9f
commit 9add6f3d55
21 changed files with 194 additions and 101 deletions
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.analysis.collectors
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
open class CheckerRunningDiagnosticCollectorVisitor(
context: CheckerContext,
@@ -19,4 +21,11 @@ open class CheckerRunningDiagnosticCollectorVisitor(
element.accept(it, context)
}
}
override fun onDeclarationExit(declaration: FirDeclaration) {
if (declaration !is FirFile) return
components.forEach {
it.endOfFile(declaration)
}
}
}
@@ -5,10 +5,13 @@
package org.jetbrains.kotlin.fir.analysis.collectors.components
import org.jetbrains.kotlin.diagnostics.DiagnosticContext
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.impl.PendingDiagnosticsCollectorWithSuppress
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.visitors.FirVisitor
abstract class AbstractDiagnosticCollectorComponent(
@@ -16,4 +19,13 @@ abstract class AbstractDiagnosticCollectorComponent(
protected val reporter: DiagnosticReporter,
) : FirVisitor<Unit, CheckerContext>() {
override fun visitElement(element: FirElement, data: CheckerContext) {}
protected fun checkAndCommitReportsOn(element: FirElement, context: DiagnosticContext?) {
if (reporter is PendingDiagnosticsCollectorWithSuppress) {
val source = element.source ?: return
reporter.checkAndCommitReportsOn(source, context, context == null)
}
}
open fun endOfFile(file: FirFile) {}
}
@@ -22,69 +22,68 @@ class DeclarationCheckersDiagnosticComponent(
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitFile(file: FirFile, data: CheckerContext) {
checkers.allFileCheckers.check(file, data, reporter)
checkers.allFileCheckers.check(file, data)
}
override fun visitProperty(property: FirProperty, data: CheckerContext) {
checkers.allPropertyCheckers.check(property, data, reporter)
checkers.allPropertyCheckers.check(property, data)
}
override fun visitClass(klass: FirClass, data: CheckerContext) {
checkers.allClassCheckers.check(klass, data, reporter)
checkers.allClassCheckers.check(klass, data)
}
override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) {
checkers.allRegularClassCheckers.check(regularClass, data, reporter)
checkers.allRegularClassCheckers.check(regularClass, data)
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: CheckerContext) {
checkers.allSimpleFunctionCheckers.check(simpleFunction, data, reporter)
checkers.allSimpleFunctionCheckers.check(simpleFunction, data)
}
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: CheckerContext) {
checkers.allTypeAliasCheckers.check(typeAlias, data, reporter)
checkers.allTypeAliasCheckers.check(typeAlias, data)
}
override fun visitConstructor(constructor: FirConstructor, data: CheckerContext) {
checkers.allConstructorCheckers.check(constructor, data, reporter)
checkers.allConstructorCheckers.check(constructor, data)
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: CheckerContext) {
checkers.allAnonymousFunctionCheckers.check(anonymousFunction, data, reporter)
checkers.allAnonymousFunctionCheckers.check(anonymousFunction, data)
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: CheckerContext) {
checkers.allPropertyAccessorCheckers.check(propertyAccessor, data, reporter)
checkers.allPropertyAccessorCheckers.check(propertyAccessor, data)
}
override fun visitBackingField(backingField: FirBackingField, data: CheckerContext) {
checkers.allBackingFieldCheckers.check(backingField, data, reporter)
checkers.allBackingFieldCheckers.check(backingField, data)
}
override fun visitValueParameter(valueParameter: FirValueParameter, data: CheckerContext) {
checkers.allValueParameterCheckers.check(valueParameter, data, reporter)
checkers.allValueParameterCheckers.check(valueParameter, data)
}
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: CheckerContext) {
checkers.allTypeParameterCheckers.check(typeParameter, data, reporter)
checkers.allTypeParameterCheckers.check(typeParameter, data)
}
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: CheckerContext) {
checkers.allEnumEntryCheckers.check(enumEntry, data, reporter)
checkers.allEnumEntryCheckers.check(enumEntry, data)
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: CheckerContext) {
checkers.allAnonymousObjectCheckers.check(anonymousObject, data, reporter)
checkers.allAnonymousObjectCheckers.check(anonymousObject, data)
}
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: CheckerContext) {
checkers.allAnonymousInitializerCheckers.check(anonymousInitializer, data, reporter)
checkers.allAnonymousInitializerCheckers.check(anonymousInitializer, data)
}
private fun <D : FirDeclaration> Collection<FirDeclarationChecker<D>>.check(
declaration: D,
context: CheckerContext,
reporter: DiagnosticReporter
context: CheckerContext
) {
for (checker in this) {
checker.check(declaration, context, reporter)
@@ -16,6 +16,7 @@ object DiagnosticComponentsFactory {
TypeCheckersDiagnosticComponent(session, reporter),
ErrorNodeDiagnosticCollectorComponent(session, reporter),
ControlFlowAnalysisDiagnosticComponent(session, reporter),
ReportCommitterDiagnosticComponent(session, reporter)
)
}
@@ -32,12 +32,12 @@ class ErrorNodeDiagnosticCollectorComponent(
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
val source = errorLoop.source ?: return
reportFirDiagnostic(errorLoop.diagnostic, source, reporter, data)
reportFirDiagnostic(errorLoop.diagnostic, source, data)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
val source = errorTypeRef.source ?: return
reportFirDiagnostic(errorTypeRef.diagnostic, source, reporter, data)
reportFirDiagnostic(errorTypeRef.diagnostic, source, data)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: CheckerContext) {
@@ -71,7 +71,7 @@ class ErrorNodeDiagnosticCollectorComponent(
) return
}
reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data, qualifiedAccessOrAnnotationCall?.source)
reportFirDiagnostic(errorNamedReference.diagnostic, source, data, qualifiedAccessOrAnnotationCall?.source)
}
private fun FirExpression?.cannotBeResolved(): Boolean {
@@ -86,28 +86,27 @@ class ErrorNodeDiagnosticCollectorComponent(
override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) {
val source = errorExpression.source ?: return
reportFirDiagnostic(errorExpression.diagnostic, source, reporter, data)
reportFirDiagnostic(errorExpression.diagnostic, source, data)
}
override fun visitErrorFunction(errorFunction: FirErrorFunction, data: CheckerContext) {
val source = errorFunction.source ?: return
reportFirDiagnostic(errorFunction.diagnostic, source, reporter, data)
reportFirDiagnostic(errorFunction.diagnostic, source, data)
}
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier, data: CheckerContext) {
val source = errorResolvedQualifier.source ?: return
reportFirDiagnostic(errorResolvedQualifier.diagnostic, source, reporter, data)
reportFirDiagnostic(errorResolvedQualifier.diagnostic, source, data)
}
override fun visitErrorImport(errorImport: FirErrorImport, data: CheckerContext) {
val source = errorImport.source ?: return
reportFirDiagnostic(errorImport.diagnostic, source, reporter, data)
reportFirDiagnostic(errorImport.diagnostic, source, data)
}
private fun reportFirDiagnostic(
diagnostic: ConeDiagnostic,
source: KtSourceElement,
reporter: DiagnosticReporter,
context: CheckerContext,
qualifiedAccessSource: KtSourceElement? = null
) {
@@ -21,137 +21,136 @@ class ExpressionCheckersDiagnosticComponent(
private val checkers: ExpressionCheckers = session.checkersComponent.expressionCheckers,
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: CheckerContext) {
checkers.allTypeOperatorCallCheckers.check(typeOperatorCall, data, reporter)
checkers.allTypeOperatorCallCheckers.check(typeOperatorCall, data)
}
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: CheckerContext) {
checkers.allConstExpressionCheckers.check(constExpression, data, reporter)
checkers.allConstExpressionCheckers.check(constExpression, data)
}
override fun visitAnnotation(annotation: FirAnnotation, data: CheckerContext) {
checkers.allAnnotationCheckers.check(annotation, data, reporter)
checkers.allAnnotationCheckers.check(annotation, data)
}
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: CheckerContext) {
checkers.allAnnotationCallCheckers.check(annotationCall, data, reporter)
checkers.allAnnotationCallCheckers.check(annotationCall, data)
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: CheckerContext) {
checkers.allQualifiedAccessExpressionCheckers.check(qualifiedAccessExpression, data, reporter)
checkers.allQualifiedAccessExpressionCheckers.check(qualifiedAccessExpression, data)
}
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: CheckerContext) {
checkers.allQualifiedAccessExpressionCheckers.check(propertyAccessExpression, data, reporter)
checkers.allQualifiedAccessExpressionCheckers.check(propertyAccessExpression, data)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) {
checkers.allFunctionCallCheckers.check(functionCall, data, reporter)
checkers.allFunctionCallCheckers.check(functionCall, data)
}
override fun visitIntegerLiteralOperatorCall(integerLiteralOperatorCall: FirIntegerLiteralOperatorCall, data: CheckerContext) {
checkers.allIntegerLiteralOperatorCallCheckers.check(integerLiteralOperatorCall, data, reporter)
checkers.allIntegerLiteralOperatorCallCheckers.check(integerLiteralOperatorCall, data)
}
override fun visitImplicitInvokeCall(implicitInvokeCall: FirImplicitInvokeCall, data: CheckerContext) {
checkers.allFunctionCallCheckers.check(implicitInvokeCall, data, reporter)
checkers.allFunctionCallCheckers.check(implicitInvokeCall, data)
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: CheckerContext) {
checkers.allCallableReferenceAccessCheckers.check(callableReferenceAccess, data, reporter)
checkers.allCallableReferenceAccessCheckers.check(callableReferenceAccess, data)
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: CheckerContext) {
checkers.allThisReceiverExpressionCheckers.check(thisReceiverExpression, data, reporter)
checkers.allThisReceiverExpressionCheckers.check(thisReceiverExpression, data)
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: CheckerContext) {
checkers.allResolvedQualifierCheckers.check(resolvedQualifier, data, reporter)
checkers.allResolvedQualifierCheckers.check(resolvedQualifier, data)
}
override fun visitWhenExpression(whenExpression: FirWhenExpression, data: CheckerContext) {
checkers.allWhenExpressionCheckers.check(whenExpression, data, reporter)
checkers.allWhenExpressionCheckers.check(whenExpression, data)
}
override fun visitWhileLoop(whileLoop: FirWhileLoop, data: CheckerContext) {
checkers.allWhileLoopCheckers.check(whileLoop, data, reporter)
checkers.allWhileLoopCheckers.check(whileLoop, data)
}
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: CheckerContext) {
checkers.allDoWhileLoopCheckers.check(doWhileLoop, data, reporter)
checkers.allDoWhileLoopCheckers.check(doWhileLoop, data)
}
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
checkers.allLoopExpressionCheckers.check(errorLoop, data, reporter)
checkers.allLoopExpressionCheckers.check(errorLoop, data)
}
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: CheckerContext) {
checkers.allLogicExpressionCheckers.check(binaryLogicExpression, data, reporter)
checkers.allLogicExpressionCheckers.check(binaryLogicExpression, data)
}
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: CheckerContext) {
checkers.allArrayOfCallCheckers.check(arrayOfCall, data, reporter)
checkers.allArrayOfCallCheckers.check(arrayOfCall, data)
}
override fun visitStringConcatenationCall(stringConcatenationCall: FirStringConcatenationCall, data: CheckerContext) {
checkers.allStringConcatenationCallCheckers.check(stringConcatenationCall, data, reporter)
checkers.allStringConcatenationCallCheckers.check(stringConcatenationCall, data)
}
override fun visitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, data: CheckerContext) {
checkers.allCheckNotNullCallCheckers.check(checkNotNullCall, data, reporter)
checkers.allCheckNotNullCallCheckers.check(checkNotNullCall, data)
}
override fun visitElvisExpression(elvisExpression: FirElvisExpression, data: CheckerContext) {
checkers.allElvisExpressionCheckers.check(elvisExpression, data, reporter)
checkers.allElvisExpressionCheckers.check(elvisExpression, data)
}
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: CheckerContext) {
checkers.allSafeCallExpressionCheckers.check(safeCallExpression, data, reporter)
checkers.allSafeCallExpressionCheckers.check(safeCallExpression, data)
}
override fun visitTryExpression(tryExpression: FirTryExpression, data: CheckerContext) {
checkers.allTryExpressionCheckers.check(tryExpression, data, reporter)
checkers.allTryExpressionCheckers.check(tryExpression, data)
}
override fun visitClassReferenceExpression(classReferenceExpression: FirClassReferenceExpression, data: CheckerContext) {
checkers.allClassReferenceExpressionCheckers.check(classReferenceExpression, data, reporter)
checkers.allClassReferenceExpressionCheckers.check(classReferenceExpression, data)
}
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: CheckerContext) {
checkers.allGetClassCallCheckers.check(getClassCall, data, reporter)
checkers.allGetClassCallCheckers.check(getClassCall, data)
}
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: CheckerContext) {
checkers.allEqualityOperatorCallCheckers.check(equalityOperatorCall, data, reporter)
checkers.allEqualityOperatorCallCheckers.check(equalityOperatorCall, data)
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) {
checkers.allVariableAssignmentCheckers.check(variableAssignment, data, reporter)
checkers.allVariableAssignmentCheckers.check(variableAssignment, data)
}
override fun visitReturnExpression(returnExpression: FirReturnExpression, data: CheckerContext) {
checkers.allReturnExpressionCheckers.check(returnExpression, data, reporter)
checkers.allReturnExpressionCheckers.check(returnExpression, data)
}
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: CheckerContext) {
checkers.allLoopJumpCheckers.check(breakExpression, data, reporter)
checkers.allLoopJumpCheckers.check(breakExpression, data)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: CheckerContext) {
checkers.allLoopJumpCheckers.check(continueExpression, data, reporter)
checkers.allLoopJumpCheckers.check(continueExpression, data)
}
override fun visitBlock(block: FirBlock, data: CheckerContext) {
checkers.allBlockCheckers.check(block, data, reporter)
checkers.allBlockCheckers.check(block, data)
}
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: CheckerContext) {
checkers.allCallCheckers.check(delegatedConstructorCall, data, reporter)
checkers.allCallCheckers.check(delegatedConstructorCall, data)
}
private fun <E : FirStatement> Collection<FirExpressionChecker<E>>.check(
expression: E,
context: CheckerContext,
reporter: DiagnosticReporter
context: CheckerContext
) {
for (checker in this) {
checker.check(expression, context, reporter)
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2022 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.collectors.components
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.declarations.FirFile
class ReportCommitterDiagnosticComponent(
session: FirSession,
reporter: DiagnosticReporter
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitElement(element: FirElement, data: CheckerContext) {
checkAndCommitReportsOn(element, data)
}
override fun endOfFile(file: FirFile) {
checkAndCommitReportsOn(file, null)
}
}
@@ -22,41 +22,40 @@ class TypeCheckersDiagnosticComponent(
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun visitDynamicTypeRef(dynamicTypeRef: FirDynamicTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(dynamicTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(dynamicTypeRef, data)
}
override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(functionTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(functionTypeRef, data)
}
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(userTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(userTypeRef, data)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(resolvedTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(resolvedTypeRef, data)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(errorTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(errorTypeRef, data)
}
override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability, data: CheckerContext) {
checkers.allTypeRefCheckers.check(typeRefWithNullability, data, reporter)
checkers.allTypeRefCheckers.check(typeRefWithNullability, data)
}
override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(implicitTypeRef, data, reporter)
checkers.allTypeRefCheckers.check(implicitTypeRef, data)
}
override fun visitTypeRef(typeRef: FirTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(typeRef, data, reporter)
checkers.allTypeRefCheckers.check(typeRef, data)
}
private fun <T : FirTypeRef> Collection<FirTypeChecker<T>>.check(
typeRef: T,
context: CheckerContext,
reporter: DiagnosticReporter
context: CheckerContext
) {
for (checker in this) {
checker.check(typeRef, context, reporter)