Skip to content
Closed
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
9 changes: 6 additions & 3 deletions tools/generator/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,16 +323,19 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve
if (api_versions_xml != null)
ApiVersionsSupport.AssignApiLevels (gens, api_versions_xml);

foreach (GenBase gen in gens)
foreach (var gen in gens)
gen.FixupCovariantReturnTypes ();

foreach (var gen in gens)
gen.FillProperties ();

foreach (var gen in gens)
gen.UpdateEnums (opt);

foreach (GenBase gen in gens)
foreach (var gen in gens)
gen.FixupMethodOverrides ();

foreach (GenBase gen in gens)
foreach (var gen in gens)
gen.FixupExplicitImplementation ();

GenerateAnnotationAttributes (gens, annotations_zips);
Expand Down
20 changes: 20 additions & 0 deletions tools/generator/GenBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,26 @@ public void StripNonBindables ()
n.StripNonBindables ();
}

public void FixupCovariantReturnTypes()
{
//Fix up Java covariant return types, C# return type must match the base return type
foreach (Method m in methods) {
var baseCovariantMethod = BaseGen?.methods.FirstOrDefault (bm => bm.IsCovariantOverride (m));
if (baseCovariantMethod == null) {
baseCovariantMethod = ifaces.OfType<InterfaceGen> ()
.SelectMany (i => i.methods)
.FirstOrDefault (im => im.IsCovariantOverride (m));
}
if (baseCovariantMethod != null && m.ManagedReturn == null) {
m.RetVal.FullName = baseCovariantMethod.ReturnType;
m.RetVal.ToNativeOverride = baseCovariantMethod.RetVal.ToNative;
}
}

foreach (var nt in NestedTypes)
nt.FixupCovariantReturnTypes ();
}

public void FillProperties ()
{
if (property_filled)
Expand Down
19 changes: 17 additions & 2 deletions tools/generator/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ protected Method (GenBase declaringType, IMethodBaseSupport support)

internal void FillReturnType ()
{
retval = new ReturnValue (this, Return, ManagedReturn, IsReturnEnumified);
retval = new ReturnValue (Return, ManagedReturn, IsReturnEnumified);
}

public bool GenerateDispatchingSetter { get; protected set; }
Expand Down Expand Up @@ -456,7 +456,22 @@ string GetDelegateType ()
}
return delegate_type;
}


public bool IsCovariantOverride (Method overriddenMethod)
{
//A method with a covariant return type would have the following to be true:
// 1) Neither is generic
// 2) JavaName is the same
// 3) retval.JavaName is *different*
// 4) Same number of parameters
// 5) JavaSignature for parameters is the same
return !IsGeneric && !overriddenMethod.IsGeneric &&
JavaName == overriddenMethod.JavaName &&
retval.JavaName != overriddenMethod.retval.JavaName &&
Parameters.Count == overriddenMethod.Parameters.Count &&
Parameters.JavaSignature == overriddenMethod.Parameters.JavaSignature;
}

