From bed7f22514acc5121601b8e09ebfc2e0b54c4e21 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Fri, 8 May 2026 10:06:32 -0500 Subject: [PATCH] =?UTF-8?q?Fix=20#945=20=E2=80=94=20clean=20up=20build=20w?= =?UTF-8?q?arnings=20across=20Lite,=20Dashboard,=20Installer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lite went from 190 warnings to 0, Dashboard from 3 to 0, Installer was already clean. Total fixes: - Add repo-root .editorconfig suppressing CA1873 ("potentially expensive logging") with rationale. This rule fires on every non-literal argument to a logging method including trivial field accesses, which accounts for ~97% of Lite's warning count and is pure noise — the cost the rule warns about is consistently negligible. Proper fix is migrating to LoggerMessage source generators, tracked separately. - Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs: guard against null .Result on completed comparison-data tasks before passing to .Select() (CS8604 ×2). The author already wrote `?.Count ?? 0` for the same fields elsewhere, so null was anticipated; the .Select calls just missed the guard. - Lite/Mcp/McpAnalysisTools.cs: tighten FormatBaselineContext return type from object? to Dictionary?, removing the unnecessary boxing (CA1859). - Dashboard/ServerTab.Plans.cs: discard the bool returns from three int.TryParse calls with `_ =`, making the "ignore failure, use default 0" intent explicit (CA1806 ×3). Behavior unchanged — TryParse already sets the out param to default on failure. Co-Authored-By: Claude Opus 4.7 (1M context) --- .editorconfig | 13 +++++++++++++ Dashboard/ServerTab.Plans.cs | 6 +++--- .../Controls/CorrelatedTimelineLanesControl.xaml.cs | 4 ++-- Lite/Mcp/McpAnalysisTools.cs | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..5ff966f9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*.cs] + +# CA1873: Avoid potentially expensive logging +# +# This rule fires on any non-literal argument to a logging method (including +# trivial field accesses like `_logger.LogInformation("X: {Path}", _path)`), +# on the theory that the argument might be expensive to evaluate when the +# level is disabled. In this codebase the cost is consistently negligible — +# the proper fix is migrating to LoggerMessage source generators, which is +# a larger separate effort. Until then, this rule is pure noise. +dotnet_diagnostic.CA1873.severity = none diff --git a/Dashboard/ServerTab.Plans.cs b/Dashboard/ServerTab.Plans.cs index c07435f0..bbb5a6fe 100644 --- a/Dashboard/ServerTab.Plans.cs +++ b/Dashboard/ServerTab.Plans.cs @@ -341,7 +341,7 @@ private async Task ShowBlockedProcessPlanAsync(object sender, bool blockingSide) int stmtStart = 0; int stmtEnd = -1; - int.TryParse(frame.Attribute("stmtstart")?.Value, out stmtStart); + _ = int.TryParse(frame.Attribute("stmtstart")?.Value, out stmtStart); if (int.TryParse(frame.Attribute("stmtend")?.Value, out var se)) stmtEnd = se; frames.Add((handle!, stmtStart, stmtEnd)); @@ -426,7 +426,7 @@ private async void ViewDeadlockProcessPlan_Click(object sender, RoutedEventArgs !string.Equals(procHandle, ZeroSqlHandle, StringComparison.OrdinalIgnoreCase)) { int ps = 0, pe = -1; - int.TryParse(process.Attribute("stmtstart")?.Value, out ps); + _ = int.TryParse(process.Attribute("stmtstart")?.Value, out ps); if (int.TryParse(process.Attribute("stmtend")?.Value, out var peParsed)) pe = peParsed; frames.Add((procHandle!, ps, pe)); } @@ -441,7 +441,7 @@ private async void ViewDeadlockProcessPlan_Click(object sender, RoutedEventArgs if (string.Equals(handle, ZeroSqlHandle, StringComparison.OrdinalIgnoreCase)) continue; int fs = 0, fe = -1; - int.TryParse(frame.Attribute("stmtstart")?.Value, out fs); + _ = int.TryParse(frame.Attribute("stmtstart")?.Value, out fs); if (int.TryParse(frame.Attribute("stmtend")?.Value, out var feParsed)) fe = feParsed; frames.Add((handle!, fs, fe)); } diff --git a/Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs b/Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs index 2b73b71a..af872f07 100644 --- a/Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs +++ b/Lite/Controls/CorrelatedTimelineLanesControl.xaml.cs @@ -174,11 +174,11 @@ await Task.WhenAll(cpuTask, waitTask, blockingTask, deadlockTask, memoryTask, fi $"Comparison: refFrom={refFrom:o}, refTo={refTo:o}, shift={timeShift.TotalHours:F1}h, " + $"cpuRows={refCpuTask.Result?.Count ?? 0}, waitRows={refWaitTask.Result?.Count ?? 0}"); - if (refCpuTask.IsCompletedSuccessfully) + if (refCpuTask.IsCompletedSuccessfully && refCpuTask.Result != null) AddGhostLine(CpuChart, refCpuTask.Result .Select(d => (d.SampleTime.Add(timeShift).ToOADate(), (double)d.SqlServerCpu)).ToList(), "#4FC3F7"); - if (refWaitTask.IsCompletedSuccessfully) + if (refWaitTask.IsCompletedSuccessfully && refWaitTask.Result != null) AddGhostLine(WaitStatsChart, refWaitTask.Result .Select(d => (d.CollectionTime.AddMinutes(utcOffset).Add(timeShift).ToOADate(), d.WaitTimeMsPerSecond)).ToList(), "#FFB74D"); diff --git a/Lite/Mcp/McpAnalysisTools.cs b/Lite/Mcp/McpAnalysisTools.cs index c29dca0e..fbbd48bb 100644 --- a/Lite/Mcp/McpAnalysisTools.cs +++ b/Lite/Mcp/McpAnalysisTools.cs @@ -840,7 +840,7 @@ public static List GetForStoryPath(string storyPath) /// Formats baseline context from anomaly fact metadata into a human-readable object /// for MCP output. Example: "4.1σ above baseline for Tue 14:00, mean 68.2" /// - private static object? FormatBaselineContext(Dictionary metadata) + private static Dictionary? FormatBaselineContext(Dictionary metadata) { var result = new Dictionary();