Skip to content

Commit

Permalink
[Java.Interop.Tools.JavaSource] Add {@docroot} support (#930)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
pjcollins authored Jan 24, 2022
1 parent 0c90cf5 commit 13def0e
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
| SpecialDeclaration
| FormCtrlDeclaration
*/
| InlineHyperLinkDeclaration
| grammar.InlineTagsTerms.AllInlineTerms
| UnknownHtmlElementStart
,
Expand Down Expand Up @@ -94,6 +95,36 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
FinishParse (context, parseNode).Remarks.Add (p);
parseNode.AstNode = p;
};

InlineHyperLinkDeclaration.Rule = InlineHyperLinkOpenTerm + InlineDeclarations + CreateEndElement ("a", grammar, optional: true);
InlineHyperLinkDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
var unparsedAElementValue = string.Empty;
foreach (var cn in parseNode.ChildNodes) {
if (cn.ChildNodes?.Count > 1) {
foreach (var gcn in cn.ChildNodes) {
unparsedAElementValue += gcn.AstNode?.ToString ();
}
} else {
unparsedAElementValue += cn.AstNode?.ToString ();
}
}
XNode astNodeElement = new XText (unparsedAElementValue);
try {
var seeElement = XElement.Parse ($"<see href={unparsedAElementValue}</see>");
var hrefValue = seeElement.Attribute ("href")?.Value ?? string.Empty;
if (!string.IsNullOrEmpty (hrefValue) &&
(hrefValue.StartsWith ("http", StringComparison.OrdinalIgnoreCase) || hrefValue.StartsWith ("www", StringComparison.OrdinalIgnoreCase))) {
parseNode.AstNode = seeElement;
} else {
// TODO: Need to convert relative paths or code references to appropriate CREF value.
parseNode.AstNode = astNodeElement;
}
} catch (Exception) {
Console.Error.WriteLine ($"# Unable to parse HTML element: <see href={unparsedAElementValue}</see>");
parseNode.AstNode = astNodeElement;
}
};
}

static IEnumerable<XElement> GetParagraphs (ParseTreeNodeList children)
Expand Down Expand Up @@ -161,6 +192,13 @@ static IEnumerable<XElement> GetParagraphs (ParseTreeNodeList children)
public readonly NonTerminal BlockDeclaration = new NonTerminal (nameof (BlockDeclaration), ConcatChildNodes);
public readonly NonTerminal PBlockDeclaration = new NonTerminal (nameof (PBlockDeclaration), ConcatChildNodes);
public readonly NonTerminal PreBlockDeclaration = new NonTerminal (nameof (PreBlockDeclaration), ConcatChildNodes);
public readonly NonTerminal InlineHyperLinkDeclaration = new NonTerminal (nameof (InlineHyperLinkDeclaration), ConcatChildNodes);

public readonly Terminal InlineHyperLinkOpenTerm = new RegexBasedTerminal ("<a href=", @"<a\s*href=") {
AstConfig = new AstNodeConfig {
NodeCreator = (context, parseNode) => parseNode.AstNode = "",
},
};

public readonly Terminal UnknownHtmlElementStart = new UnknownHtmlElementStartTerminal (nameof (UnknownHtmlElementStart)) {
AstConfig = new AstNodeConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ internal void CreateRules (SourceJavadocToXmldocGrammar grammar)

DocRootDeclaration.Rule = grammar.ToTerm ("{@docRoot}");
DocRootDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
parseNode.AstNode = new XText ("[TODO: @docRoot]");
var docRoot = grammar.XmldocSettings.DocRootValue;
if (!string.IsNullOrEmpty (docRoot)) {
if (!docRoot.EndsWith ("/", StringComparison.OrdinalIgnoreCase)) {
docRoot += "/";
}
} else {
docRoot = "{@docRoot}";
}
parseNode.AstNode = new XText (docRoot);
};

