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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun addSuppressedDiagnostics(
|
||||||
|
diagnosticNames: Collection<String>,
|
||||||
|
allInfosSuppressed: Boolean,
|
||||||
|
allWarningsSuppressed: Boolean,
|
||||||
|
allErrorsSuppressed: Boolean
|
||||||
|
): PersistentCheckerContext
|
||||||
}
|
}
|
||||||
|
|
||||||
class PersistentCheckerContext private constructor(
|
class PersistentCheckerContext private constructor(
|
||||||
@@ -111,7 +118,7 @@ class PersistentCheckerContext private constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addSuppressedDiagnostics(
|
override fun addSuppressedDiagnostics(
|
||||||
diagnosticNames: Collection<String>,
|
diagnosticNames: Collection<String>,
|
||||||
allInfosSuppressed: Boolean,
|
allInfosSuppressed: Boolean,
|
||||||
allWarningsSuppressed: 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.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
|
||||||
object FirConstructorAllowedChecker : FirConstructorChecker() {
|
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.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
|
||||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.modality
|
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.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.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.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.isPotentiallyArray
|
import org.jetbrains.kotlin.fir.resolve.calls.isPotentiallyArray
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
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 kotlinCloneableType = ClassId.fromString("kotlin/Cloneable").constructClassLikeType(emptyArray(), false)
|
||||||
private val javaCloneableType = ClassId.fromString("java/lang/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) {
|
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (!declaration.isInlineOrValueClass()) {
|
if (!declaration.isInlineOrValueClass()) {
|
||||||
return
|
return
|
||||||
@@ -41,7 +44,7 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
|
|
||||||
for (supertypeEntry in declaration.superTypeRefs) {
|
for (supertypeEntry in declaration.superTypeRefs) {
|
||||||
if (supertypeEntry.toRegularClass(context.session)?.isInterface != true) {
|
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 -> {
|
innerDeclaration.body != null -> {
|
||||||
val bodySource = innerDeclaration.body!!.source
|
val body = innerDeclaration.body!!
|
||||||
reporter.reportOn(bodySource, FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, context)
|
withSuppressedDiagnostics(innerDeclaration, context) { context ->
|
||||||
|
reporter.reportOnWithSuppression(
|
||||||
|
body, FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, context
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FirRegularClass -> {
|
is FirRegularClass -> {
|
||||||
if (innerDeclaration.isInner) {
|
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 -> {
|
is FirSimpleFunction -> {
|
||||||
val functionName = innerDeclaration.name.asString()
|
val functionName = innerDeclaration.name.asString()
|
||||||
|
|
||||||
if (functionName in reservedFunctionNames) {
|
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 -> {
|
is FirField -> {
|
||||||
if (innerDeclaration.isSynthetic) {
|
if (innerDeclaration.isSynthetic) {
|
||||||
val delegatedTypeRefSource = (innerDeclaration.returnTypeRef as FirResolvedTypeRef).delegatedTypeRef?.source
|
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 -> {
|
is FirProperty -> {
|
||||||
@@ -92,16 +107,18 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
} else {
|
} else {
|
||||||
when {
|
when {
|
||||||
innerDeclaration.delegate != null ->
|
innerDeclaration.delegate != null ->
|
||||||
reporter.reportOn(
|
withSuppressedDiagnostics(innerDeclaration, context) { context ->
|
||||||
innerDeclaration.delegate!!.source,
|
reporter.reportOn(
|
||||||
FirErrors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS,
|
innerDeclaration.delegate!!.source,
|
||||||
context
|
FirErrors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS,
|
||||||
)
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
innerDeclaration.hasBackingField &&
|
innerDeclaration.hasBackingField &&
|
||||||
innerDeclaration.source?.kind !is FirFakeSourceElementKind ->
|
innerDeclaration.source?.kind !is FirFakeSourceElementKind ->
|
||||||
reporter.reportOn(
|
reporter.reportOnWithSuppression(
|
||||||
innerDeclaration.source,
|
innerDeclaration,
|
||||||
FirErrors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS,
|
FirErrors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS,
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
@@ -117,32 +134,36 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (primaryConstructorParameter == null) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
withSuppressedDiagnostics(primaryConstructor, context) { context ->
|
||||||
primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorProperty) ->
|
withSuppressedDiagnostics(primaryConstructorParameter, context) { context ->
|
||||||
reporter.reportOn(
|
when {
|
||||||
primaryConstructorParameter.source,
|
primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorProperty) ->
|
||||||
FirErrors.INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER,
|
reporter.reportOn(
|
||||||
context
|
primaryConstructorParameter.source,
|
||||||
)
|
FirErrors.INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() ->
|
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() ->
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
primaryConstructorParameter.returnTypeRef.source,
|
primaryConstructorParameter.returnTypeRef.source,
|
||||||
FirErrors.INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
|
FirErrors.INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
|
||||||
primaryConstructorParameter.returnTypeRef.coneType,
|
primaryConstructorParameter.returnTypeRef.coneType,
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
|
||||||
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) ->
|
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) ->
|
||||||
reporter.reportOn(
|
reporter.reportOnWithSuppression(
|
||||||
primaryConstructorParameter.returnTypeRef.source,
|
primaryConstructorParameter.returnTypeRef,
|
||||||
FirErrors.INLINE_CLASS_CANNOT_BE_RECURSIVE,
|
FirErrors.INLINE_CLASS_CANNOT_BE_RECURSIVE,
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-16
@@ -33,12 +33,6 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
override val scopeSession: ScopeSession = ScopeSession(),
|
override val scopeSession: ScopeSession = ScopeSession(),
|
||||||
returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorForFullBodyResolve()
|
returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorForFullBodyResolve()
|
||||||
) : SessionHolder {
|
) : 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<*>> {
|
fun collectDiagnostics(firFile: FirFile): List<FirDiagnostic<*>> {
|
||||||
if (!componentsInitialized) {
|
if (!componentsInitialized) {
|
||||||
throw IllegalStateException("Components are not initialized")
|
throw IllegalStateException("Components are not initialized")
|
||||||
@@ -307,16 +301,7 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addSuppressedDiagnosticsToContext(annotationContainer: FirAnnotationContainer) {
|
private fun addSuppressedDiagnosticsToContext(annotationContainer: FirAnnotationContainer) {
|
||||||
val annotations = annotationContainer.annotations.filter {
|
val arguments = getDiagnosticsSuppressedForContainer(annotationContainer) ?: return
|
||||||
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? }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context = context.addSuppressedDiagnostics(
|
context = context.addSuppressedDiagnostics(
|
||||||
arguments,
|
arguments,
|
||||||
allInfosSuppressed = SUPPRESS_ALL_INFOS in arguments,
|
allInfosSuppressed = SUPPRESS_ALL_INFOS in arguments,
|
||||||
@@ -334,6 +319,25 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
currentAction = oldAction
|
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) {
|
enum class DiagnosticCollectorDeclarationAction(val checkInCurrentDeclaration: Boolean, val lookupForNestedDeclaration: Boolean) {
|
||||||
|
|||||||
+69
@@ -6,8 +6,11 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
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.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||||
|
|
||||||
abstract class DiagnosticReporter {
|
abstract class DiagnosticReporter {
|
||||||
abstract fun report(diagnostic: FirDiagnostic<*>?, context: CheckerContext)
|
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) }
|
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