Skip to content

Commit 265ad76

Browse files
authored
[Java.Interop.Tools.JavaSource] Fix tag parsing errors (#997)
Improve tag parsing by adding grammar rules for `@hide`, `@inheritDoc`, and `{@see}`. The new grammar rules are not complete, but these new grammar rules, along with improvements to existing rules, reduces the number of `## Unable to translate remarks for …` errors from 740 to 391, nearly in half. The rules for `@param`, `@return`, `@throws`, and `@unknown` have been updated to handle more variations of these tags. In some cases, these tags are only followed by a single word or no content at all. New line character filters and tab have been added to `nonSpaceTerm` to fix instances where an "empty" tag would be merged with the tag on the following line. See [`Android.Database.DatabaseUtils.GetCollationKey(String)`][0] as an example. Before `nonSpaceTerm` change: <param name="name">To be added.</param> <param name="name&#xA;@return&#xA;@return">the collation key</param> <summary>return the collation key</summary> <returns>To be added.</returns> After `nonSpaceTerm` change: <param name="name">name</param> <summary>return the collation key</summary> <returns>the collation key</returns> [0]: https://github.com/xamarin/android-api-docs/blob/a7e914965a0e80c9454149399551d87a18997b2e/docs/Mono.Android/en/Android.Database/DatabaseUtils.xml#L1505-L1508
1 parent 99c68a8 commit 265ad76

File tree

6 files changed

+115
-15
lines changed

6 files changed

+115
-15
lines changed

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
2525
| DeprecatedDeclaration
2626
| DeprecatedSinceDeclaration
2727
| ExceptionDeclaration
28+
| InheritDocDeclaration
29+
| HideDeclaration
2830
| ParamDeclaration
2931
| ReturnDeclaration
3032
| SeeDeclaration
@@ -78,7 +80,7 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
7880
parseNode.AstNode = p;
7981
};
8082

81-
var nonSpaceTerm = new RegexBasedTerminal ("[^ ]", "[^ ]+") {
83+
var nonSpaceTerm = new RegexBasedTerminal ("[^ \n\r\t]", "[^ \n\r\t]+") {
8284
AstConfig = new AstNodeConfig {
8385
NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value,
8486
},
@@ -99,19 +101,42 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
99101
FinishParse (context, parseNode);
100102
};
101103

102-
ParamDeclaration.Rule = "@param" + nonSpaceTerm + BlockValues;
104+
// Ignore @hide tags
105+
HideDeclaration.Rule = "@hide";
106+
HideDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
107+
FinishParse (context, parseNode);
108+
};
109+
110+
InheritDocDeclaration.Rule = "@inheritDoc";
111+
InheritDocDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
112+
if (!grammar.ShouldImport (ImportJavadoc.InheritDocTag)) {
113+
return;
114+
}
115+
// TODO: Iterate through parents for corresponding javadoc element.
116+
FinishParse (context, parseNode);
117+
};
118+
119+
ParamDeclaration.Rule = "@param" + nonSpaceTerm
120+
| "@param" + nonSpaceTerm + BlockValues
121+
;
103122
ParamDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
104123
if (!grammar.ShouldImport (ImportJavadoc.ParamTag)) {
105124
return;
106125
}
107-
var p = new XElement ("param",
108-
new XAttribute ("name", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))),
109-
AstNodeToXmlContent (parseNode.ChildNodes [2]));
126+
var paramName = string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]));
127+
var p = new XElement ("param", new XAttribute ("name", paramName));
128+
if (parseNode.ChildNodes.Count >= 3) {
129+
p.Add (AstNodeToXmlContent (parseNode.ChildNodes [2]));
130+
} else {
131+
p.Add (paramName);
132+
}
110133
FinishParse (context, parseNode).Parameters.Add (p);
111134
parseNode.AstNode = p;
112135
};
113136

