From 7eb9b1188f4997e358f662959f330c16a16ff3e3 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 5 Mar 2021 16:21:41 +0300 Subject: [PATCH] FIR: implement helpers for diagnostic suppression on elements children --- .../checkers/context/CheckerContext.kt | 9 +- .../FirConstructorAllowedChecker.kt | 1 - .../declaration/FirDeclarationCheckerUtils.kt | 1 - .../FirInlineClassDeclarationChecker.kt | 89 ++++++++++++------- .../collectors/AbstractDiagnosticCollector.kt | 36 ++++---- .../diagnostics/DiagnosticReporter.kt | 69 ++++++++++++++ 6 files changed, 152 insertions(+), 53 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt index 02bdebb26c5..c4b10689a09 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt @@ -44,6 +44,13 @@ abstract class CheckerContext { return null } + + abstract fun addSuppressedDiagnostics( + diagnosticNames: Collection, + allInfosSuppressed: Boolean, + allWarningsSuppressed: Boolean, + allErrorsSuppressed: Boolean + ): PersistentCheckerContext } class PersistentCheckerContext private constructor( @@ -111,7 +118,7 @@ class PersistentCheckerContext private constructor( ) } - fun addSuppressedDiagnostics( + override fun addSuppressedDiagnostics( diagnosticNames: Collection, allInfosSuppressed: Boolean, allWarningsSuppressed: Boolean, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorAllowedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorAllowedChecker.kt index 3bf7cb9268f..f850ffcfbaa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorAllowedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorAllowedChecker.kt @@ -14,7 +14,6 @@ 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.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens object FirConstructorAllowedChecker : FirConstructorChecker() { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index 6b0bd54d208..150307f73c7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality 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.modality diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt index fa089274aeb..f2341cf7970 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt @@ -12,6 +12,8 @@ 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.analysis.diagnostics.reportOnWithSuppression +import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.calls.isPotentiallyArray import org.jetbrains.kotlin.fir.resolve.defaultType @@ -26,6 +28,7 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() { private val kotlinCloneableType = ClassId.fromString("kotlin/Cloneable").constructClassLikeType(emptyArray(), false) private val javaCloneableType = ClassId.fromString("java/lang/Cloneable").constructClassLikeType(emptyArray(), false) + @Suppress("NAME_SHADOWING") override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.isInlineOrValueClass()) { return @@ -41,7 +44,7 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() { for (supertypeEntry in declaration.superTypeRefs) { if (supertypeEntry.toRegularClass(context.session)?.isInterface != true) { - reporter.reportOn(supertypeEntry.source, FirErrors.INLINE_CLASS_CANNOT_EXTEND_CLASSES, context) + reporter.reportOnWithSuppression(supertypeEntry, FirErrors.INLINE_CLASS_CANNOT_EXTEND_CLASSES, context) } } @@ -63,27 +66,39 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() { } innerDeclaration.body != null -> { - val bodySource = innerDeclaration.body!!.source - reporter.reportOn(bodySource, FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, context) + val body = innerDeclaration.body!! + withSuppressedDiagnostics(innerDeclaration, context) { context -> + reporter.reportOnWithSuppression( + body, FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, context + ) + } } } } is FirRegularClass -> { if (innerDeclaration.isInner) { - reporter.reportOn(innerDeclaration.source, FirErrors.INNER_CLASS_INSIDE_INLINE_CLASS, context) + reporter.reportOnWithSuppression(innerDeclaration, FirErrors.INNER_CLASS_INSIDE_INLINE_CLASS, context) } } is FirSimpleFunction -> { val functionName = innerDeclaration.name.asString() if (functionName in reservedFunctionNames) { - reporter.reportOn(innerDeclaration.source, FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS, functionName, context) + reporter.reportOnWithSuppression( + innerDeclaration, FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS, functionName, context + ) } } is FirField -> { if (innerDeclaration.isSynthetic) { val delegatedTypeRefSource = (innerDeclaration.returnTypeRef as FirResolvedTypeRef).delegatedTypeRef?.source - reporter.reportOn(delegatedTypeRefSource, FirErrors.INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, context) + withSuppressedDiagnostics(innerDeclaration, context) { context -> + reporter.reportOn( + delegatedTypeRefSource, + FirErrors.INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, + context + ) + } } } is FirProperty -> { @@ -92,16 +107,18 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() { } else { when { innerDeclaration.delegate != null -> - reporter.reportOn( - innerDeclaration.delegate!!.source, - FirErrors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS, - context - ) + withSuppressedDiagnostics(innerDeclaration, context) { context -> + reporter.reportOn( + innerDeclaration.delegate!!.source, + FirErrors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS, + context + ) + } innerDeclaration.hasBackingField && innerDeclaration.source?.kind !is FirFakeSourceElementKind -> - reporter.reportOn( - innerDeclaration.source, + reporter.reportOnWithSuppression( + innerDeclaration, FirErrors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS, context ) @@ -117,32 +134,36 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() { } if (primaryConstructorParameter == null) { - reporter.reportOn(primaryConstructor.source, FirErrors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, context) + reporter.reportOnWithSuppression(primaryConstructor, FirErrors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, context) return } - when { - primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorProperty) -> - reporter.reportOn( - primaryConstructorParameter.source, - FirErrors.INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, - context - ) + withSuppressedDiagnostics(primaryConstructor, context) { context -> + withSuppressedDiagnostics(primaryConstructorParameter, context) { context -> + when { + primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorProperty) -> + reporter.reportOn( + primaryConstructorParameter.source, + FirErrors.INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, + context + ) - primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() -> - reporter.reportOn( - primaryConstructorParameter.returnTypeRef.source, - FirErrors.INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, - primaryConstructorParameter.returnTypeRef.coneType, - context - ) + primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() -> + reporter.reportOn( + primaryConstructorParameter.returnTypeRef.source, + FirErrors.INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, + primaryConstructorParameter.returnTypeRef.coneType, + context + ) - primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) -> - reporter.reportOn( - primaryConstructorParameter.returnTypeRef.source, - FirErrors.INLINE_CLASS_CANNOT_BE_RECURSIVE, - context - ) + primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) -> + reporter.reportOnWithSuppression( + primaryConstructorParameter.returnTypeRef, + FirErrors.INLINE_CLASS_CANNOT_BE_RECURSIVE, + context + ) + } + } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt index 60b6d677c03..7bf7eca07c9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt @@ -33,12 +33,6 @@ abstract class AbstractDiagnosticCollector( override val scopeSession: ScopeSession = ScopeSession(), returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorForFullBodyResolve() ) : SessionHolder { - companion object { - private const val SUPPRESS_ALL_INFOS = "infos" - private const val SUPPRESS_ALL_WARNINGS = "warnings" - private const val SUPPRESS_ALL_ERRORS = "errors" - } - fun collectDiagnostics(firFile: FirFile): List> { if (!componentsInitialized) { throw IllegalStateException("Components are not initialized") @@ -307,16 +301,7 @@ abstract class AbstractDiagnosticCollector( } private fun addSuppressedDiagnosticsToContext(annotationContainer: FirAnnotationContainer) { - val annotations = annotationContainer.annotations.filter { - val type = it.annotationTypeRef.coneType as? ConeClassLikeType ?: return@filter false - type.lookupTag.classId == StandardClassIds.Suppress - } - if (annotations.isEmpty()) return - val arguments = annotations.flatMap { annotationCall -> - annotationCall.arguments.filterIsInstance().flatMap { varargArgument -> - varargArgument.arguments.mapNotNull { (it as? FirConstExpression<*>)?.value as? String? } - } - } + val arguments = getDiagnosticsSuppressedForContainer(annotationContainer) ?: return context = context.addSuppressedDiagnostics( arguments, allInfosSuppressed = SUPPRESS_ALL_INFOS in arguments, @@ -334,6 +319,25 @@ abstract class AbstractDiagnosticCollector( currentAction = oldAction } } + + companion object { + const val SUPPRESS_ALL_INFOS = "infos" + const val SUPPRESS_ALL_WARNINGS = "warnings" + const val SUPPRESS_ALL_ERRORS = "errors" + + fun getDiagnosticsSuppressedForContainer(annotationContainer: FirAnnotationContainer): List? { + val annotations = annotationContainer.annotations.filter { + val type = it.annotationTypeRef.coneType as? ConeClassLikeType ?: return@filter false + type.lookupTag.classId == StandardClassIds.Suppress + } + if (annotations.isEmpty()) return null + return annotations.flatMap { annotationCall -> + annotationCall.arguments.filterIsInstance().flatMap { varargArgument -> + varargArgument.arguments.mapNotNull { (it as? FirConstExpression<*>)?.value as? String? } + } + } + } + } } enum class DiagnosticCollectorDeclarationAction(val checkInCurrentDeclaration: Boolean, val lookupForNestedDeclaration: Boolean) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt index f52c0b4b5a0..190e6c2a143 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt @@ -6,8 +6,11 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.fir.FirAnnotationContainer +import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector abstract class DiagnosticReporter { abstract fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext) @@ -51,3 +54,69 @@ inline fun Unit +) { + val arguments = (element as? FirAnnotationContainer)?.let { AbstractDiagnosticCollector.getDiagnosticsSuppressedForContainer(it) } + if (arguments != null) { + f( + context.addSuppressedDiagnostics( + arguments, + allInfosSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_INFOS in arguments, + allWarningsSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_WARNINGS in arguments, + allErrorsSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_ERRORS in arguments + ) + ) + return + } + f(context) +} + +inline fun DiagnosticReporter.reportOnWithSuppression( + element: FirElement, + factory: FirDiagnosticFactory0, + context: CheckerContext +) { + withSuppressedDiagnostics(element, context) { + reportOn(element.source as? T, factory, it) + } +} + +inline fun DiagnosticReporter.reportOnWithSuppression( + element: FirElement, + factory: FirDiagnosticFactory1, + a: A, + context: CheckerContext +) { + withSuppressedDiagnostics(element, context) { + reportOn(element.source as? T, factory, a, it) + } +} + +inline fun DiagnosticReporter.reportOnWithSuppression( + element: FirElement, + factory: FirDiagnosticFactory2, + a: A, + b: B, + context: CheckerContext +) { + withSuppressedDiagnostics(element, context) { + reportOn(element.source as? T, factory, a, b, it) + } +} + +inline fun DiagnosticReporter.reportOnWithSuppression( + element: FirElement, + factory: FirDiagnosticFactory3, + a: A, + b: B, + c: C, + context: CheckerContext +) { + withSuppressedDiagnostics(element, context) { + reportOn(element.source as? T, factory, a, b, c, it) + } +} +