Skip to content

Commit 13def0e

Browse files
authored
[Java.Interop.Tools.JavaSource] Add {@docroot} support (#930)
Partially fixes: #907 Context: https://docs.microsoft.com/en-us/dotnet/api/android.app.backup.backupagent.onrestore?view=xamarin-android-sdk-12#Android_App_Backup_BackupAgent_OnRestore_Android_App_Backup_BackupDataInput_System_Int64_Android_OS_ParcelFileDescriptor_ Context: https://docs.microsoft.com/en-us/dotnet/api/android.animation.animatorlisteneradapter.onanimationend?view=xamarin-android-sdk-12#definition Original support for the [`{@docroot}` inline Javadoc tag][0] in commit 7574f16 was a "TODO"; `{@docroot}` would expand to `[TODO: @docroot]`, resulting in documentation containing such monstrosities as: > The value of the > <a href="[TODO: @docroot]guide/topics/manifest/manifest-element.html#vcode">android:versionCode</a> > manifest attribute… Add support for the `{@docroot}` inline tag, along with grammar support for `<a href="…">…</a>` elements. This allows: <a href="{@docroot}/example/path">description</a> to be converted into: <see href="http://example.com/example/path">description</see> The value of `{@docroot}` is expanded into `XmldocSettings.DocRootValue`, which comes from the `/api/javadoc-metadata/link/@docroot` element in "Javadoc XML" created by `java-source-utils.jar` (7574f16), via the new `java-source-utils.jar --doc-root-url URL` option: java -jar java-source-utils.jar \ --doc-root-url https://developer.android.com/ \ --doc-url-prefix https://developer.android.com/reference \ --doc-url-style developer.android.com/reference@2020-Nov \ … TODO: Update the [`@(JavaSourceJar)` Build action][1] so that e.g. `%(JavaSourceJar.DocRootUrl)` item metadata will be used as the `java-source-utils.jar --doc-root-url` value. [0]: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#docRoot [1]: https://docs.microsoft.com/en-us/xamarin/android/deploy-test/building-apps/build-items#javasourcejar
1 parent 0c90cf5 commit 13def0e

File tree

13 files changed

+163
-33
lines changed

13 files changed

+163
-33
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
3333
| SpecialDeclaration
3434
| FormCtrlDeclaration
3535
*/
36+
| InlineHyperLinkDeclaration
3637
| grammar.InlineTagsTerms.AllInlineTerms
3738
| UnknownHtmlElementStart
3839
,
@@ -94,6 +95,36 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
9495
FinishParse (context, parseNode).Remarks.Add (p);
9596
parseNode.AstNode = p;
9697
};
98+
99+
InlineHyperLinkDeclaration.Rule = InlineHyperLinkOpenTerm + InlineDeclarations + CreateEndElement ("a", grammar, optional: true);
100+
InlineHyperLinkDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
101+
var unparsedAElementValue = string.Empty;
102+
foreach (var cn in parseNode.ChildNodes) {
103+
if (cn.ChildNodes?.Count > 1) {
104+
foreach (var gcn in cn.ChildNodes) {
105+
unparsedAElementValue += gcn.AstNode?.ToString ();
106+
}
107+
} else {
108+
unparsedAElementValue += cn.AstNode?.ToString ();
109+
}
110+
}
111+
112+
XNode astNodeElement = new XText (unparsedAElementValue);
113+
try {
114+
var seeElement = XElement.Parse ($"<see href={unparsedAElementValue}</see>");
115+
var hrefValue = seeElement.Attribute ("href")?.Value ?? string.Empty;
116+
if (!string.IsNullOrEmpty (hrefValue) &&
117+
(hrefValue.StartsWith ("http", StringComparison.OrdinalIgnoreCase) || hrefValue.StartsWith ("www", StringComparison.OrdinalIgnoreCase))) {
118+
parseNode.AstNode = seeElement;
119+
} else {
120+
// TODO: Need to convert relative paths or code references to appropriate CREF value.
121+
parseNode.AstNode = astNodeElement;
122+
}
123+
} catch (Exception) {
124+
Console.Error.WriteLine ($"# Unable to parse HTML element: <see href={unparsedAElementValue}</see>");
125+
parseNode.AstNode = astNodeElement;
126+
}
127+
};
97128
}
98129

