Skip to content

Commit dea75d2

Browse files
authored
Change throwaway parameter to include out and add test (#10438)
* Merge * Change throwaway parameter to include out and add test * build * Update src/Build/Evaluation/Expander.cs
1 parent eacead3 commit dea75d2

File tree

16 files changed

+170
-2
lines changed

16 files changed

+170
-2
lines changed

src/Build.UnitTests/Evaluation/Expander_Tests.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,55 @@ public void StaticMethodErrorMessageHaveMethodName1()
12921292

12931293
Assert.Fail();
12941294
}
1295+
1296+
[Fact]
1297+
public void StaticMethodWithThrowawayParameterSupported()
1298+
{
1299+
MockLogger logger = Helpers.BuildProjectWithNewOMExpectSuccess(@"
1300+
<Project>
1301+
<PropertyGroup>
1302+
<MyProperty>Value is $([System.Int32]::TryParse(""3"", out _))</MyProperty>
1303+
</PropertyGroup>
1304+
<Target Name='Build'>
1305+
<Message Text='$(MyProperty)' />
1306+
</Target>
1307+
</Project>");
1308+
1309+
logger.FullLog.ShouldContain("Value is True");
1310+
}
1311+
1312+
[Fact]
1313+
public void StaticMethodWithThrowawayParameterSupported2()
1314+
{
1315+
MockLogger logger = Helpers.BuildProjectWithNewOMExpectSuccess(@"
1316+
<Project>
1317+
<PropertyGroup>
1318+
<MyProperty>Value is $([System.Int32]::TryParse(""notANumber"", out _))</MyProperty>
1319+
</PropertyGroup>
1320+
<Target Name='Build'>
1321+
<Message Text='$(MyProperty)' />
1322+
</Target>
1323+
</Project>");
1324+
1325+
logger.FullLog.ShouldContain("Value is False");
1326+
}
1327+
1328+
[Fact]
1329+
public void StaticMethodWithUnderscoreNotConfusedWithThrowaway()
1330+
{
1331+
MockLogger logger = Helpers.BuildProjectWithNewOMExpectSuccess(@"
1332+
<Project>
1333+
<PropertyGroup>
1334+
<MyProperty>Value is $([System.String]::Join('_', 'asdf', 'jkl'))</MyProperty>
1335+
</PropertyGroup>
1336+
<Target Name='Build'>
1337+
<Message Text='$(MyProperty)' />
1338+
</Target>
1339+
</Project>");
1340+
1341+
logger.FullLog.ShouldContain("Value is asdf_jkl");
1342+
}
1343+
12951344
/// <summary>
12961345
/// Creates a set of complicated item metadata and properties, and items to exercise
12971346
/// the Expander class. The data here contains escaped characters, metadata that

src/Build/Evaluation/Expander.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,8 +3596,17 @@ internal object Execute(object objectInstance, IPropertyProvider<T> properties,
35963596
// otherwise there is the potential of running a function twice!
35973597
try
35983598
{
3599-
// First use InvokeMember using the standard binder - this will match and coerce as needed
3600-
functionResult = _receiverType.InvokeMember(_methodMethodName, _bindingFlags, Type.DefaultBinder, objectInstance, args, CultureInfo.InvariantCulture);
3599+
// If there are any out parameters, try to figure out their type and create defaults for them as appropriate before calling the method.
3600+
if (args.Any(a => "out _".Equals(a)))
3601+
{
3602+
IEnumerable<MethodInfo> methods = _receiverType.GetMethods(_bindingFlags).Where(m => m.Name.Equals(_methodMethodName) && m.GetParameters().Length == args.Length);
3603+
functionResult = GetMethodResult(objectInstance, methods, args, 0);
3604+
}
3605+
else
3606+
{
3607+
// If there are no out parameters, use InvokeMember using the standard binder - this will match and coerce as needed
3608+
functionResult = _receiverType.InvokeMember(_methodMethodName, _bindingFlags, Type.DefaultBinder, objectInstance, args, CultureInfo.InvariantCulture);
3609+
}
36013610
}
36023611
// If we're invoking a method, then there are deeper attempts that can be made to invoke the method.
36033612
// If not, we were asked to get a property or field but found that we cannot locate it. No further argument coercion is possible, so throw.
@@ -3693,6 +3702,48 @@ private bool TryExecuteWellKnownFunctionWithPropertiesParam(IPropertyProvider<T>
36933702
return false;
36943703
}
36953704

3705+
private object GetMethodResult(object objectInstance, IEnumerable<MethodInfo> methods, object[] args, int index)
3706+
{
3707+
for (int i = index; i < args.Length; i++)
3708+
{
3709+
if (args[i].Equals("out _"))
3710+
{
3711+
object toReturn = null;
3712+
foreach (MethodInfo method in methods)
3713+
{
3714+
Type t = method.GetParameters()[i].ParameterType;
3715+
args[i] = t.IsValueType ? Activator.CreateInstance(t) : null;
3716+
object currentReturnValue = GetMethodResult(objectInstance, methods, args, i + 1);
3717+
if (currentReturnValue is not null)
3718+
{
3719+
if (toReturn is null)
3720+
{
3721+
toReturn = currentReturnValue;
3722+
}
3723+
else if (!toReturn.Equals(currentReturnValue))
3724+
{
3725+
// There were multiple methods that seemed viable and gave different results. We can't differentiate between them so throw.
3726+
ErrorUtilities.ThrowArgument("CouldNotDifferentiateBetweenCompatibleMethods", _methodMethodName, args.Length);
3727+
return null;
3728+
}
3729+
}
3730+
}
3731+
3732+
return toReturn;
3733+
}
3734+
}
3735+
3736+
try
3737+
{
3738+
return _receiverType.InvokeMember(_methodMethodName, _bindingFlags, Type.DefaultBinder, objectInstance, args, CultureInfo.InvariantCulture) ?? "null";
3739+
}
3740+
catch (Exception)
3741+
{
3742+
// This isn't a viable option, but perhaps another set of parameters will work.
3743+
return null;
3744+
}
3745+
}
3746+
36963747
/// <summary>
36973748
/// Shortcut to avoid calling into binding if we recognize some most common functions.
36983749
/// Binding is expensive and throws first-chance MissingMethodExceptions, which is

src/Build/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@
604604
LOCALIZATION: "{0}" is the expression that was bad. "{1}" is a message from an FX exception that describes why the expression is bad.
605605
</comment>
606606
</data>
607+
<data name="CouldNotDifferentiateBetweenCompatibleMethods">
608+
<value>Found multiple overloads for method "{0}" with {1} parameter(s). That is currently not supported.</value>
609+
</data>
607610
<data name="InvalidFunctionPropertyExpression" xml:space="preserve">
608611
<value>MSB4184: The expression "{0}" cannot be evaluated. {1}</value>
609612
<comment>{StrBegin="MSB4184: "}

src/Build/Resources/xlf/Strings.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.fr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.it.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.ja.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Build/Resources/xlf/Strings.ko.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)