Skip to content

[generator] Add 'managedOverride' metadata to allow user to force 'override'/'virtual'. #701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,102 @@ public void WriteKotlinUnsignedArrayTypePropertiesClass ()

Assert.AreEqual (GetTargetedExpected (nameof (WriteKotlinUnsignedArrayTypePropertiesClass)), writer.ToString ().NormalizeLineEndings ());
}

[Test]
public void ManagedOverrideMethod_Virtual ()
{
var xml = @"<api>
<package name='java.lang' jni-name='java/lang'>
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
</package>
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
<class abstract='false' deprecated='not deprecated' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;'>
<method abstract='false' deprecated='not deprecated' final='true' name='DoStuff' jni-signature='()I' bridge='false' native='false' return='int' jni-return='I' static='false' synchronized='false' synthetic='false' visibility='public' managedOverride='virtual'></method>
</class>
</package>
</api>";

var gens = ParseApiDefinition (xml);
var klass = gens.Single (g => g.Name == "MyClass");

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

Assert.True (writer.ToString ().Contains ("public virtual unsafe int DoStuff ()"));
}

[Test]
public void ManagedOverrideMethod_Override ()
{
var xml = @"<api>
<package name='java.lang' jni-name='java/lang'>
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
</package>
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
<class abstract='false' deprecated='not deprecated' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;'>
<method abstract='false' deprecated='not deprecated' final='true' name='DoStuff' jni-signature='()I' bridge='false' native='false' return='int' jni-return='I' static='false' synchronized='false' synthetic='false' visibility='public' managedOverride='override'></method>
</class>
</package>
</api>";

var gens = ParseApiDefinition (xml);
var klass = gens.Single (g => g.Name == "MyClass");

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

Assert.True (writer.ToString ().Contains ("public override unsafe int DoStuff ()"));
}

[Test]
public void ManagedOverrideProperty_Virtual ()
{
var xml = @"<api>
<package name='java.lang' jni-name='java/lang'>
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
</package>
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
<class abstract='false' deprecated='not deprecated' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;'>
<method abstract='false' deprecated='not deprecated' final='true' name='getName' jni-signature='()I' bridge='false' native='false' return='int' jni-return='I' static='false' synchronized='false' synthetic='false' visibility='public' managedOverride='virtual'></method>
</class>
</package>
</api>";

var gens = ParseApiDefinition (xml);
var klass = gens.Single (g => g.Name == "MyClass");

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

Assert.True (writer.ToString ().Contains ("public virtual unsafe int Name {"));
}

[Test]
public void ManagedOverrideProperty_Override ()
{
var xml = @"<api>
<package name='java.lang' jni-name='java/lang'>
<class abstract='false' deprecated='not deprecated' final='false' name='Object' static='false' visibility='public' jni-signature='Ljava/lang/Object;' />
</package>
<package name='com.xamarin.android' jni-name='com/xamarin/android'>
<class abstract='false' deprecated='not deprecated' extends='java.lang.Object' extends-generic-aware='java.lang.Object' jni-extends='Ljava/lang/Object;' final='false' name='MyClass' static='false' visibility='public' jni-signature='Lcom/xamarin/android/MyClass;'>
<method abstract='false' deprecated='not deprecated' final='true' name='getName' jni-signature='()I' bridge='false' native='false' return='int' jni-return='I' static='false' synchronized='false' synthetic='false' visibility='public' managedOverride='override'></method>
</class>
</package>
</api>";

var gens = ParseApiDefinition (xml);
var klass = gens.Single (g => g.Name == "MyClass");

generator.Context.ContextTypes.Push (klass);
generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
generator.Context.ContextTypes.Pop ();

Assert.True (writer.ToString ().Contains ("public override unsafe int Name {"));
}
}

[TestFixture]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ public static Method CreateMethod (GenBase declaringType, XElement elem)
IsReturnEnumified = elem.Attribute ("enumReturn") != null,
IsStatic = elem.XGetAttribute ("static") == "true",
JavaName = elem.XGetAttribute ("name"),
ManagedOverride = elem.XGetAttribute ("managedOverride"),
ManagedReturn = elem.XGetAttribute ("managedReturn"),
PropertyNameOverride = elem.XGetAttribute ("propertyName"),
Return = elem.XGetAttribute ("return"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public Method (GenBase declaringType) : base (declaringType)
public bool IsStatic { get; set; }
public bool IsVirtual { get; set; }
public string JavaName { get; set; }
public string ManagedOverride { get; set; }
public string ManagedReturn { get; set; }
public string PropertyNameOverride { get; set; }
public string Return { get; set; }
Expand Down
9 changes: 9 additions & 0 deletions tools/generator/SourceWriters/BoundMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ public BoundMethod (GenBase type, Method method, CodeGenerationOptions opt, bool
if ((IsVirtual || !IsOverride) && type.RequiresNew (method.AdjustedName, method))
IsShadow = true;

// Allow user to override our virtual/override logic
if (method.ManagedOverride?.ToLowerInvariant () == "virtual") {
IsVirtual = true;
IsOverride = false;
} else if (method.ManagedOverride?.ToLowerInvariant () == "override") {
IsVirtual = false;
IsOverride = true;
}

ReturnType = new TypeReferenceWriter (opt.GetTypeReferenceName (method.RetVal));

if (method.DeclaringType.IsGeneratable)
Expand Down
9 changes: 9 additions & 0 deletions tools/generator/SourceWriters/BoundProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ public BoundProperty (GenBase gen, Property property, CodeGenerationOptions opt,
}
}

// Allow user to override our virtual/override logic
if (!forceOverride && (property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "virtual") {
IsVirtual = true;
IsOverride = false;
} else if (!forceOverride && (property.Getter ?? property.Setter).ManagedOverride?.ToLowerInvariant () == "override") {
IsVirtual = false;
IsOverride = true;
}

// Unlike [Register], [Obsolete] cannot be put on property accessors, so we can apply them only under limited condition...
if (property.Getter.Deprecated != null && (property.Setter == null || property.Setter.Deprecated != null))
Attributes.Add (new ObsoleteAttr (property.Getter.Deprecated.Replace ("\"", "\"\"").Trim () + (property.Setter != null && property.Setter.Deprecated != property.Getter.Deprecated ? " " + property.Setter.Deprecated.Replace ("\"", "\"\"").Trim () : null)));
Expand Down