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
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
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.

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>

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 as it does in Xamarin.iOS or Xamarin.Mac. However, this is unsupported and the value of `SkipRegistration` will be ignored.

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 @@ -52,6 +52,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