Skip to content

Commit 3bf5333

Browse files
jpobstjonpryor
authored andcommitted
[Java.Interop.Tools.JavaCallableWrappers] XA4213 for mangled methods (#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.
1 parent fac62f2 commit 3bf5333

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ namespace Java.Interop.Tools.Diagnostics {
103103
// XA4210 "You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute."
104104
// XA4211 AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{1} for ACW compilation.
105105
// XA4212 Type `{0}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported.
106+
// XA4213 Cannot override Kotlin-generated method '{0}' because it is not a valid Java method name. This method can only be overridden from Kotlin."
106107
// XA5xxx GCC and toolchain
107108
// XA32xx .apk generation
108109
// XA4300 Unsupported $(AndroidSupportedAbis) value '{0}'; ignoring.

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ void AddMethod (MethodDefinition registeredMethod, MethodDefinition implementedM
362362
{
363363
if (registeredMethod != null)
364364
foreach (RegisterAttribute attr in GetRegisterAttributes (registeredMethod)) {
365+
// Check for Kotlin-mangled methods that cannot be overridden
366+
if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-'))
367+
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.");
368+
365369
var msig = new Signature (implementedMethod, attr);
366370
if (!registeredMethod.IsConstructor && !methods.Any (m => m.Name == msig.Name && m.Params == msig.Params))
367371
methods.Add (msig);

src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGeneratorTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ public void ConstructorExceptions ()
3030
Assert.AreEqual (4200, e.Code);
3131
}
3232

33+
[Test]
34+
public void KotlinInvalidImplRegisterName ()
35+
{
36+
Action<string, object []> logger = (f, o) => { };
37+
38+
// Contains invalid [Register] name of "foo-impl"
39+
var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidImplRegisterName));
40+
var e = Assert.Throws<XamarinAndroidException> (() => new JavaCallableWrapperGenerator (td, logger));
41+
Assert.AreEqual (4213, e.Code);
42+
}
43+
44+
[Test]
45+
public void KotlinInvalidHashRegisterName ()
46+
{
47+
Action<string, object []> logger = (f, o) => { };
48+
49+
// Contains invalid [Register] name of "foo-f8k2a13"
50+
var td = SupportDeclarations.GetTypeDefinition (typeof (KotlinInvalidHashRegisterName));
51+
var e = Assert.Throws<XamarinAndroidException> (() => new JavaCallableWrapperGenerator (td, logger));
52+
Assert.AreEqual (4213, e.Code);
53+
}
54+
3355
[Test]
3456
public void GenerateApplication (
3557
[Values (null, "android.app.Application", "android.support.multidex.MultiDexApplication")] string applicationJavaClass

src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/SupportDeclarations.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,34 @@ public class OverrideNestedName : Java.Lang.Object
227227
}
228228
}
229229

230+
[Register ("Kotlin.InvalidRegisterName")]
231+
class KotlinInvalidRegisterName : Java.Lang.Object
232+
{
233+
[Register ("foo-impl")]
234+
public virtual void Foo ()
235+
{
236+
}
237+
238+
[Register ("foo-f8k2a13")]
239+
public virtual void Bar ()
240+
{
241+
}
242+
}
243+
244+
[Register ("Kotlin.InvalidRegisterNameSubclass")]
245+
class KotlinInvalidImplRegisterName : KotlinInvalidRegisterName
246+
{
247+
[Register ("foo-impl")]
248+
public override void Foo () => base.Foo ();
249+
}
250+
251+
[Register ("Kotlin.InvalidRegisterNameSubclass")]
252+
class KotlinInvalidHashRegisterName : KotlinInvalidRegisterName
253+
{
254+
[Register ("foo-f8k2a13")]
255+
public override void Bar () => base.Foo ();
256+
}
257+
230258
[Service (Name = "service.Name")]
231259
class ServiceName : Java.Lang.Object
232260
{

0 commit comments

Comments
 (0)