Prohibit usage of ignorability annotations without the corresponding feature enabled.
#KT-74811 Fixed
Merge-request: KT-MR-20496
Merged-by: Leonid Startsev <leonid.startsev@jetbrains.com>
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
index b782344..de5f9fe 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
@@ -1398,6 +1398,12 @@
token,
)
}
+ add(FirErrors.IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED) { firDiagnostic ->
+ IgnorabilityAnnotationsWithCheckerDisabledImpl(
+ firDiagnostic as KtPsiDiagnostic,
+ token,
+ )
+ }
add(FirJsErrors.JS_MODULE_PROHIBITED_ON_VAR) { firDiagnostic ->
JsModuleProhibitedOnVarImpl(
firDiagnostic as KtPsiDiagnostic,
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
index fbaa9ac..4b772ad 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
@@ -1004,6 +1004,10 @@
override val diagnosticClass get() = AnnotationsOnBlockLevelExpressionOnTheSameLine::class
}
+ interface IgnorabilityAnnotationsWithCheckerDisabled : KaFirDiagnostic<KtAnnotationEntry> {
+ override val diagnosticClass get() = IgnorabilityAnnotationsWithCheckerDisabled::class
+ }
+
interface JsModuleProhibitedOnVar : KaFirDiagnostic<KtElement> {
override val diagnosticClass get() = JsModuleProhibitedOnVar::class
}
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
index 33f2073..268d6b2 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
@@ -1204,6 +1204,11 @@
token: KaLifetimeToken,
) : KaAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KaFirDiagnostic.AnnotationsOnBlockLevelExpressionOnTheSameLine
+internal class IgnorabilityAnnotationsWithCheckerDisabledImpl(
+ firDiagnostic: KtPsiDiagnostic,
+ token: KaLifetimeToken,
+) : KaAbstractFirDiagnostic<KtAnnotationEntry>(firDiagnostic, token), KaFirDiagnostic.IgnorabilityAnnotationsWithCheckerDisabled
+
internal class JsModuleProhibitedOnVarImpl(
firDiagnostic: KtPsiDiagnostic,
token: KaLifetimeToken,
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFe10TestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFe10TestGenerated.java
index a17c4bc..dedc7b2 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFe10TestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLDiagnosticsFe10TestGenerated.java
@@ -9492,6 +9492,22 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ public void testAllFilesPresentInCrvDisabled() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/crvDisabled"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll|latestLV)\\.kts?$"), true);
+ }
+
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFe10TestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFe10TestGenerated.java
index 61e9e02..be5b962 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFe10TestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLReversedDiagnosticsFe10TestGenerated.java
@@ -9492,6 +9492,22 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ public void testAllFilesPresentInCrvDisabled() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/crvDisabled"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll|latestLV)\\.kts?$"), true);
+ }
+
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java
index 47506d3..83c21a1 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java
@@ -9486,6 +9486,22 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ public void testAllFilesPresentInCrvDisabled() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/crvDisabled"), Pattern.compile("^(.+)\\.(kt)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll|latestLV)\\.kts?$"), true, "multiplatform");
+ }
+
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticLightTreeTestGenerated.java
index 4b7cc7e..52476fb 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticLightTreeTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticLightTreeTestGenerated.java
@@ -9232,6 +9232,17 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticPsiTestGenerated.java
index 6259dcb..e50aa08 100644
--- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticPsiTestGenerated.java
+++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticPsiTestGenerated.java
@@ -9238,6 +9238,17 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
index 4bdb27b..fe03811 100644
--- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
+++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
@@ -463,6 +463,8 @@
parameter<String>("useSiteDescription")
}
val ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE by warning<PsiElement>()
+
+ val IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED by error<KtAnnotationEntry>()
}
val OPT_IN by object : DiagnosticGroup("OptIn") {
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
index e7a0002..769d034 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
@@ -353,6 +353,7 @@
val POTENTIALLY_NON_REPORTED_ANNOTATION: KtDiagnosticFactory0 = KtDiagnosticFactory0("POTENTIALLY_NON_REPORTED_ANNOTATION", WARNING, SourceElementPositioningStrategies.DEFAULT, KtAnnotationEntry::class)
val ANNOTATION_WILL_BE_APPLIED_ALSO_TO_PROPERTY_OR_FIELD: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("ANNOTATION_WILL_BE_APPLIED_ALSO_TO_PROPERTY_OR_FIELD", WARNING, SourceElementPositioningStrategies.DEFAULT, KtAnnotationEntry::class)
val ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE: KtDiagnosticFactory0 = KtDiagnosticFactory0("ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE", WARNING, SourceElementPositioningStrategies.DEFAULT, PsiElement::class)
+ val IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED: KtDiagnosticFactory0 = KtDiagnosticFactory0("IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED", ERROR, SourceElementPositioningStrategies.DEFAULT, KtAnnotationEntry::class)
// OptIn
val OPT_IN_USAGE: KtDiagnosticFactory2<ClassId, String> = KtDiagnosticFactory2("OPT_IN_USAGE", WARNING, SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED, PsiElement::class)
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
index bea3891..74d6b86 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
@@ -166,6 +166,7 @@
"VOLATILE_ON_VALUE",
"VOLATILE_ON_DELEGATE",
"NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION",
+ "IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED",
"JS_MODULE_PROHIBITED_ON_VAR",
"JS_MODULE_PROHIBITED_ON_NON_NATIVE",
"NESTED_JS_MODULE_PROHIBITED",
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
index 3ecde9c..8fed273 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
@@ -36,6 +36,7 @@
FirMissingDependencySupertypeInDeclarationsChecker,
FirContextParametersDeclarationChecker,
FirUnusedReturnValueChecker,
+ FirReturnValueAnnotationsChecker,
)
override val classLikeCheckers: Set<FirClassLikeChecker>
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUnusedReturnValueChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUnusedReturnValueChecker.kt
index ea3281f..a8d6a8f 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUnusedReturnValueChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUnusedReturnValueChecker.kt
@@ -11,16 +11,17 @@
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
+import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.resolved
import org.jetbrains.kotlin.fir.references.symbol
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
-import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
@@ -31,6 +32,29 @@
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.StandardClassIds
+
+object FirReturnValueAnnotationsChecker : FirBasicDeclarationChecker(MppCheckerKind.Common) {
+ override fun check(
+ declaration: FirDeclaration,
+ context: CheckerContext,
+ reporter: DiagnosticReporter,
+ ) {
+ if (context.languageVersionSettings.getFlag(AnalysisFlags.returnValueCheckerMode) != ReturnValueCheckerMode.DISABLED) return
+
+ val session = context.session
+ declaration.annotations.forEach { annotation ->
+ if (annotation.isMustUseReturnValue(session) || annotation.isIgnorableValue(session)) {
+ reporter.reportOn(
+ annotation.source,
+ FirErrors.IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED,
+ context
+ )
+ }
+ }
+ }
+}
+
+
object FirUnusedReturnValueChecker : FirUnusedCheckerBase() {
override fun isEnabled(context: CheckerContext): Boolean =
context.languageVersionSettings.getFlag(AnalysisFlags.returnValueCheckerMode) != ReturnValueCheckerMode.DISABLED
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
index bdef1e7..acd33a1 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
@@ -719,6 +719,7 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECT_REFINEMENT_ANNOTATION_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_QUALIFIER_ON_CONSTRUCTOR_CALL
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_ALL_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_ALL_TARGET_IN_MULTI_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_DEPENDENCY_SUPERCLASS_WARNING
@@ -1233,6 +1234,10 @@
"Annotations on block-level expressions are parsed differently depending on the presence of a new line. " +
"Add a new line after the annotations to annotate the entire expression."
)
+ map.put(
+ IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED,
+ "Ignorability-related annotations are experimental and cannot be used with -Xreturn-value-checker in disabled state."
+ )
// OptIn
map.put(OPT_IN_USAGE, "{1}", CLASS_ID, STRING)
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
index 8f638df..7632f54 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
@@ -368,6 +368,8 @@
DiagnosticFactory0<KtAnnotationEntry> ANNOTATION_IN_WHERE_CLAUSE_WARNING = DiagnosticFactory0.create(WARNING);
+ DiagnosticFactory0<KtAnnotationEntry> IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED = DiagnosticFactory0.create(ERROR);
+
// Const
DiagnosticFactory0<PsiElement> CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> CONST_VAL_WITH_GETTER = DiagnosticFactory0.create(ERROR);
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
index d9df441..55dc05b 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
@@ -225,6 +225,10 @@
MAP.put(NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES, "Non-parenthesized annotations on function types without receiver aren't yet supported (see KT-31734 for details)");
MAP.put(ANNOTATION_IN_WHERE_CLAUSE_WARNING, "Type parameter annotations will not be allowed inside where clauses in future releases. You should probably move annotations to the type parameter declaration");
+ MAP.put(
+ IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED,
+ "Ignorability-related annotations are experimental and cannot be used with -Xreturn-value-checker in disabled state."
+ );
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
MAP.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members");
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
index 3654fef..0f61be8 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt
@@ -88,7 +88,7 @@
DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage,
OptionalExpectationUsageChecker()
)
-private val DEFAULT_ANNOTATION_CHECKERS = listOf<AdditionalAnnotationChecker>()
+private val DEFAULT_ANNOTATION_CHECKERS = listOf<AdditionalAnnotationChecker>(ReturnValueAnnotationChecker)
private val DEFAULT_CLASH_RESOLVERS = listOf<PlatformExtensionsClashResolver<*>>(
IdentifierCheckerClashesResolver(),
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ReturnValueAnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ReturnValueAnnotationChecker.kt
new file mode 100644
index 0000000..e1fd19e
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ReturnValueAnnotationChecker.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2025 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.resolve.checkers
+
+import org.jetbrains.kotlin.config.AnalysisFlags
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.config.ReturnValueCheckerMode
+import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
+import org.jetbrains.kotlin.diagnostics.Errors
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtAnnotated
+import org.jetbrains.kotlin.psi.KtAnnotationEntry
+import org.jetbrains.kotlin.resolve.AdditionalAnnotationChecker
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingTrace
+
+object ReturnValueAnnotationChecker : AdditionalAnnotationChecker {
+ val mustUseReturnValueFq = FqName("kotlin.MustUseReturnValue")
+ val ignorableFq = FqName("kotlin.IgnorableReturnValue")
+
+ override fun checkEntries(
+ entries: List<KtAnnotationEntry>,
+ actualTargets: List<KotlinTarget>,
+ trace: BindingTrace,
+ annotated: KtAnnotated?,
+ languageVersionSettings: LanguageVersionSettings,
+ ) {
+ if (languageVersionSettings.getFlag(AnalysisFlags.returnValueCheckerMode) != ReturnValueCheckerMode.DISABLED) return
+
+ for (entry in entries) {
+ val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
+ val name = descriptor.fqName ?: continue
+ if (name == mustUseReturnValueFq || name == ignorableFq) {
+ trace.report(Errors.IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED.on(entry))
+ }
+ }
+ }
+}
diff --git a/compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt b/compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt
new file mode 100644
index 0000000..613acca
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt
@@ -0,0 +1,16 @@
+// RUN_PIPELINE_TILL: FRONTEND
+// WITH_STDLIB
+// FIR_IDENTICAL
+
+<!IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED!>@file:MustUseReturnValue<!>
+
+fun foo(): String = ""
+
+<!IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED!>@IgnorableReturnValue<!>
+fun bar(): Int = 42
+
+<!IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED!>@MustUseReturnValue<!>
+class Test {
+ <!IGNORABILITY_ANNOTATIONS_WITH_CHECKER_DISABLED!>@IgnorableReturnValue<!>
+ fun method(): Double = 0.0
+}
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
index 1a6a968..c3867c3 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java
@@ -9492,6 +9492,22 @@
}
@Nested
+ @TestMetadata("compiler/testData/diagnostics/tests/crvDisabled")
+ @TestDataPath("$PROJECT_ROOT")
+ public class CrvDisabled {
+ @Test
+ public void testAllFilesPresentInCrvDisabled() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/crvDisabled"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll|latestLV)\\.kts?$"), true);
+ }
+
+ @Test
+ @TestMetadata("disabledChecker.kt")
+ public void testDisabledChecker() {
+ runTest("compiler/testData/diagnostics/tests/crvDisabled/disabledChecker.kt");
+ }
+ }
+
+ @Nested
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
@TestDataPath("$PROJECT_ROOT")
public class CyclicHierarchy {
diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt
index cef0d47..662e651 100644
--- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt
+++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/configuration/BaseDiagnosticConfiguration.kt
@@ -226,6 +226,12 @@
}
}
+ forTestsMatching("compiler/testData/diagnostics/tests/crvDisabled/*") {
+ defaultDirectives {
+ RETURN_VALUE_CHECKER_MODE with ReturnValueCheckerMode.DISABLED
+ }
+ }
+
forTestsMatching(
"compiler/fir/analysis-tests/testData/resolve/extraCheckers/*" or
"compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/*"
diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticTest.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticTest.kt
index 78f9426..df953af 100644
--- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticTest.kt
+++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticTest.kt
@@ -114,6 +114,12 @@
}
}
+ forTestsMatching("compiler/testData/diagnostics/tests/crvDisabled/*") {
+ defaultDirectives {
+ RETURN_VALUE_CHECKER_MODE with ReturnValueCheckerMode.DISABLED
+ }
+ }
+
forTestsMatching("compiler/testData/diagnostics/tests/testsWithExplicitReturnTypes/*") {
defaultDirectives {
EXPLICIT_RETURN_TYPES_MODE with ExplicitApiMode.STRICT