Exemple #1
0
        /// <summary>
        ///     Does the location represent a place where an element can be created or replaced by a completion?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="replaceElement">
        ///     The element (if any) that will be replaced by the completion.
        /// </param>
        /// <param name="parentPath">
        ///     If specified, the location's node's parent must have the specified <see cref="XSPath"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element that can be replaced by completion; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks>
        ///     We can replace "&lt;&gt;" and "&lt;&lt;Element /&gt;".
        /// </remarks>
        public static bool CanCompleteElement(this XmlLocation location, out XSElement replaceElement, XSPath parentPath = null)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            replaceElement = null;

            // Simplest case - we're on whitespace so we can simply insert an element without replacing anything.
            if (location.IsWhitespace(out XSWhitespace whitespace) && (parentPath == null || whitespace.HasParentPath(parentPath)))
            {
                return(true);
            }

            XSElement element;

            if (!location.IsElement(out element))
            {
                return(false);
            }

            if (location.IsElementBetweenAttributes())
            {
                return(false);
            }

            // Check if we need to perform a substition of the element to be replaced (the common case is simply replacing an existing element or partial element).
            if (element.IsValid)
            {
                // Do we have an invalid parent (e.g. "<<Foo />", which yields invalid element named "" with child element named "Foo")?
                bool isParentValid = element.ParentElement?.IsValid ?? true;
                if (!isParentValid)
                {
                    // We can't handle the case where the parent isn't on the same line as the child (since that's not the case outlined above).
                    if (element.ParentElement.Start.LineNumber != location.Node.Start.LineNumber)
                    {
                        return(false);
                    }

                    // But we *can* handle this case by targeting the "parent" element (since that's the element we're actually after anyway).
                    if (location.Node.Start.ColumnNumber - element.ParentElement.Start.ColumnNumber == 1)
                    {
                        element = element.ParentElement;
                    }
                }
            }

            if (parentPath != null && !element.HasParentPath(parentPath))
            {
                return(false);
            }

            replaceElement = element;

            return(true);
        }
        /// <summary>
        ///     Create new <see cref="XSElementText"/>.
        /// </summary>
        /// <param name="textNode">
        ///     The <see cref="XmlTextSyntax"/> represented by the <see cref="XSElementText"/>.
        /// </param>
        /// <param name="range">
        ///     The <see cref="Range"/>, within the source text, spanned by the text.
        /// </param>
        /// <param name="element">
        ///     The element whose content includes the text.
        /// </param>
        public XSElementText(XmlTextSyntax textNode, Range range, XSElement element)
            : base(textNode, range)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            Element = element;
            _path   = Element.Path + Name;
        }
Exemple #3
0
        /// <summary>
        ///     Create a new <see cref="XSElement"/>.
        /// </summary>
        /// <param name="element">
        ///     The <see cref="XmlElementSyntaxBase"/> represented by the <see cref="XSElement"/>.
        /// </param>
        /// <param name="range">
        ///     The range, within the source text, spanned by the element.
        /// </param>
        /// <param name="nameRange">
        ///     The range, within the source text, spanned by the element's name.
        /// </param>
        /// <param name="attributesRange">
        ///     The range, within the source text, spanned by the element's attributes.
        /// </param>
        /// <param name="parent">
        ///     The <see cref="XSElement"/>'s parent element (if any).
        /// </param>
        protected XSElement(XmlElementSyntaxBase element, Range range, Range nameRange, Range attributesRange, XSElement parent)
            : base(element, range)
        {
            NameRange       = nameRange;
            AttributesRange = attributesRange;
            ParentElement   = parent;

            XSPath parentPath = parent?.Path ?? XSPath.Root;

            _path = parentPath + Name;
        }
