Exemplo n.º 1
0
            public override SyntaxNode VisitXmlElement(XmlElementSyntax node)
            {
                node = (XmlElementSyntax)base.VisitXmlElement(node);

                var content = node.Content;

                if (s_customStreamMethods.TryGetValue(Method.Name, out var customStreamMethodInfo) &&
                    customStreamMethodInfo.CustomDocs.TryGetValue(node.StartTag.Name.ToString(), out var comment))
                {
                    content = SingletonList((XmlNodeSyntax)XmlText(XmlTextLiteral(comment)));
                }
                else if (
                    node.StartTag.Name.LocalName.ToString() == "param" &&
                    node.StartTag.Attributes.FirstOrDefault() is XmlNameAttributeSyntax paramNameSyntax &&
                    paramNameSyntax.Identifier.ToString() == _requestParameterSyntax.Identifier.ToString())
                {
                    // Append request param tags with a note about how the AppProfileId will be added to the request object
                    // if unspecified.
                    var endingText = (XmlTextSyntax)content.Last();
                    content = content
                              .Replace(
                        endingText,
                        endingText.AddTextTokens(XmlTextLiteral(" If the ")))
                              .Add(
                        SeeTag(_requestParameterSyntax.Type.CrefMember(AppProfileIdPropertyName)))
                              .Add(XmlText(XmlTextLiteral(" has not been specified, it will be initialized from the value stored in the client.")));
                }

                return(node.WithContent(content));
            }
Exemplo n.º 2
0
        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 newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp);

            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;
                }
            }

            var list = BuildStandardTextSyntaxList(typeDeclaration, newLineText, 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 static Task <Document> SetDefaultXmlCommentForParameterName(Document document, SyntaxNode syntaxRoot, XmlElementSyntax xmlElementSyntax) =>
 Task.FromResult(
     document.WithSyntaxRoot(
         syntaxRoot.ReplaceNode(
             xmlElementSyntax,
             xmlElementSyntax.WithContent(
                 new SyntaxList <XmlNodeSyntax>(
                     XmlText(ParameterNameConstants.DefaultComment))))));
        private static Task <Document> GetTransformedDocument(Document document, SyntaxNode root, XmlElementSyntax node)
        {
            var classDeclaration  = node.FirstAncestorOrSelf <ClassDeclarationSyntax>();
            var declarationSyntax = node.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>();

            ImmutableArray <string> standardText;

            if (declarationSyntax is ConstructorDeclarationSyntax)
            {
                if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword))
                {
                    standardText = SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText;
                }
                else if (declarationSyntax.Modifiers.Any(SyntaxKind.PrivateKeyword))
                {
                    // Prefer to insert the "non-private" wording, even though both are considered acceptable by the
                    // diagnostic. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/413
                    standardText = SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText;
                }
                else
                {
                    standardText = SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText;
                }
            }
            else if (declarationSyntax is DestructorDeclarationSyntax)
            {
                standardText = SA1643DestructorSummaryDocumentationMustBeginWithStandardText.DestructorStandardText;
            }
            else
            {
                throw new InvalidOperationException("XmlElementSyntax has invalid method as its parent");
            }

            var list = BuildStandardText(classDeclaration.Identifier, classDeclaration.TypeParameterList, standardText[0], standardText[1]);

            var newContent = node.Content.InsertRange(0, list);
            var newNode    = node.WithContent(newContent);

            var newRoot = root.ReplaceNode(node, newNode);

            var newDocument = document.WithSyntaxRoot(newRoot);

            return(Task.FromResult(newDocument));
        }
