diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt index c7b27a7139b..8a45ec983ce 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression -import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -207,7 +206,7 @@ object FirOptInUsageBaseChecker { Experimentality.Severity.WARNING -> FirErrors.OPT_IN_USAGE to "should" Experimentality.Severity.ERROR -> FirErrors.OPT_IN_USAGE_ERROR to "must" } - val reportedMessage = message ?: "This declaration is experimental and its usage $verb be marked" + val reportedMessage = message?.takeIf { it.isNotBlank() } ?: "This declaration is experimental and its usage $verb be marked" reporter.reportOn(element.source, diagnostic, annotationClassId.asSingleFqName(), reportedMessage, context) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt index f1197b658c6..d4588f04d7c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -71,7 +71,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { val defaultMessage: (FqName) -> String ) : ExperimentalityDiagnostic { override fun report(trace: BindingTrace, element: PsiElement, fqName: FqName, message: String?) { - trace.reportDiagnosticOnce(factory.on(element, fqName, message ?: defaultMessage(fqName))) + trace.reportDiagnosticOnce(factory.on(element, fqName, message?.takeIf { it.isNotBlank() } ?: defaultMessage(fqName))) } } @@ -480,7 +480,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { Experimentality.Severity.ERROR -> Errors.OPT_IN_OVERRIDE_ERROR to "must" Experimentality.Severity.FUTURE_ERROR -> Errors.OPT_IN_OVERRIDE_ERROR to "must" } - val message = experimentality.message + val message = experimentality.message?.takeIf { it.isNotBlank() } ?: "This declaration overrides experimental member of supertype " + "'${member.containingDeclaration.name.asString()}' and $defaultMessageVerb be annotated " + "with '@${experimentality.annotationFqName.asString()}'" diff --git a/compiler/testData/cli/jvm/optInEmptyMessage.args b/compiler/testData/cli/jvm/optInEmptyMessage.args new file mode 100644 index 00000000000..67a333b95be --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessage.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/optInEmptyMessage.kt +-d +$TEMP_DIR$ +-opt-in=kotlin.RequiresOptIn diff --git a/compiler/testData/cli/jvm/optInEmptyMessage.kt b/compiler/testData/cli/jvm/optInEmptyMessage.kt new file mode 100644 index 00000000000..52a27dab30e --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessage.kt @@ -0,0 +1,9 @@ +@RequiresOptIn(message = " ") +annotation class EmptyMarker + +@EmptyMarker +fun foo() {} + +fun bar() { + foo() +} \ No newline at end of file diff --git a/compiler/testData/cli/jvm/optInEmptyMessage.out b/compiler/testData/cli/jvm/optInEmptyMessage.out new file mode 100644 index 00000000000..d9ea1ee1b33 --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessage.out @@ -0,0 +1,4 @@ +compiler/testData/cli/jvm/optInEmptyMessage.kt:8:5: error: this declaration is experimental and its usage must be marked with '@EmptyMarker' or '@OptIn(EmptyMarker::class)' + foo() + ^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/optInEmptyMessageFir.args b/compiler/testData/cli/jvm/optInEmptyMessageFir.args new file mode 100644 index 00000000000..360bd46a8dd --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessageFir.args @@ -0,0 +1,6 @@ +$TESTDATA_DIR$/optInEmptyMessage.kt +-d +$TEMP_DIR$ +-opt-in=kotlin.RequiresOptIn +-Xuse-fir + diff --git a/compiler/testData/cli/jvm/optInEmptyMessageFir.kt b/compiler/testData/cli/jvm/optInEmptyMessageFir.kt new file mode 100644 index 00000000000..52a27dab30e --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessageFir.kt @@ -0,0 +1,9 @@ +@RequiresOptIn(message = " ") +annotation class EmptyMarker + +@EmptyMarker +fun foo() {} + +fun bar() { + foo() +} \ No newline at end of file diff --git a/compiler/testData/cli/jvm/optInEmptyMessageFir.out b/compiler/testData/cli/jvm/optInEmptyMessageFir.out new file mode 100644 index 00000000000..09585a6ac28 --- /dev/null +++ b/compiler/testData/cli/jvm/optInEmptyMessageFir.out @@ -0,0 +1,7 @@ +warning: ATTENTION! + This build uses in-dev FIR: + -Xuse-fir +compiler/testData/cli/jvm/optInEmptyMessage.kt:8:5: error: this declaration is experimental and its usage must be marked + foo() + ^ +COMPILATION_ERROR diff --git a/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java index 28499178ba7..ee290991dde 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -799,6 +799,16 @@ public class CliTestGenerated extends AbstractCliTest { runTest("compiler/testData/cli/jvm/oldBackendLv16.args"); } + @TestMetadata("optInEmptyMessage.args") + public void testOptInEmptyMessage() throws Exception { + runTest("compiler/testData/cli/jvm/optInEmptyMessage.args"); + } + + @TestMetadata("optInEmptyMessageFir.args") + public void testOptInEmptyMessageFir() throws Exception { + runTest("compiler/testData/cli/jvm/optInEmptyMessageFir.args"); + } + @TestMetadata("pluginSimple.args") public void testPluginSimple() throws Exception { runTest("compiler/testData/cli/jvm/pluginSimple.args");