diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs
index c39c1c358aa..095d7515200 100644
--- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs
+++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs
@@ -5207,5 +5207,58 @@ 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();
+ }
+
+ ///
+ /// 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();
+ }
}
}
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)