114-
ReturnDeclaration.Rule = "@return" + BlockValues;
137+
ReturnDeclaration.Rule = "@return"
138+
| "@return" + BlockValues
139+
;
115140
ReturnDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
116141
if (!grammar.ShouldImport (ImportJavadoc.ReturnTag)) {
117142
return;
@@ -158,7 +183,9 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
158183
parseNode.AstNode = p;
159184
};
160185

161-
ThrowsDeclaration.Rule = "@throws" + nonSpaceTerm + BlockValues;
186+
ThrowsDeclaration.Rule = "@throws" + nonSpaceTerm
187+
| "@throws" + nonSpaceTerm + BlockValues
188+
;
162189
ThrowsDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
163190
if (!grammar.ShouldImport (ImportJavadoc.ExceptionTag)) {
164191
return;
@@ -205,7 +232,9 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
205232
parseNode.AstNode = parseNode.Token.Value.ToString ();
206233

207234

208-
UnknownTagDeclaration.Rule = unknownTagTerminal + BlockValues;
235+
UnknownTagDeclaration.Rule = unknownTagTerminal
236+
| unknownTagTerminal + BlockValues
237+
;
209238
UnknownTagDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
210239
if (!grammar.ShouldImport (ImportJavadoc.Remarks)) {
211240
return;
@@ -242,6 +271,8 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
242271
public readonly NonTerminal DeprecatedDeclaration = new NonTerminal (nameof (DeprecatedDeclaration));
243272
public readonly NonTerminal DeprecatedSinceDeclaration = new NonTerminal (nameof (DeprecatedSinceDeclaration));
244273
public readonly NonTerminal ExceptionDeclaration = new NonTerminal (nameof (ExceptionDeclaration));
274+
public readonly NonTerminal HideDeclaration = new NonTerminal (nameof (HideDeclaration));
275+
public readonly NonTerminal InheritDocDeclaration = new NonTerminal (nameof (InheritDocDeclaration));
245276
public readonly NonTerminal ParamDeclaration = new NonTerminal (nameof (ParamDeclaration));
246277
public readonly NonTerminal ReturnDeclaration = new NonTerminal (nameof (ReturnDeclaration));
247278
public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration));

src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocGrammar.InlineTagsBnfTerms.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
2626
| LinkDeclaration
2727
| LinkplainDeclaration
2828
| LiteralDeclaration
29+
| SeeDeclaration
2930
| ValueDeclaration
3031
;
3132

@@ -75,6 +76,14 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
7576
parseNode.AstNode = new XText (content);
7677
};
7778

79+
SeeDeclaration.Rule = grammar.ToTerm ("{@see") + InlineValue + "}";
80+
SeeDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
81+
// TODO: @see supports multiple forms; see: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see
82+
// Also need to convert to appropriate CREF value, ignore for now
83+
var target = parseNode.ChildNodes [1].AstNode;
84+
parseNode.AstNode = new XElement ("c", target);
85+
};
86+
7887
ValueDeclaration.Rule = grammar.ToTerm ("{@value}")
7988
| grammar.ToTerm ("{@value") + InlineValue + "}";
8089
ValueDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
@@ -114,10 +123,12 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
114123
public readonly NonTerminal LinkplainDeclaration = new NonTerminal (nameof (LinkplainDeclaration));
115124

116125
// https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#literal
117-
public readonly NonTerminal LiteralDeclaration = new NonTerminal (nameof (LinkplainDeclaration));
126+
public readonly NonTerminal LiteralDeclaration = new NonTerminal (nameof (LiteralDeclaration));
127+
128+
public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration));
118129

119130
// https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#value
120-
public readonly NonTerminal ValueDeclaration = new NonTerminal (nameof (ValueDeclaration));
131+
public readonly NonTerminal ValueDeclaration = new NonTerminal (nameof (ValueDeclaration));
121132
}
122133
}
123134
}

src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource/SourceJavadocToXmldocParser.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal enum ImportJavadoc {
2626
SinceTag = 1 << 9,
2727
VersionTag = 1 << 10,
2828
ExtraRemarks = 1 << 11,
29+
InheritDocTag = 1 << 12,
2930
}
3031

