[FIR] Report warning when error is suppressed
#KT-61129
This commit is contained in:
committed by
Space Team
parent
769e4ac0ac
commit
c32a0a83f9
+7
@@ -271,6 +271,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.ERROR_SUPPRESSION) { firDiagnostic ->
|
||||||
|
ErrorSuppressionImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
|
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
|
||||||
InvisibleReferenceImpl(
|
InvisibleReferenceImpl(
|
||||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||||
|
|||||||
+5
@@ -232,6 +232,11 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = InnerOnTopLevelScriptClassWarning::class
|
override val diagnosticClass get() = InnerOnTopLevelScriptClassWarning::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ErrorSuppression : KtFirDiagnostic<PsiElement> {
|
||||||
|
override val diagnosticClass get() = ErrorSuppression::class
|
||||||
|
val diagnosticName: String
|
||||||
|
}
|
||||||
|
|
||||||
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
|
interface InvisibleReference : KtFirDiagnostic<PsiElement> {
|
||||||
override val diagnosticClass get() = InvisibleReference::class
|
override val diagnosticClass get() = InvisibleReference::class
|
||||||
val reference: KtSymbol
|
val reference: KtSymbol
|
||||||
|
|||||||
+6
@@ -264,6 +264,12 @@ internal class InnerOnTopLevelScriptClassWarningImpl(
|
|||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassWarning
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InnerOnTopLevelScriptClassWarning
|
||||||
|
|
||||||
|
internal class ErrorSuppressionImpl(
|
||||||
|
override val diagnosticName: String,
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ErrorSuppression
|
||||||
|
|
||||||
internal class InvisibleReferenceImpl(
|
internal class InvisibleReferenceImpl(
|
||||||
override val reference: KtSymbol,
|
override val reference: KtSymbol,
|
||||||
override val visible: Visibility,
|
override val visible: Visibility,
|
||||||
|
|||||||
+3
@@ -105,6 +105,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
parameter<CallableId>("callableId")
|
parameter<CallableId>("callableId")
|
||||||
}
|
}
|
||||||
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError<PsiElement>(LanguageFeature.ProhibitScriptTopLevelInnerClasses)
|
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError<PsiElement>(LanguageFeature.ProhibitScriptTopLevelInnerClasses)
|
||||||
|
val ERROR_SUPPRESSION by warning<PsiElement> {
|
||||||
|
parameter<String>("diagnosticName")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ object FirErrors {
|
|||||||
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||||
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError0<PsiElement>(ProhibitScriptTopLevelInnerClasses)
|
val INNER_ON_TOP_LEVEL_SCRIPT_CLASS by deprecationError0<PsiElement>(ProhibitScriptTopLevelInnerClasses)
|
||||||
|
val ERROR_SUPPRESSION by warning1<PsiElement, String>()
|
||||||
|
|
||||||
// Unresolved
|
// Unresolved
|
||||||
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
+7
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
|||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
||||||
@@ -58,6 +59,12 @@ abstract class CheckerContext : DiagnosticContext {
|
|||||||
override fun isDiagnosticSuppressed(diagnostic: KtDiagnostic): Boolean {
|
override fun isDiagnosticSuppressed(diagnostic: KtDiagnostic): Boolean {
|
||||||
val factory = diagnostic.factory
|
val factory = diagnostic.factory
|
||||||
val name = factory.name
|
val name = factory.name
|
||||||
|
|
||||||
|
if (name == FirErrors.ERROR_SUPPRESSION.name) {
|
||||||
|
// Can't suppress warning about suppressed error
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
val suppressedByAll = when (factory.severity) {
|
val suppressedByAll = when (factory.severity) {
|
||||||
Severity.INFO -> allInfosSuppressed
|
Severity.INFO -> allInfosSuppressed
|
||||||
Severity.WARNING -> allWarningsSuppressed
|
Severity.WARNING -> allWarningsSuppressed
|
||||||
|
|||||||
+28
-2
@@ -14,17 +14,22 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind
|
import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
|
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
|
||||||
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
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FIR_NON_SUPPRESSIBLE_ERROR_NAMES
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
|
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.unwrapVarargValue
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.fqName
|
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.resolve.RequireKotlinConstants
|
import org.jetbrains.kotlin.resolve.RequireKotlinConstants
|
||||||
|
|
||||||
object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
|
object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
|
||||||
@@ -39,7 +44,8 @@ object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
|
|||||||
|
|
||||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val argumentMapping = expression.argumentMapping.mapping
|
val argumentMapping = expression.argumentMapping.mapping
|
||||||
val fqName = expression.fqName(context.session)
|
val annotationClassId = expression.toAnnotationClassId(context.session)
|
||||||
|
val fqName = annotationClassId?.asSingleFqName()
|
||||||
for (arg in argumentMapping.values) {
|
for (arg in argumentMapping.values) {
|
||||||
val argExpression = (arg as? FirNamedArgumentExpression)?.expression ?: (arg as? FirErrorExpression)?.expression ?: arg
|
val argExpression = (arg as? FirNamedArgumentExpression)?.expression ?: (arg as? FirErrorExpression)?.expression ?: arg
|
||||||
checkAnnotationArgumentWithSubElements(argExpression, context.session, reporter, context)
|
checkAnnotationArgumentWithSubElements(argExpression, context.session, reporter, context)
|
||||||
@@ -50,6 +56,7 @@ object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
|
|||||||
checkDeprecatedSinceKotlin(expression.source, fqName, argumentMapping, context, reporter)
|
checkDeprecatedSinceKotlin(expression.source, fqName, argumentMapping, context, reporter)
|
||||||
checkAnnotationUsedAsAnnotationArgument(expression, context, reporter)
|
checkAnnotationUsedAsAnnotationArgument(expression, context, reporter)
|
||||||
checkNotAClass(expression, context, reporter)
|
checkNotAClass(expression, context, reporter)
|
||||||
|
checkErrorSuppression(annotationClassId, argumentMapping, reporter, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAnnotationArgumentWithSubElements(
|
private fun checkAnnotationArgumentWithSubElements(
|
||||||
@@ -220,4 +227,23 @@ object FirAnnotationExpressionChecker : FirAnnotationCallChecker() {
|
|||||||
reporter.reportOn(annotationTypeRef.source, FirErrors.NOT_A_CLASS, context)
|
reporter.reportOn(annotationTypeRef.source, FirErrors.NOT_A_CLASS, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkErrorSuppression(
|
||||||
|
annotationClassId: ClassId?,
|
||||||
|
argumentMapping: Map<Name, FirExpression>,
|
||||||
|
reporter: DiagnosticReporter,
|
||||||
|
context: CheckerContext,
|
||||||
|
) {
|
||||||
|
if (annotationClassId != StandardClassIds.Annotations.Suppress) return
|
||||||
|
val nameExpressions = argumentMapping[StandardClassIds.Annotations.ParameterNames.suppressNames]?.unwrapVarargValue() ?: return
|
||||||
|
for (nameExpression in nameExpressions) {
|
||||||
|
val name = (nameExpression as? FirConstExpression<*>)?.value as? String ?: continue
|
||||||
|
val parameter = when (name) {
|
||||||
|
in FIR_NON_SUPPRESSIBLE_ERROR_NAMES -> name
|
||||||
|
AbstractDiagnosticCollector.SUPPRESS_ALL_ERRORS -> "all errors"
|
||||||
|
else -> continue
|
||||||
|
}
|
||||||
|
reporter.reportOn(nameExpression.source, FirErrors.ERROR_SUPPRESSION, parameter, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
|||||||
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
|
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
|
|
||||||
abstract class AbstractDiagnosticCollector(
|
abstract class AbstractDiagnosticCollector(
|
||||||
@@ -45,8 +44,6 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
const val SUPPRESS_ALL_WARNINGS = "warnings"
|
const val SUPPRESS_ALL_WARNINGS = "warnings"
|
||||||
const val SUPPRESS_ALL_ERRORS = "errors"
|
const val SUPPRESS_ALL_ERRORS = "errors"
|
||||||
|
|
||||||
private val SUPPRESS_NAMES_NAME = Name.identifier("names")
|
|
||||||
|
|
||||||
private fun correctDiagnosticCase(diagnostic: String): String = when (diagnostic) {
|
private fun correctDiagnosticCase(diagnostic: String): String = when (diagnostic) {
|
||||||
SUPPRESS_ALL_INFOS, SUPPRESS_ALL_WARNINGS, SUPPRESS_ALL_ERRORS -> diagnostic
|
SUPPRESS_ALL_INFOS, SUPPRESS_ALL_WARNINGS, SUPPRESS_ALL_ERRORS -> diagnostic
|
||||||
else -> diagnostic.uppercase()
|
else -> diagnostic.uppercase()
|
||||||
@@ -58,7 +55,9 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
for (annotation in annotationContainer.annotations) {
|
for (annotation in annotationContainer.annotations) {
|
||||||
val type = annotation.annotationTypeRef.coneType as? ConeClassLikeType ?: continue
|
val type = annotation.annotationTypeRef.coneType as? ConeClassLikeType ?: continue
|
||||||
if (type.lookupTag.classId != StandardClassIds.Annotations.Suppress) continue
|
if (type.lookupTag.classId != StandardClassIds.Annotations.Suppress) continue
|
||||||
val argumentValues = annotation.findArgumentByName(SUPPRESS_NAMES_NAME)?.unwrapVarargValue() ?: continue
|
val argumentValues =
|
||||||
|
annotation.findArgumentByName(StandardClassIds.Annotations.ParameterNames.suppressNames)?.unwrapVarargValue()
|
||||||
|
?: continue
|
||||||
|
|
||||||
for (argumentValue in argumentValues) {
|
for (argumentValue in argumentValues) {
|
||||||
val value = (argumentValue as? FirConstExpression<*>)?.value as? String ?: continue
|
val value = (argumentValue as? FirConstExpression<*>)?.value as? String ?: continue
|
||||||
|
|||||||
+6
@@ -205,6 +205,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPL
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_SUPPRESSION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER
|
||||||
@@ -748,6 +749,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
NAME_OF_CONTAINING_DECLARATION_OR_FILE
|
NAME_OF_CONTAINING_DECLARATION_OR_FILE
|
||||||
)
|
)
|
||||||
map.put(INNER_ON_TOP_LEVEL_SCRIPT_CLASS, "Top level script class cannot be inner.")
|
map.put(INNER_ON_TOP_LEVEL_SCRIPT_CLASS, "Top level script class cannot be inner.")
|
||||||
|
map.put(
|
||||||
|
ERROR_SUPPRESSION,
|
||||||
|
"This code uses error suppression for ''{0}''. While it might compile and work, the compiler behavior is UNSPECIFIED and WON''T BE PRESERVED. Please report your use case to the Kotlin issue tracker instead: https://kotl.in/issue",
|
||||||
|
TO_STRING
|
||||||
|
)
|
||||||
map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", NULLABLE_STRING)
|
map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", NULLABLE_STRING)
|
||||||
map.put(UNRESOLVED_IMPORT, "Unresolved reference: {0}", NULLABLE_STRING) // &
|
map.put(UNRESOLVED_IMPORT, "Unresolved reference: {0}", NULLABLE_STRING) // &
|
||||||
map.put(UNRESOLVED_LABEL, "Unresolved label")
|
map.put(UNRESOLVED_LABEL, "Unresolved label")
|
||||||
|
|||||||
@@ -223,6 +223,8 @@ object StandardClassIds {
|
|||||||
val deprecatedSinceKotlinErrorSince = Name.identifier("errorSince")
|
val deprecatedSinceKotlinErrorSince = Name.identifier("errorSince")
|
||||||
val deprecatedSinceKotlinHiddenSince = Name.identifier("hiddenSince")
|
val deprecatedSinceKotlinHiddenSince = Name.identifier("hiddenSince")
|
||||||
|
|
||||||
|
val suppressNames = Name.identifier("names")
|
||||||
|
|
||||||
val parameterNameName = StandardNames.NAME
|
val parameterNameName = StandardNames.NAME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user