/// <summary> /// BuildItemGroup element is provided /// </summary> internal BuildItemGroupXml(XmlElement element) { ErrorUtilities.VerifyThrowNoAssert(element != null, "Need a valid XML node."); ProjectXmlUtilities.VerifyThrowElementName(element, XMakeElements.itemGroup); this.element = element; this.conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(element, true /*no other attributes allowed*/); }
/// <summary> /// Read in and validate an <ItemDefinitionGroup> element and all its children. /// This is currently only called from ItemDefinitionLibrary. Projects don't know about it. /// </summary> internal BuildItemDefinitionGroupXml(XmlElement element, Project parentProject) { ProjectXmlUtilities.VerifyThrowElementName(element, XMakeElements.itemDefinitionGroup); ProjectXmlUtilities.VerifyThrowProjectValidNamespace(element); this.element = element; this.parentProject = parentProject; this.conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(element, /* sole attribute */ true); this.condition = ProjectXmlUtilities.GetAttributeValue(conditionAttribute); // Currently, don't bother validating the children until evaluation time }
/// <summary> /// Constructor for the Choose object. Parses the contents of the Choose /// and sets up list of When blocks /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentProject"></param> /// <param name="parentGroupingCollection"></param> /// <param name="chooseElement"></param> /// <param name="importedFromAnotherProject"></param> /// <param name="nestingDepth">stack overflow guard</param> internal Choose ( Project parentProject, GroupingCollection parentGroupingCollection, XmlElement chooseElement, bool importedFromAnotherProject, int nestingDepth ) { whenClauseList = new ArrayList(); error.VerifyThrow(chooseElement != null, "Need valid <Choose> element."); // Make sure this really is the <Choose> node. ProjectXmlUtilities.VerifyThrowElementName(chooseElement, XMakeElements.choose); // Stack overflow guard. The only way in the MSBuild file format that MSBuild elements can be // legitimately nested without limit is the <Choose> construct. So, enforce a nesting limit // to avoid blowing our stack. nestingDepth++; ProjectErrorUtilities.VerifyThrowInvalidProject(nestingDepth <= maximumChooseNesting, chooseElement, "ChooseOverflow", maximumChooseNesting); this.importedFromAnotherProject = importedFromAnotherProject; // This <Choose> is coming from an existing XML element, so // walk through all the attributes and child elements, creating the // necessary When objects. // No attributes on the <Choose> element, so don't allow any. ProjectXmlUtilities.VerifyThrowProjectNoAttributes(chooseElement); bool foundOtherwise = false; // Loop through the child nodes of the <Choose> element. foreach (XmlNode chooseChildNode in chooseElement) { switch (chooseChildNode.NodeType) { // Handle XML comments under the <PropertyGroup> node (just ignore them). case XmlNodeType.Comment: // fall through case XmlNodeType.Whitespace: // ignore whitespace break; case XmlNodeType.Element: // The only two types of child nodes that a <Choose> element can contain // is are <When> elements and zero or one <Otherwise> elements. ProjectXmlUtilities.VerifyThrowProjectValidNamespace((XmlElement)chooseChildNode); if (chooseChildNode.Name == XMakeElements.when) { // don't allow <When> to follow <Otherwise> ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "WhenNotAllowedAfterOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessWhen, nestingDepth); this.whenClauseList.Add(newWhen); } else if (chooseChildNode.Name == XMakeElements.otherwise) { ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "MultipleOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessOtherwise, nestingDepth); otherwiseClause = newWhen; foundOtherwise = true; } else { ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); } break; default: // Unrecognized child element. ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject(this.whenClauseList.Count != 0, chooseElement, "ChooseMustContainWhen"); }
/// <summary> /// Internal constructor /// </summary> /// <param name="importElement"></param> /// <param name="isImported"></param> /// <owner>LukaszG</owner> internal Import(XmlElement importElement, Project parentProject, bool isImported) { this.importedFromAnotherProject = isImported; // Make sure the <Import> node has been given to us. ErrorUtilities.VerifyThrow(importElement != null, "Need an XML node representing the <Import> element."); this.importElement = importElement; // Make sure we have a valid parent Project ErrorUtilities.VerifyThrow(parentProject != null, "Need a parent Project object to instantiate an Import."); this.parentProject = parentProject; // Make sure this really is the <Import> node. ProjectXmlUtilities.VerifyThrowElementName(importElement, XMakeElements.import); // Loop through the list of attributes on the <Import> element. foreach (XmlAttribute importAttribute in importElement.Attributes) { switch (importAttribute.Name) { // The "project" attribute points us at the project file to import. case XMakeAttributes.project: // Just store the attribute value at this point. We want to make sure that we evaluate any // Condition attribute before looking at the Project attribute - if the Condition is going to be false, // it's legitimate for the value of the Project attribute to be completely invalid. // For example, <Import Project="$(A)" Condition="$(A)!=''"/> should not cause an error // that the Project attribute is empty. this.projectPathAttribute = importAttribute; break; // If the "condition" attribute is present, then it must evaluate to "true". case XMakeAttributes.condition: this.conditionAttribute = importAttribute; break; // We've come across an attribute in the <Import> element that we // don't recognize. Fail due to invalid project file. default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(importAttribute); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject((this.projectPathAttribute != null) && (this.projectPathAttribute.Value.Length != 0), importElement, "MissingRequiredAttribute", XMakeAttributes.project, XMakeElements.import); // Make sure this node has no children. Our schema doesn't support having // children beneath the <Import> element. if (importElement.HasChildNodes) { // Don't put the "if" condition inside the first parameter to // VerifyThrow..., because we'll get null reference exceptions, // since the parameter importElement.FirstChild.Name is being // passed in regardless of whether the condition holds true or not. ProjectXmlUtilities.ThrowProjectInvalidChildElement(importElement.FirstChild); } }
/// <summary> /// Initializes a persisted target from an existing <Target> element which exists either in the main parent project /// file or one of the imported files. /// </summary> /// <param name="targetElement"></param> /// <param name="project"></param> /// <param name="importedFromAnotherProject"></param> internal Target ( XmlElement targetElement, Project project, bool importedFromAnotherProject ) { // Make sure a valid node has been given to us. error.VerifyThrow(targetElement != null, "Need a valid XML node."); // Make sure this really is the <target> node. ProjectXmlUtilities.VerifyThrowElementName(targetElement, XMakeElements.target); this.targetElement = targetElement; this.parentProject = project; this.parentEngine = project.ParentEngine; this.conditionAttribute = null; this.taskElementList = null; this.importedFromAnotherProject = importedFromAnotherProject; this.buildState = BuildState.NotStarted; this.id = project.ParentEngine.GetNextTargetId(); // The target name and target dependendencies (dependencies on other // targets) are specified as attributes of the <target> element. XmlAttribute returnsAttribute = null; // Loop through all the attributes on the <target> element. foreach (XmlAttribute targetAttribute in targetElement.Attributes) { switch (targetAttribute.Name) { // Process the "condition" attribute. case XMakeAttributes.condition: this.conditionAttribute = targetAttribute; break; // Process the "name" attribute. case XMakeAttributes.name: this.targetName = EscapingUtilities.UnescapeAll(targetAttribute.Value); // Target names cannot contain MSBuild special characters, embedded properties, // or item lists. int indexOfSpecialCharacter = this.targetName.IndexOfAny(XMakeElements.illegalTargetNameCharacters); if (indexOfSpecialCharacter >= 0) { ProjectErrorUtilities.VerifyThrowInvalidProject(false, targetAttribute, "NameInvalid", targetName, targetName[indexOfSpecialCharacter]); } break; // Process the "dependsOnTargets" attribute. case XMakeAttributes.dependsOnTargets: this.dependsOnTargetsAttribute = targetAttribute; break; case XMakeAttributes.inputs: this.inputsAttribute = targetAttribute; recalculateBatchableParameters = true; break; case XMakeAttributes.outputs: this.outputsAttribute = targetAttribute; recalculateBatchableParameters = true; break; // This is only recognized by the new OM: // so that the compat tests keep passing, // ignore it. case XMakeAttributes.keepDuplicateOutputs: break; // This is only recognized by the new OM: // so that the compat tests keep passing, // ignore it. case XMakeAttributes.returns: returnsAttribute = targetAttribute; break; // These are only recognized by the new OM: // while the solution wrapper generator is using // the old OM to parse projects for dependencies, // we must make sure to not fail for these case XMakeAttributes.beforeTargets: case XMakeAttributes.afterTargets: break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(targetAttribute); break; } } // Hack to help the 3.5 engine at least pretend to still be able to build on top of // the 4.0 targets. In cases where there is no Outputs attribute, just a Returns attribute, // we can approximate the correct behaviour by making the Returns attribute our "outputs" attribute. if (this.outputsAttribute == null && returnsAttribute != null) { this.outputsAttribute = returnsAttribute; recalculateBatchableParameters = true; } // It's considered an error if a target does not have a name. ProjectErrorUtilities.VerifyThrowInvalidProject((targetName != null) && (targetName.Length > 0), targetElement, "MissingRequiredAttribute", XMakeAttributes.name, XMakeElements.target); this.taskElementList = new ArrayList(); // Process each of the child nodes beneath the <Target>. XmlElement anyOnErrorElement = null; List <XmlElement> childElements = ProjectXmlUtilities.GetValidChildElements(targetElement); foreach (XmlElement childElement in childElements) { bool onErrorOutOfOrder = false; switch (childElement.Name) { case XMakeElements.onError: anyOnErrorElement = childElement; break; default: onErrorOutOfOrder = (anyOnErrorElement != null); this.taskElementList.Add(new BuildTask(childElement, this, this.importedFromAnotherProject)); break; } // Check for out-of-order OnError ProjectErrorUtilities.VerifyThrowInvalidProject(!onErrorOutOfOrder, anyOnErrorElement, "NodeMustBeLastUnderElement", XMakeElements.onError, XMakeElements.target, childElement.Name); } }