Skip to content

Commit 7c1ad51

Browse files
authored
[java-source-utils] Properly represent unresolved types (#758)
Context: #687 (comment) Commit 69e1b80 stated: > We don't want to *require* that everything be resolvable -- it's painful, and > possibly impossible, e.g. w/ internal types -- so instead we should "demark" > the unresolvable types. > > `.params.txt` output will use `.*` as a type prefix, e.g. > > method(.*UnresolvableType foo, int bar); > > `docs.xml` will output `L.*UnresolvableType;`. …except this didn't actually happen: `java-source.utils.jar --output-javadoc` didn't have an `L` prefix and `;` suffix for the JNI type representation. Additionally, it would include generic type parameters! Thus, a declaration such as: static UnknownType<String, Integer> method(AnotherUnknownType<Class> p); would result in: <method name="method" jni-return=".*UnknownType&lt;String, Integer&gt;" jni-signature="(.*AnotherUnknownType&lt;Class&gt;).*UnkonwnType&lt;String, Integer&gt;"> which was not at all intended, and causes subsequent issued in PR #687 as the JNI signature parser would break when encountering `.`. Update `java-source-utils.jar` & `//*/@jni-signature` so that [unresolved types are properly represented][0]: `//*/@jni-type` and `//*/@jni-signature` shouldn't contain generic type parameters, and should also (somewhat) "conform" to JNI convention, with a leading `L` and trailing `;`, emitting: <method name="method" jni-return="L.*UnknownType;" jni-signature="(L.*AnotherUnknownType;)L.*UnknownType;"> Additionally, update `JavaType.java` to cause it to have "orphaned" Javadoc comments; this change was forgotten in c1bc5c8. [0]: #687 (comment)
1 parent c1bc5c8 commit 7c1ad51

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
/**
77
* JNI sig: Lcom/xamarin/JavaEnum;
88
*/
9+
// Disconnective comment?
910
enum JavaEnum {
1011
/** FIRST; JNI sig: Lcom/xamarin/JavaEnum; */
1112
FIRST,
@@ -161,6 +162,7 @@ public int compareTo (JavaType<E> value) {
161162
}
162163

163164
/** JNI sig: func.(Ljava/lang/StringBuilder;)Ljava/util/List; */
165+
// Comment to "disconnect" Javadoc from the member
164166
public List<String> func (StringBuilder value) {
165167
return null;
166168
}

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

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ static String getJavaType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, Type t
361361
final ResolvedType rt = type.resolve();
362362
return rt.describe();
363363
} catch (final Throwable thr) {
364-
return ".*" + type.asString();
364+
return getUnresolvedJavaType(type);
365365
}
366366
}
367367

@@ -389,7 +389,8 @@ static String getJniType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, Type ty
389389
}
390390
catch (final Exception thr) {
391391
}
392-
return ".*" + type.asString();
392+
393+
return getUnresolvedJniType(type);
393394
}
394395

395396
static String getJniType(JniTypeInfo typeInfo, JniMethodInfo methodInfo, ArrayType type) {
@@ -412,7 +413,7 @@ static String getPrimitiveJniType(String javaType) {
412413
case "short": return "S";
413414
case "void": return "V";
414415
}
415-
throw new Error("Don't know JNI type for `" + javaType + "`!");
416+
throw new Error("Don't know JNI type for primitive type `" + javaType + "`!");
416417
}
417418

418419
static String getJniType(ResolvedType type) {
@@ -453,4 +454,42 @@ static String getJniType(ResolvedReferenceType type) {
453454
name.append(";");
454455
return name.toString();
455456
}
457+
458+
static String getUnresolvedJavaType(Type type) {
459+
final StringBuilder jniType = new StringBuilder();
460+
461+
jniType.append(".*");
462+
463+
if (type.isClassOrInterfaceType()) {
464+
// Special-case class-or-interface declarations so that we skip type parameters.
465+
type.ifClassOrInterfaceType(c -> {
466+
c.getScope().ifPresent(s -> jniType.append(s.asString()).append("."));
467+
jniType.append(c.getName().asString());
468+
});
469+
} else {
470+
jniType.append(type.asString());
471+
}
472+
473+
return jniType.toString();
474+
}
475+
476+
static String getUnresolvedJniType(Type type) {
477+
final StringBuilder jniType = new StringBuilder();
478+
479+
jniType.append("L.*");
480+
481+
if (type.isClassOrInterfaceType()) {
482+
// Special-case class-or-interface declarations so that we skip type parameters.
483+
type.ifClassOrInterfaceType(c -> {
484+
c.getScope().ifPresent(s -> jniType.append(s.asString()).append("."));
485+
jniType.append(c.getName().asString());
486+
});
487+
} else {
488+
jniType.append(type.asString());
489+
}
490+
491+
jniType.append(";");
492+
493+
return jniType.toString();
494+
}
456495
}

tools/java-source-utils/src/test/java/com/microsoft/android/JavadocXmlGeneratorTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ public void testWritePackages_JavaType_java() throws Throwable {
109109
testWritePackages("../../../com/xamarin/JavaType.java", "JavaType.xml");
110110
}
111111

112+
@Test
113+
public void testWritePackages_UnresolvedTypes_txt() throws Throwable {
114+
testWritePackages("../../../UnresolvedTypes.txt", "../../../UnresolvedTypes.xml");
115+
}
116+
112117
private static void testWritePackages(final String resourceJava, final String resourceXml) throws Throwable {
113118
final JavaParser parser = JniPackagesInfoFactoryTest.createParser();
114119
final JniPackagesInfoFactory factory = new JniPackagesInfoFactory(parser);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package example;
2+
3+
public class UnresolvedTypes {
4+
/**
5+
* Method using unresolvable types. As such, we make do.
6+
*
7+
* JNI Sig: method.(L.*example.name.UnresolvedParameterType;)L.*UnresolvedReturnType;
8+
*/
9+
public static UnresolvedReturnType<String, Integer> method(example.name.UnresolvedParameterType<Class> parameter) {
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<api api-source="java-source-utils">
3+
<package jni-name="example" name="example">
4+
<class jni-signature="Lexample/UnresolvedTypes;" name="UnresolvedTypes">
5+
<method jni-return="L.*UnresolvedReturnType;" jni-signature="(L.*example.name.UnresolvedParameterType;)L.*UnresolvedReturnType;" name="method" return=".*UnresolvedReturnType">
6+
<parameter jni-type="L.*example.name.UnresolvedParameterType;" name="parameter" type=".*example.name.UnresolvedParameterType"/>
7+
<javadoc><![CDATA[Method using unresolvable types. As such, we make do.
8+
9+
JNI Sig: method.(L.*example.name.UnresolvedParameterType;)L.*UnresolvedReturnType;]]></javadoc>
10+
</method>
11+
</class>
12+
</package>
13+
</api>

0 commit comments

Comments
 (0)