FIR: implement helpers for diagnostic suppression on elements children
This commit is contained in:
+8
-1
@@ -44,6 +44,13 @@ abstract class CheckerContext {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
abstract fun addSuppressedDiagnostics(
|
||||
diagnosticNames: Collection<String>,
|
||||
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<String>,
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
|
||||
-1
@@ -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() {
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
+55
-34
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-16
@@ -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<FirDiagnostic<*>> {
|
||||
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<FirVarargArgumentsExpression>().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<String>? {
|
||||
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<FirVarargArgumentsExpression>().flatMap { varargArgument ->
|
||||
varargArgument.arguments.mapNotNull { (it as? FirConstExpression<*>)?.value as? String? }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class DiagnosticCollectorDeclarationAction(val checkInCurrentDeclaration: Boolean, val lookupForNestedDeclaration: Boolean) {
|
||||
|
||||
+69
@@ -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 <reified T : FirSourceElement, P : PsiElement, A : Any, B : Any, C :
|
||||
source?.let { report(factory.on(it, a, b, c), context) }
|
||||
}
|
||||
|
||||
inline fun withSuppressedDiagnostics(
|
||||
element: FirElement,
|
||||
context: CheckerContext,
|
||||
f: (CheckerContext) -> 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 <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.reportOnWithSuppression(
|
||||
element: FirElement,
|
||||
factory: FirDiagnosticFactory0<T, P>,
|
||||
context: CheckerContext
|
||||
) {
|
||||
withSuppressedDiagnostics(element, context) {
|
||||
reportOn(element.source as? T, factory, it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any> DiagnosticReporter.reportOnWithSuppression(
|
||||
element: FirElement,
|
||||
factory: FirDiagnosticFactory1<T, P, A>,
|
||||
a: A,
|
||||
context: CheckerContext
|
||||
) {
|
||||
withSuppressedDiagnostics(element, context) {
|
||||
reportOn(element.source as? T, factory, a, it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any, B : Any> DiagnosticReporter.reportOnWithSuppression(
|
||||
element: FirElement,
|
||||
factory: FirDiagnosticFactory2<T, P, A, B>,
|
||||
a: A,
|
||||
b: B,
|
||||
context: CheckerContext
|
||||
) {
|
||||
withSuppressedDiagnostics(element, context) {
|
||||
reportOn(element.source as? T, factory, a, b, it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> DiagnosticReporter.reportOnWithSuppression(
|
||||
element: FirElement,
|
||||
factory: FirDiagnosticFactory3<T, P, A, B, C>,
|
||||
a: A,
|
||||
b: B,
|
||||
c: C,
|
||||
context: CheckerContext
|
||||
) {
|
||||
withSuppressedDiagnostics(element, context) {
|
||||
reportOn(element.source as? T, factory, a, b, c, it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user