From e6c696fa6b0bfe5ef013e1179765ce1dcb071c38 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 19 Apr 2022 19:11:58 -0400 Subject: [PATCH] add immutable stack trace to cache stack info --- .../Deprecations/DeprecationManager.cs | 4 +- .../Deprecations/DeprecationWarning.cs | 4 +- .../Deprecations/ImmutableStackTrace.cs | 53 +++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/SMAPI/Framework/Deprecations/ImmutableStackTrace.cs diff --git a/src/SMAPI/Framework/Deprecations/DeprecationManager.cs b/src/SMAPI/Framework/Deprecations/DeprecationManager.cs index da17ce7e..84ce2132 100644 --- a/src/SMAPI/Framework/Deprecations/DeprecationManager.cs +++ b/src/SMAPI/Framework/Deprecations/DeprecationManager.cs @@ -63,7 +63,7 @@ namespace StardewModdingAPI.Framework.Deprecations return; // queue warning - var stack = new StackTrace(skipFrames: 1); // skip this method + ImmutableStackTrace stack = ImmutableStackTrace.Get(skipFrames: 1); this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, stack)); } @@ -134,7 +134,7 @@ namespace StardewModdingAPI.Framework.Deprecations /// Get the simplest stack trace which shows where in the mod the deprecated code was called from. /// The stack trace. /// The mod for which to show a stack trace. - private string GetSimplifiedStackTrace(StackTrace stack, IModMetadata? mod) + private string GetSimplifiedStackTrace(ImmutableStackTrace stack, IModMetadata? mod) { // unknown mod, show entire stack trace if (mod == null) diff --git a/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs b/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs index 38062daf..e00881b1 100644 --- a/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs +++ b/src/SMAPI/Framework/Deprecations/DeprecationWarning.cs @@ -24,7 +24,7 @@ namespace StardewModdingAPI.Framework.Deprecations public DeprecationLevel Level { get; } /// The stack trace when the deprecation warning was raised. - public StackTrace StackTrace { get; } + public ImmutableStackTrace StackTrace { get; } /********* @@ -36,7 +36,7 @@ namespace StardewModdingAPI.Framework.Deprecations /// The SMAPI version which deprecated it. /// The deprecation level for the affected code. /// The stack trace when the deprecation warning was raised. - public DeprecationWarning(IModMetadata? mod, string nounPhrase, string version, DeprecationLevel level, StackTrace stackTrace) + public DeprecationWarning(IModMetadata? mod, string nounPhrase, string version, DeprecationLevel level, ImmutableStackTrace stackTrace) { this.Mod = mod; this.NounPhrase = nounPhrase; diff --git a/src/SMAPI/Framework/Deprecations/ImmutableStackTrace.cs b/src/SMAPI/Framework/Deprecations/ImmutableStackTrace.cs new file mode 100644 index 00000000..059d871c --- /dev/null +++ b/src/SMAPI/Framework/Deprecations/ImmutableStackTrace.cs @@ -0,0 +1,53 @@ +using System.Diagnostics; + +namespace StardewModdingAPI.Framework.Deprecations +{ + /// An immutable stack trace that caches its values. + internal class ImmutableStackTrace + { + /********* + ** Fields + *********/ + /// The underlying stack trace. + private readonly StackTrace StackTrace; + + /// The individual method calls in the stack trace. + private StackFrame[]? Frames; + + /// The string representation of the stack trace. + private string? StringForm; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The underlying stack trace. + public ImmutableStackTrace(StackTrace stackTrace) + { + this.StackTrace = stackTrace; + } + + /// Get the underlying frames. + /// This is a reference to the underlying stack frames, so this array should not be edited. + public StackFrame[] GetFrames() + { + return this.Frames ??= this.StackTrace.GetFrames(); + } + + /// + public override string ToString() + { + return this.StringForm ??= this.StackTrace.ToString(); + } + + /// Get the current stack trace. + /// The number of frames up the stack from which to start the trace. + public static ImmutableStackTrace Get(int skipFrames = 0) + { + return new ImmutableStackTrace( + new StackTrace(skipFrames: skipFrames + 1) // also skip this method + ); + } + } +}