Skip to content

Commit 73687e9

Browse files
atsushienojonpryor
authored andcommitted
[class-parse] add support for external parameter name descriptor files
Context: https://github.com/atsushieno/xamarin-android-docimporter-ng/blob/bee36c1181ac0778b63350987aba20a7c3d4410c/Xamarin.Android.Tools.JavaStubImporter/JavaApiParameterNamesXmlExporter.cs#L78 Add a new `class-parse --parameter-names=PATH` option, which allows providing a new fileformat for providing Java method parameter names: package packageName; class Collection<T> add(T value) This format is more readable than XML.
1 parent 61c70ec commit 73687e9

File tree

8 files changed

+183
-13
lines changed

8 files changed

+183
-13
lines changed

src/Xamarin.Android.Tools.Bytecode/ClassPath.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public enum JavaDocletType {
1717
Java6,
1818
Java7,
1919
Java8,
20-
_ApiXml
20+
_ApiXml,
21+
JavaApiParameterNamesXml,
2122
}
2223

2324
public class ClassPath {
@@ -231,15 +232,16 @@ void FixupParametersFromDocs (XElement api)
231232
}
232233
}
233234

234-
IAndroidDocScraper CreateDocScraper (string src)
235+
IJavaMethodParameterNameProvider CreateDocScraper (string src)
235236
{
236-
switch (AndroidDocScraper.GetDocletType (src)) {
237+
switch (JavaMethodParameterNameProvider.GetDocletType (src)) {
237238
default: return new DroidDoc2Scraper (src);
238239
case JavaDocletType.DroidDoc: return new DroidDocScraper (src);
239240
case JavaDocletType.Java6: return new JavaDocScraper (src);
240241
case JavaDocletType.Java7: return new Java7DocScraper (src);
241242
case JavaDocletType.Java8: return new Java8DocScraper (src);
242243
case JavaDocletType._ApiXml: return new ApiXmlDocScraper (src);
244+
case JavaDocletType.JavaApiParameterNamesXml: return new JavaParameterNamesLoader (src);
243245
}
244246
}
245247

src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ protected override string StripTagsFromParameters (string value)
129129
}
130130
}
131131

132-
public abstract class AndroidDocScraper : IAndroidDocScraper
132+
public abstract class AndroidDocScraper : IJavaMethodParameterNameProvider
133133
{
134134
readonly String pattern_head;
135135
readonly String reset_pattern_head;
@@ -290,6 +290,14 @@ public static void LoadXml (String filename)
290290
Log.Error ("Annotations parser error: " + ex);
291291
}
292292
}
293+
}
294+
295+
public interface IJavaMethodParameterNameProvider
296+
{
297+
String[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs);
298+
}
299+
300+
public static class JavaMethodParameterNameProvider {
293301

294302
public static JavaDocletType GetDocletType (string path)
295303
{
@@ -322,18 +330,17 @@ public static JavaDocletType GetDocletType (string path)
322330
}
323331
if (rawXML.Contains ("<api>") && rawXML.Contains ("<package"))
324332
kind = JavaDocletType._ApiXml;
333+
else if (rawXML.StartsWith ("package", StringComparison.Ordinal) ||
334+
rawXML.StartsWith (";", StringComparison.Ordinal)) {
335+
kind = JavaDocletType.JavaApiParameterNamesXml;
336+
}
325337
}
326338

327339
return kind;
328340
}
329341
}
330342

