Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions src/Xamarin.Android.Tools.Bytecode/ClassPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,34 +237,44 @@ JavaDocletType GetDocletType (string path)
{
var kind = JavaDocletType.DroidDoc;
char [] buf = new char [500];

string packagesHtml = Path.Combine (path, "packages.html");
if (File.Exists (packagesHtml) && File.ReadAllText (packagesHtml).Contains ("<body class=\"gc-documentation develop reference api "))
kind = JavaDocletType.DroidDoc2;
using (var reader = File.OpenText (Path.Combine (path, "index.html")))
reader.ReadBlock (buf, 0, buf.Length);
string rawHTML = new string (buf);
if (rawHTML.Contains ("Generated by javadoc (build 1.6"))
kind = JavaDocletType.Java6;
else if (rawHTML.Contains ("Generated by javadoc (version 1.7"))
kind = JavaDocletType.Java7;
else if (rawHTML.Contains ("Generated by javadoc (1.8"))
kind = JavaDocletType.Java8;

string indexHtml = Path.Combine (path, "index.html");
if (File.Exists (indexHtml)) {
using (var reader = File.OpenText (indexHtml))
reader.ReadBlock (buf, 0, buf.Length);
string rawHTML = new string (buf);
if (rawHTML.Contains ("Generated by javadoc (build 1.6"))
kind = JavaDocletType.Java6;
else if (rawHTML.Contains ("Generated by javadoc (version 1.7"))
kind = JavaDocletType.Java7;
else if (rawHTML.Contains ("Generated by javadoc (1.8"))
kind = JavaDocletType.Java8;
}

// Check to see if it's an api.xml formatted doc
string rawXML = null;
using (var reader = File.OpenText (path)) {
int len = reader.ReadBlock (buf, 0, buf.Length);
rawXML = new string (buf, 0, len);
if (File.Exists (path)) {
string rawXML = null;
using (var reader = File.OpenText (path)) {
int len = reader.ReadBlock (buf, 0, buf.Length);
rawXML = new string (buf, 0, len);
}
if (rawXML.Contains ("<api>") && rawXML.Contains ("<package"))
kind = JavaDocletType._ApiXml;
}
if (rawXML.Contains ("<api>") && rawXML.Contains ("<package"))
kind = JavaDocletType._ApiXml;

return kind;
}

IAndroidDocScraper CreateDocScraper (string src)
{
switch (DocletType ?? GetDocletType (src)) {
if (!DocletType.HasValue)
DocletType = GetDocletType(src);

switch (DocletType) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly relevant to your patch, but given that CreateDocScraper() can be called multiple times, for multiple paths -- once per value in ClassPath.DocumentationPaths -- then I don't think DocletType should be used at all. What happens if/when ClassPath.DocumentationPaths contains multiple different types: the first one "wins"?

This should probably just be:

switch (GetDocletType (src)) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any objection to making GetDocletType public then? need some way to surface this code to tests.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, from what I can tell, the intention behind DocletType in the first place was to allow classe-parse.exe to override the automatic detection. This property gets set if you invoke said exe with --docstype=...

So I guess we should leave this behaviour as is (leave the switch (DocletType ?? GetDocletType (..))) and just make public the GetDocletType method.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's troubling about this statement is that class-parse always sets ClassPath.DocletType. docsType is a JavaDocletType, not a JavaDocletType?, so if class-parse --docstype isn't used, then ClassPath.DocletType will be set to JavaDocletType.DroidDoc, which is almost certainly wrong.

I'm starting to think we should [Obsolete] the ClassPath.DocletType property, and make it an error to use it entirely. :-/

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that matter, we could pretty much do away with all the various <ItemGroup> names currently out there and just use a <JavaParameterNameDocsPath .. /> or something similar since ClassPath already does the work of checking. In fact, the ClassParse task just concatenates all of these different items into a single set of doc paths: https://github.com/xamarin/xamarin-android/blob/master/src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs#L36-L41

So, if we obsolete ClassPath.DocletType we should also make it an error to specify --docstype= in class-parse.exe.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might also explain some weirdness i've seen in getting the generator to parse parameter names for the android support library bindings which are known to be in the documentation... Seems like maybe it's just getting detected as a DroidDoc always.

default: return new DroidDoc2Scraper (src);
case JavaDocletType.DroidDoc: return new DroidDocScraper (src);
case JavaDocletType.Java6: return new JavaDocScraper (src);
Expand Down
27 changes: 27 additions & 0 deletions src/Xamarin.Android.Tools.Bytecode/Tests/ClassFileFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ protected static string LoadString (string resource)
return r.ReadToEnd ();
}

protected static string LoadToTempFile (string resource)
{
var tempFilePath = Path.GetTempFileName ();

using (var w = File.Create (tempFilePath))
using (var s = Assembly.GetExecutingAssembly ().GetManifestResourceStream (resource))
s.CopyTo (w);

return tempFilePath;
}

protected static void AssertXmlDeclaration (string classResource, string xmlResource, string documentationPath = null, JavaDocletType? javaDocletType = null)
{
var classPathBuilder = new ClassPath () {
Expand Down Expand Up @@ -67,6 +78,22 @@ protected static void AssertXmlDeclaration (string[] classResources, string xmlR

Assert.AreEqual (expected, actual.ToString ());
}

protected static void AssertDocletType (string path, JavaDocletType docletType)
{
var classPathBuilder = new ClassPath () {
ApiSource = "class-parse",
DocumentationPaths = new string[] {
path,
},
AutoRename = true
};

var actual = new StringWriter ();
classPathBuilder.SaveXmlDescription (actual);

Assert.AreEqual (docletType, classPathBuilder.DocletType);
}
}
}

65 changes: 51 additions & 14 deletions src/Xamarin.Android.Tools.Bytecode/Tests/ParameterFixupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,22 @@ public void XmlDeclaration_FixedUpFromDocumentation()
}

[Test]
public void XmlDeclaration_FixedUpFromApiXmlDocumentation()
public void XmlDeclaration_FixedUpFromApiXmlDocumentation ()
{
string tempFile = null;

try
{
tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, LoadString("ParameterFixupApiXmlDocs.xml"));
try {
tempFile = LoadToTempFile ("ParameterFixupApiXmlDocs.xml");

AssertXmlDeclaration("Collection.class", "ParameterFixupFromDocs.xml", tempFile, Bytecode.JavaDocletType._ApiXml);
}
catch (Exception ex)
{
try
{
if (File.Exists(tempFile))
File.Delete(tempFile);
AssertXmlDeclaration ("Collection.class", "ParameterFixupFromDocs.xml", tempFile, Bytecode.JavaDocletType._ApiXml);
} catch (Exception ex) {
try {
if (File.Exists (tempFile))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be in the catch block, this should be in a finally block, so that we always delete tempFile. (Looks like this was a bug in the original code.)

File.Delete (tempFile);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't need to be wrapped in try/catch.

}
catch { }

Assert.Fail("An unexpected exception was thrown : {0}", ex);
Assert.Fail ("An unexpected exception was thrown : {0}", ex);
}
}

Expand All @@ -63,6 +58,48 @@ public void XmlDeclaration_DoesNotThrowAnExceptionIfDocumentationNotFound ()
Assert.Fail ("An unexpected exception was thrown : {0}", ex);
}
}

