From fddb5d8c1815edbd3bc93a9a1fd6be6dc9bf1605 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 18 Jul 2023 09:38:21 -0400 Subject: [PATCH] Annotate Trace.Assert/Fail with [DoesNotReturn{If}] (#89066) As with Debug.Assert/Fail, by default failures result in fail fasts. It's possible for other trace listeners to be plugged in instead, but there's no way to model that with nullable reference types. There's no reason Trace should be on a different plan from Debug, so this moves it to having the same annotations Debug has had for years. --- .../ref/System.Diagnostics.TraceSource.cs | 12 ++- .../src/System/Diagnostics/Trace.cs | 110 ++++++++++----------- .../src/System/Diagnostics/TraceInternal.cs | 6 ++ 3 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs b/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs index 3831073..45e6a34 100644 --- a/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs +++ b/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs @@ -119,17 +119,19 @@ namespace System.Diagnostics public static System.Diagnostics.TraceListenerCollection Listeners { get { throw null; } } public static bool UseGlobalLock { get { throw null; } set { } } [System.Diagnostics.ConditionalAttribute("TRACE")] - public static void Assert(bool condition) { } + public static void Assert([System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute(false)] bool condition) { } [System.Diagnostics.ConditionalAttribute("TRACE")] - public static void Assert(bool condition, string? message) { } + public static void Assert([System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute(false)] bool condition, string? message) { } [System.Diagnostics.ConditionalAttribute("TRACE")] - public static void Assert(bool condition, string? message, string? detailMessage) { } + public static void Assert([System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute(false)] bool condition, string? message, string? detailMessage) { } [System.Diagnostics.ConditionalAttribute("TRACE")] public static void Close() { } [System.Diagnostics.ConditionalAttribute("TRACE")] - public static void Fail(string? message) { } + [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] + public static void Fail(string? message) { throw null; } [System.Diagnostics.ConditionalAttribute("TRACE")] - public static void Fail(string? message, string? detailMessage) { } + [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] + public static void Fail(string? message, string? detailMessage) { throw null; } [System.Diagnostics.ConditionalAttribute("TRACE")] public static void Flush() { } [System.Diagnostics.ConditionalAttribute("TRACE")] diff --git a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/Trace.cs b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/Trace.cs index 22e4c6b..e00b5b8 100644 --- a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/Trace.cs +++ b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/Trace.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #define TRACE -using System; using System.Diagnostics.CodeAnalysis; -using System.Collections; using System.Threading; namespace System.Diagnostics @@ -40,7 +38,7 @@ namespace System.Diagnostics /// /// - /// Gets or sets whether should be called on the after every write. + /// Gets or sets whether should be called on the after every write. /// /// public static bool AutoFlush @@ -92,19 +90,19 @@ namespace System.Diagnostics /// /// Clears the output buffer, and causes buffered data to - /// be written to the . + /// be written to the . /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Flush() { TraceInternal.Flush(); } /// - /// Clears the output buffer, and then closes the so that they no + /// Clears the output buffer, and then closes the so that they no /// longer receive debugging output. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Close() { TraceInternal.Close(); @@ -115,8 +113,8 @@ namespace System.Diagnostics /// condition /// is . /// - [System.Diagnostics.Conditional("TRACE")] - public static void Assert(bool condition) + [Conditional("TRACE")] + public static void Assert([DoesNotReturnIf(false)] bool condition) { TraceInternal.Assert(condition); } @@ -125,8 +123,8 @@ namespace System.Diagnostics /// Checks for a condition, and displays a message if the condition is /// . /// - [System.Diagnostics.Conditional("TRACE")] - public static void Assert(bool condition, string? message) + [Conditional("TRACE")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message) { TraceInternal.Assert(condition, message); } @@ -135,8 +133,8 @@ namespace System.Diagnostics /// Checks for a condition, and displays both messages if the condition /// is . /// - [System.Diagnostics.Conditional("TRACE")] - public static void Assert(bool condition, string? message, string? detailMessage) + [Conditional("TRACE")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message, string? detailMessage) { TraceInternal.Assert(condition, message, detailMessage); } @@ -144,7 +142,8 @@ namespace System.Diagnostics /// /// Emits or displays a message for an assertion that always fails. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] + [DoesNotReturn] public static void Fail(string? message) { TraceInternal.Fail(message); @@ -153,7 +152,8 @@ namespace System.Diagnostics /// /// Emits or displays both messages for an assertion that always fails. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] + [DoesNotReturn] public static void Fail(string? message, string? detailMessage) { TraceInternal.Fail(message, detailMessage); @@ -177,47 +177,47 @@ namespace System.Diagnostics TraceInternal.Refresh(); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceInformation(string? message) { TraceInternal.TraceEvent(TraceEventType.Information, 0, message, null); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceInformation([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[]? args) { TraceInternal.TraceEvent(TraceEventType.Information, 0, format, args); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceWarning(string? message) { TraceInternal.TraceEvent(TraceEventType.Warning, 0, message, null); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceWarning([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[]? args) { TraceInternal.TraceEvent(TraceEventType.Warning, 0, format, args); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceError(string? message) { TraceInternal.TraceEvent(TraceEventType.Error, 0, message, null); } - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void TraceError([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[]? args) { TraceInternal.TraceEvent(TraceEventType.Error, 0, format, args); } /// - /// Writes a message to the trace listeners in the + /// Writes a message to the trace listeners in the /// collection. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Write(string? message) { TraceInternal.Write(message); @@ -225,9 +225,9 @@ namespace System.Diagnostics /// /// Writes the name of the - /// parameter to the trace listeners in the collection. + /// parameter to the trace listeners in the collection. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Write(object? value) { TraceInternal.Write(value); @@ -235,9 +235,9 @@ namespace System.Diagnostics /// /// Writes a category name and message to the trace listeners - /// in the collection. + /// in the collection. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Write(string? message, string? category) { TraceInternal.Write(message, category); @@ -245,9 +245,9 @@ namespace System.Diagnostics /// /// Writes a category name and the name of the value parameter to the trace listeners - /// in the collection. + /// in the collection. /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Write(object? value, string? category) { TraceInternal.Write(value, category); @@ -255,20 +255,20 @@ namespace System.Diagnostics /// /// Writes a message followed by a line terminator to the - /// trace listeners in the collection. + /// trace listeners in the collection. /// The default line terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLine(string? message) { TraceInternal.WriteLine(message); } /// - /// Writes the name of the parameter followed by a line terminator to the trace listeners in the collection. The default line + /// Writes the name of the parameter followed by a line terminator to the trace listeners in the collection. The default line /// terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLine(object? value) { TraceInternal.WriteLine(value); @@ -276,11 +276,11 @@ namespace System.Diagnostics /// /// Writes a category name and message followed by a line terminator to the trace - /// listeners in the + /// listeners in the /// collection. The default line terminator is a carriage return followed by a line /// feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLine(string? message, string? category) { TraceInternal.WriteLine(message, category); @@ -288,20 +288,20 @@ namespace System.Diagnostics /// /// Writes a name and the name of the parameter followed by a line - /// terminator to the trace listeners in the collection. The default line + /// terminator to the trace listeners in the collection. The default line /// terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLine(object? value, string? category) { TraceInternal.WriteLine(value, category); } /// - /// Writes a message to the trace listeners in the collection + /// Writes a message to the trace listeners in the collection /// if a condition is . /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteIf(bool condition, string? message) { TraceInternal.WriteIf(condition, message); @@ -309,20 +309,20 @@ namespace System.Diagnostics /// /// Writes the name of the - /// parameter to the trace listeners in the collection if a condition is + /// parameter to the trace listeners in the collection if a condition is /// . /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteIf(bool condition, object? value) { TraceInternal.WriteIf(condition, value); } /// - /// Writes a category name and message to the trace listeners in the + /// Writes a category name and message to the trace listeners in the /// collection if a condition is . /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteIf(bool condition, string? message, string? category) { TraceInternal.WriteIf(condition, message, category); @@ -330,10 +330,10 @@ namespace System.Diagnostics /// /// Writes a category name and the name of the parameter to the trace - /// listeners in the collection + /// listeners in the collection /// if a condition is . /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteIf(bool condition, object? value, string? category) { TraceInternal.WriteIf(condition, value, category); @@ -341,11 +341,11 @@ namespace System.Diagnostics /// /// Writes a message followed by a line terminator to the trace listeners in the - /// collection if a condition is + /// collection if a condition is /// . The default line terminator is a carriage return followed /// by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLineIf(bool condition, string? message) { TraceInternal.WriteLineIf(condition, message); @@ -353,12 +353,12 @@ namespace System.Diagnostics /// /// Writes the name of the parameter followed by a line terminator to the - /// trace listeners in the collection + /// trace listeners in the collection /// if a condition is /// . The default line /// terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLineIf(bool condition, object? value) { TraceInternal.WriteLineIf(condition, value); @@ -366,10 +366,10 @@ namespace System.Diagnostics /// /// Writes a category name and message followed by a line terminator to the trace - /// listeners in the collection if a condition is + /// listeners in the collection if a condition is /// . The default line terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLineIf(bool condition, string? message, string? category) { TraceInternal.WriteLineIf(condition, message, category); @@ -377,11 +377,11 @@ namespace System.Diagnostics /// /// Writes a category name and the name of the parameter followed by a line - /// terminator to the trace listeners in the collection + /// terminator to the trace listeners in the collection /// if a is . The /// default line terminator is a carriage return followed by a line feed (\r\n). /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void WriteLineIf(bool condition, object? value, string? category) { TraceInternal.WriteLineIf(condition, value, category); @@ -390,7 +390,7 @@ namespace System.Diagnostics /// /// [To be supplied.] /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Indent() { TraceInternal.Indent(); @@ -399,7 +399,7 @@ namespace System.Diagnostics /// /// [To be supplied.] /// - [System.Diagnostics.Conditional("TRACE")] + [Conditional("TRACE")] public static void Unindent() { TraceInternal.Unindent(); diff --git a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceInternal.cs b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceInternal.cs index 0454ae3..cb4f182 100644 --- a/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceInternal.cs +++ b/src/libraries/System.Diagnostics.TraceSource/src/System/Diagnostics/TraceInternal.cs @@ -213,6 +213,7 @@ namespace System.Diagnostics Fail(message, detailMessage); } + [DoesNotReturn] public static void Fail(string? message) { if (UseGlobalLock) @@ -245,8 +246,11 @@ namespace System.Diagnostics } } } +#pragma warning disable 8763 // "A method marked [DoesNotReturn] should not return." } +#pragma warning restore 8763 + [DoesNotReturn] public static void Fail(string? message, string? detailMessage) { if (UseGlobalLock) @@ -279,7 +283,9 @@ namespace System.Diagnostics } } } +#pragma warning disable 8763 // "A method marked [DoesNotReturn] should not return." } +#pragma warning restore 8763 private static void InitializeSettings() { -- 2.7.4