331-
public interface IAndroidDocScraper
332-
{
333-
String[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs);
334-
}
335-
336-
public class ApiXmlDocScraper : IAndroidDocScraper
343+
public class ApiXmlDocScraper : IJavaMethodParameterNameProvider
337344
{
338345
public ApiXmlDocScraper (string apiXmlFile)
339346
{
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Xml.Linq;
6+
using System.Xml.XPath;
7+
8+
namespace Xamarin.Android.Tools.Bytecode
9+
{
10+
public class JavaParameterNamesLoader : IJavaMethodParameterNameProvider
11+
{
12+
List<Package> packages;
13+
14+
public JavaParameterNamesLoader(string path)
15+
{
16+
packages = this.LoadParameterFixupDescription(path);
17+
}
18+
19+
class Parameter
20+
{
21+
public string Type { get; set; }
22+
public string Name { get; set; }
23+
}
24+
25+
class Method
26+
{
27+
public string Name { get; set; }
28+
public List<Parameter> Parameters { get; set; }
29+
public bool Applied { get; set; }
30+
}
31+
32+
class Type
33+
{
34+
public string Name { get; set; }
35+
public List<Method> Methods { get; set; }
36+
}
37+
38+
class Package
39+
{
40+
public string Name { get; set; }
41+
public List<Type> Types { get; set; }
42+
}
43+
44+
// from https://github.com/atsushieno/xamarin-android-docimporter-ng/blob/master/Xamarin.Android.Tools.JavaStubImporter/JavaApiParameterNamesXmlExporter.cs#L78
45+
/*
46+
* The Text Format is:
47+
*
48+
* package {packagename}
49+
* #---------------------------------------
50+
* interface {interfacename}{optional_type_parameters} -or-
51+
* class {classname}{optional_type_parameters}
52+
* {optional_type_parameters}{methodname}({parameters})
53+
*
54+
* Anything after # is treated as comment.
55+
*
56+
* optional_type_parameters: "" -or- "<A,B,C>" (no constraints allowed)
57+
* parameters: type1 p0, type2 p1 (pairs of {type} {name}, joined by ", ")
58+
*
59+
* It is with strict indentations. two spaces for types, four spaces for methods.
60+
*
61+
* Constructors are named as "#ctor".
62+
*
63+
* Commas are used by both parameter types and parameter separators,
64+
* but only parameter separators can be followed by a whitespace.
65+
* It is useful when writing text parsers for this format.
66+
*
67+
* Type names may contain whitespaces in case it is with generic constraints (e.g. "? extends FooBar"),
68+
* so when parsing a parameter type-name pair, the only trustworthy whitespace for tokenizing name is the *last* one.
69+
*
70+
*/
71+
List<Package> LoadParameterFixupDescription (string path)
72+
{
73+
var fixup = new List<Package> ();
74+
string package = null;
75+
var types = new List<Type> ();
76+
string type = null;
77+
var methods = new List<Method> ();
78+
foreach (var l in File.ReadAllLines (path)) {
79+
var line = l.IndexOf ('#') >= 0 ? l.Substring (0, l.IndexOf ('#')) : l;
80+
if (line.Trim ().Length == 0)
81+
continue;
82+
if (line.StartsWith ("package ", StringComparison.Ordinal)) {
83+
package = line.Substring ("package ".Length);
84+
types = new List<Type> ();
85+
fixup.Add (new Package { Name = package, Types = types });
86+
continue;
87+
} else if (line.StartsWith (" ", StringComparison.Ordinal)) {
88+
int open = line.IndexOf ('(');
89+
string parameters = line.Substring (open + 1).TrimEnd (')');
90+
string name = line.Substring (4, open - 4);
91+
if (name.FirstOrDefault () == '<') // generic method can begin with type parameters.
92+
name = name.Substring (name.IndexOf (' ') + 1);
93+
methods.Add (new Method {
94+
Name = name,
95+
Parameters = parameters.Replace (", ", "\0").Split ('\0')
96+
.Select (s => s.Split (' '))
97+
.Select (a => new Parameter { Type = string.Join (" ", a.Take (a.Length - 1)), Name = a.Last () }).ToList ()
98+
});
99+
} else {
100+
type = line.Substring (line.IndexOf (' ', 2) + 1);
101+
// To match type name from class-parse, we need to strip off generic arguments here (generics are erased).
102+
if (type.IndexOf ('<') > 0)
103+
type = type.Substring (0, type.IndexOf ('<'));
104+
methods = new List<Method> ();
105+
types.Add (new Type { Name = type, Methods = methods });
106+
}
107+
}
108+
return fixup;
109+
}
110+
111+
public string[] GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs)
112+
{
113+
var methods = this.packages
114+
.Where(p => p.Name == package)
115+
.SelectMany(p => p.Types)
116+
.Where(t => t.Name == type)
117+
.SelectMany(t => t.Methods)
118+
.Where(m => m.Name == method);
119+
var namedMethod = methods.FirstOrDefault (m => ParametersEqual (m.Parameters, ptypes));
120+
if (namedMethod == null)
121+
return null;
122+
return namedMethod.Parameters.Select (p => p.Name).ToArray ();
123+
}
124+
125+
static bool ParametersEqual (List<Parameter> methodParameters, string[] ptypes)
126+
{
127+
if (methodParameters.Count != ptypes.Length)
128+
return false;
129+
for (int i = 0; i < ptypes.Length; ++i) {
130+
if (methodParameters[i].Type != ptypes [i])
131+
return false;
132+
}
133+
return true;
134+
}
135+
}
136+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package java.util
2+
class Collection<E>
3+
add(E e)

src/Xamarin.Android.Tools.Bytecode/Tests/ParameterFixupTests.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void DocletType_ShouldDetectApiXml ()
6363
try {
6464
tempFile = LoadToTempFile ("ParameterFixupApiXmlDocs.xml");
6565

66-
Assert.AreEqual (JavaDocletType._ApiXml, AndroidDocScraper.GetDocletType (tempFile));
66+
Assert.AreEqual (JavaDocletType._ApiXml, JavaMethodParameterNameProvider.GetDocletType (tempFile));
6767
} finally {
6868
if (File.Exists (tempFile))
6969
File.Delete (tempFile);
@@ -85,7 +85,23 @@ public void DocletType_ShouldDetectDroidDocs ()
8585
if (!Directory.Exists (droidDocsPath))
8686
Assert.Fail("The Android SDK Documentation path `{0}` was not found.", droidDocsPath);
8787

88-
Assert.AreEqual(JavaDocletType.DroidDoc2, AndroidDocScraper.GetDocletType(droidDocsPath));
88+
Assert.AreEqual(JavaDocletType.DroidDoc2, JavaMethodParameterNameProvider.GetDocletType(droidDocsPath));
89+
}
90+
91+
[Test]
92+
public void XmlDeclaration_FixedUpFromParameterDescription ()
93+
{
94+
string tempFile = null;
95+
96+
try {
97+
tempFile = LoadToTempFile ("ParameterDescription.txt");
98+
99+
AssertXmlDeclaration (new string [] { "Collection.class" }, "ParameterFixupFromDocs.xml", tempFile);
100+
}
101+
finally {
102+
if (File.Exists (tempFile))
103+
File.Delete (tempFile);
104+
}
89105
}
90106
}
91107
}

