private void ClassifyXmlAttribute(XmlAttributeSyntax attribute) { ClassifyXmlName(attribute.Name); AddXmlClassification( attribute.EqualsToken, ClassificationTypeNames.XmlDocCommentDelimiter ); AddXmlClassification( attribute.StartQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes ); switch (attribute.Kind()) { case SyntaxKind.XmlTextAttribute: ClassifyXmlTextTokens(((XmlTextAttributeSyntax)attribute).TextTokens); break; case SyntaxKind.XmlCrefAttribute: ClassifyNode(((XmlCrefAttributeSyntax)attribute).Cref); break; case SyntaxKind.XmlNameAttribute: ClassifyNode(((XmlNameAttributeSyntax)attribute).Identifier); break; } AddXmlClassification( attribute.EndQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes ); }
private bool IsAttributeValueContext(SyntaxToken token, out string tagName, out string attributeName) { XmlAttributeSyntax attributeSyntax = null; if (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute, out XmlNameAttributeSyntax xmlName)) { // Handle the special 'name' attributes: name="bar$$ attributeSyntax = xmlName; } else if (token.IsKind(SyntaxKind.XmlTextLiteralToken) && token.Parent.IsKind(SyntaxKind.XmlTextAttribute, out XmlTextAttributeSyntax xmlText)) { // Handle the other general text attributes: foo="bar$$ attributeSyntax = xmlText; } else if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute, out attributeSyntax) || token.Parent.IsKind(SyntaxKind.XmlTextAttribute, out attributeSyntax)) { // When there's no attribute value yet, the parent attribute is returned: // name="$$ // foo="$$ if (token != attributeSyntax.StartQuoteToken) { attributeSyntax = null; } } if (attributeSyntax != null) { attributeName = attributeSyntax.Name.LocalName.ValueText; var emptyElement = attributeSyntax.GetAncestor <XmlEmptyElementSyntax>(); if (emptyElement != null) { // Empty element tags: <tag attr=... /> tagName = emptyElement.Name.LocalName.Text; return(true); } var startTagSyntax = token.GetAncestor <XmlElementStartTagSyntax>(); if (startTagSyntax != null) { // Non-empty element start tags: <tag attr=... > tagName = startTagSyntax.Name.LocalName.Text; return(true); } } attributeName = null; tagName = null; return(false); }
public static void AddAttributeValueReferences( this BoundSourceFileBuilder binder, XmlAttributeSyntax attribute, params ReferenceSymbol[] references) { var node = attribute?.ValueNode.As <XmlStringSyntax>()?.TextTokens.Node; if (node != null) { binder.AnnotateReferences(node.Start, node.FullWidth, references); } }
public static void AddAttributeNameReferences( this BoundSourceFileBuilder binder, XmlAttributeSyntax attribute, params ReferenceSymbol[] references) { var node = attribute?.NameNode; if (node != null) { binder.AnnotateReferences(node.Start, node.FullWidth, references); } }
public static void AddAttributeValueDefinition( this BoundSourceFileBuilder binder, XmlAttributeSyntax attribute, DefinitionSymbol definition) { var node = attribute?.ValueNode.As <XmlStringSyntax>()?.TextTokens.Node; if (node != null) { binder.AnnotateDefinition(node.Start, node.FullWidth, definition); } }
public static DocumentationCommentAttribute FromXmlAttributeSyntax(XmlAttributeSyntax syntax) { if (syntax is XmlCrefAttributeSyntax) { return(FromXmlCref(syntax)); } if (syntax is XmlNameAttributeSyntax) { return(FromXmlName(syntax)); } return(FromXmlText(syntax as XmlTextAttributeSyntax)); }
public static IEnumerable <ReferenceSpan> GetAttributeValueExpressionSpans(this XmlAttributeSyntax element, ExpressionProcessor customStringProcessor = null, string referencingItemName = null) { var valueNode = element?.ValueNode.As <XmlStringSyntax>()?.TextTokens.Node; if (valueNode == null) { return(Enumerable.Empty <ReferenceSpan>()); } return(ProcessExpressions(valueNode.Start, valueNode.ToFullString(), customStringProcessor, referencingItemName)); }
private static DocumentationCommentAttribute FromXmlName(XmlAttributeSyntax syntax) => new DocumentationCommentAttribute { Identifier = new Identifier { Name = new AsciiStringReference { Value = "name" } }, Value = new Identifier { Name = new AsciiStringReference { Value = (syntax as XmlNameAttributeSyntax).Identifier.ToString() } } };
private string GetAttributeValue(XmlAttributeSyntax attribute) { switch (attribute) { case XmlTextAttributeSyntax textAttribute: // Decode any XML enities and concatentate the results return(textAttribute.TextTokens.GetValueText()); case XmlNameAttributeSyntax nameAttribute: return(nameAttribute.Identifier.Identifier.ValueText); default: return(null); } }
/// <summary> /// This is used to determine whether or not the current caret location is in an attribute value context /// </summary> /// <param name="token">The token to check</param> /// <param name="elementName">On return, this will contain the element name if it is an attribute value /// context, null if not.</param> /// <param name="attributeName">On return, this will contain the attribute name if it is an attribute /// value context, null if not.</param> /// <returns>True if it is within the attribute value context, false if not.</returns> private static bool IsAttributeValueContext(SyntaxToken token, out string elementName, out string attributeName) { XmlAttributeSyntax attributeSyntax = null; if (token.IsKind(SyntaxKind.XmlTextLiteralToken) && token.Parent.IsKind(SyntaxKind.XmlTextAttribute)) { // General attribute: attr="value| attributeSyntax = (XmlTextAttributeSyntax)token.Parent; } else if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || token.Parent.IsKind(SyntaxKind.XmlTextAttribute)) { // Return the parent attribute if there is no value yet: attr="| attributeSyntax = (XmlAttributeSyntax)token.Parent; if (token != attributeSyntax.StartQuoteToken) { attributeSyntax = null; } } if (attributeSyntax != null) { attributeName = attributeSyntax.Name.LocalName.ValueText; var emptyElement = attributeSyntax.GetAncestor <XmlEmptyElementSyntax>(); if (emptyElement != null) { // Self-closing or incomplete element: <elem attr="|" /> or <elem attr="|" elementName = emptyElement.Name.LocalName.Text; return(true); } var startTag = token.Parent?.FirstAncestorOrSelf <XmlElementStartTagSyntax>(); if (startTag != null) { // Start tag: <elem attr="|"> elementName = startTag.Name.LocalName.Text; return(true); } } attributeName = elementName = null; return(false); }
/// <summary> /// Get a <see cref="Range"/> representing the attribute's span (without quotes) in the XML. /// </summary> /// <param name="attribute"> /// The attribute. /// </param> /// <param name="xmlPositions"> /// The XML position lookup. /// </param> /// <returns> /// The <see cref="Range"/>. /// </returns> public static Range GetValueRange(this XmlAttributeSyntax attribute, TextPositions xmlPositions) { if (attribute == null) { throw new ArgumentNullException(nameof(attribute)); } if (xmlPositions == null) { throw new ArgumentNullException(nameof(xmlPositions)); } Range valueRange = attribute.ValueNode.Span.ToNative(xmlPositions); // Trim off leading and trailing quotes. return(valueRange.Transform(moveStartColumns: 1, moveEndColumns: -1)); }
private void FormatTagAttribute(XmlAttributeSyntax node) { FormatTagName(node.Name); EnqueueTrailingTriviaChange(node.Name, string.Empty); EnqueueLeadingTriviaChange(node.EqualsToken, string.Empty); AddWord(node.EqualsToken.Span); EnqueueTrailingTriviaChange(node.EqualsToken, string.Empty); EnqueueLeadingTriviaChange(node.StartQuoteToken, string.Empty); AddWord(node.StartQuoteToken.Span); switch (node.Kind()) { case SyntaxKind.XmlCrefAttribute: FormatTagCrefAttribute((XmlCrefAttributeSyntax)node); break; case SyntaxKind.XmlNameAttribute: FormatTagNameAttribute((XmlNameAttributeSyntax)node); break; case SyntaxKind.XmlTextAttribute: FormatTagTextAttribute((XmlTextAttributeSyntax)node); break; default: FormatTagUnknownAttribute(node); break; } AddWord(node.EndQuoteToken.Span); }
/// <summary> /// Visit an <see cref="XmlAttributeSyntax"/>. /// </summary> /// <param name="attribute"> /// The <see cref="XmlAttributeSyntax"/>. /// </param> /// <returns> /// The <see cref="XmlAttributeSyntax"/> (unchanged). /// </returns> public override SyntaxNode VisitXmlAttribute(XmlAttributeSyntax attribute) { if (!HaveCurrentElement) { return(attribute); } Range attributeRange = attribute.Span.ToNative(_textPositions); Range nameRange = attribute.NameNode?.Span.ToNative(_textPositions) ?? attributeRange; Range valueRange = attribute.ValueNode?.Span.ToNative(_textPositions) ?? Range.Zero; if (valueRange != Range.Zero && valueRange.End.ColumnNumber - valueRange.Start.ColumnNumber >= 2) { valueRange = valueRange.Transform(moveStartColumns: 1, moveEndColumns: -1); // Trim off quotes. } else { valueRange = nameRange; } XSAttribute xsAttribute; if (String.IsNullOrWhiteSpace(attribute.Name) || nameRange == attributeRange || valueRange == attributeRange) { xsAttribute = new XSInvalidAttribute(attribute, CurrentElement, attributeRange, nameRange, valueRange); } else { xsAttribute = new XSAttribute(attribute, CurrentElement, attributeRange, nameRange, valueRange); } CurrentElement.Attributes = CurrentElement.Attributes.Add(xsAttribute); DiscoveredNodes.Add(xsAttribute); return(attribute); }
internal static string GetName(this XmlAttributeSyntax value) => value?.Name.LocalName.ValueText;
private void ClassifyXmlAttribute(XmlAttributeSyntax attribute) { ClassifyXmlName(attribute.Name); AddXmlClassification(attribute.EqualsToken, ClassificationTypeNames.XmlDocCommentDelimiter); AddXmlClassification(attribute.StartQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes); switch (attribute.Kind()) { case SyntaxKind.XmlTextAttribute: ClassifyXmlTextTokens(((XmlTextAttributeSyntax)attribute).TextTokens); break; case SyntaxKind.XmlCrefAttribute: ClassifyNode(((XmlCrefAttributeSyntax)attribute).Cref); break; case SyntaxKind.XmlNameAttribute: ClassifyNode(((XmlNameAttributeSyntax)attribute).Identifier); break; } AddXmlClassification(attribute.EndQuoteToken, ClassificationTypeNames.XmlDocCommentAttributeQuotes); }
private void FormatTagUnknownAttribute(XmlAttributeSyntax node) { Debug.Assert(false); AddWord(TextSpan.FromBounds(node.StartQuoteToken.Span.End, node.EndQuoteToken.Span.Start)); }
/// <summary> /// Determine <see cref="XmlLocationFlags"/> for the current position. /// </summary> /// <returns> /// <see cref="XmlLocationFlags"/> describing the position. /// </returns> XmlLocationFlags ComputeLocationFlags(XSNode node, int absolutePosition) { if (node == null) { throw new ArgumentNullException(nameof(node)); } XmlLocationFlags flags = XmlLocationFlags.None; if (!node.IsValid) { flags |= XmlLocationFlags.Invalid; } switch (node) { case XSEmptyElement element: { flags |= XmlLocationFlags.Element | XmlLocationFlags.Empty; XmlEmptyElementSyntax syntaxNode = element.ElementNode; TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan(); if (nameSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Name; } TextSpan attributesSpan = new TextSpan(); if (syntaxNode.SlashGreaterThanToken != null) // This is the most accurate way to measure the span of text where the element's attributes can be located. { attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.SlashGreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End); } else if (syntaxNode.AttributesNode != null) { attributesSpan = syntaxNode.AttributesNode.FullSpan; // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above. } if (attributesSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Attributes; } break; } case XSElementWithContent elementWithContent: { flags |= XmlLocationFlags.Element; XmlElementSyntax syntaxNode = elementWithContent.ElementNode; TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan(); if (nameSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Name; } TextSpan startTagSpan = syntaxNode.StartTag?.Span ?? new TextSpan(); if (startTagSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.OpeningTag; } TextSpan attributesSpan = new TextSpan(); if (syntaxNode.StartTag?.GreaterThanToken != null) // This is the most accurate way to measure the span of text where the element's attributes can be located. { attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.StartTag.GreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End); } else if (syntaxNode.AttributesNode != null) { attributesSpan = syntaxNode.AttributesNode.FullSpan; // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above. } if (attributesSpan.Contains(absolutePosition) || absolutePosition == attributesSpan.End) // In this particular case, we need an inclusive comparison. { flags |= XmlLocationFlags.Attributes; } TextSpan endTagSpan = syntaxNode.EndTag?.Span ?? new TextSpan(); if (endTagSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.ClosingTag; } if (absolutePosition >= startTagSpan.End && absolutePosition <= endTagSpan.Start) { flags |= XmlLocationFlags.Value; } break; } case XSInvalidElement invalidElement: { flags |= XmlLocationFlags.Element; XmlElementSyntaxBase syntaxNode = invalidElement.ElementNode; TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan(); if (nameSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Name; } TextSpan attributesSpan = syntaxNode.AttributesNode?.FullSpan ?? new TextSpan(); if (attributesSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Attributes; } break; } case XSAttribute attribute: { flags |= XmlLocationFlags.Attribute; XmlAttributeSyntax syntaxNode = attribute.AttributeNode; TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan(); if (nameSpan.Contains(absolutePosition)) { flags |= XmlLocationFlags.Name; } TextSpan valueSpan = syntaxNode.ValueNode?.Span ?? new TextSpan(); if (absolutePosition >= valueSpan.Start + 1 && absolutePosition <= valueSpan.End - 1) { flags |= XmlLocationFlags.Value; } break; } case XSElementText text: { flags |= XmlLocationFlags.Text | XmlLocationFlags.Element | XmlLocationFlags.Value; break; } case XSWhitespace whitespace: { flags |= XmlLocationFlags.Whitespace | XmlLocationFlags.Element | XmlLocationFlags.Value; break; } } return(flags); }
public TameXmlAttributeSyntax(XmlAttributeSyntax node) { Node = node; AddChildren(); }
private string GetAttributeName(XmlAttributeSyntax attribute) => attribute.Name.LocalName.ValueText;
internal static bool IsInXmlAttributeValue(int position, XmlAttributeSyntax attribute) { return IsBetweenTokens(position, attribute.StartQuoteToken, attribute.EndQuoteToken); }
internal static bool IsInXmlAttributeValue(int position, XmlAttributeSyntax attribute) { return(IsBetweenTokens(position, attribute.StartQuoteToken, attribute.EndQuoteToken)); }
/// <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) { }