Example #1
0
        private async Task <Document> CreateChangedDocument(CodeFixContext context, PropertyDeclarationSyntax propertyDeclarationSyntax, CancellationToken cancellationToken)
        {
            DocumentationCommentTriviaSyntax documentationComment = propertyDeclarationSyntax.GetDocumentationCommentTriviaSyntax();

            if (documentationComment == null)
            {
                return(context.Document);
            }

            XmlElementSyntax summaryElement = (XmlElementSyntax)documentationComment.Content.GetFirstXmlElement("summary");

            if (summaryElement == null)
            {
                return(context.Document);
            }

            SyntaxList <XmlNodeSyntax> summaryContent = summaryElement.Content;
            XmlNodeSyntax firstContent = summaryContent.FirstOrDefault(IsContentElement);
            XmlTextSyntax firstText    = firstContent as XmlTextSyntax;

            if (firstText != null)
            {
                string firstTextContent = string.Concat(firstText.DescendantTokens());
                if (firstTextContent.TrimStart().StartsWith("Gets ", StringComparison.Ordinal))
                {
                    // Find the token containing "Gets "
                    SyntaxToken getsToken = default(SyntaxToken);
                    foreach (SyntaxToken textToken in firstText.TextTokens)
                    {
                        if (textToken.IsMissing)
                        {
                            continue;
                        }

                        if (!textToken.Text.TrimStart().StartsWith("Gets ", StringComparison.Ordinal))
                        {
                            continue;
                        }

                        getsToken = textToken;
                        break;
                    }

                    if (!getsToken.IsMissing)
                    {
                        string text      = getsToken.Text;
                        string valueText = getsToken.ValueText;
                        int    index     = text.IndexOf("Gets ");
                        if (index >= 0)
                        {
                            bool additionalCharacters = index + 5 < text.Length;
                            text = text.Substring(0, index)
                                   + (additionalCharacters ? char.ToUpperInvariant(text[index + 5]).ToString() : string.Empty)
                                   + text.Substring(index + (additionalCharacters ? (5 + 1) : 5));
                        }

                        index = valueText.IndexOf("Gets ");
                        if (index >= 0)
                        {
                            valueText = valueText.Remove(index, 5);
                        }

                        SyntaxToken replaced = SyntaxFactory.Token(getsToken.LeadingTrivia, getsToken.Kind(), text, valueText, getsToken.TrailingTrivia);
                        summaryContent = summaryContent.Replace(firstText, firstText.ReplaceToken(getsToken, replaced));
                    }
                }
            }

            string        defaultValueToken = "NullIfNotIncluded";
            SemanticModel semanticModel     = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclarationSyntax);

            if (propertySymbol != null)
            {
                ITypeSymbol propertyType = propertySymbol.Type;
                if (propertyType.IsImmutableArray())
                {
                    defaultValueToken = "DefaultArrayIfNotIncluded";
                }
            }

            XmlElementSyntax valueElement =
                XmlSyntaxFactory.MultiLineElement(
                    "value",
                    XmlSyntaxFactory.List(
                        XmlSyntaxFactory.ParaElement(XmlSyntaxFactory.PlaceholderElement(summaryContent.WithoutFirstAndLastNewlines())),
                        XmlSyntaxFactory.NewLine(),
                        XmlSyntaxFactory.TokenElement(defaultValueToken)));

            XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine();

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

            DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(
                documentationComment.Content.InsertRange(documentationComment.Content.Count - 1,
                                                         XmlSyntaxFactory.List(
                                                             leadingNewLine,
                                                             valueElement)));

            SyntaxNode root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newRoot = root.ReplaceNode(documentationComment, newDocumentationComment);

            return(context.Document.WithSyntaxRoot(newRoot));
        }