src/Xamarin.Android.Tools.Bytecode/Tests/Xamarin.Android.Tools.Bytecode-Tests.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@
162162
<EmbeddedResource Include="ParameterFixupApiXmlDocs.xml">
163163
<LogicalName>ParameterFixupApiXmlDocs.xml</LogicalName>
164164
</EmbeddedResource>
165-
</ItemGroup>
165+
<EmbeddedResource Include="ParameterDescription.txt">
166+
<LogicalName>ParameterDescription.txt</LogicalName>
167+
</EmbeddedResource> </ItemGroup>
166168
<ItemGroup>
167169
<None Include="packages.config" />
168170
</ItemGroup>

src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<Compile Include="JavaDocumentScraper.cs" />
5050
<Compile Include="ClassPath.cs" />
5151
<Compile Include="Log.cs" />
52+
<Compile Include="JavaParameterNamesLoader.cs" />
5253
</ItemGroup>
5354
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
5455
</Project>

tools/class-parse/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public static void Main (string[] args)
3838
{ "docspath=",
3939
"Documentation {PATH} for parameter fixup",
4040
doc => docsPaths.Add (doc) },
41+
{ "parameter-names=",
42+
"{PATH} for Java method parameter name information",
43+
doc => docsPaths.Add (doc) },
4144
{ "docstype=",
4245
"OBSOLETE: Previously used to specify a doc type (now auto detected).",
4346
t => docsType = t != null },

0 commit comments

Comments
 (0)