Skip to content

Commit

Permalink
[Java.Interop.Tools.JavaCallableWrappers] XA4213 for mangled methods (#…
Browse files Browse the repository at this point in the history
…537)

Context: #534
Context: #535
Context: 0065de4

There are cases where Kotlin generates Java methods that are not
valid Java identifiers:

	// `javap` output for a Kotlin type using UInt parameters
	public abstract class Bar {
	    abstract void foo-WZ4Q5Ns(int);
	}

	public interface IBar {
	    void foo-WZ4Q5Ns(int);
	}

In this case we cannot allow the user to inherit from the class or
implement the interface as the mangled method cannot be present
within Java Callable Wrapper source code.

We still need the class to be bound because there might be a Kotlin-
created subclass that needs the base class to exist.

There's no foolproof way to mark these as "not implementable".  The
best we can do for now is to detect if the user implements them in
the `<GenerateJavaStubs/>` task / `JavaCallableWrapperGenerator` and
give an informative error at that point.

Update `JavaCallableWrapperGenerator` so that when a Kotlin-generated
mangled method name is encountered, an XA4213 error is emitted:

	error XA4213: Cannot override Kotlin-generated method 'foo-WZ4Q5Ns'
	because it is not a valid Java method name.
	This method can only be overridden from Kotlin.
  • Loading branch information
jpobst authored and jonpryor committed Dec 12, 2019
1 parent fac62f2 commit 3bf5333
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ namespace Java.Interop.Tools.Diagnostics {
// XA4210 "You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute."
// XA4211 AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{1} for ACW compilation.
// XA4212 Type `{0}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported.
// XA4213 Cannot override Kotlin-generated method '{0}' because it is not a valid Java method name. This method can only be overridden from Kotlin."
// XA5xxx GCC and toolchain
// XA32xx .apk generation
// XA4300 Unsupported $(AndroidSupportedAbis) value '{0}'; ignoring.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,10 @@ void AddMethod (MethodDefinition registeredMethod, MethodDefinition implementedM
{
if (registeredMethod != null)
foreach (RegisterAttribute attr in GetRegisterAttributes (registeredMethod)) {
// Check for Kotlin-mangled methods that cannot be overridden
if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-'))
Diagnostic.Error (4213, LookupSource (implementedMethod), $"Cannot override Kotlin-generated method '{attr.Name}' because it is not a valid Java method name. This method can only be overridden from Kotlin.");

var msig = new Signature (implementedMethod, attr);
if (!registeredMethod.IsConstructor && !methods.Any (m => m.Name == msig.Name && m.Params == msig.Params))
methods.Add (msig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@ public void ConstructorExceptions ()
Assert.AreEqual (4200, e.Code);
}

[Test]
public void KotlinInvalidImplRegisterName ()
{
Action<string, object []> logger = (f, o) => { };

// Contains invalid [Register] name of "foo-impl"
var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidImplRegisterName));
var e = Assert.Throws<XamarinAndroidException> (() => new JavaCallableWrapperGenerator (td, logger));
Assert.AreEqual (4213, e.Code);
}

[Test]
public void KotlinInvalidHashRegisterName ()
{
Action<string, object []> logger = (f, o) => { };

// Contains invalid [Register] name of "foo-f8k2a13"
var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidHashRegisterName));
var e = Assert.Throws<XamarinAndroidException> (() => new JavaCallableWrapperGenerator (td, logger));
Assert.AreEqual (4213, e.Code);
}

[Test]
public void GenerateApplication (
[Values (null, "android.app.Application", "android.support.multidex.MultiDexApplication")] string applicationJavaClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,34 @@ public class OverrideNestedName : Java.Lang.Object
}
}

[Register ("Kotlin.InvalidRegisterName")]
class KotlinInvalidRegisterName : Java.Lang.Object
{
[Register ("foo-impl")]
public virtual void Foo ()
{
}

[Register ("foo-f8k2a13")]
public virtual void Bar ()
{
}
}

[Register ("Kotlin.InvalidRegisterNameSubclass")]
class KotlinInvalidImplRegisterName : KotlinInvalidRegisterName
{
[Register ("foo-impl")]
public override void Foo () => base.Foo ();
}

[Register ("Kotlin.InvalidRegisterNameSubclass")]
class KotlinInvalidHashRegisterName : KotlinInvalidRegisterName
{
[Register ("foo-f8k2a13")]
public override void Bar () => base.Foo ();
}

[Service (Name = "service.Name")]
class ServiceName : Java.Lang.Object
{
Expand Down

0 comments on commit 3bf5333

Please sign in to comment.