Exemplo n.º 5
0
            public override SyntaxNode VisitXmlElement(XmlElementSyntax node)
            {
                var originalNode = node;

                node = (XmlElementSyntax)base.VisitXmlElement(node);

                if (originalNode.StartTag.Name.LocalName.ToString() == "param" &&
                    originalNode.StartTag.Attributes.FirstOrDefault() is XmlNameAttributeSyntax paramNameSyntax &&
                    paramNameSyntax.Identifier.ToString() == _callSettingsParameterSyntax.Identifier.ToString())
                {
                    // Replace the parameter doc comments for the cancellation token.
                    node = node.WithContent(List(new XmlNodeSyntax[] {
                        XmlText("A "),
                        SeeTag(TypeCref(ParseTypeName($"st::{nameof(CancellationToken)}"))),
                        XmlText(XmlTextLiteral(" to use for this RPC."))
                    }));
                }

                return(node);
            }
        private SyntaxNode RemoveUnnecessaryParagraphs(XmlElementSyntax originalNode, XmlElementSyntax rewrittenNode)
        {
            bool hasUnnecessary = false;
            SyntaxList <XmlNodeSyntax> content = rewrittenNode.Content;

            for (int i = 0; i < content.Count; i++)
            {
                if (content[i].HasAnnotation(UnnecessaryParagraphAnnotation))
                {
                    hasUnnecessary = true;
                    XmlElementSyntax unnecessaryElement = (XmlElementSyntax)content[i];
                    content = content.ReplaceRange(unnecessaryElement, unnecessaryElement.Content);
                    i      += unnecessaryElement.Content.Count;
                }
            }

            if (!hasUnnecessary)
            {
                return(rewrittenNode);
            }

            return(rewrittenNode.WithContent(content));
        }
        private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode enclosingNode = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true);

            if (!(enclosingNode is XmlNodeSyntax xmlNodeSyntax))
            {
                return(document);
            }

            XmlElementSyntax xmlElementSyntax = xmlNodeSyntax.FirstAncestorOrSelf <XmlElementSyntax>();

            if (xmlElementSyntax == null)
            {
                return(document);
            }

            SyntaxToken startToken = root.FindToken(diagnostic.Location.SourceSpan.Start, findInsideTrivia: true);

            if (!(startToken.Parent is XmlNodeSyntax startNode) || startNode == xmlElementSyntax)
            {
                return(document);
            }

            while (startNode.Parent != xmlElementSyntax)
            {
                startNode = startNode.Parent as XmlNodeSyntax;
                if (startNode == null)
                {
                    return(document);
                }
            }

            SyntaxToken stopToken = root.FindToken(diagnostic.Location.SourceSpan.End - 1, findInsideTrivia: true);

            if (!(stopToken.Parent is XmlNodeSyntax stopNode) || stopNode == xmlElementSyntax)
            {
                return(document);
            }

            while (stopNode.Parent != xmlElementSyntax)
            {
                stopNode = stopNode.Parent as XmlNodeSyntax;
                if (stopNode == null)
                {
                    return(document);
                }
            }

            int startIndex = xmlElementSyntax.Content.IndexOf(startNode);
            int stopIndex  = xmlElementSyntax.Content.IndexOf(stopNode);

            if (startIndex < 0 || stopIndex < 0)
            {
                return(document);
            }

            XmlElementSyntax           paragraph = XmlSyntaxFactory.ParaElement(xmlElementSyntax.Content.Skip(startIndex).Take(stopIndex - startIndex + 1).ToArray());
            SyntaxList <XmlNodeSyntax> leadingWhitespaceContent;
            SyntaxList <XmlNodeSyntax> trailingWhitespaceContent;

            paragraph = TrimWhitespaceContent(paragraph, out leadingWhitespaceContent, out trailingWhitespaceContent);

            SyntaxList <XmlNodeSyntax> newContent = XmlSyntaxFactory.List();

            newContent = newContent.AddRange(xmlElementSyntax.Content.Take(startIndex));
            newContent = newContent.AddRange(leadingWhitespaceContent);
            newContent = newContent.Add(paragraph);
            newContent = newContent.AddRange(trailingWhitespaceContent);
            newContent = newContent.AddRange(xmlElementSyntax.Content.Skip(stopIndex + 1));
            return(document.WithSyntaxRoot(root.ReplaceNode(xmlElementSyntax, xmlElementSyntax.WithContent(newContent))));
        }
        private static XmlElementSyntax TrimWhitespaceContent(XmlElementSyntax paragraph, out SyntaxList <XmlNodeSyntax> leadingWhitespaceContent, out SyntaxList <XmlNodeSyntax> trailingWhitespaceContent)
        {
            SyntaxList <XmlNodeSyntax> completeContent = XmlSyntaxFactory.List(paragraph.Content.SelectMany(ExpandTextNodes).ToArray());

            leadingWhitespaceContent  = XmlSyntaxFactory.List(completeContent.TakeWhile(x => XmlCommentHelper.IsConsideredEmpty(x)).ToArray());
            trailingWhitespaceContent = XmlSyntaxFactory.List(completeContent.Skip(leadingWhitespaceContent.Count).Reverse().TakeWhile(x => XmlCommentHelper.IsConsideredEmpty(x)).Reverse().ToArray());

            SyntaxList <XmlNodeSyntax> trimmedContent = XmlSyntaxFactory.List(completeContent.Skip(leadingWhitespaceContent.Count).Take(completeContent.Count - leadingWhitespaceContent.Count - trailingWhitespaceContent.Count).ToArray());
            SyntaxTriviaList           leadingTrivia  = SyntaxFactory.TriviaList();
            SyntaxTriviaList           trailingTrivia = SyntaxFactory.TriviaList();

            if (trimmedContent.Any())
            {
                leadingTrivia  = trimmedContent[0].GetLeadingTrivia();
                trailingTrivia = trimmedContent.Last().GetTrailingTrivia();
                trimmedContent = trimmedContent.Replace(trimmedContent[0], trimmedContent[0].WithoutLeadingTrivia());
                trimmedContent = trimmedContent.Replace(trimmedContent.Last(), trimmedContent.Last().WithoutTrailingTrivia());
            }
            else
            {
                leadingTrivia  = SyntaxFactory.TriviaList();
                trailingTrivia = SyntaxFactory.TriviaList();
            }

            XmlElementSyntax result = paragraph;

            if (leadingWhitespaceContent.Any())
            {
                var first    = leadingWhitespaceContent[0];
                var newFirst = first.WithLeadingTrivia(first.GetLeadingTrivia().InsertRange(0, paragraph.GetLeadingTrivia()));
                leadingWhitespaceContent = leadingWhitespaceContent.Replace(first, newFirst);
            }
            else
            {
                leadingTrivia = leadingTrivia.InsertRange(0, result.GetLeadingTrivia());
            }

            if (trailingWhitespaceContent.Any())
            {
                var last    = trailingWhitespaceContent.Last();
                var newLast = last.WithLeadingTrivia(last.GetLeadingTrivia().AddRange(paragraph.GetTrailingTrivia()));
                trailingWhitespaceContent = trailingWhitespaceContent.Replace(last, newLast);
            }
            else
            {
                trailingTrivia = trailingTrivia.AddRange(result.GetTrailingTrivia());
            }

            if (trimmedContent.FirstOrDefault() is XmlTextSyntax firstTextNode &&
                firstTextNode.TextTokens.Any())
            {
                SyntaxToken firstTextToken    = firstTextNode.TextTokens[0];
                string      leadingWhitespace = new(firstTextToken.Text.Cast <char>().TakeWhile(char.IsWhiteSpace).ToArray());
                if (leadingWhitespace.Length > 0)
                {
                    SyntaxToken   newFirstTextToken = XmlSyntaxFactory.TextLiteral(firstTextToken.Text.Substring(leadingWhitespace.Length)).WithTriviaFrom(firstTextToken);
                    XmlTextSyntax newFirstTextNode  = firstTextNode.WithTextTokens(firstTextNode.TextTokens.Replace(firstTextToken, newFirstTextToken));
                    trimmedContent = trimmedContent.Replace(firstTextNode, newFirstTextNode);
                    leadingTrivia  = leadingTrivia.Add(SyntaxFactory.Whitespace(leadingWhitespace));
                }
            }

            if (trimmedContent.LastOrDefault() is XmlTextSyntax lastTextNode &&
                lastTextNode.TextTokens.Any())
            {
                SyntaxToken lastTextToken      = lastTextNode.TextTokens.Last();
                string      trailingWhitespace = new(lastTextToken.Text.Cast <char>().Reverse().TakeWhile(char.IsWhiteSpace).Reverse().ToArray());
                if (trailingWhitespace.Length > 0)
                {
                    SyntaxToken   newLastTextToken = XmlSyntaxFactory.TextLiteral(lastTextToken.Text.Substring(0, lastTextToken.Text.Length - trailingWhitespace.Length)).WithTriviaFrom(lastTextToken);
                    XmlTextSyntax newLastTextNode  = lastTextNode.WithTextTokens(lastTextNode.TextTokens.Replace(lastTextToken, newLastTextToken));
                    trimmedContent = trimmedContent.Replace(lastTextNode, newLastTextNode);
                    trailingTrivia = trailingTrivia.Insert(0, SyntaxFactory.Whitespace(trailingWhitespace));
                }
            }

            return(result.WithContent(trimmedContent)
                   .WithLeadingTrivia(leadingTrivia)
                   .WithTrailingTrivia(trailingTrivia));
        }
        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);
        }
        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");
            }

            var list = BuildStandardText(typeDeclaration.Identifier, typeParameterList, standardText[0], standardText[1]);

            var newContent = node.Content.InsertRange(0, list);
            var newNode    = node.WithContent(newContent);

            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, CancellationToken cancellationToken)
        {
            var  typeDeclaration   = node.FirstAncestorOrSelf <BaseTypeDeclarationSyntax>();
            var  declarationSyntax = node.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>();
            bool isStruct          = typeDeclaration.IsKind(SyntaxKind.StructDeclaration);
            var  settings          = document.Project.AnalyzerOptions.GetStyleCopSettings(cancellationToken);
            var  culture           = new CultureInfo(settings.DocumentationRules.DocumentationCulture);
            var  resourceManager   = DocumentationResources.ResourceManager;

            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)
            {
                var typeKindText = resourceManager.GetString(isStruct ? nameof(DocumentationResources.TypeTextStruct) : nameof(DocumentationResources.TypeTextClass), culture);
                if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword))
                {
                    standardText = ImmutableArray.Create(
                        string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextFirstPart), culture), typeKindText),
                        string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextSecondPart), culture), typeKindText));
                }
                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/brunocunhasilva/StyleCopAnalyzers/issues/413
                    standardText = ImmutableArray.Create(
                        string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextFirstPart), culture), typeKindText),
                        string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextSecondPart), culture), typeKindText));
                }
            }
            else if (declarationSyntax is DestructorDeclarationSyntax)
            {
                standardText =
                    ImmutableArray.Create(
                        resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextFirstPart), culture),
                        resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextSecondPart), culture));
            }
            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));
        }