Skip to content

Commit 5dcf896

Browse files
authored
[generator] Don't invalidate interface if static method is invalidated (#660)
Fixes: #588 If we cannot bind a method on an interface we mark the interface as unbindable and omit the interface from the generated code, and invalidate anything that depends on the interface. This is because an interface with a missing method cannot be implemented in C#. However, if the method is `static` then we *can* remove the method while keeping the interface, as the user is not required to implement the static method. Update `GenBase.OnValidate()` so that invalid static methods don't invalidate their declaring interface. Note we already properly handled Default Interface Methods, this adds support for `static` methods as well.
1 parent 1b59dcc commit 5dcf896

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs

+35
Original file line numberDiff line numberDiff line change
@@ -396,5 +396,40 @@ public void RespectNoAlternativesForInterfaces ()
396396
Assert.False (writer.ToString ().Contains ("class ParentConsts"));
397397
Assert.False (writer.ToString ().Contains ("class Parent"));
398398
}
399+
400+
[Test]
401+
public void DontInvalidateInterfaceDueToStaticOrDefaultMethods ()
402+
{
403+
// This interface contains a static and a default interface method that cannot
404+
// be bound due to an unknown return type. However the user doesn't have to
405+
// provide an implementation for these methods, so it's ok to bind the interface.
406+
407+
var xml = @"<api>
408+
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
409+
<interface abstract='true' deprecated='not deprecated' final='false' name='Parent' static='false' visibility='public' jni-signature='Lcom/xamarin/android/Parent;'>
410+
<method abstract='true' deprecated='not deprecated' name='normalMethod' jni-signature='()I' return='int' static='false' transient='false' visibility='public' volatile='false'></method>
411+
<method abstract='false' deprecated='not deprecated' name='staticMethod' jni-signature='()Lfoo/bar/baz;' return='Lfoo/bar/baz;' static='true' transient='false' visibility='public' volatile='false'></method>
412+
<method abstract='false' deprecated='not deprecated' name='defaultMethod' jni-signature='()Lfoo/bar/baz;' return='Lfoo/bar/baz;' static='false' transient='false' visibility='public' volatile='false'></method>
413+
</interface>
414+
</package>
415+
</api>";
416+
417+
var gens = ParseApiDefinition (xml);
418+
var iface = gens.OfType<InterfaceGen> ().Single ();
419+
420+
var result = iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ());
421+
422+
// Inteface should pass validation despite invalid static/default methods
423+
Assert.True (result);
424+
425+
generator.WriteInterface (iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly"));
426+
427+
var generated = writer.ToString ();
428+
429+
Assert.True (generated.Contains ("interface IParent"));
430+
Assert.True (generated.Contains ("NormalMethod"));
431+
Assert.False (generated.Contains ("StaticMethod"));
432+
Assert.False (generated.Contains ("DefaultMethod"));
433+
}
399434
}
400435
}

tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -677,11 +677,11 @@ protected virtual bool OnValidate (CodeGenerationOptions opt, GenericParameterDe
677677
}
678678
Fields = valid_fields;
679679

680-
// If we can't validate a default interface method it's ok to ignore it and still bind the interface
681-
var method_cnt = Methods.Where (m => !m.IsInterfaceDefaultMethod).Count ();
680+
// If we can't validate a static or default interface method it's ok to ignore it and still bind the interface
681+
var method_cnt = Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic).Count ();
682682

683683
Methods = Methods.Where (m => ValidateMethod (opt, m, context)).ToList ();
684-
MethodValidationFailed = method_cnt != Methods.Where (m => !m.IsInterfaceDefaultMethod).Count ();
684+
MethodValidationFailed = method_cnt != Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic).Count ();
685685

686686
foreach (Method m in Methods) {
687687
if (m.IsVirtual)

0 commit comments

Comments
 (0)