diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index 3e508598bbf63..57d114e2100ef 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -8271,6 +8271,56 @@ interface IGoo { } List y = null; """)); + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53384")] + public Task TestDocumentationCData2() + => TestAsync(""" + using I$$ = IGoo; + /// + /// summary for interface IGoo + /// + /// + interface IGoo { } + """, + MainDescription("interface IGoo"), + Documentation(""" + summary for interface IGoo + + void M() + { + Console.WriteLine(); + } + """)); + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53384")] + public Task TestDocumentationCData3() + => TestAsync(""" + using I$$ = IGoo; + /// + /// summary for interface IGoo + /// + /// + interface IGoo { } + """, + MainDescription("interface IGoo"), + Documentation(""" + summary for interface IGoo + + void M() + { + Console.WriteLine(); + } + """)); + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37503")] public Task DoNotNormalizeWhitespaceForCode() => TestAsync(""" diff --git a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs index a8d81cb41ebcb..92ac708a5ffff 100644 --- a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs +++ b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs @@ -309,10 +309,20 @@ public ImmutableArray Format(string rawXmlText, ISymbol symbol, Sema private static void AppendTextFromNode(FormatterState state, XNode node, Compilation compilation) { - if (node.NodeType is XmlNodeType.Text or XmlNodeType.CDATA) + if (node is XText textNode) { - // cast is safe since XCData inherits XText - AppendTextFromTextNode(state, (XText)node); + if (textNode.NodeType == XmlNodeType.Text) + { + AppendTextFromTextNode(state, textNode, replaceNewLineWithPara: false); + } + else if (textNode.NodeType == XmlNodeType.CDATA) + { + state.PushStyle(TaggedTextStyle.Code | TaggedTextStyle.PreserveWhitespace); + AppendTextFromTextNode(state, textNode, replaceNewLineWithPara: true); + state.PopStyle(); + } + + return; } if (node.NodeType != XmlNodeType.Element) @@ -402,8 +412,8 @@ DocumentationCommentXmlNames.SeeAlsoElementName or state.NextListItem(); } - if (name is DocumentationCommentXmlNames.ParaElementName - or DocumentationCommentXmlNames.CodeElementName) + if (name is DocumentationCommentXmlNames.ParaElementName or + DocumentationCommentXmlNames.CodeElementName) { state.MarkBeginOrEndPara(); } @@ -417,8 +427,8 @@ DocumentationCommentXmlNames.SeeAlsoElementName or AppendTextFromNode(state, childNode, compilation); } - if (name is DocumentationCommentXmlNames.ParaElementName - or DocumentationCommentXmlNames.CodeElementName) + if (name is DocumentationCommentXmlNames.ParaElementName or + DocumentationCommentXmlNames.CodeElementName) { state.MarkBeginOrEndPara(); } @@ -544,13 +554,19 @@ private static string TrimCrefPrefix(string value) return value; } - private static void AppendTextFromTextNode(FormatterState state, XText element) + private static void AppendTextFromTextNode(FormatterState state, XText element, bool replaceNewLineWithPara) { var rawText = element.Value; if ((state.Style & TaggedTextStyle.PreserveWhitespace) == TaggedTextStyle.PreserveWhitespace) { - // Don't normalize code from middle. Only trim leading/trailing new lines. + if (replaceNewLineWithPara && rawText is ['\n', ..]) + state.MarkBeginOrEndPara(); + state.AppendString(rawText.Trim('\n')); + + if (replaceNewLineWithPara && rawText is [.., '\n']) + state.MarkBeginOrEndPara(); + return; }