99130
static IEnumerable<XElement> GetParagraphs (ParseTreeNodeList children)
@@ -161,6 +192,13 @@ static IEnumerable<XElement> GetParagraphs (ParseTreeNodeList children)
161192
public readonly NonTerminal BlockDeclaration = new NonTerminal (nameof (BlockDeclaration), ConcatChildNodes);
162193
public readonly NonTerminal PBlockDeclaration = new NonTerminal (nameof (PBlockDeclaration), ConcatChildNodes);
163194
public readonly NonTerminal PreBlockDeclaration = new NonTerminal (nameof (PreBlockDeclaration), ConcatChildNodes);
195+
public readonly NonTerminal InlineHyperLinkDeclaration = new NonTerminal (nameof (InlineHyperLinkDeclaration), ConcatChildNodes);
196+
197+
public readonly Terminal InlineHyperLinkOpenTerm = new RegexBasedTerminal ("<a href=", @"<a\s*href=") {
198+
AstConfig = new AstNodeConfig {
199+
NodeCreator = (context, parseNode) => parseNode.AstNode = "",
200+
},
201+
};
164202

165203
public readonly Terminal UnknownHtmlElementStart = new UnknownHtmlElementStartTerminal (nameof (UnknownHtmlElementStart)) {
166204
AstConfig = new AstNodeConfig {

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,15 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
3636

3737
DocRootDeclaration.Rule = grammar.ToTerm ("{@docRoot}");
3838
DocRootDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
39-
parseNode.AstNode = new XText ("[TODO: @docRoot]");
39+
var docRoot = grammar.XmldocSettings.DocRootValue;
40+
if (!string.IsNullOrEmpty (docRoot)) {
41+
if (!docRoot.EndsWith ("/", StringComparison.OrdinalIgnoreCase)) {
42+
docRoot += "/";
43+
}
44+
} else {
45+
docRoot = "{@docRoot}";
46+
}
47+
parseNode.AstNode = new XText (docRoot);
4048
};
4149

4250
InheritDocDeclaration.Rule = grammar.ToTerm ("{@inheritDoc}");

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ public partial class SourceJavadocToXmldocGrammar : Grammar {
1616
public readonly InlineTagsBnfTerms InlineTagsTerms;
1717
public readonly HtmlBnfTerms HtmlTerms;
1818

19-
public readonly XmldocStyle XmldocStyle;
19+
public readonly XmldocSettings XmldocSettings;
2020

21-
public SourceJavadocToXmldocGrammar (XmldocStyle style)
21+
public SourceJavadocToXmldocGrammar (XmldocSettings settings)
2222
{
2323
BlockTagsTerms = new BlockTagsBnfTerms ();
2424
InlineTagsTerms = new InlineTagsBnfTerms ();
2525
HtmlTerms = new HtmlBnfTerms ();
2626

27-
XmldocStyle = style;
27+
XmldocSettings = settings;
2828

2929
BlockTagsTerms.CreateRules (this);
3030
InlineTagsTerms.CreateRules (this);
@@ -55,7 +55,7 @@ public SourceJavadocToXmldocGrammar (XmldocStyle style)
5555

5656
internal bool ShouldImport (ImportJavadoc value)
5757
{
58-
var v = (ImportJavadoc) XmldocStyle;
58+
var v = (ImportJavadoc) XmldocSettings.Style;
5959
return v.HasFlag (value);
6060
}
6161

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,19 @@ public enum XmldocStyle {
5656

5757
public class SourceJavadocToXmldocParser : Irony.Parsing.Parser {
5858

59-
public SourceJavadocToXmldocParser (XmldocStyle style = XmldocStyle.Full)
60-
: base (CreateGrammar (style))
59+
public SourceJavadocToXmldocParser (XmldocSettings settings)
60+
: base (CreateGrammar (settings))
6161
{
62-
XmldocStyle = style;
62+
XmldocSettings = settings;
6363
}
6464

65-
public XmldocStyle XmldocStyle { get; }
65+
public XmldocSettings XmldocSettings { get; }
6666

67-
public XElement[]? ExtraRemarks { get; set; }
6867

69-
static Grammar CreateGrammar (XmldocStyle style)
68+
69+
static Grammar CreateGrammar (XmldocSettings settings)
7070
{
71-
return new SourceJavadocToXmldocGrammar (style) {
71+
return new SourceJavadocToXmldocGrammar (settings) {
7272
LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst,
7373
};
7474
}
@@ -102,13 +102,13 @@ IEnumerable<XNode> CreateParseIterator (ParseTree parseTree)
102102
var summary = CreateSummaryNode (info);
103103
if (summary != null)
104104
yield return summary;
105-
var style = (ImportJavadoc) XmldocStyle;
105+
var style = (ImportJavadoc) XmldocSettings.Style;
106106
if (style.HasFlag (ImportJavadoc.Remarks) &&
107-
(info.Remarks.Count > 0 || ExtraRemarks?.Length > 0)) {
108-
yield return new XElement ("remarks", info.Remarks, ExtraRemarks);
107+
(info.Remarks.Count > 0 || XmldocSettings.ExtraRemarks?.Length > 0)) {
108+
yield return new XElement ("remarks", info.Remarks, XmldocSettings.ExtraRemarks);
109109
}
110-
else if (style.HasFlag (ImportJavadoc.ExtraRemarks) && ExtraRemarks?.Length > 0) {
111-
yield return new XElement ("remarks", ExtraRemarks);
110+
else if (style.HasFlag (ImportJavadoc.ExtraRemarks) && XmldocSettings.ExtraRemarks?.Length > 0) {
111+
yield return new XElement ("remarks", XmldocSettings.ExtraRemarks);
112112
}
113113
foreach (var n in info.Returns) {
114114
yield return n;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Xml.Linq;
3+
4+
namespace Java.Interop.Tools.JavaSource
5+
{
6+
public class XmldocSettings
7+
{
8+
public string DocRootValue { get; set; } = string.Empty;
9+
public XElement []? ExtraRemarks { get; set; }
10+
public XmldocStyle Style { get; set; } = XmldocStyle.Full;
11+
}
12+
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,21 @@ public void PreBlockDeclaration ()
4747
r.Root.AstNode.ToString ());
4848

4949
}
50+
51+
[Test]
52+
public void HyperLinkDeclaration ()
53+
{
54+
var p = CreateParser (g => g.HtmlTerms.InlineHyperLinkDeclaration);
55+
56+
var r = p.Parse ("<a href=\"https://developer.android.com/guide/topics/manifest/application-element.html\">application</a>");
57+
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
58+
Assert.AreEqual ("<see href=\"https://developer.android.com/guide/topics/manifest/application-element.html\">application</see>",
59+
r.Root.AstNode.ToString ());
60+
61+
r = p.Parse ("<a href=\"AutofillService.html#FieldClassification\">field classification</a>");
62+
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
63+
Assert.AreEqual ("\"AutofillService.html#FieldClassification\"&gt;field classification",
64+
r.Root.AstNode.ToString ());
65+
}
5066
}
5167
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void DocRootDeclaration ()
3131

3232
var r = p.Parse ("{@docRoot}");
3333
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
34-
Assert.AreEqual ("[TODO: @docRoot]", r.Root.AstNode.ToString ());
34+
Assert.AreEqual (DocRootPrefixExpected, r.Root.AstNode.ToString ());
3535
}
3636

3737
[Test]

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,16 @@ namespace Java.Interop.Tools.JavaSource.Tests
1717
[TestFixture]
1818
public class SourceJavadocToXmldocGrammarFixture {
1919

20+
protected const string DocRootPrefixActual = "https://developer.android.com";
21+
protected const string DocRootPrefixExpected = DocRootPrefixActual + "/";
22+
2023
public static Parser CreateParser (Func<SourceJavadocToXmldocGrammar, NonTerminal> root)
2124
{
22-
var g = new SourceJavadocToXmldocGrammar (XmldocStyle.Full) {
25+
var g = new SourceJavadocToXmldocGrammar (new XmldocSettings {
26+
Style = XmldocStyle.Full,
27+
DocRootValue = DocRootPrefixActual,
28+
})
29+
{
2330
LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst,
2431
};
2532
g.Root = root (g);

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@ public class SourceJavadocToXmldocParserTests : SourceJavadocToXmldocGrammarFixt
2121
public void TryParse (ParseResult parseResult)
2222
{
2323
ParseTree parseTree;
24-
var p = new SourceJavadocToXmldocParser (XmldocStyle.Full);
24+
var p = new SourceJavadocToXmldocParser (new XmldocSettings {
25+
Style = XmldocStyle.Full,
26+
DocRootValue = DocRootPrefixActual,
27+
});
2528
var n = p.TryParse (parseResult.Javadoc, null, out parseTree);
2629
Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p));
2730
Assert.AreEqual (parseResult.FullXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```");
2831

29-
p = new SourceJavadocToXmldocParser (XmldocStyle.IntelliSense);
32+
p = new SourceJavadocToXmldocParser (new XmldocSettings {
33+
Style = XmldocStyle.IntelliSense,
34+
DocRootValue = DocRootPrefixActual,
35+
});
3036
n = p.TryParse (parseResult.Javadoc, null, out parseTree);
3137
Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p));
3238
Assert.AreEqual (parseResult.IntelliSenseXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```");
@@ -168,6 +174,28 @@ more description here.</para>
168174
</member>",
169175
IntelliSenseXml = @"<member>
170176
<summary>Summary.</summary>
177+
</member>",
178+
},
179+
new ParseResult {
180+
Javadoc = @"See <a href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</a>. Insert
181+
more description here.
182+
How about another link <a href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</a>
183+
@param manifest The value of the <a
184+
href=""{@docRoot}guide/topics/manifest/manifest-element.html#vcode"">{@code
185+
android:versionCode}</a> manifest attribute.
186+
",
187+
FullXml = $@"<member>
188+
<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>
189+
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
190+
<remarks>
191+
<para>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>. Insert
192+
more description here.
193+
How about another link <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see></para>
194+
</remarks>
195+
</member>",
196+
IntelliSenseXml = $@"<member>
197+
<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>
198+
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
171199
</member>",
172200
},
173201
};

tools/generator/Java.Interop.Tools.Generator.ObjectModel/JavadocInfo.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public sealed class JavadocInfo {
2525
public XElement[] Copyright { get; set; }
2626

2727
public XmldocStyle XmldocStyle { get; set; }
28+
public string DocRootReplacement { get; set; }
2829

2930
string MemberDescription;
3031

@@ -44,13 +45,15 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
4445
var extras = GetExtra (element, style, declaringJniType, declaringMemberName, declaringMemberParamString, appendCopyrightExtra);
4546
XElement[] extra = extras.Extras;
4647
XElement[] copyright = extras.Copyright;
48+
string docRoot = extras.DocRoot;
4749

4850
if (string.IsNullOrEmpty (javadoc) && extra == null)
4951
return null;
5052

5153
var info = new JavadocInfo () {
5254
ExtraRemarks = extra,
5355
Copyright = copyright,
56+
DocRootReplacement = docRoot,
5457
Javadoc = javadoc,
5558
MemberDescription = declaringMemberName == null
5659
? declaringJniType
@@ -95,10 +98,10 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
9598
return (declaringJniType, declaringMemberName, declaringMemberParameterString);
9699
}
97100

98-
static (XElement[] Extras, XElement[] Copyright) GetExtra (XElement element, XmldocStyle style, string declaringJniType, string declaringMemberName, string declaringMemberParameterString, bool appendCopyrightExtra)
101+
static (XElement[] Extras, XElement[] Copyright, string DocRoot) GetExtra (XElement element, XmldocStyle style, string declaringJniType, string declaringMemberName, string declaringMemberParameterString, bool appendCopyrightExtra)
99102
{
100103
if (!style.HasFlag (XmldocStyle.IntelliSenseAndExtraRemarks))
101-
return (null, null);
104+
return (null, null, null);
102105

103106
XElement javadocMetadata = null;
104107
while (element != null) {
@@ -111,10 +114,12 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
111114

112115
List<XElement> extra = null;
113116
IEnumerable<XElement> copyright = null;
117+
string docRoot = null;
114118
if (javadocMetadata != null) {
115119
var link = javadocMetadata.Element ("link");
116120
var urlPrefix = (string) link.Attribute ("prefix");
117121
var linkStyle = (string) link.Attribute ("style");
122+
docRoot = (string) link.Attribute ("docroot");
118123
var kind = ParseApiLinkStyle (linkStyle);
119124

120125
XElement docLink = null;
@@ -128,7 +133,7 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
128133
extra.AddRange (copyright);
129134
}
130135
}
131-
return (extra?.ToArray (), copyright?.ToArray ());
136+
return (extra?.ToArray (), copyright?.ToArray (), docRoot);
132137
}
133138

134139
static ApiLinkStyle ParseApiLinkStyle (string style)
@@ -159,9 +164,11 @@ public IEnumerable<XNode> ParseJavadoc ()
159164
IEnumerable<XNode> nodes = null;
160165

161166
try {
162-
var parser = new SourceJavadocToXmldocParser (XmldocStyle) {
163-
ExtraRemarks = ExtraRemarks,
164-
};
167+
var parser = new SourceJavadocToXmldocParser (new XmldocSettings {
168+
Style = XmldocStyle,
169+
ExtraRemarks = ExtraRemarks,
170+
DocRootValue = DocRootReplacement,
171+
});
165172
nodes = parser.TryParse (Javadoc, fileName: null, out tree);
166173
}
167174
catch (Exception e) {

tools/java-source-utils/src/main/java/com/microsoft/android/App.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static void generateParamsTxt(String filename, JniPackagesInfo packages) throws
6868

6969
static void generateXml(JavaSourceUtilsOptions options, JniPackagesInfo packages) throws Throwable {
7070
try (final JavadocXmlGenerator javadocXmlGen = new JavadocXmlGenerator(options.outputJavadocXml)) {
71-
javadocXmlGen.writeCopyrightInfo(options.docCopyrightFile, options.docUrlPrefix, options.docUrlStyle);
71+
javadocXmlGen.writeCopyrightInfo(options.docCopyrightFile, options.docUrlPrefix, options.docUrlStyle, options.docRootUrl);
7272
javadocXmlGen.writePackages(packages);
7373
}
7474
}

tools/java-source-utils/src/main/java/com/microsoft/android/JavaSourceUtilsOptions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ public class JavaSourceUtilsOptions implements AutoCloseable {
7474
" Stored in //javadoc-metadata/link/@style.\n" +
7575
" Supported styles include:\n" +
7676
" - developer.android.com/reference@2020-Nov\n" +
77+
" --doc-root-url URL Base URL to use in place of @{docRoot} elements.\n" +
78+
" Stored in //javadoc-metadata/link/@docroot.\n" +
7779
"\n" +
7880
"Output file options:\n" +
7981
" -P, --output-params FILE Write method parameter names to FILE.\n" +
@@ -94,6 +96,7 @@ public class JavaSourceUtilsOptions implements AutoCloseable {
9496
public File docCopyrightFile;
9597
public String docUrlPrefix;
9698
public String docUrlStyle;
99+
public String docRootUrl;
97100

98101
private final Collection<File> sourceDirectoryFiles = new ArrayList<File>();
99102
private File extractedTempDir;
@@ -204,6 +207,11 @@ private final JavaSourceUtilsOptions parse(Iterator<String> args) throws IOExcep
204207
docUrlStyle = style;
205208
break;
206209
}
210+
case "--doc-root-url": {
211+
final String docRoot = getNextOptionValue(args, arg);
212+
docRootUrl = docRoot;
213+
break;
214+
}
207215
case "-j":
208216
case "--jar": {
209217
final File file = getNextOptionFile(args, arg);

0 commit comments

Comments
 (0)