Skip to content

Conversation

@jonpryor
Copy link
Contributor

@jonpryor jonpryor commented Nov 22, 2021

Fixes: #920

Context: 69e1b80

java-source-utils.jar isn't always able to fully resolve types.
When it is unable to do so, it uses an "alternate encoding":

In some scenarios, types won't be resolvable. What should output be?

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;.

The problem is that class-parse --parameter-names=PATH didn't check
for this "unresolvable type" pattern, so if you had a method which
contained them, e.g. the target parameter in:

<interface jni-signature="Landroidx/core/view/NestedScrollingParent3;" name="NestedScrollingParent3">
  <method jni-return="V" jni-signature="(L.*View;IIIII[I)V" name="onNestedScroll" return="void">
    <parameter jni-type="L.*View;" name="target" type=".*View"/>
    <parameter jni-type="I" name="dxConsumed" type="int"/>
    <parameter jni-type="I" name="dyConsumed" type="int"/>
    <parameter jni-type="I" name="dxUnconsumed" type="int"/>
    <parameter jni-type="I" name="dyUnconsumed" type="int"/>
    <parameter jni-type="I" name="type" type="int"/>
    <parameter jni-type="[I" name="consumed" type="int[]"/>

then class-parse --parameter-names=params.xml lib.jar wouldn't
try to "loosely match" these parameter types. Consequently,
parameter names were not imported.

Update the IJavaMethodParameterNameProvider.GetParameterNames()
method to take a new JavaMethodParameterNameInfo type, instead of
five (5) parameters, as I wanted to increase the amount of data
available to GetParameterNames().

Update ApiXmlDocScraper.GetParameterNames() twofold:

  1. Use XLinq instead of computing an XPath expression, and
  2. Loosely match parameter types when //parameter/@jni-name
    starts with L.*.

This allows us to import parameter names for unresolvable types.

"Force" the issue by adding JavaInterfaceNoParameters.java and a
ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml,
generated via:

java -jar bin/Debug/java-source-utils.jar \
  tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaInterfaceNoParameters.java \
  > tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml

then altering the resulting XML so that instead of e.g.
Ljava/lang/Object;, L.*Object; is used.

This should permit appropriate parameter name overrides e.g. via:

mono bin/Debug/class-parse.exe \
  --parameter-names tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml \
  tests/Xamarin.Android.Tools.Bytecode-Tests/obj/Debug/classes/com/xamarin/JavaInterfaceNoParameters.class

Testing found a deficiency in java-source-utils: it didn't properly
represent "varargs" arrays. Update tools/java-source-utils so that
params-arrays are properly represented.

@jonpryor jonpryor force-pushed the jonp-support-unresolved-types-in-param-name-import branch from ae5b249 to ce9d952 Compare November 22, 2021 22:01
@jonpryor
Copy link
Contributor Author

TODO:

  • Unit tests?
  • What are the semantics of isVarArgs?

Fixes: dotnet#920

Context: 69e1b80

`java-source-utils.jar` isn't always able to fully resolve types.
When it is unable to do so, it uses an "alternate encoding":

> In some scenarios, types won't be resolvable.  What should output be?
>
> 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;`.

The problem is that `class-parse --parameter-names=PATH` didn't check
for this "unresolvable type" pattern, so if you had a method which
contained them, e.g. the `target` parameter in:

	<interface jni-signature="Landroidx/core/view/NestedScrollingParent3;" name="NestedScrollingParent3">
	  <method jni-return="V" jni-signature="(L.*View;IIIII[I)V" name="onNestedScroll" return="void">
	    <parameter jni-type="L.*View;" name="target" type=".*View"/>
	    <parameter jni-type="I" name="dxConsumed" type="int"/>
	    <parameter jni-type="I" name="dyConsumed" type="int"/>
	    <parameter jni-type="I" name="dxUnconsumed" type="int"/>
	    <parameter jni-type="I" name="dyUnconsumed" type="int"/>
	    <parameter jni-type="I" name="type" type="int"/>
	    <parameter jni-type="[I" name="consumed" type="int[]"/>

then `class-parse --parameter-names=params.xml lib.jar` wouldn't
try to "loosely match" these parameter types.  Consequently,
parameter names were not imported.

Update the `IJavaMethodParameterNameProvider.GetParameterNames()`
method to take a new `JavaMethodParameterNameInfo` type, instead of
five (5) parameters, as I wanted to increase the amount of data
available to `GetParameterNames()`.

Update `ApiXmlDocScraper.GetParameterNames()` twofold:

 1. Use XLinq instead of computing an XPath expression, and
 2. Loosely match parameter types when `//parameter/@jni-name`
    starts with `L.*`.

This allows us to import parameter names for unresolvable types.

"Force" the issue by adding `JavaInterfaceNoParameters.java` and a
`ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml`,
generated via:

	java -jar bin/Debug/java-source-utils.jar \
	  tests/Xamarin.Android.Tools.Bytecode-Tests/java/com/xamarin/JavaInterfaceNoParameters.java \
	  > tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml

then altering the resulting XML so that instead of e.g.
`Ljava/lang/Object;`, `L.*Object;` is used.

This should permit appropriate parameter name overrides e.g. via:

	mono bin/Debug/class-parse.exe \
	  --parameter-names tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/ParameterFixup_JavaInterfaceNoParameters_JavaSourceUtils.xml \
	  tests/Xamarin.Android.Tools.Bytecode-Tests/obj/Debug/classes/com/xamarin/JavaInterfaceNoParameters.class

Testing found a deficiency in `java-source-utils`: it didn't properly
represent "varargs" arrays.  Update `tools/java-source-utils` so that
params-arrays are properly represented.
@jonpryor jonpryor force-pushed the jonp-support-unresolved-types-in-param-name-import branch from ce9d952 to 708bb1b Compare November 23, 2021 18:08
@jonpryor jonpryor requested a review from jpobst November 23, 2021 18:22
@jonpryor jonpryor marked this pull request as ready for review November 23, 2021 18:22
@jonpryor
Copy link
Contributor Author

TODO:

  • Unit tests?

Added.

  • What are the semantics of isVarArgs?

Lol? All GetParameterNames() codepaths I found always use isVarArgs: false.

That said, thinking about variable argument lists led me to a bug in java-source-utils, so that was fun...

@jonpryor jonpryor merged commit 77c9c5f into dotnet:main Nov 29, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Apr 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

java-source-utils unable to extract parameters in AndroidX.Core source jar

2 participants