diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index ca2a731a82d..11a505c2fd4 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -1118,6 +1118,37 @@ public void HasMetadata() logger.AssertLogContains("[One|Three|Four]"); } + + /// + /// Filter items by WithoutMetadataValue function + /// + [Fact] + public void WithoutMetadataValue() + { + MockLogger logger = Helpers.BuildProjectWithNewOMExpectSuccess(""" + + + <_Item Include="One"> + true + + <_Item Include="Two"> + false + + <_Item Include="Three"> + + + <_Item Include="Four"> + + + + + + + + """); + + logger.AssertLogContains("[Two|Three|Four]"); + } [Fact] public void DirectItemMetadataReferenceShouldBeCaseInsensitive() { diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index d0c6ea7f0fe..177dfd9f5b3 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -2583,12 +2583,9 @@ internal static IEnumerable> Metadata(Expander expander, I { metadataValue = item.Value.GetMetadataValueEscaped(metadataName); } - catch (ArgumentException ex) // Blank metadata name - { - ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); - } - catch (InvalidOperationException ex) + catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { + // Blank metadata name ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); } @@ -2788,12 +2785,9 @@ internal static IEnumerable> HasMetadata(Expander expander { metadataValue = item.Value.GetMetadataValueEscaped(metadataName); } - catch (ArgumentException ex) // Blank metadata name - { - ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); - } - catch (InvalidOperationException ex) + catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { + // Blank metadata name ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); } @@ -2826,16 +2820,46 @@ internal static IEnumerable> WithMetadataValue(Expander ex { metadataValue = item.Value.GetMetadataValueEscaped(metadataName); } - catch (ArgumentException ex) // Blank metadata name + catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { + // Blank metadata name ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); } - catch (InvalidOperationException ex) + + if (metadataValue != null && String.Equals(metadataValue, metadataValueToFind, StringComparison.OrdinalIgnoreCase)) + { + // return a result through the enumerator + yield return new Pair(item.Key, item.Value); + } + } + } + + /// + /// Intrinsic function that returns those items don't have the given metadata value + /// Using a case insensitive comparison. + /// + internal static IEnumerable> WithoutMetadataValue(Expander expander, IElementLocation elementLocation, bool includeNullEntries, string functionName, IEnumerable> itemsOfType, string[] arguments) + { + ProjectErrorUtilities.VerifyThrowInvalidProject(arguments?.Length == 2, elementLocation, "InvalidItemFunctionSyntax", functionName, arguments == null ? 0 : arguments.Length); + + string metadataName = arguments[0]; + string metadataValueToFind = arguments[1]; + + foreach (Pair item in itemsOfType) + { + string metadataValue = null; + + try + { + metadataValue = item.Value.GetMetadataValueEscaped(metadataName); + } + catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { + // Blank metadata name ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); } - if (metadataValue != null && String.Equals(metadataValue, metadataValueToFind, StringComparison.OrdinalIgnoreCase)) + if (!String.Equals(metadataValue, metadataValueToFind, StringComparison.OrdinalIgnoreCase)) { // return a result through the enumerator yield return new Pair(item.Key, item.Value); @@ -2865,12 +2889,9 @@ internal static IEnumerable> AnyHaveMetadataValue(Expander { metadataValue = item.Value.GetMetadataValueEscaped(metadataName); } - catch (ArgumentException ex) // Blank metadata name - { - ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); - } - catch (InvalidOperationException ex) + catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { + // Blank metadata name ProjectErrorUtilities.ThrowInvalidProject(elementLocation, "CannotEvaluateItemMetadata", metadataName, ex.Message); }