Skip to content
This repository has been archived by the owner on Oct 25, 2021. It is now read-only.

NameGenerator now honors the RegisterAttribute #482

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
47 changes: 47 additions & 0 deletions docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,53 @@ Selectors on the [NSObjectProtocol](https://developer.apple.com/reference/object

Note: The list of reserved selectors will evolve with new versions of the tool.

<h3><a name="EM1060"/>Invalid `RegisterAttribute` found on class `T`. Expected the first constructor parameter to be of type `string` but found type `U` instead.</h3>

This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: use proper casing Objective-C instead of all lowercase (there are also more cases below).


When either one or two arguments are passed into the constructor, the first must be of type `System.String` but in this case, some other type was provided instead. For this to happen, the `RegisterAttribute` did not come from Xamarin.iOS or Xamarin.Mac.

If an argument was not also passed for named parameter "Name" then the class will be named according to the default convention.

<h3><a name="EM1061"/>Invalid `RegisterAttribute` found on class `T`. Expected a constructor with either 1 or 2 parameters but found {argsCount} instead..</h3>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: two periods at the end of the sentence.


This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.

Either one or two arguments are passed into the constructor, the first must be of type `System.String`. In this case, {argsCount} were found instead. For this to happen, the `RegisterAttribute` did not come from Xamarin.iOS or Xamarin.Mac.

If an argument was not also passed for named parameter "Name" then the class will be named according to the default convention.

<h3><a name="EM1062"/>Invalid `RegisterAttribute` found on class `T`. Conflicting values specified for `Name`, using value of named parameter: '{propVal}' instead of constructor parameter: '{name}'.</h3>

This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.

However, two conflicting values were given for 'Name': one as a positional argument, the other as a named parameter. For example, consider: `[Register("myFoo", Name = "foo")]`.

The value of the named parameter, 'foo' will be used instead of value provided to the positional parameter: 'myFoo'. If that is not the value intended, remove the named argument.

<h3><a name="EM1063"/>Invalid `RegisterAttribute` found on class `T`. Named parameter `SkipRegistration` is not supported and will be ignored.</h3>

This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.

Users already familiar with the `RegisterAttribute` might expect `SkipRegistration` to function is it does in Xamarin.iOS or Xamarin.Android. However, this is unsupported and the value of `SkipRegistration` will be ignored.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure SkipRegistration is applicable to Xamarin.Android (I don't know anything about XA). Did you mean Xamarin.Mac instead of Xamarin.Android?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I did, thanks for catching that. My fingers seem to have their own L4 cache…


This warning is informational only. If a custom class name was also passed either via positional argument or a named argument, then the value provided will still be used.

<h3><a name="EM1064"/>Invalid `RegisterAttribute` found on class `T`. Named parameter {propName} is not supported and will be ignored.</h3>

This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.

The `RegisterAttribute` decorating class `T` included named parameters which were unexpected and unsupported. For this to happen, the `RegisterAttribute` did not come from Xamarin.iOS or Xamarin.Mac.

This warning is informational only. If a custom class name was also passed either via positional argument or a named argument, then the provided value will still be used.

<h3><a name="EM1065"/>Invalid `RegisterAttribute` found on class `T`. No name argument for was provided to the constructor via positional or named parameters. Will use the default class naming convention instead.</h3>

This is a **warning** that the class `T` was decorated with a `RegisterAttribute`, indicating the author wishes to rename the name of generated objective-c class.

However, no value was actually provided to the attribute. This can happen when an attribute is provided without any arguments (`[Register]`).

The class will be named as if it had not been decorated with `RegisterAttribute` to begin with.

<!-- 2xxx: code generation -->

Expand Down
65 changes: 65 additions & 0 deletions objcgen/NameGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,71 @@ public static class NameGenerator {

public static string GetObjCName (Type t)
{
if (t.IsClass) {
string name = null;
var delayed = new List<Exception> ();

var attrib = t.GetCustomAttributesData ().SingleOrDefault (a => a.AttributeType.Name.Equals ("RegisterAttribute"));
if (attrib != null) {
var argsCount = attrib.ConstructorArguments.Count;
switch (argsCount) {
// case 0 is considered invalid for use here, so handle it the same as the default case.
case 1:
case 2: {
// Since we aren't enforcing RegisterAttribute come from
// a Xamarin-provided assembly, check to ensure the RA we
// found conforms to our expectations.
var arg = attrib.ConstructorArguments [0].ArgumentType;
if (Type.GetTypeCode (arg) == TypeCode.String) {
name = (string)attrib.ConstructorArguments [0].Value;
} else {
delayed.Add (ErrorHelper.CreateWarning (1060, $"Invalid RegisterAttribute found on class '{t.FullName}'. Expected the first constructor parameter to be of type `string` but found type `{arg.FullName}` instead."));
}
break;
}
default:
delayed.Add (ErrorHelper.CreateWarning (1061, $"Invalid RegisterAttribute found on class '{t.FullName}'. Expected a constructor with either 1 or 2 parameters but found {argsCount} instead."));
break;
}
// Handle cases where some used named properties.
// If they mixed both positional and named params,
// then assume the more specific one (the named)
// parameter is correct, and issue a warning.
if (attrib.NamedArguments.Any (a => !a.IsField)) {
foreach (var prop in attrib.NamedArguments) {
var propName = prop.MemberName;
switch (propName) {
case "IsWrapper":
continue; // Intentionally ignore.
case "Name":
if (string.IsNullOrWhiteSpace (name)) {
name = (string)prop.TypedValue.Value;
} else {
var propVal = (string)prop.TypedValue.Value;
if (!name.Equals (propVal)) {
delayed.Add (ErrorHelper.CreateWarning (1062, $"Invalid RegisterAttribute found on class '{t.FullName}'. Conflicting values specified for 'Name', using value of named parameter: '{propVal}' instead of constructor parameter: '{name}'."));
}
name = propVal;
}
break;
case "SkipRegistration":
delayed.Add (ErrorHelper.CreateWarning (1063, $"Invalid RegisterAttribute found on class '{t.FullName}'. SkipRegistration is not supported, and will be ignored."));
break;
default:
delayed.Add (ErrorHelper.CreateWarning (1064, $"Invalid RegisterAttribute found on class '{t.FullName}'. Named parameter {propName} is not supported and will be ignored."));
break;
}
}
}
if (!string.IsNullOrWhiteSpace (name)) {
ErrorHelper.Show (delayed);
return name;
}
// Fall back to the default strategy.
delayed.Add (ErrorHelper.CreateWarning (1065, $"Invalid RegisterAttribute found on class '{t.FullName}'. No name argument for was provided to the constructor via either position or named parameter. Will use the default class naming convention instead."));
ErrorHelper.Show (delayed);
}
}
return t.FullName.Replace ('.', '_').Replace ("+", "_");
}

Expand Down