diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index 8b0dc9a91d517..ab440347d3059 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -398,6 +398,25 @@ await TestAsync(markup, Documentation("summary for interface IGoo")); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/60725")] + public async Task TestMergedRemarks() + { + var markup = + """ + /// hello1 + public partial class C { + } + + /// hello2 + public partial class $$C { + } + """; + + await TestAsync(markup, + MainDescription("class C"), + Remarks("hello1 hello2")); + } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/991466")] public async Task TestDocumentationInUsingDirectiveWithAlias3() { @@ -516,7 +535,9 @@ void M() // SingleLine doc comment with '\r' line separators await TestAsync(""" - ///Hello! /// class C { void M() { $$C obj; } } + ///Hello! + /// + class C { void M() { $$C obj; } } """, MainDescription("class C"), Documentation("Hello!")); @@ -632,7 +653,12 @@ void M() // Multiline doc comment with '\r' line separators await TestAsync(""" - /** * * Hello! * */ class C { void M() { $$C obj; } } + /** + * + * Hello! + * + */ + class C { void M() { $$C obj; } } """, MainDescription("class C"), Documentation("Hello!")); diff --git a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb index d3a06bef056a3..8e99c1e4e54a4 100644 --- a/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb +++ b/src/EditorFeatures/Test2/Workspaces/SymbolDescriptionServiceTests.vb @@ -10,10 +10,8 @@ Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.LanguageService Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces - <[UseExportProvider]> Public Class SymbolDescriptionServiceTests - Private Shared Async Function TestAsync(languageServiceProvider As HostLanguageServices, workspace As EditorTestWorkspace, expectedDescription As String) As Task Dim solution = workspace.CurrentSolution diff --git a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentFormattingService.cs b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentFormattingService.cs index 4ee4086912483..4f51468a72599 100644 --- a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentFormattingService.cs +++ b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentFormattingService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.DocumentationComments; @@ -12,11 +10,6 @@ namespace Microsoft.CodeAnalysis.CSharp.DocumentationComments; [ExportLanguageService(typeof(IDocumentationCommentFormattingService), LanguageNames.CSharp), Shared] -internal class CSharpDocumentationCommentFormattingService : AbstractDocumentationCommentFormattingService -{ - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpDocumentationCommentFormattingService() - { - } -} +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class CSharpDocumentationCommentFormattingService() : AbstractDocumentationCommentFormattingService; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs b/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs index 695466d6a1358..168cd9319471b 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs @@ -7,8 +7,8 @@ using System.Collections.Immutable; using System.Xml; using Microsoft.CodeAnalysis.PooledObjects; -using XmlNames = Roslyn.Utilities.DocumentationCommentXmlNames; using Microsoft.CodeAnalysis.Shared.Extensions; +using XmlNames = Roslyn.Utilities.DocumentationCommentXmlNames; namespace Microsoft.CodeAnalysis.Shared.Utilities; @@ -227,89 +227,98 @@ private static string TrimEachLine(string text) private void ParseCallback(XmlReader reader) { - if (reader.NodeType == XmlNodeType.Element) + if (reader.NodeType != XmlNodeType.Element) { - var localName = reader.LocalName; - if (XmlNames.ElementEquals(localName, XmlNames.ExampleElementName) && _comment.ExampleText == null) - { - _comment.ExampleText = TrimEachLine(reader.ReadInnerXml()); - } - else if (XmlNames.ElementEquals(localName, XmlNames.SummaryElementName) && _comment.SummaryText == null) - { - _comment.SummaryText = TrimEachLine(reader.ReadInnerXml()); - } - else if (XmlNames.ElementEquals(localName, XmlNames.ReturnsElementName) && _comment.ReturnsText == null) - { - _comment.ReturnsText = TrimEachLine(reader.ReadInnerXml()); - } - else if (XmlNames.ElementEquals(localName, XmlNames.ValueElementName) && _comment.ValueText == null) - { - _comment.ValueText = TrimEachLine(reader.ReadInnerXml()); - } - else if (XmlNames.ElementEquals(localName, XmlNames.RemarksElementName) && _comment.RemarksText == null) + // We came across something that isn't a start element, like a block of text. Skip it. + reader.Read(); + return; + } + + var localName = reader.LocalName; + if (XmlNames.ElementEquals(localName, XmlNames.ExampleElementName)) + { + _comment.ExampleText = InitializeValue(_comment.ExampleText, TrimEachLine(reader.ReadInnerXml())); + } + else if (XmlNames.ElementEquals(localName, XmlNames.SummaryElementName)) + { + _comment.SummaryText = InitializeValue(_comment.SummaryText, TrimEachLine(reader.ReadInnerXml())); + } + else if (XmlNames.ElementEquals(localName, XmlNames.ReturnsElementName)) + { + _comment.ReturnsText = InitializeValue(_comment.ReturnsText, TrimEachLine(reader.ReadInnerXml())); + } + else if (XmlNames.ElementEquals(localName, XmlNames.ValueElementName)) + { + _comment.ValueText = InitializeValue(_comment.ValueText, TrimEachLine(reader.ReadInnerXml())); + } + else if (XmlNames.ElementEquals(localName, XmlNames.RemarksElementName)) + { + _comment.RemarksText = InitializeValue(_comment.RemarksText, TrimEachLine(reader.ReadInnerXml())); + } + else if (XmlNames.ElementEquals(localName, XmlNames.ParameterElementName)) + { + var name = reader.GetAttribute(XmlNames.NameAttributeName); + var paramText = reader.ReadInnerXml(); + + if (!string.IsNullOrWhiteSpace(name) && !_comment._parameterTexts.ContainsKey(name)) { - _comment.RemarksText = TrimEachLine(reader.ReadInnerXml()); + (_parameterNamesBuilder ??= ImmutableArray.CreateBuilder()).Add(name); + _comment._parameterTexts.Add(name, TrimEachLine(paramText)); } - else if (XmlNames.ElementEquals(localName, XmlNames.ParameterElementName)) - { - var name = reader.GetAttribute(XmlNames.NameAttributeName); - var paramText = reader.ReadInnerXml(); + } + else if (XmlNames.ElementEquals(localName, XmlNames.TypeParameterElementName)) + { + var name = reader.GetAttribute(XmlNames.NameAttributeName); + var typeParamText = reader.ReadInnerXml(); - if (!string.IsNullOrWhiteSpace(name) && !_comment._parameterTexts.ContainsKey(name)) - { - (_parameterNamesBuilder ??= ImmutableArray.CreateBuilder()).Add(name); - _comment._parameterTexts.Add(name, TrimEachLine(paramText)); - } - } - else if (XmlNames.ElementEquals(localName, XmlNames.TypeParameterElementName)) + if (!string.IsNullOrWhiteSpace(name) && !_comment._typeParameterTexts.ContainsKey(name)) { - var name = reader.GetAttribute(XmlNames.NameAttributeName); - var typeParamText = reader.ReadInnerXml(); - - if (!string.IsNullOrWhiteSpace(name) && !_comment._typeParameterTexts.ContainsKey(name)) - { - (_typeParameterNamesBuilder ??= ImmutableArray.CreateBuilder()).Add(name); - _comment._typeParameterTexts.Add(name, TrimEachLine(typeParamText)); - } + (_typeParameterNamesBuilder ??= ImmutableArray.CreateBuilder()).Add(name); + _comment._typeParameterTexts.Add(name, TrimEachLine(typeParamText)); } - else if (XmlNames.ElementEquals(localName, XmlNames.ExceptionElementName)) - { - var type = reader.GetAttribute(XmlNames.CrefAttributeName); - var exceptionText = reader.ReadInnerXml(); - - if (!string.IsNullOrWhiteSpace(type)) - { - if (_exceptionTextBuilders == null || !_exceptionTextBuilders.ContainsKey(type)) - { - (_exceptionTypesBuilder ??= ImmutableArray.CreateBuilder()).Add(type); - (_exceptionTextBuilders ??= []).Add(type, ImmutableArray.CreateBuilder()); - } + } + else if (XmlNames.ElementEquals(localName, XmlNames.ExceptionElementName)) + { + var type = reader.GetAttribute(XmlNames.CrefAttributeName); + var exceptionText = reader.ReadInnerXml(); - _exceptionTextBuilders[type].Add(exceptionText); - } - } - else if (XmlNames.ElementEquals(localName, XmlNames.CompletionListElementName)) + if (!string.IsNullOrWhiteSpace(type)) { - var cref = reader.GetAttribute(XmlNames.CrefAttributeName); - if (!string.IsNullOrWhiteSpace(cref)) + if (_exceptionTextBuilders == null || !_exceptionTextBuilders.ContainsKey(type)) { - _comment.CompletionListCref = cref; + (_exceptionTypesBuilder ??= ImmutableArray.CreateBuilder()).Add(type); + (_exceptionTextBuilders ??= []).Add(type, ImmutableArray.CreateBuilder()); } - reader.ReadInnerXml(); + _exceptionTextBuilders[type].Add(exceptionText); } - else + } + else if (XmlNames.ElementEquals(localName, XmlNames.CompletionListElementName)) + { + var cref = reader.GetAttribute(XmlNames.CrefAttributeName); + if (!string.IsNullOrWhiteSpace(cref)) { - // This is an element we don't handle. Skip it. - reader.Read(); + _comment.CompletionListCref = cref; } + + reader.ReadInnerXml(); } else { - // We came across something that isn't a start element, like a block of text. - // Skip it. + // This is an element we don't handle. Skip it. reader.Read(); } + + return; + + static string InitializeValue(string? existingValue, string newValue) + { + // The use of Environment.NewLine matches the behavior of StringBuilder.AppendLine used in multiple + // places in this file. + return existingValue is null or "" + ? newValue + : $"{existingValue}{Environment.NewLine}{newValue}"; + } } } diff --git a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs index 2664563f9815e..7868727b2feda 100644 --- a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentTests.cs @@ -2,351 +2,389 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.UnitTests +namespace Microsoft.CodeAnalysis.UnitTests; + +public class DocumentationCommentTests { - public class DocumentationCommentTests + [Fact] + public void ParseEmptyXmlFragment() + { + var document = DocumentationComment.FromXmlFragment(""); + + Assert.Null(document.ExampleText); + Assert.Null(document.ReturnsText); + Assert.Null(document.ValueText); + Assert.Null(document.SummaryText); + } + + [Fact] + public void ParseFullTag() + { + var comment = DocumentationComment.FromXmlFragment( + """ + Hello, world! + 42. + 43. + goo.Bar(); + A goo. + A type. + An exception + A remark + """); + + Assert.Equal("Hello, world!", comment.SummaryText); + Assert.Equal("42.", comment.ReturnsText); + Assert.Equal("43.", comment.ValueText); + Assert.Equal("goo.Bar();", comment.ExampleText); + Assert.Equal("goo", comment.ParameterNames[0]); + Assert.Equal("A goo.", comment.GetParameterText("goo")); + Assert.Equal("T", comment.TypeParameterNames[0]); + Assert.Equal("A type.", comment.GetTypeParameterText("T")); + Assert.Equal("System.Exception", comment.ExceptionTypes[0]); + Assert.Equal("An exception", comment.GetExceptionTexts("System.Exception")[0]); + Assert.Equal("A remark", comment.RemarksText); + } + + [Fact] + public void ParseFullTagEmptyValues() + { + var comment = DocumentationComment.FromXmlFragment( + """ + + + + + + + + + """); + + Assert.Equal(string.Empty, comment.SummaryText); + Assert.Equal(string.Empty, comment.ReturnsText); + Assert.Equal(string.Empty, comment.ValueText); + Assert.Equal(string.Empty, comment.ExampleText); + Assert.Equal("goo", comment.ParameterNames[0]); + Assert.Equal(string.Empty, comment.GetParameterText("goo")); + Assert.Equal("T", comment.TypeParameterNames[0]); + Assert.Equal(string.Empty, comment.GetTypeParameterText("T")); + Assert.Equal("System.Exception", comment.ExceptionTypes[0]); + Assert.Equal(string.Empty, comment.GetExceptionTexts("System.Exception")[0]); + Assert.Equal(string.Empty, comment.RemarksText); + } + + [Fact] + public void ParseTagWithMultipleSummaries() + { + var comment = DocumentationComment.FromXmlFragment("Summary 1Summary 2"); + + Assert.Equal(""" + Summary 1 + Summary 2 + """, comment.SummaryText); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/522741")] + public void ParseTagWithMultiLineComments() + { + var comment = DocumentationComment.FromXmlFragment(""" + + Summary 1 + Summary 2 + + """); + + Assert.Equal(""" + Summary 1 + Summary 2 + """, comment.SummaryText); + } + + [Fact] + public void ParseInvalidXML() + { + var comment = DocumentationComment.FromXmlFragment("goo"); + + Assert.True(comment.HadXmlParseError); + Assert.Null(comment.SummaryText); + } + + [Fact] + public void PreserveParameterNameOrdering() + { + var comment = DocumentationComment.FromXmlFragment( + """ + Z + A + B + """); + + Assert.Equal("z", comment.ParameterNames[0]); + Assert.Equal("a", comment.ParameterNames[1]); + Assert.Equal("b", comment.ParameterNames[2]); + } + + [Fact] + public void PreserveTypeParameterNameOrdering() + { + var comment = DocumentationComment.FromXmlFragment( + """ + Z + A + B + """); + + Assert.Equal("z", comment.TypeParameterNames[0]); + Assert.Equal("a", comment.TypeParameterNames[1]); + Assert.Equal("b", comment.TypeParameterNames[2]); + } + + [Fact] + public void PreserveExceptionTypeOrdering() + { + var comment = DocumentationComment.FromXmlFragment( + """ + Z + A + B + """); + + Assert.Equal("z", comment.ExceptionTypes[0]); + Assert.Equal("a", comment.ExceptionTypes[1]); + Assert.Equal("b", comment.ExceptionTypes[2]); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] + public void UnknownTag() + { + var comment = DocumentationComment.FromXmlFragment( + """ + This is a summary. + This is another summary. + The param named 'a' + """); + + Assert.Equal("This is a summary.", comment.SummaryText); + Assert.Equal("a", comment.ParameterNames[0]); + Assert.Equal("The param named 'a'", comment.GetParameterText("a")); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] + public void TextOutsideTag() + { + var comment = DocumentationComment.FromXmlFragment( + """ + This is a summary. + This is random top-level text. + The param named 'a' + """); + + Assert.Equal("This is a summary.", comment.SummaryText); + Assert.Equal("a", comment.ParameterNames[0]); + Assert.Equal("The param named 'a'", comment.GetParameterText("a")); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] + public void SingleTopLevelTag() + { + var comment = DocumentationComment.FromXmlFragment( + """ + + This is a summary. + This is random top-level text. + The param named 'a' + + """); + + Assert.Equal("This is a summary.", comment.SummaryText); + Assert.Equal("a", comment.ParameterNames[0]); + Assert.Equal("The param named 'a'", comment.GetParameterText("a")); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] + public void MultipleParamsWithSameName() + { + var comment = DocumentationComment.FromXmlFragment( + """ + This comment should be retained. + This comment should not be retained. + """); + + Assert.Equal(1, comment.ParameterNames.Length); + Assert.Equal("a", comment.ParameterNames[0]); + Assert.Equal("This comment should be retained.", comment.GetParameterText("a")); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] + public void MultipleTypeParamsWithSameName() + { + var comment = DocumentationComment.FromXmlFragment( + """ + This comment should be retained. + This comment should not be retained. + """); + + Assert.Equal(1, comment.TypeParameterNames.Length); + Assert.Equal("a", comment.TypeParameterNames[0]); + Assert.Equal("This comment should be retained.", comment.GetTypeParameterText("a")); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] + public void MultipleExceptionsWithSameName() + { + var comment = DocumentationComment.FromXmlFragment( + """ + First A description + First B description + Second A description + Second B description + """); + + Assert.Equal(2, comment.ExceptionTypes.Length); + Assert.Equal("A", comment.ExceptionTypes[0]); + Assert.Equal("B", comment.ExceptionTypes[1]); + Assert.Equal(2, comment.GetExceptionTexts("A").Length); + Assert.Equal("First A description", comment.GetExceptionTexts("A")[0]); + Assert.Equal("Second A description", comment.GetExceptionTexts("A")[1]); + Assert.Equal(2, comment.GetExceptionTexts("B").Length); + Assert.Equal("First B description", comment.GetExceptionTexts("B")[0]); + Assert.Equal("Second B description", comment.GetExceptionTexts("B")[1]); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] + public void NoExceptionWithGivenName() + { + var comment = DocumentationComment.FromXmlFragment(@"This is a summary"); + + Assert.Equal(0, comment.GetExceptionTexts("A").Length); + } + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531189")] + public void NoNameAttribute() { - [Fact] - public void ParseEmptyXmlFragment() - { - var document = DocumentationComment.FromXmlFragment(""); - - Assert.Null(document.ExampleText); - Assert.Null(document.ReturnsText); - Assert.Null(document.ValueText); - Assert.Null(document.SummaryText); - } - - [Fact] - public void ParseFullTag() - { - var comment = DocumentationComment.FromXmlFragment( - @"Hello, world! - 42. - 43. - goo.Bar(); - A goo. - A type. - An exception - A remark"); - - Assert.Equal("Hello, world!", comment.SummaryText); - Assert.Equal("42.", comment.ReturnsText); - Assert.Equal("43.", comment.ValueText); - Assert.Equal("goo.Bar();", comment.ExampleText); - Assert.Equal("goo", comment.ParameterNames[0]); - Assert.Equal("A goo.", comment.GetParameterText("goo")); - Assert.Equal("T", comment.TypeParameterNames[0]); - Assert.Equal("A type.", comment.GetTypeParameterText("T")); - Assert.Equal("System.Exception", comment.ExceptionTypes[0]); - Assert.Equal("An exception", comment.GetExceptionTexts("System.Exception")[0]); - Assert.Equal("A remark", comment.RemarksText); - } - - [Fact] - public void ParseFullTagEmptyValues() - { - var comment = DocumentationComment.FromXmlFragment( - @" - - - - - - - "); - - Assert.Equal(string.Empty, comment.SummaryText); - Assert.Equal(string.Empty, comment.ReturnsText); - Assert.Equal(string.Empty, comment.ValueText); - Assert.Equal(string.Empty, comment.ExampleText); - Assert.Equal("goo", comment.ParameterNames[0]); - Assert.Equal(string.Empty, comment.GetParameterText("goo")); - Assert.Equal("T", comment.TypeParameterNames[0]); - Assert.Equal(string.Empty, comment.GetTypeParameterText("T")); - Assert.Equal("System.Exception", comment.ExceptionTypes[0]); - Assert.Equal(string.Empty, comment.GetExceptionTexts("System.Exception")[0]); - Assert.Equal(string.Empty, comment.RemarksText); - } - - [Fact] - public void ParseTagWithMultipleSummaries() - { - var comment = DocumentationComment.FromXmlFragment("Summary 1Summary 2"); - - Assert.Equal("Summary 1", comment.SummaryText); - } - - [Fact(Skip = "Bug 522741")] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/522741")] - public void ParseTagWithMultiLineComments() - { - var comment = DocumentationComment.FromXmlFragment(@" -Summary 1 -Summary 2 -"); - - Assert.Equal("Summary 1 Summary 2", comment.SummaryText); - } - - [Fact] - public void ParseInvalidXML() - { - var comment = DocumentationComment.FromXmlFragment("goo"); - - Assert.True(comment.HadXmlParseError); - Assert.Null(comment.SummaryText); - } - - [Fact] - public void PreserveParameterNameOrdering() - { - var comment = DocumentationComment.FromXmlFragment( -@"Z -A -B"); - - Assert.Equal("z", comment.ParameterNames[0]); - Assert.Equal("a", comment.ParameterNames[1]); - Assert.Equal("b", comment.ParameterNames[2]); - } - - [Fact] - public void PreserveTypeParameterNameOrdering() - { - var comment = DocumentationComment.FromXmlFragment( -@"Z -A -B"); - - Assert.Equal("z", comment.TypeParameterNames[0]); - Assert.Equal("a", comment.TypeParameterNames[1]); - Assert.Equal("b", comment.TypeParameterNames[2]); - } - - [Fact] - public void PreserveExceptionTypeOrdering() - { - var comment = DocumentationComment.FromXmlFragment( -@"Z -A -B"); - - Assert.Equal("z", comment.ExceptionTypes[0]); - Assert.Equal("a", comment.ExceptionTypes[1]); - Assert.Equal("b", comment.ExceptionTypes[2]); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] - public void UnknownTag() - { - var comment = DocumentationComment.FromXmlFragment( -@"This is a summary. -This is another summary. -The param named 'a'"); - - Assert.Equal("This is a summary.", comment.SummaryText); - Assert.Equal("a", comment.ParameterNames[0]); - Assert.Equal("The param named 'a'", comment.GetParameterText("a")); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] - public void TextOutsideTag() - { - var comment = DocumentationComment.FromXmlFragment( -@"This is a summary. -This is random top-level text. -The param named 'a'"); - - Assert.Equal("This is a summary.", comment.SummaryText); - Assert.Equal("a", comment.ParameterNames[0]); - Assert.Equal("The param named 'a'", comment.GetParameterText("a")); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546732")] - public void SingleTopLevelTag() - { - var comment = DocumentationComment.FromXmlFragment( -@" -This is a summary. -This is random top-level text. -The param named 'a' -"); - - Assert.Equal("This is a summary.", comment.SummaryText); - Assert.Equal("a", comment.ParameterNames[0]); - Assert.Equal("The param named 'a'", comment.GetParameterText("a")); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] - public void MultipleParamsWithSameName() - { - var comment = DocumentationComment.FromXmlFragment( -@"This comment should be retained. -This comment should not be retained."); - - Assert.Equal(1, comment.ParameterNames.Length); - Assert.Equal("a", comment.ParameterNames[0]); - Assert.Equal("This comment should be retained.", comment.GetParameterText("a")); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] - public void MultipleTypeParamsWithSameName() - { - var comment = DocumentationComment.FromXmlFragment( -@"This comment should be retained. -This comment should not be retained."); - - Assert.Equal(1, comment.TypeParameterNames.Length); - Assert.Equal("a", comment.TypeParameterNames[0]); - Assert.Equal("This comment should be retained.", comment.GetTypeParameterText("a")); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] - public void MultipleExceptionsWithSameName() - { - var comment = DocumentationComment.FromXmlFragment( -@"First A description -First B description -Second A description -Second B description"); - - Assert.Equal(2, comment.ExceptionTypes.Length); - Assert.Equal("A", comment.ExceptionTypes[0]); - Assert.Equal("B", comment.ExceptionTypes[1]); - Assert.Equal(2, comment.GetExceptionTexts("A").Length); - Assert.Equal("First A description", comment.GetExceptionTexts("A")[0]); - Assert.Equal("Second A description", comment.GetExceptionTexts("A")[1]); - Assert.Equal(2, comment.GetExceptionTexts("B").Length); - Assert.Equal("First B description", comment.GetExceptionTexts("B")[0]); - Assert.Equal("Second B description", comment.GetExceptionTexts("B")[1]); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530760")] - public void NoExceptionWithGivenName() - { - var comment = DocumentationComment.FromXmlFragment(@"This is a summary"); - - Assert.Equal(0, comment.GetExceptionTexts("A").Length); - } - - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531189")] - public void NoNameAttribute() - { - var comment = DocumentationComment.FromXmlFragment(@""); - - Assert.Equal(0, comment.ParameterNames.Length); - Assert.Equal(0, comment.TypeParameterNames.Length); - Assert.Equal(0, comment.ExceptionTypes.Length); - } - - [Fact, WorkItem(612456, "DevDiv2/DevDiv")] - public void ReservedXmlNamespaceInName() - { - var fragment = @""; - - var comments = DocumentationComment.FromXmlFragment(fragment); - - Assert.Equal(fragment, comments.FullXmlFragment); - Assert.True(comments.HadXmlParseError); - } - - [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/18901")] - public void TrimEachLine() - { - var multiLineText = @" - - - -Hello - World . -+ -....... - - - - -123 - - 1"; - - var fullXml = $@"{multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText}"; - - var expected = @"Hello - World . -+ -....... -123 - 1"; + var comment = DocumentationComment.FromXmlFragment(@""); + + Assert.Equal(0, comment.ParameterNames.Length); + Assert.Equal(0, comment.TypeParameterNames.Length); + Assert.Equal(0, comment.ExceptionTypes.Length); + } + + [Fact, WorkItem(612456, "DevDiv2/DevDiv")] + public void ReservedXmlNamespaceInName() + { + var fragment = @""; + + var comments = DocumentationComment.FromXmlFragment(fragment); - var comment = DocumentationComment.FromXmlFragment(fullXml); - - Assert.Equal(expected, comment.SummaryText); - Assert.Equal(expected, comment.ReturnsText); - Assert.Equal(expected, comment.ValueText); - Assert.Equal(expected, comment.ExampleText); - Assert.Equal(expected, comment.GetParameterText("goo")); - Assert.Equal(expected, comment.GetTypeParameterText("T")); - Assert.Equal(expected, comment.RemarksText); - } + Assert.Equal(fragment, comments.FullXmlFragment); + Assert.True(comments.HadXmlParseError); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/18901")] + public void TrimEachLine() + { + var multiLineText = """ + + + + + Hello + World . + + + ....... + + + + + 123 + + 1 + """; + + var fullXml = $""" + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + """; + + var expected = """ + Hello + World . + + + ....... + 123 + 1 + """; + + var comment = DocumentationComment.FromXmlFragment(fullXml); + + Assert.Equal(expected, comment.SummaryText); + Assert.Equal(expected, comment.ReturnsText); + Assert.Equal(expected, comment.ValueText); + Assert.Equal(expected, comment.ExampleText); + Assert.Equal(expected, comment.GetParameterText("goo")); + Assert.Equal(expected, comment.GetTypeParameterText("T")); + Assert.Equal(expected, comment.RemarksText); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/18901")] + public void TrimEachLineCommonOffset() + { + var multiLineText = """ - [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/18901")] - public void TrimEachLineCommonOffset() - { - var multiLineText = @" - Hello - World . - + - ....... - + Hello + World . + + + ....... + - 123 + 123 - 1"; + 1 + """; - var fullXml = $@"{multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText} - {multiLineText}"; + var fullXml = $""" + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + {multiLineText} + """; - var expected = @"Hello - World . -+ -....... + var expected = """ + Hello + World . + + + ....... - 123 - 1"; + 123 + 1 + """; - var comment = DocumentationComment.FromXmlFragment(fullXml); + var comment = DocumentationComment.FromXmlFragment(fullXml); - Assert.Equal(expected, comment.SummaryText); - Assert.Equal(expected, comment.ReturnsText); - Assert.Equal(expected, comment.ValueText); - Assert.Equal(expected, comment.ExampleText); - Assert.Equal(expected, comment.GetParameterText("goo")); - Assert.Equal(expected, comment.GetTypeParameterText("T")); - Assert.Equal(expected, comment.RemarksText); - } + Assert.Equal(expected, comment.SummaryText); + Assert.Equal(expected, comment.ReturnsText); + Assert.Equal(expected, comment.ValueText); + Assert.Equal(expected, comment.ExampleText); + Assert.Equal(expected, comment.GetParameterText("goo")); + Assert.Equal(expected, comment.GetTypeParameterText("T")); + Assert.Equal(expected, comment.RemarksText); } }