Skip to content
29 changes: 16 additions & 13 deletions src/Build.UnitTests/Evaluation/Expander_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3400,22 +3400,25 @@ public void PropertyFunctionStaticMethodIntrinsicMaths()

double expectedResult = 9223372036854775807D + 20D;
Assert.Equal(expectedResult.ToString(), result);
}

result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);

Assert.Equal((40 | 2).ToString(), result);

result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);

Assert.Equal((42 & 2).ToString(), result);

result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);

Assert.Equal((213 ^ 255).ToString(), result);
/// <summary>
/// Expand intrinsic property functions that call a bit operator
/// </summary>
[Fact]
public void PropertyFunctionStaticMethodIntrinsicBitOperations()
{
PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>();

result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);
Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg, FileSystems.Default);

Assert.Equal((~-43).ToString(), result);
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((40 | 2).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((42 & 2).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((213 ^ 255).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((~-43).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::LeftShift(1, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((1 << 2).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShift(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >> 2).ToString());
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShiftUnsigned(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >>> 2).ToString());
}

/// <summary>
Expand Down
92 changes: 88 additions & 4 deletions src/Build/Evaluation/Expander.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3887,6 +3887,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Unescape), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArg(args, out string arg0))
{
returnVal = IntrinsicFunctions.Unescape(arg0);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.GetPathOfFileAbove), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out string arg0, out string arg1))
Expand All @@ -3899,31 +3907,39 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
{
if (TryGetArgs(args, out double arg0, out double arg1))
{
returnVal = arg0 + arg1;
returnVal = IntrinsicFunctions.Add(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Subtract), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out double arg0, out double arg1))
{
returnVal = arg0 - arg1;
returnVal = IntrinsicFunctions.Subtract(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Multiply), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out double arg0, out double arg1))
{
returnVal = arg0 * arg1;
returnVal = IntrinsicFunctions.Multiply(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Divide), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out double arg0, out double arg1))
{
returnVal = arg0 / arg1;
returnVal = IntrinsicFunctions.Divide(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Modulo), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out double arg0, out double arg1))
{
returnVal = IntrinsicFunctions.Modulo(arg0, arg1);
return true;
}
}
Expand Down Expand Up @@ -4113,6 +4129,62 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseOr), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.BitwiseOr(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseAnd), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.BitwiseAnd(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseXor), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.BitwiseXor(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseNot), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0))
{
returnVal = IntrinsicFunctions.BitwiseNot(arg0);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.LeftShift), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.LeftShift(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShift), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.RightShift(arg0, arg1);
return true;
}
}
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShiftUnsigned), StringComparison.OrdinalIgnoreCase))
{
if (TryGetArgs(args, out int arg0, out int arg1))
{
returnVal = IntrinsicFunctions.RightShiftUnsigned(arg0, arg1);
return true;
}
}
}
else if (_receiverType == typeof(Path))
{
Expand Down Expand Up @@ -4489,6 +4561,18 @@ private static bool TryGetArgs(object[] args, out string arg0, out StringCompari
return Enum.TryParse(comparisonTypeName, out arg1);
}

private static bool TryGetArgs(object[] args, out int arg0)
{
arg0 = 0;

if (args.Length != 1)
{
return false;
}

return TryConvertToInt(args[0], out arg0);
}

private static bool TryGetArgs(object[] args, out int arg0, out int arg1)
{
arg0 = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/Build/Evaluation/IntrinsicFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ internal static int BitwiseNot(int first)
return ~first;
}

internal static int LeftShift(int operand, int count)
{
return operand << count;
}

internal static int RightShift(int operand, int count)
{
return operand >> count;
}

internal static int RightShiftUnsigned(int operand, int count)
{
return operand >>> count;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware this existed. Always nice to learn something new!

}

/// <summary>
/// Get the value of the registry key and value, default value is null
/// </summary>
Expand Down