InheritDocDeclaration.Rule = grammar.ToTerm ("{@inheritDoc}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public partial class SourceJavadocToXmldocGrammar : Grammar {
public readonly InlineTagsBnfTerms InlineTagsTerms;
public readonly HtmlBnfTerms HtmlTerms;

public readonly XmldocStyle XmldocStyle;
public readonly XmldocSettings XmldocSettings;

public SourceJavadocToXmldocGrammar (XmldocStyle style)
public SourceJavadocToXmldocGrammar (XmldocSettings settings)
{
BlockTagsTerms = new BlockTagsBnfTerms ();
InlineTagsTerms = new InlineTagsBnfTerms ();
HtmlTerms = new HtmlBnfTerms ();

XmldocStyle = style;
XmldocSettings = settings;

BlockTagsTerms.CreateRules (this);
InlineTagsTerms.CreateRules (this);
Expand Down Expand Up @@ -55,7 +55,7 @@ public SourceJavadocToXmldocGrammar (XmldocStyle style)

internal bool ShouldImport (ImportJavadoc value)
{
var v = (ImportJavadoc) XmldocStyle;
var v = (ImportJavadoc) XmldocSettings.Style;
return v.HasFlag (value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ public enum XmldocStyle {

public class SourceJavadocToXmldocParser : Irony.Parsing.Parser {

public SourceJavadocToXmldocParser (XmldocStyle style = XmldocStyle.Full)
: base (CreateGrammar (style))
public SourceJavadocToXmldocParser (XmldocSettings settings)
: base (CreateGrammar (settings))
{
XmldocStyle = style;
XmldocSettings = settings;
}

public XmldocStyle XmldocStyle { get; }
public XmldocSettings XmldocSettings { get; }

public XElement[]? ExtraRemarks { get; set; }

static Grammar CreateGrammar (XmldocStyle style)

static Grammar CreateGrammar (XmldocSettings settings)
{
return new SourceJavadocToXmldocGrammar (style) {
return new SourceJavadocToXmldocGrammar (settings) {
LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst,
};
}
Expand Down Expand Up @@ -102,13 +102,13 @@ IEnumerable<XNode> CreateParseIterator (ParseTree parseTree)
var summary = CreateSummaryNode (info);
if (summary != null)
yield return summary;
var style = (ImportJavadoc) XmldocStyle;
var style = (ImportJavadoc) XmldocSettings.Style;
if (style.HasFlag (ImportJavadoc.Remarks) &&
(info.Remarks.Count > 0 || ExtraRemarks?.Length > 0)) {
yield return new XElement ("remarks", info.Remarks, ExtraRemarks);
(info.Remarks.Count > 0 || XmldocSettings.ExtraRemarks?.Length > 0)) {
yield return new XElement ("remarks", info.Remarks, XmldocSettings.ExtraRemarks);
}
else if (style.HasFlag (ImportJavadoc.ExtraRemarks) && ExtraRemarks?.Length > 0) {
yield return new XElement ("remarks", ExtraRemarks);
else if (style.HasFlag (ImportJavadoc.ExtraRemarks) && XmldocSettings.ExtraRemarks?.Length > 0) {
yield return new XElement ("remarks", XmldocSettings.ExtraRemarks);
}
foreach (var n in info.Returns) {
yield return n;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Xml.Linq;

namespace Java.Interop.Tools.JavaSource
{
public class XmldocSettings
{
public string DocRootValue { get; set; } = string.Empty;
public XElement []? ExtraRemarks { get; set; }
public XmldocStyle Style { get; set; } = XmldocStyle.Full;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,21 @@ public void PreBlockDeclaration ()
r.Root.AstNode.ToString ());

}

[Test]
public void HyperLinkDeclaration ()
{
var p = CreateParser (g => g.HtmlTerms.InlineHyperLinkDeclaration);

var r = p.Parse ("<a href=\"https://developer.android.com/guide/topics/manifest/application-element.html\">application</a>");
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
Assert.AreEqual ("<see href=\"https://developer.android.com/guide/topics/manifest/application-element.html\">application</see>",
r.Root.AstNode.ToString ());

r = p.Parse ("<a href=\"AutofillService.html#FieldClassification\">field classification</a>");
Assert.IsFalse (r.HasErrors (), DumpMessages (r, p));
Assert.AreEqual ("\"AutofillService.html#FieldClassification\"&gt;field classification",
r.Root.AstNode.ToString ());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void DocRootDeclaration ()

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

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,16 @@ namespace Java.Interop.Tools.JavaSource.Tests
[TestFixture]
public class SourceJavadocToXmldocGrammarFixture {

protected const string DocRootPrefixActual = "https://developer.android.com";
protected const string DocRootPrefixExpected = DocRootPrefixActual + "/";

public static Parser CreateParser (Func<SourceJavadocToXmldocGrammar, NonTerminal> root)
{
var g = new SourceJavadocToXmldocGrammar (XmldocStyle.Full) {
var g = new SourceJavadocToXmldocGrammar (new XmldocSettings {
Style = XmldocStyle.Full,
DocRootValue = DocRootPrefixActual,
})
{
LanguageFlags = LanguageFlags.Default | LanguageFlags.CreateAst,
};
g.Root = root (g);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ public class SourceJavadocToXmldocParserTests : SourceJavadocToXmldocGrammarFixt
public void TryParse (ParseResult parseResult)
{
ParseTree parseTree;
var p = new SourceJavadocToXmldocParser (XmldocStyle.Full);
var p = new SourceJavadocToXmldocParser (new XmldocSettings {
Style = XmldocStyle.Full,
DocRootValue = DocRootPrefixActual,
});
var n = p.TryParse (parseResult.Javadoc, null, out parseTree);
Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p));
Assert.AreEqual (parseResult.FullXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```");

p = new SourceJavadocToXmldocParser (XmldocStyle.IntelliSense);
p = new SourceJavadocToXmldocParser (new XmldocSettings {
Style = XmldocStyle.IntelliSense,
DocRootValue = DocRootPrefixActual,
});
n = p.TryParse (parseResult.Javadoc, null, out parseTree);
Assert.IsFalse (parseTree.HasErrors (), DumpMessages (parseTree, p));
Assert.AreEqual (parseResult.IntelliSenseXml, GetMemberXml (n), $"while parsing input: ```{parseResult.Javadoc}```");
Expand Down Expand Up @@ -168,6 +174,28 @@ more description here.</para>
</member>",
IntelliSenseXml = @"<member>
<summary>Summary.</summary>
</member>",
},
new ParseResult {
Javadoc = @"See <a href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</a>. Insert
more description here.
How about another link <a href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</a>
@param manifest The value of the <a
href=""{@docRoot}guide/topics/manifest/manifest-element.html#vcode"">{@code
android:versionCode}</a> manifest attribute.
",
FullXml = $@"<member>
<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>
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
<remarks>
<para>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>. Insert
more description here.
How about another link <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see></para>
</remarks>
</member>",
IntelliSenseXml = $@"<member>
<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>
<summary>See <see href=""http://man7.org/linux/man-pages/man2/accept.2.html"">accept(2)</see>.</summary>
</member>",
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public sealed class JavadocInfo {
public XElement[] Copyright { get; set; }

public XmldocStyle XmldocStyle { get; set; }
public string DocRootReplacement { get; set; }

string MemberDescription;

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

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

var info = new JavadocInfo () {
ExtraRemarks = extra,
Copyright = copyright,
DocRootReplacement = docRoot,
Javadoc = javadoc,
MemberDescription = declaringMemberName == null
? declaringJniType
Expand Down Expand Up @@ -95,10 +98,10 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
return (declaringJniType, declaringMemberName, declaringMemberParameterString);
}

static (XElement[] Extras, XElement[] Copyright) GetExtra (XElement element, XmldocStyle style, string declaringJniType, string declaringMemberName, string declaringMemberParameterString, bool appendCopyrightExtra)
static (XElement[] Extras, XElement[] Copyright, string DocRoot) GetExtra (XElement element, XmldocStyle style, string declaringJniType, string declaringMemberName, string declaringMemberParameterString, bool appendCopyrightExtra)
{
if (!style.HasFlag (XmldocStyle.IntelliSenseAndExtraRemarks))
return (null, null);
return (null, null, null);

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

List<XElement> extra = null;
IEnumerable<XElement> copyright = null;
string docRoot = null;
if (javadocMetadata != null) {
var link = javadocMetadata.Element ("link");
var urlPrefix = (string) link.Attribute ("prefix");
var linkStyle = (string) link.Attribute ("style");
docRoot = (string) link.Attribute ("docroot");
var kind = ParseApiLinkStyle (linkStyle);

XElement docLink = null;
Expand All @@ -128,7 +133,7 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
extra.AddRange (copyright);
}
}
return (extra?.ToArray (), copyright?.ToArray ());
return (extra?.ToArray (), copyright?.ToArray (), docRoot);
}

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

try {
var parser = new SourceJavadocToXmldocParser (XmldocStyle) {
ExtraRemarks = ExtraRemarks,
};
var parser = new SourceJavadocToXmldocParser (new XmldocSettings {
Style = XmldocStyle,
ExtraRemarks = ExtraRemarks,
DocRootValue = DocRootReplacement,
});
nodes = parser.TryParse (Javadoc, fileName: null, out tree);
}
catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static void generateParamsTxt(String filename, JniPackagesInfo packages) throws

static void generateXml(JavaSourceUtilsOptions options, JniPackagesInfo packages) throws Throwable {
try (final JavadocXmlGenerator javadocXmlGen = new JavadocXmlGenerator(options.outputJavadocXml)) {
javadocXmlGen.writeCopyrightInfo(options.docCopyrightFile, options.docUrlPrefix, options.docUrlStyle);
javadocXmlGen.writeCopyrightInfo(options.docCopyrightFile, options.docUrlPrefix, options.docUrlStyle, options.docRootUrl);
javadocXmlGen.writePackages(packages);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class JavaSourceUtilsOptions implements AutoCloseable {
" Stored in //javadoc-metadata/link/@style.\n" +
" Supported styles include:\n" +
" - developer.android.com/reference@2020-Nov\n" +
" --doc-root-url URL Base URL to use in place of @{docRoot} elements.\n" +
" Stored in //javadoc-metadata/link/@docroot.\n" +
"\n" +
"Output file options:\n" +
" -P, --output-params FILE Write method parameter names to FILE.\n" +
Expand All @@ -94,6 +96,7 @@ public class JavaSourceUtilsOptions implements AutoCloseable {
public File docCopyrightFile;
public String docUrlPrefix;
public String docUrlStyle;
public String docRootUrl;

private final Collection<File> sourceDirectoryFiles = new ArrayList<File>();
private File extractedTempDir;
Expand Down Expand Up @@ -204,6 +207,11 @@ private final JavaSourceUtilsOptions parse(Iterator<String> args) throws IOExcep
docUrlStyle = style;
break;
}
case "--doc-root-url": {
final String docRoot = getNextOptionValue(args, arg);
docRootUrl = docRoot;
break;
}
case "-j":
case "--jar": {
final File file = getNextOptionFile(args, arg);
Expand Down
Loading

0 comments on commit 13def0e

Please sign in to comment.