private static XmlNodeSyntax[] EnvolveXmlDocSyntaxWithNewLine(XmlElementSyntax xmlElementSyntax) { var emptyTriviaList = SyntaxFactory.TriviaList(); var syntaxTriviaList = SyntaxFactory.TriviaList(SyntaxFactory.DocumentationCommentExterior(@"///")); var xmlTextLiteral = SyntaxFactory.XmlTextNewLine(syntaxTriviaList, WHITESPACE, WHITESPACE, emptyTriviaList); var withTextTokens = SyntaxFactory.XmlText(SyntaxFactory.TokenList(xmlTextLiteral)); var xmlNewTextLiteral = SyntaxFactory.XmlTextNewLine(emptyTriviaList, string.Empty, string.Empty, SyntaxFactory.TriviaList(SyntaxFactory.ElasticCarriageReturnLineFeed)); var withNewLineTokens = SyntaxFactory.XmlText(SyntaxFactory.TokenList(xmlNewTextLiteral)); return new XmlNodeSyntax[] { withTextTokens, xmlElementSyntax, withNewLineTokens }; }
private static string GetText(XmlElementSyntax child) { var lines = new List<string>(); foreach (var textSyntax in child.Content.OfType<XmlTextSyntax>()) { var lines2 = from textLine in textSyntax.GetText().Lines let line = textLine.ToString().TrimStart() let text = (line.StartsWith("///") ? line.Substring(3).TrimStart() : line).Trim() where !string.IsNullOrEmpty(text) select text; lines.AddRange(lines2); } var joined = string.Join("\r\n", lines); return joined.Trim(); }
private bool HasFollowingEndTagTrivia(XmlElementSyntax parentElement, SyntaxToken lessThanSlashToken) { var expectedEndTagText = "</" + parentElement.StartTag.Name.LocalName.ValueText + ">"; var token = lessThanSlashToken.GetNextToken(includeDocumentationComments: true); while (token.Parent.IsKind(SyntaxKind.XmlText)) { if (token.ValueText == expectedEndTagText) { return true; } token = token.GetNextToken(includeDocumentationComments: true); } return false; }
private async Task<Document> GetTransformedDocumentAsync(Document document, XmlElementSyntax elementSyntax, CancellationToken cancellationToken) { SyntaxList<XmlNodeSyntax> content = elementSyntax.Content; if (content.Count == 0) { return document; } var leadingTrivia = elementSyntax.StartTag.GetLeadingTrivia(); leadingTrivia = leadingTrivia.AddRange(elementSyntax.StartTag.GetTrailingTrivia()); leadingTrivia = leadingTrivia.AddRange(content[0].GetLeadingTrivia()); content = content.Replace(content[0], content[0].WithLeadingTrivia(leadingTrivia)); var trailingTrivia = content[content.Count - 1].GetTrailingTrivia(); trailingTrivia = trailingTrivia.AddRange(elementSyntax.EndTag.GetLeadingTrivia()); trailingTrivia = trailingTrivia.AddRange(elementSyntax.EndTag.GetTrailingTrivia()); content = content.Replace(content[content.Count - 1], content[content.Count - 1].WithTrailingTrivia(trailingTrivia)); SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxNode newRoot = root.ReplaceNode(elementSyntax, content); return document.WithSyntaxRoot(newRoot); }
private static XmlElementSyntax GetPreviousElement(DocumentationCommentTriviaSyntax comment, XmlElementSyntax element) { SyntaxList <XmlNodeSyntax> content = comment.Content; int index = content.IndexOf(element); for (int i = index - 1; i >= 0; i--) { if (content[i].IsKind(SyntaxKind.XmlElement)) { return((XmlElementSyntax)content[i]); } } return(null); }
/// <summary> /// /// </summary> /// <param name="node"></param> public override sealed void VisitXmlElement(XmlElementSyntax node) { this.OnNodeVisited(node, this.type.IsInstanceOfType(node)); base.VisitXmlElement(node); }
/// <summary> /// /// </summary> /// <param name="node"></param> public override sealed void VisitXmlElement(XmlElementSyntax node) { this.OnNodeVisited(node); if (!this.traverseRootOnly) base.VisitXmlElement(node); }
private static bool IsBlockLevelElement(XmlElementSyntax element, bool includePotentialElements) { return(IsBlockLevelName(element.StartTag?.Name, includePotentialElements)); }
private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node) { var typeDeclaration = node.FirstAncestorOrSelf <BaseTypeDeclarationSyntax>(); var declarationSyntax = node.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>(); bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration); TypeParameterListSyntax typeParameterList; ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax; if (classDeclaration != null) { typeParameterList = classDeclaration.TypeParameterList; } else { typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList; } ImmutableArray <string> standardText; if (declarationSyntax is ConstructorDeclarationSyntax) { if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)) { if (isStruct) { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " struct."); } else { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " class."); } } else { // Prefer to insert the "non-private" wording for all constructors, even though both are considered // acceptable for private constructors by the diagnostic. // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/413 if (isStruct) { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " struct."); } else { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " class."); } } } else if (declarationSyntax is DestructorDeclarationSyntax) { standardText = SA1643DestructorSummaryDocumentationMustBeginWithStandardText.DestructorStandardText; } else { throw new InvalidOperationException("XmlElementSyntax has invalid method as its parent"); } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); string trailingString = string.Empty; var newContent = RemoveMalformattedStandardText(node.Content, typeDeclaration.Identifier, standardText[0], standardText[1], ref trailingString); var list = BuildStandardText(typeDeclaration.Identifier, typeParameterList, newLineText, standardText[0], standardText[1] + trailingString); newContent = newContent.InsertRange(0, list); var newNode = node.WithContent(newContent).AdjustDocumentationCommentNewLineTrivia(); var newRoot = root.ReplaceNode(node, newNode); var newDocument = document.WithSyntaxRoot(newRoot); return(Task.FromResult(newDocument)); }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node) { var typeDeclaration = node.FirstAncestorOrSelf<BaseTypeDeclarationSyntax>(); var declarationSyntax = node.FirstAncestorOrSelf<BaseMethodDeclarationSyntax>(); bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration); TypeParameterListSyntax typeParameterList; ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax; if (classDeclaration != null) { typeParameterList = classDeclaration.TypeParameterList; } else { typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList; } ImmutableArray<string> standardText; if (declarationSyntax is ConstructorDeclarationSyntax) { if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)) { if (isStruct) { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " struct."); } else { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " class."); } } else { // Prefer to insert the "non-private" wording for all constructors, even though both are considered // acceptable for private constructors by the diagnostic. // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/413 if (isStruct) { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " struct."); } else { standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " class."); } } } else if (declarationSyntax is DestructorDeclarationSyntax) { standardText = SA1643DestructorSummaryDocumentationMustBeginWithStandardText.DestructorStandardText; } else { throw new InvalidOperationException("XmlElementSyntax has invalid method as its parent"); } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); var list = BuildStandardText(typeDeclaration.Identifier, typeParameterList, newLineText, standardText[0], standardText[1]); var newContent = node.Content.InsertRange(0, list); var newNode = node.WithContent(newContent).AdjustDocumentationCommentNewLineTrivia(); var newRoot = root.ReplaceNode(node, newNode); var newDocument = document.WithSyntaxRoot(newRoot); return Task.FromResult(newDocument); }
protected override SeparatedSyntaxList <ParameterSyntax> GetParameters(XmlElementSyntax syntax) { var method = syntax.Ancestors().OfType <ConstructorDeclarationSyntax>().First(); return(method.ParameterList.Parameters); }
/// <summary> /// Verify if a given XmlElement is correct /// </summary> /// <param name="xmlElement">The XmlElement object to validate</param> /// <param name="tagName">The name of the tag the XML element should have</param> /// <param name="innerText">The text inside the XmlElement</param> /// private void VerifyXmlElement(XmlElementSyntax xmlElement, string tagName, string innerText) { // if the innerText is empty, then the content has no nodes. if (innerText == string.Empty) { Assert.Equal(0, xmlElement.Content.Count); } else { var elementInnerText = GetXmlElementText(xmlElement); Assert.Equal(innerText, elementInnerText); } Assert.Equal(tagName, xmlElement.StartTag.Name.LocalName.Value); Assert.Equal(tagName, xmlElement.EndTag.Name.LocalName.Value); }
private List <ElementInfo <TNode> > GetElementInfos( DocumentationCommentTriviaSyntax comment, SeparatedSyntaxList <TNode> nodes) { Dictionary <string, XmlElementSyntax> dic = CreateNameElementMap(comment); var elementInfos = new List <ElementInfo <TNode> >(); for (int i = 0; i < nodes.Count; i++) { if (!dic.ContainsKey(GetName(nodes[i]))) { int insertIndex = -1; var newLinePosition = NewLinePosition.Beginning; for (int j = i - 1; j >= 0; j--) { if (dic.TryGetValue(GetName(nodes[j]), out XmlElementSyntax element)) { insertIndex = element.FullSpan.End; break; } } if (insertIndex == -1) { for (int j = i + 1; j < nodes.Count; j++) { if (dic.TryGetValue(GetName(nodes[j]), out XmlElementSyntax element)) { XmlElementSyntax previousElement = GetPreviousElement(comment, element); if (previousElement != null) { insertIndex = previousElement.FullSpan.End; } else { insertIndex = comment.FullSpan.Start; newLinePosition = NewLinePosition.End; } break; } } } if (insertIndex == -1) { insertIndex = GetDefaultIndex(comment); if (insertIndex == comment.FullSpan.Start) { newLinePosition = NewLinePosition.End; } } ElementInfo <TNode> elementInfo = CreateInfo(nodes[i], insertIndex, newLinePosition); elementInfos.Add(elementInfo); } } return(elementInfos); }
public override void VisitXmlElement(XmlElementSyntax node) { throw new NotSupportedException(); }
public override void VisitXmlElement(XmlElementSyntax node) { Debug.Fail(node.ToString()); base.VisitXmlElement(node); }
private static bool IsMultiLine(XmlElementSyntax node) { var lineSpan = node.GetLineSpan(); return(lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line); }
private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node, CancellationToken cancellationToken) { var typeDeclaration = node.FirstAncestorOrSelf <BaseTypeDeclarationSyntax>(); var declarationSyntax = node.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>(); var standardText = GenerateStandardText(document, declarationSyntax, typeDeclaration, cancellationToken); string trailingString = string.Empty; var newContent = RemoveMalformattedStandardText(node.Content, standardText[0], standardText[1], ref trailingString); if (newContent.Count == 1 && newContent[0] is XmlTextSyntax xmlText) { if (string.IsNullOrWhiteSpace(xmlText.ToString())) { newContent = default; } } SyntaxList <XmlNodeSyntax> list; if (IsMultiLine(node)) { string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); list = BuildStandardTextSyntaxList(typeDeclaration, newLineText, standardText[0], standardText[1] + trailingString); } else { list = BuildStandardTextSyntaxList(typeDeclaration, standardText[0], standardText[1] + trailingString); } newContent = newContent.InsertRange(0, list); newContent = RemoveTrailingEmptyLines(newContent); var newNode = node.WithContent(newContent).AdjustDocumentationCommentNewLineTrivia(); var newRoot = root.ReplaceNode(node, newNode); var newDocument = document.WithSyntaxRoot(newRoot); return(Task.FromResult(newDocument)); }
private void ClassifyXmlElement(XmlElementSyntax node) { ClassifyXmlElementStartTag(node.StartTag); foreach (var xmlNode in node.Content) { ClassifyXmlNode(xmlNode); } ClassifyXmlElementEndTag(node.EndTag); }
private static void HandleSectionOrBlockXmlElement(SyntaxNodeAnalysisContext context, StyleCopSettings settings, XmlElementSyntax xmlElement, bool startingWithFinalParagraph) { var startTag = xmlElement.StartTag?.Name?.LocalName.ValueText; if (settings.DocumentationRules.ExcludeFromPunctuationCheck.Contains(startTag)) { return; } var currentParagraphDone = false; for (var i = xmlElement.Content.Count - 1; i >= 0; i--) { if (xmlElement.Content[i] is XmlTextSyntax contentNode) { for (var j = contentNode.TextTokens.Count - 1; !currentParagraphDone && (j >= 0); j--) { var textToken = contentNode.TextTokens[j]; var textWithoutTrailingWhitespace = textToken.Text.TrimEnd(' ', '\r', '\n'); if (!string.IsNullOrEmpty(textWithoutTrailingWhitespace)) { if (!textWithoutTrailingWhitespace.EndsWith(".", StringComparison.Ordinal) && (startingWithFinalParagraph || !textWithoutTrailingWhitespace.EndsWith(":", StringComparison.Ordinal)) && !textWithoutTrailingWhitespace.EndsWith("-or-", StringComparison.Ordinal)) { var location = Location.Create(xmlElement.SyntaxTree, new TextSpan(textToken.SpanStart + textWithoutTrailingWhitespace.Length, 1)); context.ReportDiagnostic(Diagnostic.Create(Descriptor, location)); } currentParagraphDone = true; } } } else if (xmlElement.Content[i].IsInlineElement() && !currentParagraphDone) { // Treat empty XML elements as a "word not ending with a period" var location = Location.Create(xmlElement.SyntaxTree, new TextSpan(xmlElement.Content[i].Span.End, 1)); context.ReportDiagnostic(Diagnostic.Create(Descriptor, location)); currentParagraphDone = true; } else if (xmlElement.Content[i] is XmlElementSyntax childXmlElement) { switch (childXmlElement.StartTag?.Name?.LocalName.ValueText) { case XmlCommentHelper.NoteXmlTag: case XmlCommentHelper.ParaXmlTag: // Recursively handle <note> and <para> elements HandleSectionOrBlockXmlElement(context, settings, childXmlElement, startingWithFinalParagraph); break; default: break; } if (childXmlElement.IsBlockElement()) { currentParagraphDone = false; startingWithFinalParagraph = false; } } else if (xmlElement.Content[i] is XmlEmptyElementSyntax emptyElement) { // Treat the empty element <para/> as a paragraph separator if (emptyElement.Name?.LocalName.ValueText == XmlCommentHelper.ParaXmlTag) { currentParagraphDone = false; startingWithFinalParagraph = false; } } } }
/// <summary> /// Gets the string representation for a XmlElementText /// </summary> /// <param name="xmlElement"></param> /// <returns></returns> private string GetXmlElementText(XmlElementSyntax xmlElement) { StringBuilder sb = new StringBuilder(); foreach (var element in xmlElement.Content) { if (element.GetType() == typeof(XmlElementSyntax)) { sb.Append(element.ToFullString()); } else if (element.GetType() == typeof(XmlTextSyntax)) { sb.Append((element as XmlTextSyntax).TextTokens.ToFullString()); } else if (element.GetType() == typeof(XmlCDataSectionSyntax)) { sb.Append(element.ToFullString()); } } return sb.ToString(); // return getTextFromTextTokens((xmlElement.Content[0] as XmlTextSyntax).TextTokens); }
private async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan); if (syntax == null) { return(document); } PropertyDeclarationSyntax propertyDeclarationSyntax = syntax.FirstAncestorOrSelf <PropertyDeclarationSyntax>(); if (propertyDeclarationSyntax == null) { return(document); } DocumentationCommentTriviaSyntax documentationComment = propertyDeclarationSyntax.GetDocumentationCommentTriviaSyntax(); if (documentationComment == null) { return(document); } XmlElementSyntax summaryElement = documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.SummaryXmlTag) as XmlElementSyntax; if (summaryElement == null) { return(document); } SyntaxList <XmlNodeSyntax> summaryContent = summaryElement.Content; if (!this.TryRemoveSummaryPrefix(ref summaryContent, "Gets or sets ")) { if (!this.TryRemoveSummaryPrefix(ref summaryContent, "Gets ")) { this.TryRemoveSummaryPrefix(ref summaryContent, "Sets "); } } SyntaxList <XmlNodeSyntax> content = summaryContent.WithoutFirstAndLastNewlines(); if (!string.IsNullOrWhiteSpace(content.ToFullString())) { // wrap the content in a <placeholder> element for review content = XmlSyntaxFactory.List(XmlSyntaxFactory.PlaceholderElement(content)); } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); XmlElementSyntax valueElement = XmlSyntaxFactory.MultiLineElement(XmlCommentHelper.ValueXmlTag, newLineText, content); XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine(newLineText); // HACK: The formatter isn't working when contents are added to an existing documentation comment, so we // manually apply the indentation from the last line of the existing comment to each new line of the // generated content. SyntaxTrivia exteriorTrivia = GetLastDocumentationCommentExteriorTrivia(documentationComment); if (!exteriorTrivia.Token.IsMissing) { leadingNewLine = leadingNewLine.ReplaceExteriorTrivia(exteriorTrivia); valueElement = valueElement.ReplaceExteriorTrivia(exteriorTrivia); } // Try to replace an existing <value> element if the comment contains one. Otherwise, add it as a new element. SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxNode newRoot; XmlNodeSyntax existingValue = documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.ValueXmlTag); if (existingValue != null) { newRoot = root.ReplaceNode(existingValue, valueElement); } else { DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent( documentationComment.Content.InsertRange( documentationComment.Content.Count - 1, XmlSyntaxFactory.List(leadingNewLine, valueElement))); newRoot = root.ReplaceNode(documentationComment, newDocumentationComment); } return(document.WithSyntaxRoot(newRoot)); }
private string AttributeSelector(XmlElementSyntax element, string attribute) { if (!element.StartTag.IsMissing && !element.EndTag.IsMissing) { var startTag = element.StartTag; var nameAttribute = startTag.Attributes.OfType<XmlNameAttributeSyntax>().FirstOrDefault(a => a.Name.LocalName.ValueText == NameAttributeName); if (nameAttribute != null) { if (startTag.Name.LocalName.ValueText == attribute) { return nameAttribute.Identifier.Identifier.ValueText; } } } return null; }
public override void VisitXmlElement(XmlElementSyntax node) { }
// // Summary: // Called when the visitor visits a XmlElementSyntax node. public virtual void VisitXmlElement(XmlElementSyntax node);
private static void HandleXmlElement(SyntaxNodeAnalysisContext context) { XmlElementSyntax syntax = (XmlElementSyntax)context.Node; CheckTag(context, syntax.StartTag?.Name?.ToString()); }