Exemple #4
0
            /// <summary>
            ///     Push an <see cref="XSElement"/> onto the stack.
            /// </summary>
            /// <param name="element">
            ///     The <see cref="XSElement"/> being processed.
            /// </param>
            /// <returns>
            ///     The <see cref="XSElement"/>.
            /// </returns>
            XSElement PushElement(XSElement element)
            {
                if (element == null)
                {
                    throw new ArgumentNullException(nameof(element));
                }

                _elementStack.Push(element);

                DiscoveredNodes.Add(element);

                return(element);
            }
Exemple #5
0
        /// <summary>
        ///     Create a new <see cref="XSAttribute"/>.
        /// </summary>
        /// <param name="attribute">
        ///     The <see cref="XmlAttributeSyntax"/> represented by the <see cref="XSAttribute"/>.
        /// </param>
        /// <param name="element">
        ///     The element that contains the attribute.
        /// </param>
        /// <param name="attributeRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the attribute.
        /// </param>
        /// <param name="nameRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the attribute's name.
        /// </param>
        /// <param name="valueRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the attribute's value.
        /// </param>
        public XSAttribute(XmlAttributeSyntax attribute, XSElement element, Range attributeRange, Range nameRange, Range valueRange)
            : base(attribute, attributeRange)
        {
            if (element == null)
            {
                throw new ArgumentNullException(nameof(element));
            }

            NameRange  = nameRange;
            ValueRange = valueRange;
            Element    = element;
            _path      = Element.Path + Name;
        }
Exemple #6
0
        /// <summary>
        ///     Create new <see cref="XSWhitespace"/>.
        /// </summary>
        /// <param name="range">
        ///     The <see cref="Range"/>, within the source text, spanned by the whitespace.
        /// </param>
        /// <param name="parent">
        ///     The <see cref="XSElement"/> that contains the whitespace.
        /// </param>
        public XSWhitespace(Range range, XSElement parent)
            : base(range)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            ParentElement = parent;

            XSPath parentPath = parent?.Path ?? XSPath.Root;

            _path = parentPath + Name;
        }
Exemple #7
0
        /// <summary>
        ///     Does the location represent an element's attributes range (but not a specific attribute)?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="element">
        ///     Receives the <see cref="XSElement"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementBetweenAttributes(this XmlLocation location, out XSElement element)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            if (location.IsElementBetweenAttributes())
            {
                element = (XSElement)location.Node;

                return(true);
            }
            else
            {
                element = null;

                return(false);
            }
        }
Exemple #8
0
        /// <summary>
        ///     Create a new <see cref="XSElement"/>.
        /// </summary>
        /// <param name="element">
        ///     The <see cref="XmlElementSyntaxBase"/> represented by the <see cref="XSElement"/>.
        /// </param>
        /// <param name="range">
        ///     The range, within the source text, spanned by the element.
        /// </param>
        /// <param name="nameRange">
        ///     The range, within the source text, spanned by the element's name.
        /// </param>
        /// <param name="attributesRange">
        ///     The range, within the source text, spanned by the element's attributes.
        /// </param>
        /// <param name="parent">
        ///     The <see cref="XSElement"/>'s parent element (if any).
        /// </param>
        protected XSElement(XmlElementSyntaxBase element, Range range, Range nameRange, Range attributesRange, XSElement parent)
            : base(element, range)
        {
            if (nameRange == null)
            {
                throw new ArgumentNullException(nameof(nameRange));
            }

            if (nameRange == null)
            {
                throw new ArgumentNullException(nameof(nameRange));
            }

            NameRange       = nameRange;
            AttributesRange = attributesRange;
            ParentElement   = parent;

            XSPath parentPath = parent?.Path ?? XSPath.Root;

            _path = parentPath + Name;
        }
        /// <summary>
        ///     Create a new <see cref="MSBuildProperty"/>.
        /// </summary>
        /// <param name="property">
        ///     The underlying MSBuild <see cref="ProjectProperty"/>.
        /// </param>
        /// <param name="declaringXml">
        ///     The <see cref="ProjectPropertyElement"/> that results in the underlying MSBuild <see cref="ProjectProperty"/>'s current value.
        /// </param>
        /// <param name="propertyElement">
        ///     An <see cref="XSElement"/> representing the property's XML element.
        /// </param>
        public MSBuildProperty(ProjectProperty property, ProjectPropertyElement declaringXml, XSElement propertyElement)
            : base(property, propertyElement)
        {
            if (declaringXml == null)
            {
                throw new ArgumentNullException(nameof(declaringXml));
            }

            DeclaringXml = declaringXml;
        }
Exemple #10
0
        /// <summary>
        ///     Create a new <see cref="MSBuildItemGroup"/>.
        /// </summary>
        /// <param name="items">
        ///     The underlying MSBuild <see cref="ProjectItem"/>s.
        /// </param>
        /// <param name="originatingElement">
        ///     The MSBuild <see cref="ProjectItemElement"/> from where the items originate.
        /// </param>
        /// <param name="itemElement">
        ///     An <see cref="XSElement"/> representing the item's XML element.
        /// </param>
        public MSBuildItemGroup(IReadOnlyList <ProjectItem> items, ProjectItemElement originatingElement, XSElement itemElement)
            : base(items, itemElement)
        {
            if (Items.Count == 0)
            {
                throw new ArgumentException("Must specify at least one ProjectItem.", nameof(items));
            }

            if (originatingElement == null)
            {
                throw new ArgumentNullException(nameof(originatingElement));
            }

            Name = itemElement.Name;
            OriginatingElement = originatingElement;
        }
 /// <summary>
 ///     Create a new <see cref="MSBuildTarget"/>.
 /// </summary>
 /// <param name="target">
 ///     The underlying MSBuild <see cref="ProjectTargetElement"/>.
 /// </param>
 /// <param name="element">
 ///     An <see cref="XSElement"/> representing the target's XML element.
 /// </param>
 public MSBuildTarget(ProjectTargetElement target, XSElement element)
     : base(target, element)
 {
 }
 /// <summary>
 ///     Create a new <see cref="MSBuildProperty"/>.
 /// </summary>
 /// <param name="propertyElement">
 ///     An <see cref="ProjectPropertyElement"/> representing the MSBuild property.
 /// </param>
 /// <param name="declaringElement">
 ///     An <see cref="XSElement"/> representing the property's declaring XML element.
 /// </param>
 public MSBuildUnusedProperty(ProjectPropertyElement propertyElement, XSElement declaringElement)
     : base(propertyElement, declaringElement)
 {
 }
Exemple #13
0
 /// <summary>
 ///     Create a new <see cref="XSInvalidAttribute"/>.
 /// </summary>
 /// <param name="attribute">
 ///     The <see cref="XmlAttributeSyntax"/> represented by the <see cref="XSInvalidAttribute"/>.
 /// </param>
 /// <param name="element">
 ///     The element that contains the attribute.
 /// </param>
 /// <param name="range">
 ///     The <see cref="Range"/>, within the source text, spanned by the attribute.
 /// </param>
 /// <param name="nameRange">
 ///     The <see cref="Range"/>, within the source text, spanned by the attribute's name.
 /// </param>
 /// <param name="valueRange">
 ///     The <see cref="Range"/>, within the source text, spanned by the attribute's value.
 /// </param>
 public XSInvalidAttribute(XmlAttributeSyntax attribute, XSElement element, Range range, Range nameRange, Range valueRange)
     : base(attribute, element, range, nameRange, valueRange)
 {
 }
 /// <summary>
 ///     The range, within the source text, spanned by the node.
 /// </summary>
 /// <param name="element">
 ///     The <see cref="XmlElementSyntax"/> represented by the <see cref="XSElementWithContent"/>.
 /// </param>
 /// <param name="range">
 ///     The <see cref="Range"/>, within the source text, spanned by the element and its content.
 /// </param>
 /// <param name="nameRange">
 ///     The range, within the source text, spanned by the element's name.
 /// </param>
 /// <param name="openingTagRange">
 ///     The <see cref="Range"/>, within the source text, spanned by the element's opening tag.
 /// </param>
 /// <param name="attributesRange">
 ///     The range, within the source text, spanned by the element's attributes.
 /// </param>
 /// <param name="contentRange">
 ///     The <see cref="Range"/>, within the source text, spanned by the element's content.
 /// </param>
 /// <param name="closingTagRange">
 ///     The <see cref="Range"/>, within the source text, spanned by the element's closing tag.
 /// </param>
 /// <param name="parent">
 ///     The <see cref="XSElementWithContent"/>'s parent element (if any).
 /// </param>
 public XSElementWithContent(XmlElementSyntax element, Range range, Range nameRange, Range openingTagRange, Range attributesRange, Range contentRange, Range closingTagRange, XSElement parent)
     : base(element, range, nameRange, attributesRange, parent)
 {
     OpeningTagRange = openingTagRange;
     ContentRange    = contentRange;
     ClosingTagRange = closingTagRange;
 }
 /// <summary>
 ///     Create a new <see cref="XSEmptyElement"/>.
 /// </summary>
 /// <param name="emptyElement">
 ///     The <see cref="XmlEmptyElementSyntax"/> represented by the <see cref="XSEmptyElement"/>.
 /// </param>
 /// <param name="range">
 ///     The <see cref="Range"/>, within the source text, spanned by the node.
 /// </param>
 /// <param name="nameRange">
 ///     The range, within the source text, spanned by the element's name.
 /// </param>
 /// <param name="attributesRange">
 ///     The range, within the source text, spanned by the element's attributes.
 /// </param>
 /// <param name="parent">
 ///     The <see cref="XSEmptyElement"/>'s parent element (if any).
 /// </param>
 public XSEmptyElement(XmlEmptyElementSyntax emptyElement, Range range, Range nameRange, Range attributesRange, XSElement parent)
     : base(emptyElement, range, nameRange, attributesRange, parent)
 {
 }
Exemple #16
0
 /// <summary>
 ///     Create a new <see cref="MSBuildImport"/>.
 /// </summary>
 /// <param name="imports">
 ///     The underlying MSBuild <see cref="ResolvedImport"/>.
 /// </param>
 /// <param name="importElement">
 ///     An <see cref="XSElement"/> representing the import's XML element.
 /// </param>
 public MSBuildImport(IReadOnlyList <ResolvedImport> imports, XSElement importElement)
     : base(imports, importElement)
 {
 }
Exemple #17
0
 /// <summary>
 ///     Create a new <see cref="MSBuildUnresolvedImport"/>.
 /// </summary>
 /// <param name="import">
 ///     The underlying MSBuild <see cref="ProjectImportElement"/>.
 /// </param>
 /// <param name="importElement">
 ///     An <see cref="XSElement"/> representing the import's XML element.
 /// </param>
 public MSBuildUnresolvedImport(ProjectImportElement import, XSElement importElement)
     : base(import, importElement)
 {
 }
        /// <summary>
        ///     The range, within the source text, spanned by the node.
        /// </summary>
        /// <param name="element">
        ///     The <see cref="XmlElementSyntax"/> represented by the <see cref="XSElementWithContent"/>.
        /// </param>
        /// <param name="range">
        ///     The <see cref="Range"/>, within the source text, spanned by the element and its content.
        /// </param>
        /// <param name="nameRange">
        ///     The range, within the source text, spanned by the element's name.
        /// </param>
        /// <param name="openingTagRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the element's opening tag.
        /// </param>
        /// <param name="attributesRange">
        ///     The range, within the source text, spanned by the element's attributes.
        /// </param>
        /// <param name="contentRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the element's content.
        /// </param>
        /// <param name="closingTagRange">
        ///     The <see cref="Range"/>, within the source text, spanned by the element's closing tag.
        /// </param>
        /// <param name="parent">
        ///     The <see cref="XSElementWithContent"/>'s parent element (if any).
        /// </param>
        public XSElementWithContent(XmlElementSyntax element, Range range, Range nameRange, Range openingTagRange, Range attributesRange, Range contentRange, Range closingTagRange, XSElement parent)
            : base(element, range, nameRange, attributesRange, parent)
        {
            if (openingTagRange == null)
            {
                throw new ArgumentNullException(nameof(openingTagRange));
            }

            if (contentRange == null)
            {
                throw new ArgumentNullException(nameof(contentRange));
            }

            if (closingTagRange == null)
            {
                throw new ArgumentNullException(nameof(closingTagRange));
            }

            OpeningTagRange = openingTagRange;
            ContentRange    = contentRange;
            ClosingTagRange = closingTagRange;
        }
Exemple #19
0
        /// <summary>
        ///     Does the location represent a place where an attribute can be created or replaced by a completion?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="element">
        ///     The element whose attribute will be completed.
        /// </param>
        /// <param name="replaceAttribute">
        ///     The attribute (if any) that will be replaced by the completion.
        /// </param>
        /// <param name="needsPadding">
        ///     An <see cref="PaddingType"/> value indicating what sort of padding (if any) is required before / after the attribute.
        /// </param>
        /// <param name="onElementWithPath">
        ///     If specified, the location's element must have the specified path.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element that can be replaced by completion; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanCompleteAttribute(this XmlLocation location, out XSElement element, out XSAttribute replaceAttribute, out PaddingType needsPadding, XSPath onElementWithPath = null)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            replaceAttribute = null;
            needsPadding     = PaddingType.None;

            XSAttribute attribute;

            if (location.IsAttribute(out attribute) && !location.IsValue())
            {
                element = attribute.Element;
                if (location.Position == attribute.Start)
                {
                    // Since we're on an existing attribute, we'll add a new attribute after it.
                    attribute    = null;
                    needsPadding = PaddingType.Trailing;
                }
            }
            else if (location.IsElementBetweenAttributes(out element))
            {
                if (element.Attributes.Count > 0)
                {
                    // Check if we're directly before an attribute.
                    foreach (XSAttribute currentAttribute in element.Attributes)
                    {
                        if (location.Position == currentAttribute.End)
                        {
                            needsPadding = PaddingType.Leading;
                        }
                        else
                        {
                            continue;
                        }

                        break;
                    }
                }
                else if (location.Position == element.NameRange.End) // We're directly after the name.
                {
                    needsPadding = PaddingType.Leading;
                }
            }
            else if (location.IsElement(out element))
            {
                // Check if we're directly after the name.
                if (location.Position != element.NameRange.End)
                {
                    return(false);
                }

                needsPadding = PaddingType.Leading;
            }
            else
            {
                return(false);
            }

            if (onElementWithPath != null && !element.Path.Matches(onElementWithPath))
            {
                return(false);
            }

            replaceAttribute = attribute;

            return(true);
        }
Exemple #20
0
        /// <summary>
        ///     Create a new <see cref="XSInvalidElement"/>.
        /// </summary>
        /// <param name="element">
        ///     The <see cref="XmlElementSyntaxBase"/> represented by the <see cref="XSInvalidElement"/>.
        /// </param>
        /// <param name="range">
        ///     The <see cref="Range"/>, within the source text, spanned by the element.
        /// </param>
        /// <param name="nameRange">
        ///     The range, within the source text, spanned by the element's name.
        /// </param>
        /// <param name="attributesRange">
        ///     The range, within the source text, spanned by the element's attributes.
        /// </param>
        /// <param name="parent">
        ///     The <see cref="XSInvalidElement"/>'s parent element (if any).
        /// </param>
        /// <param name="hasContent">
        ///     Does the <see cref="XSInvalidElement"/> have any content (besides attributes)?
        /// </param>
        public XSInvalidElement(XmlElementSyntaxBase element, Range range, Range nameRange, Range attributesRange, XSElement parent, bool hasContent)
            : base(element, range, nameRange, attributesRange, parent)
        {
            if (parent == null)
            {
                System.Diagnostics.Debugger.Break();
            }

            HasContent = hasContent;
        }