Analyze base classes of multithreadable tasks in TaskAnalyzer - #14831
Draft
ViktorHofer with Copilot wants to merge 2 commits into
Draft
Analyze base classes of multithreadable tasks in TaskAnalyzer#14831ViktorHofer with Copilot wants to merge 2 commits into
ViktorHofer with Copilot wants to merge 2 commits into
Conversation
Contributor
|
Hello @copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo. |
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix MSBuildTask0002 reporting for inherited code
Analyze base classes of multithreadable tasks in TaskAnalyzer
Aug 25, 2026
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
MSBuildTask0002/0003/0005were silent when the offending code lived in an unannotated base class of a task carrying[MSBuildMultiThreadableTask]. Inherited members run on the shared node exactly like declared ones, so this failed in the worst possible way for a migration aid: the analyzer reported clean, and the violation surfaced later as a nondeterministic CI failure.Confirmed in the field on
dotnet/arcade'sAkaMSLinksBase, whereFile.ReadAllText(ClientCertificate)went unreported while both derived tasks analyzed clean.Two independent causes:
MultiThreadableTaskAnalyzerdecides scope per named type. Underscope = multithreadable_only, a base class is neither annotated nor otherwise in scope, soreportEnvironmentRuleswasfalsefor it.TransitiveCallChainAnalyzerseeded its BFS fromtaskType.GetMembers(), which returns declared members. A base-declaredExecute()was never a seed, andFindTaskTypesadditionally skips abstract types.This is why the issue's same-class
private statichelper reported but the inherited case did not — analysis stopped at the type boundary, not the method boundary.Changes Made
SharedAnalyzerHelpers— addedIsMultiThreadable,CollectMultiThreadableBaseTypes(walks the base chain of every annotated task in the compilation), andEnumerateTypes/EnumerateNestedTypes.MultiThreadableTaskAnalyzer— computes that set once per compilation viaLazy<T>and treats membership asanalyzeAsMultiThreadable, so the direct rules fire on inherited code. Cost per symbol callback is oneImmutableHashSet.Contains.TransitiveCallChainAnalyzer— seeds the BFS from each task type and its source-declared base chain, deduplicated so a base shared by several tasks is analyzed once rather than once per derived task.src/TaskAnalyzer/README.mdgains an "Inherited Code" subsection and a scope-table row; the MT-migration skill no longer documents this as a permanent blind spot.Diagnostics are reported at the declaration site in the base, which is where the offending code lives.
Two subtleties:
type.BaseTypereturns the constructed symbol (Base<string>) while symbol callbacks use the definition (Base<T>), so both walks normalize with.OriginalDefinition; and the walk stops at types with noDeclaringSyntaxReferences, since a referenced assembly can never derive from a source type.Testing
Nine tests covering unannotated base, grandparent, generic base, non-
ITaskbase, shared base reported once, and negative cases for a plain task's base. The seven positive tests were verified to fail with the product change reverted.Rebuilt
src/Taskswith-p:BuildAnalyzer=true— the configuration the "Linux Core Multithreaded Mode" job uses — before and after.0001/0002/0003/0006/0007are unchanged and nothing disappeared;MSBuildTask0005goes 288 → 322. The 34 new lines are 17 distinctGenerateManifestBase.Executechains across two TFMs: an abstractTask, IMultiThreadableTaskbase that was never seeded before, now reporting realFile.Copy/File.Open/File.Deletereachability.MSBuildTask0005is in that project'sWarningsNotAsErrors.Notes
The suggested interim mitigation — an informational diagnostic when the base is outside the compilation — is deliberately not included. Every task derives from metadata
Task/ToolTask, so it would fire on essentially every annotated task, and new diagnostics are a breaking change under this repo's policy. Worth revisiting as opt-in if the cross-assembly case bites in practice; that limitation is now documented rather than silent.#14772 still covers
0006/0007base-class behavior. #14791 (task inputs flowing throughIFileSystem/ICommandFactoryabstractions) is untouched — that one needs a different rule shape, not a scope fix.