Skip to content

refactor: remove unnecessary async state machines (VSTHRD202) - #201

Merged
HandyS11 merged 1 commit into
developfrom
chore/sonar-vsthrd202
Oct 16, 2026
Merged

HandyS11 merged 1 commit into
developfrom
chore/sonar-vsthrd202

Conversation

@HandyS11

Copy link
Copy Markdown
Owner

Summary

SonarQube reports 31 open code smells on develop. All of them are external_roslyn:VSTHRD202 ("Remove unnecessary async state machine"). This PR fixes every one.

  • Pass-through methods now return the inner Task directly. Each one had a single trailing await, so async/await is dropped (14 files, 31 sites in src/ and tests/).
  • .editorconfig sets dotnet_diagnostic.VSTHRD202.severity = warning. With TreatWarningsAsErrors, the local build now catches any new case before Sonar does.

Behavioural note

Four of the methods run a synchronous guard before the returned call: AnalyzeContextUseCase, AnalyzeSnapshotUseCase, ProjGraphTools.PreparePathAsync and SpectreOutputConsole.RunWithStatusAsync. Their guard exceptions are now thrown synchronously instead of coming back as a faulted task. Every caller awaits these methods directly, so callers see the same exception.

Test plan

  • dotnet build ProjGraph.slnx --no-incremental: 0 warnings, 0 errors with VSTHRD202 enforced (before the fix it reported the same 31 sites as Sonar)
  • dotnet test ProjGraph.slnx: all 1,181 tests pass
  • aot-smoke CI job: the Tests.Smoke.Aot changes compile locally but only run in CI
  • SonarQube analysis on merge shows 0 open issues

🤖 Generated with Claude Code

Resolves the 31 open SonarQube code smells on develop, all VSTHRD202:
pass-through methods now return the inner Task directly instead of
awaiting it. The rule is raised to warning in .editorconfig so the
build (TreatWarningsAsErrors) prevents regressions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 16, 2026 19:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The changes are a uniform, mechanical refactor whose only semantic effect (synchronous guard throws) is safe because every verified caller awaits the methods directly without composing the returned tasks.

0 open findings

What changed in this PR

This PR resolves all 31 SonarQube VSTHRD202 ("Remove unnecessary async state machine") code smells. It targets pass-through methods whose body was a single trailing await, rewriting them to return the inner Task directly, which removes the compiler-generated async state machine overhead. It also wires the rule into the local build so regressions are caught before Sonar.

Changes:

  • Converted 31 async/await pass-through sites across 14 src/ and tests/ files to return Task/Task<T> directly.
  • Four methods with a synchronous guard before the returned call (AnalyzeContextUseCase, AnalyzeSnapshotUseCase, ProjGraphTools.PreparePathAsync, SpectreOutputConsole.RunWithStatusAsync) now throw guard exceptions synchronously; all callers await directly, so observed behavior is unchanged.
  • Enabled dotnet_diagnostic.VSTHRD202.severity = warning in .editorconfig, enforced locally via the already-referenced Microsoft.VisualStudio.Threading.Analyzers package and TreatWarningsAsErrors.
File Description
.editorconfig Promotes VSTHRD202 to a warning so the build enforces it.
src/​ProjGraph.Mcp/​Program.cs Main returns host.RunAsync() directly.
src/​ProjGraph.Mcp/​ProjGraphTools.cs PreparePathAsync returns the resolve task; guard now throws synchronously (callers await).
src/​ProjGraph.Lib.Core/​Infrastructure/​SpectreOutputConsole.cs PromptSelectionAsync/RunWithStatusAsync return inner tasks; status lambda keeps its own async.
src/​ProjGraph.Lib.EntityFramework/​Application/​EfAnalysisService.cs Four service methods pass through tasks directly.
src/​ProjGraph.Lib.EntityFramework/​Application/​UseCases/​AnalyzeContextUseCase.cs Guard then returns analyzer task directly.
src/​ProjGraph.Lib.EntityFramework/​Application/​UseCases/​AnalyzeSnapshotUseCase.cs Guard then returns analyzer task directly.
src/​ProjGraph.Lib.EntityFramework/​Infrastructure/​EntityFileDiscovery.cs SearchDirectoryForEntitiesAsync returns the recursive task.
src/​ProjGraph.Lib.ClassDiagram/​Application/​ClassAnalysisService.cs Two analysis methods pass through tasks directly.
src/​ProjGraph.Lib.ClassDiagram/​Infrastructure/​TypeProcessor.cs ProcessTypeQueueAsync returns internal task directly.
src/​ProjGraph.Lib.ClassDiagram/​Infrastructure/​WorkspaceTypeDiscovery.cs Computes root synchronously, returns search task.
tests/​ProjGraph.Tests.Integration.Mcp/​Helpers/​McpServerProcess.cs ConnectAsync returns McpClient.CreateAsync directly.
tests/​ProjGraph.Tests.Smoke.Aot/​Helpers/​McpServerPair.cs Same connect-helper conversion.
tests/​ProjGraph.Tests.Smoke.Aot/​CliParityTests.cs Test methods return parity-assertion tasks directly.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@HandyS11
HandyS11 merged commit cf3b69f into develop Oct 16, 2026
15 checks passed
@HandyS11
HandyS11 deleted the chore/sonar-vsthrd202 branch October 16, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants