Skip to content

Avoid decoding all SuppressMessageAttributes up front#83087

Merged
333fred merged 9 commits intodotnet:mainfrom
333fred:suppression-restructure
Apr 23, 2026
Merged

Avoid decoding all SuppressMessageAttributes up front#83087
333fred merged 9 commits intodotnet:mainfrom
333fred:suppression-restructure

Conversation

@333fred
Copy link
Copy Markdown
Member

@333fred 333fred commented Apr 7, 2026

Currently, when requesting whether any attribute suppresses a specific diagnostic, we will eagerly decode all SuppressMessageAttributes in the global context. This is potentially a lot of work unrelated to the diagnostic being queried, especially if the compilation then doesn't produce any of the diagnostic that then is resolved. To avoid this, we now only resolve symbols for suppressions of a specific diagnostic ID when that diagnostic ID is requested, and never otherwise. This improves perf of a 1st-party partner team's CI by ~5x.

Microsoft Reviewers: Open in CodeFlow

Currently, when requesting whether any attribute suppresses a specific diagnostic, we will eagerly decode all `SuppressMessageAttribute`s in the global context. This is potentially a lot of work unrelated to the diagnostic being queried, especially if the compilation then doesn't produce any of the diagnostic that then is resolved. To avoid this, we now only resolve symbols for suppressions of a specific diagnostic ID when that diagnostic ID is requested, and never otherwise. This improves perf of a 1st-party partner team's CI by ~5x.
@333fred 333fred requested a review from a team as a code owner April 7, 2026 20:44
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Apr 7, 2026

@dotnet/roslyn-compiler for review

Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs Outdated
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs Outdated
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs Outdated
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs Outdated
@@ -71,12 +59,13 @@ public void AddCompilationWideSuppression(SuppressMessageInfo info)
public void AddGlobalSymbolSuppression(SuppressMessageInfo info, TargetScope scope)
{
Debug.Assert(!_lazyResolvedSuppressionsById.ContainsKey(info.Id));
Copy link
Copy Markdown
Member

@jjonescz jjonescz Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: perhaps we could strengthen the assert and require the resolved suppression dictionary is empty while we construct the unresolved dictionary. #Resolved

@333fred
Copy link
Copy Markdown
Member Author

333fred commented Apr 13, 2026

@dotnet/roslyn-compiler for a second review

@jcouv jcouv self-assigned this Apr 19, 2026
@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 19, 2026

Consider adding a test or referencing a test to illustrate the issue. That would make the issue being fixed clearer. Also, such a test could be used as benchmark, to show the impact of the PR.

private readonly Dictionary<ISymbol, Dictionary<string, SuppressMessageInfo>> _globalSymbolSuppressions = new Dictionary<ISymbol, Dictionary<string, SuppressMessageInfo>>();
// Keep targeted suppressions grouped by diagnostic ID so we only resolve target symbols
// for IDs that are actually queried.
private readonly Dictionary<string, List<(SuppressMessageInfo Info, TargetScope Scope)>> _unresolvedSuppressionsById = new Dictionary<string, List<(SuppressMessageInfo Info, TargetScope Scope)>>(StringComparer.Ordinal);
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(SuppressMessageInfo Info, TargetScope Scope)

It feels like this could be simplified. The SuppressMessageInfo.Scope string is redundant with this TargetScope Scope. I'd be tempted to remove Scope here or store a TargetScope in SuppressMessageInfo (instead of string Scope), unless there's an observable effect on benchmark.
#Closed

Copy link
Copy Markdown
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with review pass (commit 2)

333fred added 3 commits April 20, 2026 13:08
…ture

* upstream/main: (77 commits)
  Fix ArgumentNullException in VB Edit and Continue (dotnet#83250)
  Fix property pattern completion filtering out member being edited (dotnet#83230)
  Add branch merge skill (dotnet#83229)
  [main] Source code updates from dotnet/dotnet (dotnet#83215)
  Support MatchPriority comparison in LSP completion (dotnet#83164)
  Have CompleteStatement handle EOF statements (dotnet#83205)
  Minor cleanups related to attributes in VB (dotnet#83206)
  Simplify
  Address additional PR feedback
  Port remaining unit test projects to Linux (dotnet#83153)
  Unsafe evolution: allow unsafe property accessors (dotnet#83115)
  Address PR review feedback
  Allow cohost rename in Razor source-generated docs
  Refine code review skill (dotnet#82666)
  Review feedback
  Allow creation of DocumentUri instances even if System.Uri cannot parse it
  Improve TextLine and line table performance by packing existing data into unused bits (dotnet#83000)
  Skip TestFindReferencesAsync_UsingAlias on non-Windows platforms (dotnet#83188)
  [main] Source code updates from dotnet/dotnet (dotnet#83174)
  fix comment
  ...
@333fred 333fred requested a review from a team as a code owner April 21, 2026 00:20
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Apr 21, 2026

@jcouv for another look please.

var resolvedSuppressions = new Dictionary<ISymbol, SuppressMessageInfo>();
foreach (var info in suppressions)
{
foreach (var target in ResolveTargetSymbols(_compilation, info.Target, info.Scope))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var

nit: type? Also on outer foreach

}

if (TryGetTargetScope(info, out TargetScope scope))
if (info.Scope != TargetScope.Invalid)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider inverting if to decrease nesting (if (invalid) { continue; } if (info is { Scope: ... } ) { continue; }

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 21, 2026

Gentle ping on this comment


In reply to: 4276450884

Copy link
Copy Markdown
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks (commit 5) with minor comments to consider. I still think it would be good to include a targeted/stress test

333fred and others added 3 commits April 22, 2026 15:16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Apr 22, 2026

@jcouv @jjonescz for review

Copy link
Copy Markdown
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks (commit 8)

Comment thread src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs Outdated
@333fred 333fred enabled auto-merge (squash) April 23, 2026 17:33
@333fred 333fred merged commit f2f83b2 into dotnet:main Apr 23, 2026
27 of 28 checks passed
@dotnet-policy-service dotnet-policy-service Bot added this to the Next milestone Apr 23, 2026
@333fred 333fred deleted the suppression-restructure branch April 23, 2026 23:09
@JoeRobich JoeRobich modified the milestones: Next, 18.7 Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants