Exemplo n.º 1
0
        /// <summary>
        ///     Add an unresolved regular-style import (i.e. condition is false).
        /// </summary>
        /// <param name="import">
        ///     The declaring import element.
        /// </param>
        void AddUnresolvedImport(ProjectImportElement import)
        {
            if (import == null)
            {
                throw new ArgumentNullException(nameof(import));
            }

            Position importStart = import.Location.ToNative();

            XmlLocation importLocation = _projectXmlLocator.Inspect(importStart);

            if (importLocation == null)
            {
                return;
            }

            XSElement importElement;

            if (!importLocation.IsElement(out importElement))
            {
                return;
            }

            Add(
                new MSBuildUnresolvedImport(import, importElement)
                );
        }
        /// <summary>
        ///     Inspect the specified location in the XML.
        /// </summary>
        /// <param name="position">
        ///     The location's position.
        /// </param>
        /// <returns>
        ///     An <see cref="XmlLocation"/> representing the result of the inspection.
        /// </returns>
        public XmlLocation Inspect(Position position)
        {
            // Internally, we always use 1-based indexing because this is what the System.Xml APIs (and I'd rather keep things simple).
            position = position.ToOneBased();

            XSNode nodeAtPosition = FindNode(position);

            if (nodeAtPosition == null)
            {
                return(null);
            }

            // If we're on the (seamless, i.e. overlapping) boundary between 2 nodes, select the next node.
            if (nodeAtPosition.NextSibling != null)
            {
                if (position == nodeAtPosition.Range.End && position == nodeAtPosition.NextSibling.Range.Start)
                {
                    Serilog.Log.Debug("XmlLocator.Inspect moves to next sibling ({NodeKind} @ {NodeRange} -> {NextSiblingKind} @ {NextSiblingRange}).",
                                      nodeAtPosition.Kind,
                                      nodeAtPosition.Range,
                                      nodeAtPosition.NextSibling.Kind,
                                      nodeAtPosition.NextSibling.Range
                                      );

                    nodeAtPosition = nodeAtPosition.NextSibling;
                }
            }

            int absolutePosition = _documentPositions.GetAbsolutePosition(position);

            XmlLocationFlags flags            = ComputeLocationFlags(nodeAtPosition, absolutePosition);
            XmlLocation      inspectionResult = new XmlLocation(position, absolutePosition, nodeAtPosition, flags);

            return(inspectionResult);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Does the location represent a place where an attribute value can be created or replaced by a completion?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="targetAttribute">
        ///     The attribute (if any) whose value will be replaced by the completion.
        /// </param>
        /// <param name="onElementWithPath">
        ///     If specified, attribute's element must have the specified path.
        /// </param>
        /// <param name="forAttributeNamed">
        ///     If specified, the attribute must have one of the specified names.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an attribute whose value can be replaced by a completion; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanCompleteAttributeValue(this XmlLocation location, out XSAttribute targetAttribute, XSPath onElementWithPath = null, params string[] forAttributeNamed)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            targetAttribute = null;

            XSAttribute attribute;

            if (!location.IsAttributeValue(out attribute))
            {
                return(false);
            }

            if (onElementWithPath != null && !attribute.HasParentPath(onElementWithPath))
            {
                return(false);
            }

            if (forAttributeNamed.Length > 0 && Array.IndexOf(forAttributeNamed, attribute.Name) == -1)
            {
                return(false);
            }

            targetAttribute = attribute;

            return(true);
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Add a regular-style import.
        /// </summary>
        /// <param name="resolvedImports">
        ///     The resolved imports resulting from the import declaration.
        /// </param>
        void AddImport(IEnumerable <ResolvedImport> resolvedImports)
        {
            if (resolvedImports == null)
            {
                throw new ArgumentNullException(nameof(resolvedImports));
            }

            var importsByImportingElement = resolvedImports.GroupBy(import => import.ImportingElement);

            foreach (var importsForImportingElement in importsByImportingElement)
            {
                Position importStart = importsForImportingElement.Key.Location.ToNative();

                XmlLocation importLocation = _projectXmlLocator.Inspect(importStart);
                if (importLocation == null)
                {
                    continue;
                }

                XSElement importElement;
                if (!importLocation.IsElement(out importElement))
                {
                    continue;
                }

                Add(
                    new MSBuildImport(importsForImportingElement.ToArray(), importElement)
                    );
            }
        }
Exemplo n.º 5
0
        /// <summary>
        ///     Add a target.
        /// </summary>
        /// <param name="target">
        ///     The target's declaring <see cref="ProjectTargetElement"/>.
        /// </param>
        void AddTarget(ProjectTargetElement target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            XmlLocation targetLocation = _projectXmlLocator.Inspect(
                target.Location.ToNative()
                );

            if (targetLocation == null)
            {
                return;
            }

            XSElement targetElement;

            if (!targetLocation.IsElement(out targetElement))
            {
                return;
            }

            Add(
                new MSBuildTarget(target, targetElement)
                );
        }
Exemplo n.º 6
0
        /// <summary>
        ///     Get the <see cref="Range"/> represented by the <see cref="InvalidProjectFileException"/>.
        /// </summary>
        /// <param name="invalidProjectFileException">
        ///     The <see cref="InvalidProjectFileException"/>.
        /// </param>
        /// <param name="xmlLocator">
        ///     The XML locator API (if available).
        /// </param>
        /// <returns>
        ///     The <see cref="Range"/>.
        /// </returns>
        public static Range GetRange(this InvalidProjectFileException invalidProjectFileException, XmlLocator xmlLocator)
        {
            if (invalidProjectFileException == null)
            {
                throw new ArgumentNullException(nameof(invalidProjectFileException));
            }

            Position startPosition = new Position(
                invalidProjectFileException.LineNumber,
                invalidProjectFileException.ColumnNumber
                );

            // Attempt to use the range of the actual XML that the exception refers to.
            XmlLocation location = xmlLocator?.Inspect(startPosition);

            if (location != null)
            {
                return(location.Node.Range);
            }

            // Otherwise, fall back to using the exception's declared end position...
            Position endPosition = new Position(
                invalidProjectFileException.EndLineNumber,
                invalidProjectFileException.EndColumnNumber
                );

            // ...although it's sometimes less reliable.
            if (endPosition == Position.Zero)
            {
                endPosition = startPosition;
            }

            return(new Range(startPosition, endPosition));
        }
Exemplo n.º 7
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);
        }
Exemplo n.º 8
0
        /// <summary>
        ///     Does the location represent text?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents text content within an element; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsText(this XmlLocation location)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            return(location.Flags.HasFlag(XmlLocationFlags.Text));
        }
Exemplo n.º 9
0
        /// <summary>
        ///     Does the location represent an element's attributes range (but not a specific attribute)?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementBetweenAttributes(this XmlLocation location)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            return(location.IsElement() && location.Flags.HasFlag(XmlLocationFlags.Attributes));
        }
Exemplo n.º 10
0
        /// <summary>
        ///     Does the location represent an element's closing tag?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element's closing tag; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementClosingTag(this XmlLocation location)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            return(location.IsElement() && location.Flags.HasFlag(XmlLocationFlags.ClosingTag));
        }
Exemplo n.º 11
0
        /// <summary>
        ///     Does the location represent an element's textual content?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element's textual content; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementText(this XmlLocation location)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            return(location.IsElement() && location.IsText());
        }
Exemplo n.º 12
0
        /// <summary>
        ///     Does the location represent an element or an attribute?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element or attribute; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementOrAttribute(this XmlLocation location)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            return(location.IsElement() || location.IsAttribute());
        }
        /// <summary>
        ///     Does the location represent an MSBuild expression?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="expression">
        ///     Receives the expression (if any) at the location.
        /// </param>
        /// <param name="expressionRange">
        ///     The <see cref="Range"/> that contains the expression.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an MSBuild expression; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsExpression(this XmlLocation location, out ExpressionNode expression, out Range expressionRange)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            expression      = null;
            expressionRange = Range.Zero;

            string   expressionText;
            Position expressionStartPosition;

            if (location.IsElementText(out XSElementText text))
            {
                expressionText          = text.Text;
                expressionStartPosition = text.Range.Start;
            }
            else if (location.IsAttributeValue(out XSAttribute attribute))
            {
                expressionText          = attribute.Value;
                expressionStartPosition = attribute.ValueRange.Start;
            }
            else if (location.IsWhitespace(out XSWhitespace whitespace))
            {
                expressionText          = String.Empty;
                expressionStartPosition = whitespace.Range.Start;
            }
            else
            {
                return(false);
            }

            ExpressionTree expressionTree;

            if (!MSBuildExpression.TryParse(expressionText, out expressionTree))
            {
                return(false);
            }

            Position expressionPosition = location.Position.RelativeTo(expressionStartPosition);

            ExpressionNode expressionAtPosition = expressionTree.FindDeepestNodeAt(expressionPosition);

            if (expressionAtPosition == null)
            {
                return(false);
            }

            expression      = expressionAtPosition;
            expressionRange = expressionAtPosition.Range.WithOrigin(expressionStartPosition);

            return(true);
        }
Exemplo n.º 14
0
        /// <summary>
        ///     Does the location represent an element that has the specified attribute?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="attributeName">
        ///     The attribute name.
        /// </param>
        /// <param name="attribute">
        ///     Receives the attribute.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element with the specified attribute; otherwise, <c>false</c>.
        /// </returns>
        public static bool HasAttribute(this XmlLocation location, string attributeName, out XSAttribute attribute)
        {
            if (location.IsElement(out XSElement element))
            {
                attribute = element[attributeName];

                return(attribute != null);
            }

            attribute = null;

            return(false);
        }
Exemplo n.º 15
0
        /// <summary>
        ///     Does the location represent an attribute's value?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="attribute">
        ///     Receives the attribute whose value is represented by the location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an attribute's name; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsAttributeValue(this XmlLocation location, out XSAttribute attribute)
        {
            if (location.IsAttributeValue())
            {
                attribute = (XSAttribute)location.Node;

                return(true);
            }

            attribute = null;

            return(false);
        }
Exemplo n.º 16
0
        /// <summary>
        ///     Does the location represent an attribute?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="attribute">
        ///     Receives the <see cref="XSAttribute"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an attribute; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsAttribute(this XmlLocation location, out XSAttribute attribute)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            if (!location.IsAttribute())
            {
                attribute = null;

                return(false);
            }

            attribute = (XSAttribute)location.Node;

            return(true);
        }
Exemplo n.º 17
0
        /// <summary>
        ///     Does the location represent whitespace?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="whitespace">
        ///     Receives the <see cref="XSWhitespace"/> (if any) at the location.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents whitespace within element content; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsWhitespace(this XmlLocation location, out XSWhitespace whitespace)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            if (location.IsWhitespace())
            {
                whitespace = (XSWhitespace)location.Node;

                return(true);
            }

            whitespace = null;

            return(false);
        }
Exemplo n.º 18
0
        /// <summary>
        ///     Does the location represent an element's textual content?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="text">
        ///     Receives the <see cref="XSElementText"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element's textual content; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementText(this XmlLocation location, out XSElementText text)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            if (location.IsElementText())
            {
                text = (XSElementText)location.Node;

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

                return(false);
            }
        }
Exemplo n.º 19
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);
            }
        }
Exemplo n.º 20
0
        /// <summary>
        ///     Add an SDK-style import.
        /// </summary>
        /// <param name="resolvedImports">
        ///     The resolved imports resulting from the import declaration.
        /// </param>
        void AddSdkImport(IEnumerable <ResolvedImport> resolvedImports)
        {
            if (resolvedImports == null)
            {
                throw new ArgumentNullException(nameof(resolvedImports));
            }

            ResolvedImport firstImport = resolvedImports.First();
            Position       importStart = firstImport.ImportingElement.Location.ToNative();

            // If the Sdk attribute is on the Project element rather than an import element, then the location reported by MSBuild will be invalid (go figure).
            if (importStart == Position.Invalid)
            {
                importStart = Position.Origin;
            }

            XmlLocation importLocation = _projectXmlLocator.Inspect(importStart);

            if (importLocation == null)
            {
                return;
            }

            XSElement importElement;

            if (!importLocation.IsElement(out importElement))
            {
                return;
            }

            XSAttribute sdkAttribute = importElement["Sdk"];

            if (sdkAttribute == null)
            {
                return;
            }

            Add(
                new MSBuildSdkImport(resolvedImports.ToArray(), sdkAttribute)
                );
        }
Exemplo n.º 21
0
        /// <summary>
        ///     Add a property.
        /// </summary>
        /// <param name="property">
        ///     The property's declaring <see cref="ProjectPropertyElement"/>.
        /// </param>
        void AddProperty(ProjectPropertyElement property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            XmlLocation propertyLocation = _projectXmlLocator.Inspect(
                property.Location.ToNative()
                );

            if (propertyLocation == null)
            {
                return;
            }

            XSElement propertyElement;

            if (!propertyLocation.IsElement(out propertyElement))
            {
                return;
            }

            ProjectProperty evaluatedProperty = _project.GetProperty(property.Name);

            if (evaluatedProperty != null)
            {
                Add(
                    new MSBuildProperty(evaluatedProperty, property, propertyElement)
                    );
            }
            else
            {
                Add(
                    new MSBuildUnusedProperty(property, propertyElement)
                    );
            }
        }
        /// <summary>
        ///     Get the <see cref="Range"/> represented by the <see cref="XmlException"/>.
        /// </summary>
        /// <param name="invalidXml">
        ///     The <see cref="XmlException"/>.
        /// </param>
        /// <param name="xmlLocator">
        ///     The XML locator API (if available).
        /// </param>
        /// <returns>
        ///     The <see cref="Range"/>.
        /// </returns>
        public static Range GetRange(this XmlException invalidXml, XmlLocator xmlLocator)
        {
            if (invalidXml == null)
            {
                throw new ArgumentNullException(nameof(invalidXml));
            }

            Position startPosition = new Position(
                invalidXml.LineNumber,
                invalidXml.LinePosition
                );

            // Attempt to use the range of the actual XML that the exception refers to.
            XmlLocation location = xmlLocator?.Inspect(startPosition);

            if (location != null)
            {
                return(location.Node.Range);
            }

            // Otherwise, just use the start position.
            return(startPosition.ToEmptyRange());
        }
Exemplo n.º 23
0
 /// <summary>
 ///     Does the location represent an element that has the specified attribute?
 /// </summary>
 /// <param name="location">
 ///     The XML location.
 /// </param>
 /// <param name="attributeName">
 ///     The attribute name.
 /// </param>
 /// <returns>
 ///     <c>true</c>, if the location represents an element with the specified attribute; otherwise, <c>false</c>.
 /// </returns>
 public static bool HasAttribute(this XmlLocation location, string attributeName)
 {
     return(location.IsElement(out XSElement element) && element.HasAttribute(attributeName));
 }
Exemplo n.º 24
0
        /// <summary>
        ///     Add all items defined in the project.
        /// </summary>
        void AddItems()
        {
            // First, map each item to the element in the XML from where it originates.
            var itemsByXml = new Dictionary <ProjectItemElement, List <ProjectItem> >();

            foreach (ProjectItem item in _project.ItemsIgnoringCondition)
            {
                // Must be declared in main project file.
                if (!IsFromCurrentProject(item.Xml))
                {
                    continue;
                }

                Position itemStartPosition = item.Xml.Location.ToNative();

                List <ProjectItem> itemsFromXml;
                if (!itemsByXml.TryGetValue(item.Xml, out itemsFromXml))
                {
                    itemsFromXml = new List <ProjectItem>();
                    itemsByXml.Add(item.Xml, itemsFromXml);
                }

                itemsFromXml.Add(item);
            }

            // Now process item elements and their associated items.
            HashSet <ProjectItem> usedItems = new HashSet <ProjectItem>(_project.Items);

            foreach (ProjectItemElement itemXml in itemsByXml.Keys)
            {
                Position itemStart = itemXml.Location.ToNative();

                XmlLocation itemLocation = _projectXmlLocator.Inspect(itemStart);
                if (itemLocation == null)
                {
                    continue;
                }

                XSElement itemElement;
                if (!itemLocation.IsElement(out itemElement))
                {
                    continue;
                }

                List <ProjectItem> itemsFromXml;
                if (!itemsByXml.TryGetValue(itemXml, out itemsFromXml)) // AF: Should not happen.
                {
                    throw new InvalidOperationException($"Found item XML at {itemLocation.Node.Range} with no corresponding items in the MSBuild project (irrespective of condition).");
                }

                if (usedItems.Contains(itemsFromXml[0]))
                {
                    Add(
                        new MSBuildItemGroup(itemsByXml[itemXml], itemXml, itemElement)
                        );
                }
                else
                {
                    Add(
                        new MSBuildUnusedItemGroup(itemsByXml[itemXml], itemXml, itemElement)
                        );
                }
            }
        }
Exemplo n.º 25
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);
        }