| File: Construction\ProjectItemGroupElement.cs | Web Access |
| Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.Build.Collections; using Microsoft.Build.ObjectModelRemoting; using Microsoft.Build.Shared; #nullable disable namespace Microsoft.Build.Construction { /// <summary> /// ProjectItemGroupElement represents the ItemGroup element in the MSBuild project. /// </summary> [DebuggerDisplay("#Items={Count} Condition={Condition} Label={Label}")] public class ProjectItemGroupElement : ProjectElementContainer { /// <summary> /// External projects support /// </summary> internal ProjectItemGroupElement(ProjectItemGroupElementLink link) : base(link) { } /// <summary> /// True if it is known that no child items have wildcards in their /// include. An optimization helping Project.AddItem. /// Only reliable if it is true. /// </summary> private bool _definitelyAreNoChildrenWithWildcards; /// <summary> /// Initialize a parented ProjectItemGroupElement /// </summary> internal ProjectItemGroupElement(XmlElementWithLocation xmlElement, ProjectElementContainer parent, ProjectRootElement containingProject) : base(xmlElement, parent, containingProject) { ArgumentNullException.ThrowIfNull(parent); } /// <summary> /// Initialize an unparented ProjectItemGroupElement /// </summary> private ProjectItemGroupElement(XmlElementWithLocation xmlElement, ProjectRootElement containingProject) : base(xmlElement, null, containingProject) { } /// <summary> /// Get any child items. /// This is a live collection. /// </summary> public ICollection<ProjectItemElement> Items => GetChildrenOfType<ProjectItemElement>(); /// <summary> /// True if it is known that no child items have wildcards in their /// include. An optimization helping Project.AddItem. /// Only reliable if it is true. /// ONLY TO BE CALLED by ProjectItemElement. /// Should be protected+internal. /// </summary> internal bool DefinitelyAreNoChildrenWithWildcards { get { if (Link != null) { return Count == 0; } if (Count == 0) { _definitelyAreNoChildrenWithWildcards = true; } return _definitelyAreNoChildrenWithWildcards; } set => _definitelyAreNoChildrenWithWildcards = value; } /// <summary> /// Convenience method that picks a location based on a heuristic: /// Adds a new item ordered by include. /// </summary> public ProjectItemElement AddItem(string itemType, string include) { return AddItem(itemType, include, null); } /// <summary> /// Convenience method that picks a location based on a heuristic: /// Adds a new item ordered by include. /// Metadata may be null, indicating no metadata. /// </summary> public ProjectItemElement AddItem(string itemType, string include, IEnumerable<KeyValuePair<string, string>> metadata) { ArgumentException.ThrowIfNullOrEmpty(itemType); ArgumentException.ThrowIfNullOrEmpty(include); // If there are no items, or it turns out that there are only items with // item types that sort earlier, then we should go after the last child ProjectElement reference = LastChild; foreach (ProjectItemElement item in Items) { // If it's the same item type, and if (MSBuildNameIgnoreCaseComparer.Default.Equals(itemType, item.ItemType)) { // the include sorts after us, if (String.Compare(include, item.Include, StringComparison.OrdinalIgnoreCase) < 0) { // then insert before it (ie. after the previous sibling) reference = item.PreviousSibling; break; } // Otherwise go to the next item continue; } // If it's an item type that sorts after us, if (String.Compare(itemType, item.ItemType, StringComparison.OrdinalIgnoreCase) < 0) { // then insert before it (ie. after the previous sibling) reference = item.PreviousSibling; break; } } ProjectItemElement newItem = ContainingProject.CreateItemElement(itemType, include); // If reference is null, this will prepend InsertAfterChild(newItem, reference); if (metadata != null) { foreach (KeyValuePair<string, string> metadatum in metadata) { newItem.AddMetadata(metadatum.Key, metadatum.Value); } } return newItem; } /// <inheritdoc /> public override void CopyFrom(ProjectElement element) { base.CopyFrom(element); // clear out caching fields. _definitelyAreNoChildrenWithWildcards = false; } /// <summary> /// Creates an unparented ProjectItemGroupElement, wrapping an unparented XmlElement. /// Caller should then ensure the element is added to the XmlDocument in the appropriate location. /// </summary> internal static ProjectItemGroupElement CreateDisconnected(ProjectRootElement containingProject) { XmlElementWithLocation element = containingProject.CreateElement(XMakeElements.itemGroup); return new ProjectItemGroupElement(element, containingProject); } /// <summary> /// Overridden to verify that the potential parent and siblings /// are acceptable. Throws InvalidOperationException if they are not. /// </summary> internal override void VerifyThrowInvalidOperationAcceptableLocation(ProjectElementContainer parent, ProjectElement previousSibling, ProjectElement nextSibling) { ErrorUtilities.VerifyThrowInvalidOperation(parent is ProjectRootElement || parent is ProjectTargetElement || parent is ProjectWhenElement || parent is ProjectOtherwiseElement, "OM_CannotAcceptParent"); } /// <inheritdoc /> protected override ProjectElement CreateNewInstance(ProjectRootElement owner) { return owner.CreateItemGroupElement(); } } }