Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 14 additions & 5 deletions src/Xamarin.Android.Tools.Bytecode/ClassPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,23 @@ void FixupParametersFromDocs (XElement api, string path)
if (!parameterElements.Select (x => x.Attribute ("name")?.Value).Any (p => p != null && IsGeneratedName (p)))
continue;

var parameters = parameterElements
.Select (p => p.Attribute ("type")?.Value!)
.Where (p => p != null);
var parameterTypes = parameterElements
.Select (p => new JavaMethodParameterTypeInfo ((string) p.Attribute ("jni-type"), (string) p.Attribute ("type")))
.ToArray ();

if (!parameters.Any ())
if (!parameterTypes.Any ())
continue;

var pnames = jdoc.GetParameterNames (currentpackage, className, currentMethod, parameters.ToArray (), isVarArgs: false);
var nameInfo = new JavaMethodParameterNameInfo (
currentpackage,
className,
currentMethod,
(string) method.Attribute ("jni-signature"),
parameterTypes,
isVarArgs: false
);

var pnames = jdoc.GetParameterNames (nameInfo);
if (pnames == null || pnames.Length != parameterElements.Count)
continue;
for (int i = 0; i < parameterElements.Count; i++) {
Expand Down
121 changes: 88 additions & 33 deletions src/Xamarin.Android.Tools.Bytecode/JavaDocumentScraper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,14 @@ protected virtual string StripTagsFromParameters (string value)
{
return value;
}
public virtual String[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs)

public virtual string[]? GetParameterNames (JavaMethodParameterNameInfo info)
{
var package = info.PackageName;
var type = info.TypeName;
var method = info.MethodName;
var ptypes = info.ParameterTypes.Select (p => p.JavaType).ToArray ();

string path = package.Replace ('.', '/') + '/' + type.Replace ('$', '.') + ".html";
string file = Path.Combine (root, path);
if (!File.Exists (file)) {
Expand Down Expand Up @@ -301,9 +306,39 @@ public static void LoadXml (String filename)
}
}

public readonly struct JavaMethodParameterTypeInfo {
public string JniType {get;}
public string JavaType {get;}

public JavaMethodParameterTypeInfo (string jniType, string javaType)
{
JniType = jniType;
JavaType = javaType;
}
}

public readonly struct JavaMethodParameterNameInfo {
public string PackageName {get;}
public string TypeName {get;}
public string MethodName {get;}
public string? MethodSignature {get;}
public bool IsVarArgs {get;}
public JavaMethodParameterTypeInfo[] ParameterTypes {get;}

public JavaMethodParameterNameInfo (string packageName, string typeName, string methodName, string? methodSignature, JavaMethodParameterTypeInfo[] parameterTypes, bool isVarArgs)
{
PackageName = packageName;
TypeName = typeName;
MethodName = methodName;
MethodSignature = methodSignature;
ParameterTypes = parameterTypes;
IsVarArgs = isVarArgs;
}
}

public interface IJavaMethodParameterNameProvider
{
String[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs);
string[]? GetParameterNames (JavaMethodParameterNameInfo info);
}

public static class JavaMethodParameterNameProvider {
Expand Down Expand Up @@ -360,39 +395,59 @@ public ApiXmlDocScraper (string apiXmlFile)

XDocument xdoc;

public string[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs)
public string[]? GetParameterNames (JavaMethodParameterNameInfo info)
{
var methodOrCtor = method == "constructor" ?
"constructor[" : $"method[@name='{method}'";

var pcount = ptypes.Length;

var xpath = new StringBuilder ();

xpath.Append ($"/api/package[@name='{package}']/*[self::class or self::interface]/");

if (method == "constructor")
xpath.Append ("constructor[");
else
xpath.Append ($"method[@name='{method}'");

xpath.Append ($" and count(parameter)={pcount}");

if (pcount > 0) {
xpath.Append (" and ");
xpath.Append (string.Join (" and ", ptypes.Select ((pt, pindex) => $"parameter[{pindex + 1}][@type='{pt}']")));
var xtype = xdoc
.Elements ("api")
.Elements ("package")
.Where (p => ((string) p.Attribute ("name")) == info.PackageName)
.Elements ()
.Where (t => ((string) t.Attribute ("name")) == info.TypeName)
.FirstOrDefault ();
if (xtype == null) {
return null;
}

xpath.Append ("]");

var methodElem = xdoc.XPathSelectElement (xpath.ToString ());

if (methodElem != null)
return methodElem.Elements ("parameter")
.Select (pe => pe.Attribute ("name")?.Value ?? "")
.ToArray ();

return null;
var members = info.MethodName == "constructor"
? xtype.Elements ("constructor")
: xtype.Elements ("method").Where (m => ((string) m.Attribute ("name")) == info.MethodName);
var pcount = info.ParameterTypes.Length;
members = members
.Where (m => m.Elements ("parameter").Count () == pcount);

XElement? member =
members.FirstOrDefault (m => info.MethodSignature == (string) m.Attribute ("jni-signature"));
if (member == null) {
foreach (var m in members) {
var found = true;
int i = 0;
foreach (var p in m.Elements ("parameter")) {
if (!ParameterTypesMatch (p, info.ParameterTypes [i++].JavaType)) {
found = false;
break;
}
}
if (found) {
member = m;
break;
}
}
}
if (member == null)
return null;
return member.Elements ("parameter")
.Select (p => (string) p.Attribute ("name"))
.ToArray ();

bool ParameterTypesMatch (XElement parameter, string ptype)
{
var jtype = (string) parameter.Attribute ("type");
if (!jtype.StartsWith (".*", StringComparison.Ordinal)) {
return jtype == ptype;
}
jtype = "." + jtype.Substring (".*".Length);
return ptype.EndsWith (jtype, StringComparison.Ordinal);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,13 @@ List<Package> LoadParameterFixupDescription (string path)
return fixup;
}

public string[]? GetParameterNames (string package, string type, string method, string[] ptypes, bool isVarArgs)
public string[]? GetParameterNames (JavaMethodParameterNameInfo info)
{
var package = info.PackageName;
var type = info.TypeName;
var method = info.MethodName;
var ptypes = info.ParameterTypes.Select (p => p.JavaType).ToArray ();

var methods = this.packages
.Where(p => p.Name == package && p.Types != null)
.SelectMany(p => p.Types!)
Expand Down
15 changes: 15 additions & 0 deletions tests/Xamarin.Android.Tools.Bytecode-Tests/ParameterFixupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ public void XmlDeclaration_FixedUpFromApiXmlDocumentation ()
}
}

[Test]
public void XmlDeclaration_FixedUpFromUnresolvedApiXmlDocumentation ()
{
string docsPath = null;

try {
docsPath = LoadToTempFile ("ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml");

AssertXmlDeclaration ("JavaInterfaceNoParameters.class", "ParameterFixup_JavaInterfaceNoParameters.xml", docsPath);
} finally {
if (File.Exists (docsPath))
File.Delete (docsPath);
}
}

[Test]
public void XmlDeclaration_DoesNotThrowAnExceptionIfDocumentationNotFound ()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<api
api-source="class-parse">
<package
name="com.xamarin"
jni-name="com/xamarin">
<interface
abstract="true"
deprecated="not deprecated"
final="false"
name="JavaInterfaceNoParameters"
jni-signature="Lcom/xamarin/JavaInterfaceNoParameters;"
source-file-name="JavaInterfaceNoParameters.java"
static="false"
visibility="public">
<method
abstract="true"
deprecated="not deprecated"
final="false"
name="asList"
native="false"
return="java.util.List&lt;T&gt;"
jni-return="Ljava/util/List&lt;TT;&gt;;"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="([Ljava/lang/Object;)Ljava/util/List;">
<typeParameters>
<typeParameter
name="T"
jni-classBound="Ljava/lang/Object;"
classBound="java.lang.Object"
interfaceBounds=""
jni-interfaceBounds="" />
</typeParameters>
<parameter
name="a"
type="T..."
jni-type="[TT;" />
</method>
<method
abstract="true"
deprecated="not deprecated"
final="false"
name="binarySearch"
native="false"
return="int"
jni-return="I"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="([Ljava/lang/Object;IILjava/lang/Object;)I">
<parameter
name="a"
type="java.lang.Object[]"
jni-type="[Ljava/lang/Object;" />
<parameter
name="fromIndex"
type="int"
jni-type="I" />
<parameter
name="toIndex"
type="int"
jni-type="I" />
<parameter
name="key"
type="java.lang.Object"
jni-type="Ljava/lang/Object;" />
</method>
</interface>
</package>
</api>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<api api-source="java-source-utils">
<package jni-name="com/xamarin" name="com.xamarin">
<interface jni-signature="Lcom/xamarin/JavaInterfaceNoParameters;" name="JavaInterfaceNoParameters">
<method jni-return="L.*List;" jni-signature="([L.*Object;)L.*List;" name="asList" return=".*List&lt;T&gt;">
<parameter jni-type="[L.*Object;" name="a" type="T..."/>
<javadoc>
<![CDATA[JNI sig: (Lcom/xamarin/JavaTypeNoParameters;)V]]>
</javadoc>
</method>
<method jni-return="I" jni-signature="([L.*Object;IIL.*Object;)I" name="binarySearch" return="int">
<parameter jni-type="[L.*Object;" name="a" type=".*Object[]"/>
<parameter jni-type="I" name="fromIndex" type="int"/>
<parameter jni-type="I" name="toIndex" type="int"/>
<parameter jni-type="L.*Object;" name="key" type=".*Object"/>
</method>
</interface>
</package>
</api>
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\IParameterInterface.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaAnnotation.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaEnum.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaInterfaceNoParameters.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaType%241.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaType%241MyStringList.class" />
<EmbeddedResource Include="$(IntermediateOutputPath)classes\com\xamarin\JavaType%24ASC.class" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.xamarin;

public interface JavaInterfaceNoParameters {
/**
* JNI sig: ([Ljava/lang/Object;)Ljava/util/List;
*/
<T> java.util.List<T> asList(T... a);

/**
* JNI sig: ([Ljava/lang/Object;IILjava/lang/Object;)I
*
* @param a [Ljava/lang/Object;
* @param fromIndex int
* @param toIndex int
* @param key Ljava/lang/Object
* @return int
*/
int binarySearch(Object[] a, int fromIndex, int toIndex, Object key);
}
Loading