3132
[Flags]
@@ -43,6 +44,7 @@ public enum XmldocStyle {
4344
| ImportJavadoc.SinceTag
4445
| ImportJavadoc.VersionTag
4546
| ImportJavadoc.ExtraRemarks
47+
| ImportJavadoc.InheritDocTag
4648
,
4749
IntelliSense = ImportJavadoc.Summary
4850
| ImportJavadoc.ExceptionTag

tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.BlockTagsBnfTermsTests.cs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,39 @@ public void ExceptionDeclaration ()
5656
//Assert.AreEqual ("<exception cref=\"Throwable\">Just Because.</exception>", r.Root.AstNode.ToString ());
5757
}
5858

59+
[Test]
60+
public void InheritDocDeclaration ()
61+
{
62+
var p = CreateParser (g => g.BlockTagsTerms.InheritDocDeclaration);
63+
64+
var r = p.Parse ("@inheritDoc");
65+
Assert.IsFalse (r.HasErrors (), "@inheritDoc: " + DumpMessages (r, p));
66+
// TODO: Enable after adding support for @inheritDoc
67+
Assert.IsNull (r.Root.AstNode, "@inheritDoc should be ignored, but node was not null.");
68+
}
69+
70+
[Test]
71+
public void HideDeclaration ()
72+
{
73+
var p = CreateParser (g => g.BlockTagsTerms.HideDeclaration);
74+
75+
var r = p.Parse ("@hide");
76+
Assert.IsFalse (r.HasErrors (), "@hide: " + DumpMessages (r, p));
77+
Assert.IsNull (r.Root.AstNode, "@hide should be ignored, but node was not null.");
78+
}
79+
5980
[Test]
6081
public void ParamDeclaration ()
6182
{
6283
var p = CreateParser (g => g.BlockTagsTerms.ParamDeclaration);
6384

64-
var r = p.Parse ("@param a Insert description here\n");
85+
var r = p.Parse ("@param a Insert description here\nand here.");
6586
Assert.IsFalse (r.HasErrors (), "@param: " + DumpMessages (r, p));
66-
Assert.AreEqual ("<param name=\"a\">Insert description here</param>", r.Root.AstNode.ToString ());
87+
Assert.AreEqual ($"<param name=\"a\">Insert description here{Environment.NewLine}and here.</param>", r.Root.AstNode.ToString ());
88+
89+
r = p.Parse ("@param b");
90+
Assert.IsFalse (r.HasErrors (), "name only @param: " + DumpMessages (r, p));
91+
Assert.AreEqual ("<param name=\"b\">b</param>", r.Root.AstNode.ToString ());
6792
}
6893

6994
[Test]
@@ -120,16 +145,21 @@ public void ThrowsDeclaration ()
120145
var p = CreateParser (g => g.BlockTagsTerms.ThrowsDeclaration);
121146

122147
var r = p.Parse ("@throws Throwable the {@code Exception} raised by this method");
123-
Assert.IsFalse (r.HasErrors (), "@throws: " + DumpMessages (r, p));
148+
Assert.IsFalse (r.HasErrors (), "{@code} @throws: " + DumpMessages (r, p));
124149
Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but node with code block was not null.");
125150
// TODO: Re-enable when we can generate valid crefs
126151
//Assert.AreEqual ("<exception cref=\"Throwable\">the <c>Exception</c> raised by this method</exception>", r.Root.AstNode.ToString ());
127152

128153
r = p.Parse ("@throws Throwable something <i>or other</i>!");
129-
Assert.IsFalse (r.HasErrors (), "@throws: " + DumpMessages (r, p));
130-
Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but node was not null.");
154+
Assert.IsFalse (r.HasErrors (), "<i> @throws: " + DumpMessages (r, p));
155+
Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but node with <i> was not null.");
131156
// TODO: Re-enable when we can generate valid crefs
132157
//Assert.AreEqual ("<exception cref=\"Throwable\">something <i>or other</i>!</exception>", r.Root.AstNode.ToString ());
158+
159+
r = p.Parse ("@throws android.content.ActivityNotFoundException");
160+
Assert.IsFalse (r.HasErrors (), "name only @throws: " + DumpMessages (r, p));
161+
// TODO: Re-enable when we can generate valid crefs
162+
Assert.IsNull (r.Root.AstNode, "@throws should be ignored, but name only node was not null.");
133163
}
134164

135165
[Test]
@@ -140,6 +170,10 @@ public void UnknownTagDeclaration ()
140170
var r = p.Parse ("@this-is-not-supported something {@code foo} else.");
141171
Assert.IsFalse (r.HasErrors (), "@this-is-not-supported: " + DumpMessages (r, p));
142172
Assert.AreEqual (null, r.Root.AstNode);
173+
174+
r = p.Parse ("@standalonetag");
175+
Assert.IsFalse (r.HasErrors (), "@standalonetag: " + DumpMessages (r, p));
176+
Assert.AreEqual (null, r.Root.AstNode);
143177
}
144178
}
145179
}

tests/Java.Interop.Tools.JavaSource-Tests/SourceJavadocToXmldocGrammar.InlineTagsBnfTermsTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ public void LiteralDeclaration ()
7575
Assert.AreEqual ("A&lt;B&gt;C", r.Root.AstNode.ToString ());
7676
}
7777

78+
[Test]
79+
public void SeeDeclaration ()
80+
{
81+
var p = CreateParser (g => g.InlineTagsTerms.SeeDeclaration);
82+
83+
var r = p.Parse ("{@see #cancelNotification(String, String, int)}");
84+
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
85+
Assert.AreEqual ("<c>#cancelNotification(String, String, int)</c>", r.Root.AstNode.ToString ());
86+
}
87+
7888
[Test]
7989
public void ValueDeclaration ()
8090
{

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,15 @@ What about soft paragraphs?
104104
<p>What about <i>hard</i> paragraphs?
105105
106106
@param a something
107+
@param b
108+
@param c
107109
@see #method()
108110
@apiSince 1
109111
",
110112
FullXml = @"<member>
111113
<param name=""a"">something</param>
114+
<param name=""b"">b</param>
115+
<param name=""c"">c</param>
112116
<summary>This is the summary sentence.</summary>
113117
<remarks>
114118
<para>This is the summary sentence. Insert
@@ -120,6 +124,8 @@ more description here.</para>
120124
</member>",
121125
IntelliSenseXml = @"<member>
122126
<param name=""a"">something</param>
127+
<param name=""b"">b</param>
128+
<param name=""c"">c</param>
123129
<summary>This is the summary sentence.</summary>
124130
</member>",
125131
},
@@ -183,19 +189,25 @@ more description here.
183189
@param manifest The value of the <a
184190
href=""{@docRoot}guide/topics/manifest/manifest-element.html#vcode"">{@code
185191
android:versionCode}</a> manifest attribute.
192+
@param empty
193+
@return the return value
186194
",
187195
FullXml = $@"<member>
188196
<param name=""manifest"">The value of the <see href=""{DocRootPrefixExpected}guide/topics/manifest/manifest-element.html#vcode""><c>android:versionCode</c></see> manifest attribute.</param>
197+
<param name=""empty"">empty</param>
189198
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
190199
<remarks>
191200
<para>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>. Insert
192201
more description here.
193202
How about another link <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see></para>
194203
</remarks>
204+
<returns>the return value</returns>
195205
</member>",
196206
IntelliSenseXml = $@"<member>
197207
<param name=""manifest"">The value of the <see href=""{DocRootPrefixExpected}guide/topics/manifest/manifest-element.html#vcode""><c>android:versionCode</c></see> manifest attribute.</param>
208+
<param name=""empty"">empty</param>
198209
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
210+
<returns>the return value</returns>
199211
</member>",
200212
},
201213
};

0 commit comments

Comments
 (0)