Skip to content

Commit

Permalink
[generator] Use + for nested types, not /
Browse files Browse the repository at this point in the history
Context: dotnet/android#9747
Context: https://discord.com/channels/732297728826277939/732297837953679412/1336353039031734352
Context: https://discord.com/channels/732297728826277939/732297837953679412/1336358257769316372

The `[Register]` attribute provides "connector method" names, and for
interface methods this will also include the name of the type which
declares the method, which itself may be in a nested type:

	namespace Android.App {
	  public partial class Application {
	    public partial interface IActivityLifecycleCallbacks : IJavaObject, IJavaPeerable {
	      [Register (
	          name: "onActivityCreated",
	          signature: "(Landroid/app/Activity;Landroid/os/Bundle;)V",
	          connector: "GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler:Android.App.Application/IActivityLifecycleCallbacksInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
	      void OnActivityCreated (Android.App.Activity activity, Android.OS.Bundle? savedInstanceState);

	      // …
	    }
	  }
	}

This output has been largely unchanged for *years*, but there is a
problem with it: the `connector` parameter contains a nested type,
and uses `/` to separate the "outer" type from the "inner" type.

This works on MonoVM.

This *fails* on NativeAOT and CoreCLR:

	Could not resolve type 'Android.App.Application/IActivityLifecycleCallbacksInvoker' in assembly 'Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065'.

The `/` needs to be a `+` in order for `Type.GetType()` to find it:

	[Register (
	    name: "onActivityCreated",
	    signature: "(Landroid/app/Activity;Landroid/os/Bundle;)V",
	    connector: "GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler:Android.App.Application+IActivityLifecycleCallbacksInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
	void OnActivityCreated (Android.App.Activity activity, Android.OS.Bundle? savedInstanceState);

Update `generator` so that `+` is used within the `connector`
parameter.

However, to maintain compatibility with existing binding assemblies,
update `Java.Interop.Tools.JavaCallableWrappers` so that it replaces
`/` with `+` on import, so that the resulting Java Callable Wrappers
contain `+` and not `/`:

	// Java Callable Wrapper
	/* partial */ class MauiApplication_ActivityLifecycleCallbacks
	{
	  public static final String __md_methods;
	  static {
	    __md_methods =
	      // …
	      "n_onActivityCreated:(Landroid/app/Activity;Landroid/os/Bundle;)V:GetOnActivityCreated_Landroid_app_Activity_Landroid_os_Bundle_Handler:Android.App.Application+IActivityLifecycleCallbacksInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n" +
	      // …
	      "";
	    mono.android.Runtime.register ("Microsoft.Maui.MauiApplication+ActivityLifecycleCallbacks, Microsoft.Maui", MauiApplication_ActivityLifecycleCallbacks.class, __md_methods);
	  }
	}
  • Loading branch information
jonpryor committed Feb 4, 2025
1 parent dd3c1d0 commit 06b9c48
Show file tree
Hide file tree
Showing 9 changed files with 12 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ static CallableWrapperMethod CreateMethod (MethodDefinition methodDefinition, Ca
static CallableWrapperMethod CreateMethod (string name, CallableWrapperType declaringType, string? signature, string? connector, string? managedParameters, string? outerType, string? superCall)
{
signature = signature ?? throw new ArgumentNullException ("`connector` cannot be null.", nameof (connector));
var method_name = "n_" + name + ":" + signature + ":" + connector;
var method_name = "n_" + name + ":" + signature + ":" + connector?.Replace ('/', '+');

var method = new CallableWrapperMethod (declaringType, name, method_name, signature);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ static string ToCliTypePart (string part)
for (int i = 0; i < parts.Length; ++i) {
parts [i] = ToPascalCase (parts [i], 1);
}
return string.Join ("/", parts);
return string.Join ("+", parts);
}

static string ToPascalCase (string value, int minLength)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ public partial interface IParent : IJavaObject, IJavaPeerable {
}

// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']"
[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParent/IChildInvoker")]
[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParent+IChildInvoker")]
public partial interface IChild : IJavaObject, IJavaPeerable {
int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent/IChildInvoker, MyAssembly")]
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent+IChildInvoker, MyAssembly")]
get;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public partial interface IParent : IJavaObject, IJavaPeerable {
public partial interface IChild : IJavaObject, IJavaPeerable {
int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent/IChildInvoker, MyAssembly")]
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent+IChildInvoker, MyAssembly")]
get;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ public void GenerateProperNestedInterfaceSignatures ()

var generated = writer.ToString ();

Assert.True (generated.Contains ("GetOnActivityDestroyed_IHandler:Com.Xamarin.Android.Application/IActivityLifecycleInterface, MyAssembly"));
Assert.True (generated.Contains ("GetOnActivityDestroyed_IHandler:Com.Xamarin.Android.Application+IActivityLifecycleInterface, MyAssembly"));
Assert.False (generated.Contains ("GetOnActivityDestroyed_IHandler:Com.Xamarin.Android.Application.IActivityLifecycleInterface, MyAssembly"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public partial class PublicClass : global::Java.Lang.Object {
[Register ("xamarin/test/PublicClass$ProtectedInterface", "", "Xamarin.Test.PublicClass/IProtectedInterfaceInvoker")]
protected internal partial interface IProtectedInterface : IJavaObject, IJavaPeerable {
// Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='PublicClass.ProtectedInterface']/method[@name='foo' and count(parameter)=0]"
[Register ("foo", "()V", "GetFooHandler:Xamarin.Test.PublicClass/IProtectedInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
[Register ("foo", "()V", "GetFooHandler:Xamarin.Test.PublicClass+IProtectedInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
void Foo ();

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public partial class View : global::Java.Lang.Object {
[Register ("android/view/View$OnClickListener", "", "Android.Views.View/IOnClickListenerInvoker")]
public partial interface IOnClickListener : IJavaObject, IJavaPeerable {
// Metadata.xml XPath method reference: path="/api/package[@name='android.view']/interface[@name='View.OnClickListener']/method[@name='onClick' and count(parameter)=1 and parameter[1][@type='android.view.View']]"
[Register ("onClick", "(Landroid/view/View;)V", "GetOnClick_Landroid_view_View_Handler:Android.Views.View/IOnClickListenerInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
[Register ("onClick", "(Landroid/view/View;)V", "GetOnClick_Landroid_view_View_Handler:Android.Views.View+IOnClickListenerInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
void OnClick (global::Android.Views.View v);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public abstract partial class Action : global::Java.Lang.Object {
[Register ("xamarin/test/NotificationCompatBase$Action$Factory", "", "Xamarin.Test.NotificationCompatBase/Action/IFactoryInvoker")]
public partial interface IFactory : IJavaObject, IJavaPeerable {
// Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']/method[@name='build' and count(parameter)=1 and parameter[1][@type='int']]"
[Register ("build", "(I)Lxamarin/test/NotificationCompatBase$Action;", "GetBuild_IHandler:Xamarin.Test.NotificationCompatBase/Action/IFactoryInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
[Register ("build", "(I)Lxamarin/test/NotificationCompatBase$Action;", "GetBuild_IHandler:Xamarin.Test.NotificationCompatBase+Action+IFactoryInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
global::Xamarin.Test.NotificationCompatBase.Action Build (int p0);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ IEnumerable<GenBase> Ancestors ()
public string AnnotatedVisibility => support.AnnotatedVisibility;

// not: not currently assembly qualified, but it uses needed
// Type.GetType() conventions such as '/' for nested types.
// Type.GetType() conventions such as '+' for nested types.
public string AssemblyQualifiedName => string.IsNullOrWhiteSpace (Namespace)
? $"{FullName.Replace ('.', '/')}"
: $"{Namespace}." + $"{FullName.Substring (Namespace.Length + 1).Replace ('.', '/')}";
? $"{FullName.Replace ('.', '+')}"
: $"{Namespace}." + $"{FullName.Substring (Namespace.Length + 1).Replace ('.', '+')}";

public int ApiAvailableSince { get; set; }

Expand Down

0 comments on commit 06b9c48

Please sign in to comment.