Example #2
0
        public static SyntaxList <XmlNodeSyntax> WithoutFirstAndLastNewlines(this SyntaxList <XmlNodeSyntax> summaryContent)
        {
            if (summaryContent.Count == 0)
            {
                return(summaryContent);
            }

            XmlTextSyntax firstSyntax = summaryContent[0] as XmlTextSyntax;

            if (firstSyntax == null)
            {
                return(summaryContent);
            }

            XmlTextSyntax lastSyntax = summaryContent[summaryContent.Count - 1] as XmlTextSyntax;

            if (lastSyntax == null)
            {
                return(summaryContent);
            }

            SyntaxTokenList firstSyntaxTokens = firstSyntax.TextTokens;

            int removeFromStart;

            if (IsXmlNewLine(firstSyntaxTokens[0]))
            {
                removeFromStart = 1;
            }
            else
            {
                if (!IsXmlWhitespace(firstSyntaxTokens[0]))
                {
                    return(summaryContent);
                }

                if (!IsXmlNewLine(firstSyntaxTokens[1]))
                {
                    return(summaryContent);
                }

                removeFromStart = 2;
            }

            SyntaxTokenList lastSyntaxTokens = lastSyntax.TextTokens;

            int removeFromEnd;

            if (IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
            {
                removeFromEnd = 1;
            }
            else
            {
                if (!IsXmlWhitespace(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
                {
                    return(summaryContent);
                }

                if (!IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 2]))
                {
                    return(summaryContent);
                }

                removeFromEnd = 2;
            }

            for (int i = 0; i < removeFromStart; i++)
            {
                firstSyntaxTokens = firstSyntaxTokens.RemoveAt(0);
            }

            if (firstSyntax == lastSyntax)
            {
                lastSyntaxTokens = firstSyntaxTokens;
            }

            for (int i = 0; i < removeFromEnd; i++)
            {
                if (!lastSyntaxTokens.Any())
                {
                    break;
                }

                lastSyntaxTokens = lastSyntaxTokens.RemoveAt(lastSyntaxTokens.Count - 1);
            }

            summaryContent = summaryContent.RemoveAt(summaryContent.Count - 1);
            if (lastSyntaxTokens.Count != 0)
            {
                summaryContent = summaryContent.Add(lastSyntax.WithTextTokens(lastSyntaxTokens));
            }

            if (firstSyntax != lastSyntax)
            {
                summaryContent = summaryContent.RemoveAt(0);
                if (firstSyntaxTokens.Count != 0)
                {
                    summaryContent = summaryContent.Insert(0, firstSyntax.WithTextTokens(firstSyntaxTokens));
                }
            }

            if (summaryContent.Count > 0)
            {
                // Make sure to remove the leading trivia
                summaryContent = summaryContent.Replace(summaryContent[0], summaryContent[0].WithLeadingTrivia());

                // Remove leading spaces (between the <para> start tag and the start of the paragraph content)
                XmlTextSyntax firstTextSyntax = summaryContent[0] as XmlTextSyntax;
                if (firstTextSyntax != null && firstTextSyntax.TextTokens.Count > 0)
                {
                    SyntaxToken firstTextToken = firstTextSyntax.TextTokens[0];
                    string      firstTokenText = firstTextToken.Text;
                    string      trimmed        = firstTokenText.TrimStart();
                    if (trimmed != firstTokenText)
                    {
                        SyntaxToken newFirstToken = SyntaxFactory.Token(
                            firstTextToken.LeadingTrivia,
                            firstTextToken.Kind(),
                            trimmed,
                            firstTextToken.ValueText.TrimStart(),
                            firstTextToken.TrailingTrivia);

                        summaryContent = summaryContent.Replace(firstTextSyntax, firstTextSyntax.ReplaceToken(firstTextToken, newFirstToken));
                    }
                }
            }

            return(summaryContent);
        }
Example #3
0
        private bool TryRemoveSummaryPrefix(ref SyntaxList <XmlNodeSyntax> summaryContent, string prefix)
        {
            XmlNodeSyntax firstContent = summaryContent.FirstOrDefault(IsContentElement);
            XmlTextSyntax firstText    = firstContent as XmlTextSyntax;

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

            string firstTextContent = string.Concat(firstText.DescendantTokens());

            if (!firstTextContent.TrimStart().StartsWith(prefix, StringComparison.Ordinal))
            {
                return(false);
            }

            // Find the token containing the prefix, such as "Gets or sets "
            SyntaxToken prefixToken = default(SyntaxToken);

            foreach (SyntaxToken textToken in firstText.TextTokens)
            {
                if (textToken.IsMissing)
                {
                    continue;
                }

                if (!textToken.Text.TrimStart().StartsWith(prefix, StringComparison.Ordinal))
                {
                    continue;
                }

                prefixToken = textToken;
                break;
            }

            if (prefixToken.IsMissingOrDefault())
            {
                return(false);
            }

            string text      = prefixToken.Text;
            string valueText = prefixToken.ValueText;
            int    index     = text.IndexOf(prefix);

            if (index >= 0)
            {
                bool additionalCharacters = index + prefix.Length < text.Length;
                text = text.Substring(0, index)
                       + (additionalCharacters ? char.ToUpperInvariant(text[index + prefix.Length]).ToString() : string.Empty)
                       + text.Substring(index + (additionalCharacters ? (prefix.Length + 1) : prefix.Length));
            }

            index = valueText.IndexOf(prefix);
            if (index >= 0)
            {
                valueText = valueText.Remove(index, prefix.Length);
            }

            SyntaxToken replaced = SyntaxFactory.Token(prefixToken.LeadingTrivia, prefixToken.Kind(), text, valueText, prefixToken.TrailingTrivia);

            summaryContent = summaryContent.Replace(firstText, firstText.ReplaceToken(prefixToken, replaced));
            return(true);
        }