From a86064a4304dfdbdf3f900a52f58ae36ab707a73 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Tue, 28 Apr 2026 07:58:48 +0200 Subject: [PATCH] Migrate ResolveCodeAnalysisRuleSet to multithreaded execution Adds [MSBuildMultiThreadableTask] and IMultiThreadableTask, routing ruleset and include-directory path resolution through TaskEnvironment.GetAbsolutePath so the task no longer depends on process CWD when running under multithreaded mode. Closes #13569. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tasks/ResolveCodeAnalysisRuleSet.cs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Tasks/ResolveCodeAnalysisRuleSet.cs b/src/Tasks/ResolveCodeAnalysisRuleSet.cs index 8c1f481d630..19ba3cda53c 100644 --- a/src/Tasks/ResolveCodeAnalysisRuleSet.cs +++ b/src/Tasks/ResolveCodeAnalysisRuleSet.cs @@ -13,10 +13,16 @@ namespace Microsoft.Build.Tasks /// Determines which file, if any, to be used as the code analysis rule set based /// on the supplied code analysis properties. /// - public sealed class ResolveCodeAnalysisRuleSet : TaskExtension + [MSBuildMultiThreadableTask] + public sealed class ResolveCodeAnalysisRuleSet : TaskExtension, IMultiThreadableTask { #region Properties + /// + /// Gets or sets the task execution environment for thread-safe path resolution. + /// + public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; + /// /// The desired code analysis rule set file. May be a simple name, relative /// path, or full path. @@ -84,7 +90,8 @@ private string GetResolvedRuleSetPath() if (!string.IsNullOrEmpty(MSBuildProjectDirectory)) { string fullName = Path.Combine(MSBuildProjectDirectory, CodeAnalysisRuleSet); - if (FileSystems.Default.FileExists(fullName)) + AbsolutePath absolute = TaskEnvironment.GetAbsolutePath(fullName); + if (FileSystems.Default.FileExists(absolute)) { return CodeAnalysisRuleSet; } @@ -96,7 +103,8 @@ private string GetResolvedRuleSetPath() foreach (string directory in CodeAnalysisRuleSetDirectories) { string fullName = Path.Combine(directory, CodeAnalysisRuleSet); - if (FileSystems.Default.FileExists(fullName)) + AbsolutePath absolute = TaskEnvironment.GetAbsolutePath(fullName); + if (FileSystems.Default.FileExists(absolute)) { return fullName; } @@ -109,16 +117,21 @@ private string GetResolvedRuleSetPath() if (!string.IsNullOrEmpty(MSBuildProjectDirectory)) { string fullName = Path.Combine(MSBuildProjectDirectory, CodeAnalysisRuleSet); - if (FileSystems.Default.FileExists(fullName)) + AbsolutePath absolute = TaskEnvironment.GetAbsolutePath(fullName); + if (FileSystems.Default.FileExists(absolute)) { return CodeAnalysisRuleSet; } } } - else if (FileSystems.Default.FileExists(CodeAnalysisRuleSet)) + else { // This is a full path. - return CodeAnalysisRuleSet; + AbsolutePath absolute = TaskEnvironment.GetAbsolutePath(CodeAnalysisRuleSet); + if (FileSystems.Default.FileExists(absolute)) + { + return CodeAnalysisRuleSet; + } } // We can't resolve the rule set to any existing file.