Add MSBuildTask0012: require concrete MSBuild tasks to declare multithreading support - #14789
Open
ViktorHofer with Copilot wants to merge 6 commits into
Open
Add MSBuildTask0012: require concrete MSBuild tasks to declare multithreading support#14789ViktorHofer with Copilot wants to merge 6 commits into
ViktorHofer with Copilot wants to merge 6 commits into
Conversation
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add opt-in rule for declaring multithreading support in MSBuild tasks
Add MSBuildTask0012: require concrete MSBuild tasks to declare multithreading support
Aug 23, 2026
ViktorHofer
marked this pull request as ready for review
August 23, 2026 17:49
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new opt-in TaskAuthoring analyzer rule to prevent “silent” multithreading regression by requiring concrete MSBuild tasks to explicitly opt into multithreaded execution via [MSBuildMultiThreadableTask], plus a code fix and accompanying documentation/tests.
Changes:
- Introduces MSBuildTask0012 analyzer (
RequireMultiThreadableTaskAnalyzer) with opt-in viamsbuild_task_analyzer.scope = require_multithreadableor explicit severity configuration. - Adds a code fix to apply
[MSBuildMultiThreadableTask]and, when safe, implementIMultiThreadableTaskand add theTaskEnvironmentproperty. - Updates docs, release notes, and unit test infrastructure + adds new analyzer/codefix test suites.
Show a summary per file
| File | Description |
|---|---|
| src/TaskAnalyzer/WellKnownTypeNames.cs | Adds constants to support attribute detection by namespace + name. |
| src/TaskAnalyzer/SharedAnalyzerHelpers.cs | Adds new require_multithreadable scope value and helper option readers. |
| src/TaskAnalyzer/RequireMultiThreadableTaskAnalyzer.cs | New MSBuildTask0012 analyzer with opt-in gating and per-tree severity support. |
| src/TaskAnalyzer/RequireMultiThreadableTaskCodeFixProvider.cs | New code fix to declare multithreading support (attribute + optional interface/property). |
| src/TaskAnalyzer/DiagnosticIds.cs | Adds MSBuildTask0012 ID constant. |
| src/TaskAnalyzer/DiagnosticDescriptors.cs | Adds MSBuildTask0012 descriptor and includes it in the global descriptor list. |
| src/TaskAnalyzer/README.md | Documents MSBuildTask0012 and the expanded scope option behavior. |
| src/TaskAnalyzer/AnalyzerReleases.Unshipped.md | Adds unshipped release entry for MSBuildTask0012. |
| src/TaskAnalyzer.Tests/TestHelpers.cs | Extends test helpers to run arbitrary analyzers with supplied global options. |
| src/TaskAnalyzer.Tests/RequireMultiThreadableTaskAnalyzerTests.cs | New analyzer tests covering scope/severity opt-in and inheritance/abstract behavior. |
| src/TaskAnalyzer.Tests/RequireMultiThreadableTaskCodeFixProviderTests.cs | New code fix tests for the various “safe to implement interface/property” cases. |
| documentation/specs/multithreading/thread-safe-tasks.md | Documents MSBuildTask0012 as a way to keep migrated repos from regressing. |
Review details
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 12/12 changed files
- Comments generated: 2
- Review effort level: Lite
… opt-in comment Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
ViktorHofer
approved these changes
Aug 24, 2026
Comment on lines
+105
to
+106
| string.Equals(attributeClass.Name, WellKnownTypeNames.MultiThreadableTaskAttributeName, StringComparison.Ordinal) && | ||
| string.Equals(attributeClass.ContainingNamespace?.ToDisplayString(), WellKnownTypeNames.FrameworkNamespace, StringComparison.Ordinal)) |
Member
There was a problem hiding this comment.
Why doesn't this use the same machinery as the analysis that is triggered when explicitly opted in, in MultiThreadableTaskAnalyzer.OnCompilationStart?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Once a repo finishes migrating its tasks to
[MSBuildMultiThreadableTask], nothing keeps it migrated.TaskRouter.NeedsTaskHostInMultiThreadedModeroutes any task lacking the attribute to an out-of-proc TaskHost — no error, no warning, just a slower build. All 11 existing rules either skip unannotated types (scope = multithreadable_only) or only flag unsafe API usage (scope = all), so a new task that happens to touch no banned API is never told to opt in.MSBuildTask0012turns that silent regression into a diagnostic.Changes Made
New rule (
RequireMultiThreadableTaskAnalyzer.cs) — reports non-abstract classes implementingITaskwithout a directly appliedMicrosoft.Build.Framework.MSBuildMultiThreadableTaskAttribute. Attribute detection mirrors the engine: matched by namespace + name viaGetAttributes()(direct only), honoringInherited = false. Consequently:.editorconfigseverity.Opting in — silent otherwise:
msbuild_task_analyzer.scope = require_multithreadable, a third value alongsideallandmultithreadable_only, meaning "analyze all task types and require the attribute";dotnet_diagnostic.MSBuildTask0012.severity(.editorconfigper-file,.globalconfig, ruleset,<WarningsAsErrors>).Code fix — "Declare multithreading support" adds the attribute,
IMultiThreadableTask, and theTaskEnvironmentproperty, falling back to attribute-only when the type already has a conflictingTaskEnvironmentmember. The other rules then take over on the newly annotated task.Docs — the rule, and the scope option's three values, in
src/TaskAnalyzer/README.md(scope was previously undocumented); a "Keeping a Migrated Repository Migrated" section in the multithreading spec; theAnalyzerReleases.Unshipped.mdentry.Testing
23 tests across
RequireMultiThreadableTaskAnalyzerTestsandRequireMultiThreadableTaskCodeFixProviderTestscover the scope values, each severity-configuration path, the inheritance and abstract-type scoping rules, and the code fix including the conflicting-member fallback. Also verified end to end against a realdotnet build, which is how the severity bug in the notes below surfaced.Notes
Two implementation constraints worth flagging for review:
isEnabledByDefault: true, with the opt-in enforced in analyzer code. Roslyn filters disabled-by-default descriptors before an analyzer can consult its options, soisEnabledByDefault: falsecannot be re-enabled by the scope setting. To keep the cost of this at zero for unmigrated repos, no symbol action is registered at compilation start when nothing opts in.dotnet_diagnostic.*.severitynever reachesAnalyzerConfigOptions— Roslyn strips it intoTreeOptions. The severity opt-in initially looked correct but did nothing in a real build; it now readsCompilation.Options.SyntaxTreeOptionsProvider(plusSpecificDiagnosticOptionsfor rulesets).The doc nit in the issue does not apply here:
MSBuildTask0006/0007/0008are alreadyWarningin both this repo's source andAnalyzerReleases.Unshipped.md; theInfoseverities came from the shipped18.11.0-1.26420.118package. Nothing changed.