From 59294b8d187bbc751fea50f8d42ec5f76b7f7fcf Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 13 Feb 2025 12:55:12 +0100 Subject: [PATCH] Partial events and constructors: doc comments --- .../Compiler/DocumentationCommentCompiler.cs | 8 +- .../DocumentationCommentCompilerTests.cs | 1055 +++++++++++++++++ 2 files changed, 1056 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs index edd5c97d36375..ec6661e4541b2 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs @@ -258,13 +258,7 @@ public override void DefaultVisit(Symbol symbol) bool shouldSkipPartialDefinitionComments = false; if (symbol.IsPartialDefinition()) { - Symbol? implementationPart = symbol switch - { - MethodSymbol method => method.PartialImplementationPart, - SourcePropertySymbol property => property.PartialImplementationPart, - _ => null - }; - + Symbol? implementationPart = symbol.GetPartialImplementationPart(); if (implementationPart is not null) { Visit(implementationPart); diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs index 29d904d1fc47a..2377b23b1aa4b 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs @@ -2180,6 +2180,1061 @@ void verify(CSharpTestSource source) } } + [Fact] + public void PartialEvent_NoImplementation() + { + var source = """ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var comp = CreateCompilation(source, + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics( + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22), + // (4,40): error CS9400: Partial member 'C.E' must have an implementation part. + // public partial event System.Action E; + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "E").WithArguments("C.E").WithLocation(4, 40)); + var e = comp.GlobalNamespace.GetMember("C.E"); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + + + Test + + + + + """, GetDocumentationCommentText(comp, + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22))); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + Summary 1 + + """, DocumentationCommentCompiler.GetDocumentationCommentXml(e, processIncludes: true, cancellationToken: default)); + } + + [Fact] + public void PartialConstructor_NoImplementation() + { + var source = """ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var comp = CreateCompilation(source, + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics( + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22), + // (4,20): error CS9400: Partial member 'C.C()' must have an implementation part. + // public partial C(); + Diagnostic(ErrorCode.ERR_PartialMemberMissingImplementation, "C").WithArguments("C.C()").WithLocation(4, 20)); + var ctor = comp.GlobalNamespace.GetMember("C..ctor"); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + + + Test + + + + + """, GetDocumentationCommentText(comp, + // (1,22): warning CS1591: Missing XML comment for publicly visible type or member 'C' + // public partial class C + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C").WithLocation(1, 22))); + + AssertEx.AssertEqualToleratingWhitespaceDifferences(""" + + Summary 1 + + """, DocumentationCommentCompiler.GetDocumentationCommentXml(ctor, processIncludes: true, cancellationToken: default)); + } + + [Fact] + public void PartialEvent_MultipleFiles() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_ImplementationComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_DefinitionComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 1 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_ImplementationComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial C(); + } + """; + var source2 = """ + public partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_DefinitionComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + public partial class C + { + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + Summary 1 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_NoComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial event System.Action E; + } + """; + var source2 = """ + public partial class C + { + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + + """; + + var expectedDiagnostics = new[] + { + // (4,40): warning CS1591: Missing XML comment for publicly visible type or member 'C.E' + // public partial event System.Action E; + Diagnostic(ErrorCode.WRN_MissingXMLComment, "E").WithArguments("C.E").WithLocation(4, 40) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_NoComment() + { + var source1 = """ + /** Summary 0 */ + public partial class C + { + public partial C(); + } + """; + var source2 = """ + public partial class C + { + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 0 + + + + """; + + var expectedDiagnostics = new[] + { + // (4,20): warning CS1591: Missing XML comment for publicly visible type or member 'C.C()' + // public partial C(); + Diagnostic(ErrorCode.WRN_MissingXMLComment, "C").WithArguments("C.C()").WithLocation(4, 20) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialEvent_MultipleFiles_Overlap() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** Remarks 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Remarks 2 + + + + """; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_Overlap() + { + var source1 = """ + partial class C + { + /// Summary 1 + /// Param 1 + public partial C(int x, int y); + } + """; + var source2 = """ + partial class C + { + /// Remarks 2 + /// Param 2 + public partial C(int x, int y) { } + } + """; + + var expected = """ + + + + Test + + + + Remarks 2 + Param 2 + + + + """; + + var expectedDiagnostics = new[] + { + // (5,26): warning CS1573: Parameter 'x' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do) + // public partial C(int x, int y) { } + Diagnostic(ErrorCode.WRN_MissingParamTag, "x").WithArguments("x", "C.C(int, int)").WithLocation(5, 26), + // (5,33): warning CS1573: Parameter 'y' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do) + // public partial C(int x, int y); + Diagnostic(ErrorCode.WRN_MissingParamTag, "y").WithArguments("y", "C.C(int, int)").WithLocation(5, 33) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedDiagnostics)); + } + + [Fact] + public void PartialEvent_MultipleFiles_InvalidImplComment() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_InvalidImplComment() + { + var source1 = """ + partial class C + { + /** Summary 1 */ + public partial C(); + } + """; + var source2 = """ + partial class C + { + /** */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialEvent_MultipleFiles_InvalidDefComment() + { + var source1 = """ + partial class C + { + /** */ + public partial event System.Action E; + } + """; + var source2 = """ + partial class C + { + /** Summary 2 */ + public partial event System.Action E { add { } remove { } } + } + """; + + var expected = """ + + + + Test + + + + Summary 2 + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_MultipleFiles_InvalidDefComment() + { + var source1 = """ + partial class C + { + /** */ + public partial C(); + } + """; + var source2 = """ + partial class C + { + /** Summary 2 */ + public partial C() { } + } + """; + + var expected = """ + + + + Test + + + + Summary 2 + + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS1570: XML comment has badly formed XML -- 'End tag 'a' does not match the start tag 'summary'.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "a").WithArguments("a", "summary").WithLocation(3, 20), + // (3,22): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /** */ + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 22) + }; + + var comp = CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments) + .VerifyDiagnostics(expectedDiagnostics); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + } + + [Fact] + public void PartialConstructor_Paramref_01() + { + var source1 = """ + partial class C + { + /** Accepts . */ + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedDiagnostics = new[] + { + // (4,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(4, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_02() + { + var source1 = """ + partial class C + { + /** Accepts . */ + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedXmlDiagnostic = + // (3,42): warning CS1734: XML comment on 'C.C(int)' has a paramref tag for 'p2', but there is no parameter by that name + // /** Accepts . */ + Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p2").WithArguments("p2", "C.C(int)").WithLocation(3, 42); + + var expectedDiagnostics = new[] + { + expectedXmlDiagnostic, + // (4,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(4, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_03() + { + var source1 = """ + partial class C + { + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + /** Accepts . */ + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedXmlDiagnostic = + // (3,42): warning CS1734: XML comment on 'C.C(int)' has a paramref tag for 'p1', but there is no parameter by that name + // /** Accepts . */ + Diagnostic(ErrorCode.WRN_UnmatchedParamRefTag, "p1").WithArguments("p1", "C.C(int)").WithLocation(3, 42); + + var expectedDiagnostics = new[] + { + // (3,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(3, 20), + expectedXmlDiagnostic + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp, expectedXmlDiagnostic)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + + [Fact] + public void PartialConstructor_Paramref_04() + { + var source1 = """ + partial class C + { + public partial C(int p1) { } + } + """; + var source2 = """ + partial class C + { + /** Accepts . */ + public partial C(int p2); + } + """; + + var expected = """ + + + + Test + + + + Accepts . + + + + """; + + var expectedDiagnostics = new[] + { + // (3,20): warning CS9256: Partial member declarations 'C.C(int p2)' and 'C.C(int p1)' have signature differences. + // public partial C(int p1) { } + Diagnostic(ErrorCode.WRN_PartialMemberSignatureDifference, "C").WithArguments("C.C(int p2)", "C.C(int p1)").WithLocation(3, 20) + }; + + var comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source1, source2], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + comp = (CSharpCompilation)CompileAndVerify(CreateCompilation([source2, source1], + assemblyName: "Test", + parseOptions: TestOptions.RegularPreviewWithDocumentationComments), + sourceSymbolValidator: validate, + symbolValidator: validate) + .VerifyDiagnostics(expectedDiagnostics).Compilation; + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, GetDocumentationCommentText(comp)); + + static void validate(ModuleSymbol module) + { + var ctor = module.GlobalNamespace.GetMember("C..ctor"); + Assert.Equal("p2", ctor.Parameters.Single().Name); + } + } + #endregion Partial methods #region Crefs