show simplified stack trace for deprecation notices
This commit is contained in:
parent
fd136d34c5
commit
c0d0ad0282
|
@ -57,6 +57,7 @@ the C# mod that loads them is updated.
|
|||
* Added `helper.Content.ParseAssetName` to get an `IAssetName` for an arbitrary asset key.
|
||||
* If an asset is loaded multiple times in the same tick, `IAssetLoader.CanLoad` and `IAssetEditor.CanEdit` are now cached unless invalidated by `helper.Content.InvalidateCache`.
|
||||
* The `ISemanticVersion` comparison methods (`CompareTo`, `IsBetween`, `IsNewerThan`, and `IsOlderThan`) now allow null values. A null version is always considered older than any non-null version per [best practices](https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1.compareto#remarks).
|
||||
* Deprecation notices now show a shorter stack trace in most cases, so it's clearer where the deprecated code is in the mod.
|
||||
* Fixes:
|
||||
* Fixed the `SDate` constructor being case-sensitive.
|
||||
* Fixed support for using locale codes from custom languages in asset names (e.g. `Data/Achievements.eo-EU`).
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace StardewModdingAPI.Framework
|
||||
{
|
||||
|
@ -62,7 +63,8 @@ namespace StardewModdingAPI.Framework
|
|||
return;
|
||||
|
||||
// queue warning
|
||||
this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, new StackTrace(skipFrames: 1)));
|
||||
var stack = new StackTrace(skipFrames: 1); // skip this method
|
||||
this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, stack));
|
||||
}
|
||||
|
||||
/// <summary>A placeholder method used to track deprecated code for which a separate warning will be shown.</summary>
|
||||
|
@ -100,11 +102,11 @@ namespace StardewModdingAPI.Framework
|
|||
|
||||
// log message
|
||||
if (level == LogLevel.Trace)
|
||||
this.Monitor.Log($"{message}\n{warning.StackTrace}", level);
|
||||
this.Monitor.Log($"{message}\n{this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod)}", level);
|
||||
else
|
||||
{
|
||||
this.Monitor.Log(message, level);
|
||||
this.Monitor.Log(warning.StackTrace.ToString(), LogLevel.Debug);
|
||||
this.Monitor.Log(this.GetSimplifiedStackTrace(warning.StackTrace, warning.Mod), LogLevel.Debug);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,5 +130,42 @@ namespace StardewModdingAPI.Framework
|
|||
this.LoggedDeprecations.Add(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Get the simplest stack trace which shows where in the mod the deprecated code was called from.</summary>
|
||||
/// <param name="stack">The stack trace.</param>
|
||||
/// <param name="mod">The mod for which to show a stack trace.</param>
|
||||
private string GetSimplifiedStackTrace(StackTrace stack, IModMetadata? mod)
|
||||
{
|
||||
// unknown mod, show entire stack trace
|
||||
if (mod == null)
|
||||
return stack.ToString();
|
||||
|
||||
// get frame info
|
||||
var frames = stack
|
||||
.GetFrames()
|
||||
.Select(frame => (Frame: frame, Mod: this.ModRegistry.GetFrom(frame)))
|
||||
.ToArray();
|
||||
var modIds = new HashSet<string>(
|
||||
from frame in frames
|
||||
let id = frame.Mod?.Manifest.UniqueID
|
||||
where id != null
|
||||
select id
|
||||
);
|
||||
|
||||
// can't filter to the target mod
|
||||
if (modIds.Count != 1 || !modIds.Contains(mod.Manifest.UniqueID))
|
||||
return stack.ToString();
|
||||
|
||||
// get stack frames for the target mod, plus one for context
|
||||
var framesStartingAtMod = frames.SkipWhile(p => p.Mod == null).ToArray();
|
||||
var displayFrames = framesStartingAtMod.TakeWhile(p => p.Mod != null).ToArray();
|
||||
displayFrames = displayFrames.Concat(framesStartingAtMod.Skip(displayFrames.Length).Take(1)).ToArray();
|
||||
|
||||
// build stack trace
|
||||
StringBuilder str = new();
|
||||
foreach (var frame in displayFrames)
|
||||
str.Append(new StackTrace(frame.Frame));
|
||||
return str.ToString().TrimEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace StardewModdingAPI.Framework
|
|||
|
||||
/// <summary>Get metadata for a loaded mod.</summary>
|
||||
/// <param name="uniqueID">The mod's unique ID.</param>
|
||||
/// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
|
||||
/// <returns>Returns the mod's metadata, or <c>null</c> if not found.</returns>
|
||||
public IModMetadata? Get(string uniqueID)
|
||||
{
|
||||
// normalize search ID
|
||||
|
@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework
|
|||
|
||||
/// <summary>Get the mod metadata from one of its assemblies.</summary>
|
||||
/// <param name="type">The type to check.</param>
|
||||
/// <returns>Returns the mod name, or <c>null</c> if the type isn't part of a known mod.</returns>
|
||||
/// <returns>Returns the mod's metadata, or <c>null</c> if the type isn't part of a known mod.</returns>
|
||||
public IModMetadata? GetFrom(Type? type)
|
||||
{
|
||||
// null
|
||||
|
@ -89,8 +89,17 @@ namespace StardewModdingAPI.Framework
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Get the friendly name for the closest assembly registered as a source of deprecation warnings.</summary>
|
||||
/// <returns>Returns the source name, or <c>null</c> if no registered assemblies were found.</returns>
|
||||
/// <summary>Get the mod metadata from a stack frame, if any.</summary>
|
||||
/// <param name="frame">The stack frame to check.</param>
|
||||
/// <returns>Returns the mod's metadata, or <c>null</c> if the frame isn't part of a known mod.</returns>
|
||||
public IModMetadata? GetFrom(StackFrame frame)
|
||||
{
|
||||
MethodBase? method = frame.GetMethod();
|
||||
return this.GetFrom(method?.ReflectedType);
|
||||
}
|
||||
|
||||
/// <summary>Get the mod metadata from the closest assembly registered as a source of deprecation warnings.</summary>
|
||||
/// <returns>Returns the mod's metadata, or <c>null</c> if no registered assemblies were found.</returns>
|
||||
public IModMetadata? GetFromStack()
|
||||
{
|
||||
// get stack frames
|
||||
|
@ -100,8 +109,7 @@ namespace StardewModdingAPI.Framework
|
|||
// search stack for a source assembly
|
||||
foreach (StackFrame frame in frames)
|
||||
{
|
||||
MethodBase? method = frame.GetMethod();
|
||||
IModMetadata? mod = this.GetFrom(method?.ReflectedType);
|
||||
IModMetadata? mod = this.GetFrom(frame);
|
||||
if (mod != null)
|
||||
return mod;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue