private void ExecuteRemove(ProjectItemGroupTaskItemInstance child, ItemBucket bucket, HashSet <string> matchOnMetadata, MatchOnMetadataOptions matchingOptions)
        {
            ICollection <ProjectItemInstance> group = bucket.Lookup.GetItems(child.ItemType);

            if (group == null)
            {
                // No items of this type to remove
                return;
            }

            List <ProjectItemInstance> itemsToRemove;

            if (matchOnMetadata == null)
            {
                itemsToRemove = FindItemsMatchingSpecification(group, child.Remove, child.RemoveLocation, bucket.Expander);
            }
            else
            {
                itemsToRemove = FindItemsMatchingMetadataSpecification(group, child, bucket.Expander, matchOnMetadata, matchingOptions);
            }

            if (itemsToRemove != null)
            {
                if (LogTaskInputs && !LoggingContext.LoggingService.OnlyLogCriticalEvents && itemsToRemove.Count > 0)
                {
                    ItemGroupLoggingHelper.LogTaskParameter(
                        LoggingContext,
                        TaskParameterMessageKind.RemoveItem,
                        child.ItemType,
                        itemsToRemove,
                        logItemMetadata: true,
                        child.Location);
                }

                bucket.Lookup.RemoveItems(itemsToRemove);
            }
        }
        private void ExecuteAdd(ProjectItemGroupTaskItemInstance child, ItemBucket bucket, ISet <string> keepMetadata, ISet <string> removeMetadata)
        {
            // First, collect up the appropriate metadata collections.  We need the one from the item definition, if any, and
            // the one we are using for this batching bucket.
            ProjectItemDefinitionInstance itemDefinition;

            Project.ItemDefinitions.TryGetValue(child.ItemType, out itemDefinition);

            // The NestedMetadataTable will handle the aggregation of the different metadata collections
            NestedMetadataTable metadataTable         = new NestedMetadataTable(child.ItemType, bucket.Expander.Metadata, itemDefinition);
            IMetadataTable      originalMetadataTable = bucket.Expander.Metadata;

            bucket.Expander.Metadata = metadataTable;

            // Second, expand the item include and exclude, and filter existing metadata as appropriate.
            List <ProjectItemInstance> itemsToAdd = ExpandItemIntoItems(child, bucket.Expander, keepMetadata, removeMetadata);

            // Third, expand the metadata.
            foreach (ProjectItemGroupTaskMetadataInstance metadataInstance in child.Metadata)
            {
                bool condition = ConditionEvaluator.EvaluateCondition
                                 (
                    metadataInstance.Condition,
                    ParserOptions.AllowAll,
                    bucket.Expander,
                    ExpanderOptions.ExpandAll,
                    Project.Directory,
                    metadataInstance.Location,
                    LoggingContext.LoggingService,
                    LoggingContext.BuildEventContext,
                    FileSystems.Default);

                if (condition)
                {
                    string evaluatedValue = bucket.Expander.ExpandIntoStringLeaveEscaped(metadataInstance.Value, ExpanderOptions.ExpandAll, metadataInstance.Location);

                    // This both stores the metadata so we can add it to all the items we just created later, and
                    // exposes this metadata to further metadata evaluations in subsequent loop iterations.
                    metadataTable.SetValue(metadataInstance.Name, evaluatedValue);
                }
            }

            // Finally, copy the added metadata onto the new items.  The set call is additive.
            ProjectItemInstance.SetMetadata(metadataTable.AddedMetadata, itemsToAdd); // Add in one operation for potential copy-on-write

            // Restore the original metadata table.
            bucket.Expander.Metadata = originalMetadataTable;

            // Determine if we should NOT add duplicate entries
            bool keepDuplicates = ConditionEvaluator.EvaluateCondition
                                  (
                child.KeepDuplicates,
                ParserOptions.AllowAll,
                bucket.Expander,
                ExpanderOptions.ExpandAll,
                Project.Directory,
                child.KeepDuplicatesLocation,
                LoggingContext.LoggingService,
                LoggingContext.BuildEventContext,
                FileSystems.Default);

            if (LogTaskInputs && !LoggingContext.LoggingService.OnlyLogCriticalEvents && itemsToAdd?.Count > 0)
            {
                ItemGroupLoggingHelper.LogTaskParameter(
                    LoggingContext,
                    TaskParameterMessageKind.AddItem,
                    child.ItemType,
                    itemsToAdd,
                    logItemMetadata: true,
                    child.Location);
            }

            // Now add the items we created to the lookup.
            bucket.Lookup.AddNewItemsOfItemType(child.ItemType, itemsToAdd, !keepDuplicates); // Add in one operation for potential copy-on-write
        }