[Test]
public void DocletType_ShouldDetectApiXml ()
{
string tempFile = null;

try {
tempFile = LoadToTempFile ("ParameterFixupApiXmlDocs.xml");

AssertDocletType (tempFile, Bytecode.JavaDocletType._ApiXml);
} catch (Exception ex) {
try {
if (File.Exists (tempFile))
File.Delete (tempFile);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need to wrap this in try/catch.

}
catch { }

Assert.Fail ("An unexpected exception was thrown : {0}", ex);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...all the more reason to delete tempFile within a finally block instead of a catch block: this Assert wouldn't be needed anymore.

}
}

[Test]
public void DocletType_ShouldDetectDroidDocs ()
{
var androidSdkPath = Environment.GetEnvironmentVariable ("ANDROID_SDK_PATH");
if (string.IsNullOrEmpty (androidSdkPath)) {
Assert.Ignore("The `ANDROID_SDK_PATH` environment variable isn't set; " +
"cannot test importing parameter names from HTML. Skipping...");
return;
}

try {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need this try/catch block here?

var droidDocsPath = Path.Combine (androidSdkPath, "docs", "reference");

if (!Directory.Exists (droidDocsPath))
Assert.Fail("The Android SDK Documentation path `{0}` was not found.", droidDocsPath);

AssertDocletType (droidDocsPath, Bytecode.JavaDocletType.DroidDoc2);
} catch (Exception ex) {
Assert.Fail("An unexpected exception was thrown : {0}", ex);
}
}
}
}