From f6b122d3d95542a53622bd1c8858c20ddd68c628 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:00:59 +0000 Subject: [PATCH 1/3] Initial plan From 79257ce9d494c66829b3cbf7238a05203238bbbc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:16:39 +0000 Subject: [PATCH 2/3] Add fast-paths for ToolLocationHelper property functions Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com> --- .../Evaluation/Expander_Tests.cs | 34 +++++++++++++++++++ .../Evaluation/Expander/WellKnownFunctions.cs | 29 ++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index c39c1c358aa..a5c0849b55f 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -5207,5 +5207,39 @@ public void PropertyFunctionRegisterBuildCheck() logger.AllBuildEvents.Count.ShouldBe(1); } } + + /// + /// Test ToolLocationHelper.GetPlatformSDKLocation fast path + /// + [Fact] + public void PropertyFunctionToolLocationHelperGetPlatformSDKLocation() + { + PropertyDictionary pg = new PropertyDictionary(); + + Expander expander = new Expander(pg, FileSystems.Default); + + // This should use the fast path and not throw even if the SDK doesn't exist + string result = expander.ExpandIntoStringLeaveEscaped("$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKLocation('Windows', '10.0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + + // The result could be empty if SDK is not installed, but it should not throw + result.ShouldNotBeNull(); + } + + /// + /// Test ToolLocationHelper.GetPlatformSDKDisplayName fast path + /// + [Fact] + public void PropertyFunctionToolLocationHelperGetPlatformSDKDisplayName() + { + PropertyDictionary pg = new PropertyDictionary(); + + Expander expander = new Expander(pg, FileSystems.Default); + + // This should use the fast path and not throw even if the SDK doesn't exist + string result = expander.ExpandIntoStringLeaveEscaped("$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKDisplayName('Windows', '10.0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + + // The result could be a generated default name if SDK is not installed, but it should not throw + result.ShouldNotBeNull(); + } } } diff --git a/src/Build/Evaluation/Expander/WellKnownFunctions.cs b/src/Build/Evaluation/Expander/WellKnownFunctions.cs index e35c847123f..d0eecaf0a64 100644 --- a/src/Build/Evaluation/Expander/WellKnownFunctions.cs +++ b/src/Build/Evaluation/Expander/WellKnownFunctions.cs @@ -898,6 +898,35 @@ internal static bool TryExecuteWellKnownFunction(string methodName, Type receive } } } + else if (receiverType.FullName == "Microsoft.Build.Utilities.ToolLocationHelper") + { + if (string.Equals(methodName, "GetPlatformSDKLocation", StringComparison.OrdinalIgnoreCase)) + { + if (ParseArgs.TryGetArgs(args, out string? arg0, out string? arg1)) + { + // Use reflection to invoke the method, but avoid the expensive binding process + var method = receiverType.GetMethod("GetPlatformSDKLocation", new[] { typeof(string), typeof(string) }); + if (method != null) + { + returnVal = method.Invoke(null, new object?[] { arg0, arg1 }); + return true; + } + } + } + else if (string.Equals(methodName, "GetPlatformSDKDisplayName", StringComparison.OrdinalIgnoreCase)) + { + if (ParseArgs.TryGetArgs(args, out string? arg0, out string? arg1)) + { + // Use reflection to invoke the method, but avoid the expensive binding process + var method = receiverType.GetMethod("GetPlatformSDKDisplayName", new[] { typeof(string), typeof(string) }); + if (method != null) + { + returnVal = method.Invoke(null, new object?[] { arg0, arg1 }); + return true; + } + } + } + } else if (string.Equals(methodName, nameof(Regex.Replace), StringComparison.OrdinalIgnoreCase) && args.Length == 3) { if (ParseArgs.TryGetArgs(args, out string? arg1, out string? arg2, out string? arg3) && arg1 != null && arg2 != null && arg3 != null) From 29026074b7e3116e940a85d1d934bcca6788a03a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:23:11 +0000 Subject: [PATCH 3/3] Add comprehensive test for ToolLocationHelper fast paths Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com> --- .../Evaluation/Expander_Tests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index a5c0849b55f..095d7515200 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -5241,5 +5241,24 @@ public void PropertyFunctionToolLocationHelperGetPlatformSDKDisplayName() // The result could be a generated default name if SDK is not installed, but it should not throw result.ShouldNotBeNull(); } + + /// + /// Test that both ToolLocationHelper methods work together in the same property expansion + /// + [Fact] + public void PropertyFunctionToolLocationHelperBothMethodsTogether() + { + PropertyDictionary pg = new PropertyDictionary(); + + Expander expander = new Expander(pg, FileSystems.Default); + + // Test both methods in sequence + string result1 = expander.ExpandIntoStringLeaveEscaped("$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKLocation('Windows', '10.0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + string result2 = expander.ExpandIntoStringLeaveEscaped("$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKDisplayName('Windows', '10.0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + + // Both should complete without throwing + result1.ShouldNotBeNull(); + result2.ShouldNotBeNull(); + } } }