Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit 0e01fb5

Browse files
authored
[Java.Interop.Tools.JavaSource] Merge @return block values (#836)
Context: dotnet/android#5485 In an attempt to generate updated documentation for API-30 I noticed a minor issue in generator Javadoc import (7574f16): when a `<javadoc/>` element contains multiple `@return` values: <class name="Example" …> <method name="getP" …> <javadoc> <![CDATA[ … @return some docs @return additional docs ]]> </javadoc> </method> </class> We would generate multiple `<returns/>` elements, one for each `@return`: partial class Example { /// <returns>some docs</returns> /// <returns>additional docs</returns> public int P { [Register("getP", …)] get => … } } This is "fine", as far as the C# compiler is concerned, which results in a Documentation XML file containing both `<returns/>`: <doc> <members> <member name="P:Example.P"> <returns>some docs</returns> <returns>additional docs</returns> </member> </members> </doc> The problem is when we later try to *import* this documentation via `mdoc update --import`, as dotnet/android#5485 does; if it's a *method* which contains multiple `<returns/>` elements and mdoc 5.7.4.9 is used (included with macOS Mono 6.12): $ mdoc update -o docs assembly.dll --import assembly.xml Then the resulting imported [**mdoc**(5)][0] documentation only contains the *first* element: <Docs> <summary>To be added.</summary> <returns>some docs</returns> <remarks>To be added.</remarks> </Docs> Using [mdoc 5.8.0][1] will preserve both `<returns/>` elements, but "higher level" tooling such as HTML rendering or IntelliSense may not properly support multiple `<returns/>` elements. *However*, if it's a *property* which contains multiple `<returns/>` elements, then `mdoc update` will convert each `<returns/>` element into a `<value/>` element: $ mdoc update -o docs assembly.dll --import assembly.xml … <Docs> <summary>To be added.</summary> <value>some docs</value> <value>additional docs</value> <remarks>To be added.</remarks> </Docs> This is "odd", but it gets worse: on subsequent `mdoc update` invocations, *additional* `<value/>` elements are created! $ mdoc update -o docs assembly.dll --import assembly.xml … <Docs> <summary>To be added.</summary> <value>additional docs</value> <value>some docs</value> <value>additional docs</value> <remarks>To be added.</remarks> </Docs> $ mdoc update -o docs assembly.dll --import assembly.xml … <Docs> <summary>To be added.</summary> <value>some docs</value> <value>additional docs</value> <value>some docs</value> <value>additional docs</value> <remarks>To be added.</remarks> </Docs> While an `mdoc` bug, we can prevent this from happening by updating the Javadoc importer so that multiple `@returns` blocks are *merged* into a single `<returns/>` element: partial class Example { /// <returns>some docs additional docs</returns> public int P {…} } [0]: http://docs.go-mono.com/?link=man%3amdoc(5) [1]: https://www.nuget.org/packages/mdoc/5.8.0
1 parent 12e670a commit 0e01fb5

2 files changed

Lines changed: 37 additions & 18 deletions

File tree

‎src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.BlockTagsBnfTerms.cs‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,20 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
114114
if(!grammar.ShouldImport(ImportJavadoc.ReturnTag)){
115115
return;
116116
}
117-
varr=newXElement("returns",
117+
// When encountering multiple @return keys in a line, append subsequent @return key content to the original <returns> element.
118+
varjdi=FinishParse(context,parseNode);
119+
if(jdi.Returns.Count==0){
120+
varr=newXElement("returns",
118121
AstNodeToXmlContent(parseNode.ChildNodes[1]));
119-
FinishParse(context,parseNode).Returns.Add(r);
120-
parseNode.AstNode=r;
122+
FinishParse(context,parseNode).Returns.Add(r);
123+
parseNode.AstNode=r;
124+
}else{
125+
varr=jdi.Returns.First()asXElement;
126+
if(r!=null){
127+
r.Add(" ",AstNodeToXmlContent(parseNode.ChildNodes[1]));
128+
parseNode.AstNode=r;
129+
}
130+
}
121131
};
122132

123133
SeeDeclaration.Rule="@see"+BlockValues;

‎tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocParserTests.cs‎

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,19 @@ namespace Java.Interop.Tools.JavaSource.Tests
1717
[TestFixture]
1818
publicclassSourceJavadocToXmldocParserTests:SourceJavadocToXmldocGrammarFixture{
1919

20-
[Test]
21-
publicvoidTryParse()
20+
[Test,TestCaseSource(nameof(TryParse_Success))]
21+
publicvoidTryParse(ParseResultparseResult)
2222
{
23-
foreach(varvaluesinTryParse_Success){
24-
ParseTreeparseTree;
25-
varp=newSourceJavadocToXmldocParser(XmldocStyle.Full);
26-
varn=p.TryParse(values.Javadoc,null,outparseTree);
27-
Assert.IsFalse(parseTree.HasErrors(),DumpMessages(parseTree,p));
28-
Assert.AreEqual(values.FullXml,GetMemberXml(n),$"while parsing input: ```{values.Javadoc}```");
23+
ParseTreeparseTree;
24+
varp=newSourceJavadocToXmldocParser(XmldocStyle.Full);
25+
varn=p.TryParse(parseResult.Javadoc,null,outparseTree);
26+
Assert.IsFalse(parseTree.HasErrors(),DumpMessages(parseTree,p));
27+
Assert.AreEqual(parseResult.FullXml,GetMemberXml(n),$"while parsing input: ```{parseResult.Javadoc}```");
2928

30-
p=newSourceJavadocToXmldocParser(XmldocStyle.IntelliSense);
31-
n=p.TryParse(values.Javadoc,null,outparseTree);
32-
Assert.IsFalse(parseTree.HasErrors(),DumpMessages(parseTree,p));
33-
Assert.AreEqual(values.IntelliSenseXml,GetMemberXml(n),$"while parsing input: ```{values.Javadoc}```");
34-
}
29+
p=newSourceJavadocToXmldocParser(XmldocStyle.IntelliSense);
30+
n=p.TryParse(parseResult.Javadoc,null,outparseTree);
31+
Assert.IsFalse(parseTree.HasErrors(),DumpMessages(parseTree,p));
32+
Assert.AreEqual(parseResult.IntelliSenseXml,GetMemberXml(n),$"while parsing input: ```{parseResult.Javadoc}```");
3533
}
3634

3735
staticstringGetMemberXml(IEnumerable<XNode>members)
@@ -40,7 +38,7 @@ static string GetMemberXml (IEnumerable<XNode> members)
4038
returne.ToString();
4139
}
4240

43-
staticreadonlyParseResult[]TryParse_Success=newParseResult[]{
41+
publicstaticreadonlyParseResult[]TryParse_Success=newParseResult[]{
4442
newParseResult{
4543
Javadoc="Summary.\n\nP2.\n\n<p>Hello!</p>",
4644
FullXml=@"<member>
@@ -78,6 +76,17 @@ static string GetMemberXml (IEnumerable<XNode> members)
7876
<returns>
7977
<c>true</c> if something
8078
or other; otherwise <c>false</c>.</returns>
79+
</member>",
80+
},
81+
newParseResult{
82+
Javadoc="@return {@code true} if something else @return {@code false}.",
83+
FullXml=@"<member>
84+
<returns>
85+
<c>true</c> if something else <c>false</c>.</returns>
86+
</member>",
87+
IntelliSenseXml=@"<member>
88+
<returns>
89+
<c>true</c> if something else <c>false</c>.</returns>
8190
</member>",
8291
},
8392
newParseResult{
@@ -166,7 +175,7 @@ more description here.</para>
166175
},
167176
};
168177

169-
classParseResult{
178+
publicclassParseResult{
170179
publicstringJavadoc;
171180
publicstringFullXml;
172181
publicstringIntelliSenseXml;

0 commit comments

Comments
 (0)