// it used to be private though...
internal string AdjustedName {
get { return IsReturnCharSequence ? Name + "Formatted" : Name; }
Expand Down
20 changes: 13 additions & 7 deletions tools/generator/ReturnValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ public class ReturnValue {
string managed_type;
string raw_type;
bool is_enumified;
Func<CodeGenerationOptions, string, string> to_native;

public ReturnValue (Method owner, string java_type, string managed_type, bool isEnumified)
public ReturnValue (string java_type, string managed_type, bool isEnumified)
{
this.raw_type = this.java_type = java_type;
this.managed_type = managed_type;
Expand All @@ -36,12 +37,8 @@ public string DefaultValue {
}

public string FullName {
get {
if (!String.IsNullOrEmpty (managed_type))
return managed_type;
return sym.FullName;
//return sym is GenBase && !String.IsNullOrEmpty ((sym as GenBase).Marshaler) ? (sym as GenBase).Marshaler : sym.FullName;
}
get { return !String.IsNullOrEmpty (managed_type) ? managed_type : sym.FullName; }
set { managed_type = value; }
}

public void SetGeneratedEnumType (string enumType)
Expand Down Expand Up @@ -89,6 +86,12 @@ public string RawJavaType {
get { return raw_type; }
}

public Func<CodeGenerationOptions, string, string> ToNativeOverride
{
get { return to_native; }
set { to_native = value; }
}

public string FromNative (CodeGenerationOptions opt, string var_name, bool owned)
{
if (!string.IsNullOrEmpty (managed_type) && (sym is ClassGen || sym is InterfaceGen)) {
Expand All @@ -100,6 +103,9 @@ public string FromNative (CodeGenerationOptions opt, string var_name, bool owned

public string ToNative (CodeGenerationOptions opt, string var_name)
{
if (to_native != null)
return to_native (opt, var_name);

return ((sym is GenericTypeParameter) || (sym is GenericSymbol)) ? String.Format ("JNIEnv.ToLocalJniHandle ({0})", var_name) : sym.ToNative (opt, var_name);
}

Expand Down
20 changes: 20 additions & 0 deletions tools/generator/Tests/CovariantReturnTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using NUnit.Framework;

namespace generatortests
{
[TestFixture]
public class CovariantReturnTypes : BaseGeneratorTest
{
[Test]
public void GeneratedOK ()
{
AllowWarnings = true;
RunAllTargets (
outputRelativePath: "CovariantReturnTypes",
apiDescriptionFile: "expected/CovariantReturnTypes/CovariantReturnTypes.xml",
expectedRelativePath: "CovariantReturnTypes");
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using Android.Runtime;
using Java.Interop;

namespace Covariant.Returntypes {

// Metadata.xml XPath class reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantClass']"
[global::Android.Runtime.Register ("covariant/returntypes/CovariantClass", DoNotGenerateAcw=true)]
public partial class CovariantClass : global::Java.Lang.Object {

internal new static readonly JniPeerMembers _members = new JniPeerMembers ("covariant/returntypes/CovariantClass", typeof (CovariantClass));
internal static new IntPtr class_ref {
get {
return _members.JniPeerType.PeerReference.Handle;
}
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return _members.JniPeerType.PeerReference.Handle; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

protected CovariantClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {}

static Delegate cb_someMethod;
#pragma warning disable 0169
static Delegate GetSomeMethodHandler ()
{
if (cb_someMethod == null)
cb_someMethod = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, IntPtr>) n_SomeMethod);
return cb_someMethod;
}

static IntPtr n_SomeMethod (IntPtr jnienv, IntPtr native__this)
{
global::Covariant.Returntypes.CovariantClass __this = global::Java.Lang.Object.GetObject<global::Covariant.Returntypes.CovariantClass> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return JNIEnv.ToLocalJniHandle (__this.SomeMethod ());
}
#pragma warning restore 0169

// Metadata.xml XPath method reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantClass']/method[@name='someMethod' and count(parameter)=0]"
[Register ("someMethod", "()Ljava/lang/Object;", "GetSomeMethodHandler")]
public virtual unsafe global::Java.Lang.Object SomeMethod ()
{
const string __id = "someMethod.()Ljava/lang/Object;";
try {
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null);
return global::Java.Lang.Object.GetObject<global::Java.Lang.Object> (__rm.Handle, JniHandleOwnership.TransferLocalRef);
} finally {
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using Android.Runtime;
using Java.Interop;

namespace Covariant.Returntypes {

// Metadata.xml XPath class reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantInterfaceImplementation']"
[global::Android.Runtime.Register ("covariant/returntypes/CovariantInterfaceImplementation", DoNotGenerateAcw=true)]
public partial class CovariantInterfaceImplementation : global::Java.Lang.Object, global::Covariant.Returntypes.ICovariantInterface {

internal new static readonly JniPeerMembers _members = new JniPeerMembers ("covariant/returntypes/CovariantInterfaceImplementation", typeof (CovariantInterfaceImplementation));
internal static new IntPtr class_ref {
get {
return _members.JniPeerType.PeerReference.Handle;
}
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return _members.JniPeerType.PeerReference.Handle; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

protected CovariantInterfaceImplementation (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {}

// Metadata.xml XPath constructor reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantInterfaceImplementation']/constructor[@name='CovariantInterfaceImplementation' and count(parameter)=0]"
[Register (".ctor", "()V", "")]
public unsafe CovariantInterfaceImplementation ()
: base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
{
const string __id = "()V";

if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
return;

try {
var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null);
SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef);
_members.InstanceMethods.FinishCreateInstance (__id, this, null);
} finally {
}
}

static Delegate cb_someMethod;
#pragma warning disable 0169
static Delegate GetSomeMethodHandler ()
{
if (cb_someMethod == null)
cb_someMethod = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, IntPtr>) n_SomeMethod);
return cb_someMethod;
}

static IntPtr n_SomeMethod (IntPtr jnienv, IntPtr native__this)
{
global::Covariant.Returntypes.CovariantInterfaceImplementation __this = global::Java.Lang.Object.GetObject<global::Covariant.Returntypes.CovariantInterfaceImplementation> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return JNIEnv.ToLocalJniHandle (__this.SomeMethod ());
}
#pragma warning restore 0169

// Metadata.xml XPath method reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantInterfaceImplementation']/method[@name='someMethod' and count(parameter)=0]"
[Register ("someMethod", "()Ljava/lang/String;", "GetSomeMethodHandler")]
public virtual unsafe global::Java.Lang.Object SomeMethod ()
{
const string __id = "someMethod.()Ljava/lang/String;";
try {
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null);
return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef);
} finally {
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using Android.Runtime;
using Java.Interop;

namespace Covariant.Returntypes {

// Metadata.xml XPath class reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantPropertyClass']"
[global::Android.Runtime.Register ("covariant/returntypes/CovariantPropertyClass", DoNotGenerateAcw=true)]
public partial class CovariantPropertyClass : global::Java.Lang.Object {

internal new static readonly JniPeerMembers _members = new JniPeerMembers ("covariant/returntypes/CovariantPropertyClass", typeof (CovariantPropertyClass));
internal static new IntPtr class_ref {
get {
return _members.JniPeerType.PeerReference.Handle;
}
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return _members.JniPeerType.PeerReference.Handle; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

protected CovariantPropertyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {}

static Delegate cb_getObject;
#pragma warning disable 0169
static Delegate GetGetObjectHandler ()
{
if (cb_getObject == null)
cb_getObject = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, IntPtr>) n_GetObject);
return cb_getObject;
}

static IntPtr n_GetObject (IntPtr jnienv, IntPtr native__this)
{
global::Covariant.Returntypes.CovariantPropertyClass __this = global::Java.Lang.Object.GetObject<global::Covariant.Returntypes.CovariantPropertyClass> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return JNIEnv.ToLocalJniHandle (__this.Object);
}
#pragma warning restore 0169

public virtual unsafe global::Java.Lang.Object Object {
// Metadata.xml XPath method reference: path="/api/package[@name='covariant.returntypes']/class[@name='CovariantPropertyClass']/method[@name='getObject' and count(parameter)=0]"
[Register ("getObject", "()Ljava/lang/Object;", "GetGetObjectHandler")]
get {
const string __id = "getObject.()Ljava/lang/Object;";
try {
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, null);
return global::Java.Lang.Object.GetObject<global::Java.Lang.Object> (__rm.Handle, JniHandleOwnership.TransferLocalRef);
} finally {
}
}
}

}
}
Loading