diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.Designer.cs b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.Designer.cs
index 5854f1a7568c..73a673b87d76 100644
--- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.Designer.cs
+++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.Designer.cs
@@ -1352,5 +1352,194 @@ internal static string RBI0047Title {
return ResourceManager.GetString("RBI0047Title", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to A category name cannot be an empty string or have spaces..
+ ///
+ internal static string RBI0048Description {
+ get {
+ return ResourceManager.GetString("RBI0048Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' name '{1}' is empty an empty string or has white spaces.
+ ///
+ internal static string RBI0048MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0048MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category names cannot be a empty string or have white spaces.
+ ///
+ internal static string RBI0048Title {
+ get {
+ return ResourceManager.GetString("RBI0048Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A category type must be a INativeObject..
+ ///
+ internal static string RBI0049Description {
+ get {
+ return ResourceManager.GetString("RBI0049Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' type '{1}' does not implement INativeObject.
+ ///
+ internal static string RBI0049MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0049MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category types must be INativeObjects.
+ ///
+ internal static string RBI0049Title {
+ get {
+ return ResourceManager.GetString("RBI0049Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to DefaultCtorVisibility is ignored in categories..
+ ///
+ internal static string RBI0050Description {
+ get {
+ return ResourceManager.GetString("RBI0050Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' has DefaultCtorVisibility set to '{1}' but it will be ignored.
+ ///
+ internal static string RBI0050MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0050MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to DefaultCtorVisibility is ignored in categories.
+ ///
+ internal static string RBI0050Title {
+ get {
+ return ResourceManager.GetString("RBI0050Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to ErrorDomain is ignored in categories..
+ ///
+ internal static string RBI0051Description {
+ get {
+ return ResourceManager.GetString("RBI0051Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' has ErrorDomain set to '{1}' but it will be ignored.
+ ///
+ internal static string RBI0051MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0051MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to ErrorDomain is ignored in categories.
+ ///
+ internal static string RBI0051Title {
+ get {
+ return ResourceManager.GetString("RBI0051Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to IntPtrCtorVisibility is ignored in categories..
+ ///
+ internal static string RBI0052Description {
+ get {
+ return ResourceManager.GetString("RBI0052Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' has IntPtrCtorVisibility set to '{1}' but it will be ignored.
+ ///
+ internal static string RBI0052MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0052MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to IntPtrCtorVisibility is ignored in categories.
+ ///
+ internal static string RBI0052Title {
+ get {
+ return ResourceManager.GetString("RBI0052Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to ModelName is ignored in categories..
+ ///
+ internal static string RBI0053Description {
+ get {
+ return ResourceManager.GetString("RBI0053Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' has ModelName set to '{1}' but it will be ignored.
+ ///
+ internal static string RBI0053MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0053MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to ModelName is ignored in categories.
+ ///
+ internal static string RBI0053Title {
+ get {
+ return ResourceManager.GetString("RBI0053Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to StringCtorVisibility is ignored in categories..
+ ///
+ internal static string RBI0054Description {
+ get {
+ return ResourceManager.GetString("RBI0054Description", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Category '{0}' has StringCtorVisibility set to '{1}' but it will be ignored.
+ ///
+ internal static string RBI0054MessageFormat {
+ get {
+ return ResourceManager.GetString("RBI0054MessageFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to StringCtorVisibility is ignored in categories.
+ ///
+ internal static string RBI0054Title {
+ get {
+ return ResourceManager.GetString("RBI0054Title", resourceCulture);
+ }
+ }
}
}
diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.resx b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.resx
index 55f3b4c605d1..50c56253458d 100644
--- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.resx
+++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Resources.resx
@@ -638,4 +638,95 @@
Properties are not supported on categories
+
+
+
+ A category name cannot be an empty string or have spaces.
+
+
+ Category '{0}' name '{1}' is empty an empty string or has white spaces
+ {0} is the name of the category, {1} is what we found
+
+
+ Category names cannot be a empty string or have white spaces
+
+
+
+
+
+ A category type must be a INativeObject.
+
+
+ Category '{0}' type '{1}' does not implement INativeObject
+ {0} is the name of the category, {1} is the category type
+
+
+ Category types must be INativeObjects
+
+
+
+
+
+ DefaultCtorVisibility is ignored in categories.
+
+
+ Category '{0}' has DefaultCtorVisibility set to '{1}' but it will be ignored
+ {0} is the name of the category, {1} is the value
+
+
+ DefaultCtorVisibility is ignored in categories
+
+
+
+
+
+ ErrorDomain is ignored in categories.
+
+
+ Category '{0}' has ErrorDomain set to '{1}' but it will be ignored
+ {0} is the name of the category, {1} is the value
+
+
+ ErrorDomain is ignored in categories
+
+
+
+
+
+ IntPtrCtorVisibility is ignored in categories.
+
+
+ Category '{0}' has IntPtrCtorVisibility set to '{1}' but it will be ignored
+ {0} is the name of the category, {1} is the value
+
+
+ IntPtrCtorVisibility is ignored in categories
+
+
+
+
+
+ ModelName is ignored in categories.
+
+
+ Category '{0}' has ModelName set to '{1}' but it will be ignored
+ {0} is the name of the category, {1} is the value
+
+
+ ModelName is ignored in categories
+
+
+
+
+
+ StringCtorVisibility is ignored in categories.
+
+
+ Category '{0}' has StringCtorVisibility set to '{1}' but it will be ignored
+ {0} is the name of the category, {1} is the value
+
+
+ StringCtorVisibility is ignored in categories
+
+
diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/RgenDiagnostics.cs b/src/rgen/Microsoft.Macios.Bindings.Analyzer/RgenDiagnostics.cs
index a8c95d30851f..82b7d455a495 100644
--- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/RgenDiagnostics.cs
+++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/RgenDiagnostics.cs
@@ -721,4 +721,109 @@ public static class RgenDiagnostics {
description: new LocalizableResourceString (nameof (Resources.RBI0047Description), Resources.ResourceManager,
typeof (Resources))
);
+
+ ///
+ /// Diagnostic descriptor for when a category name is incorrect.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0048 = new (
+ "RBI0048",
+ new LocalizableResourceString (nameof (Resources.RBI0048Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0048MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0048Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category type is not a INativeObject.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0049 = new (
+ "RBI0049",
+ new LocalizableResourceString (nameof (Resources.RBI0049Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0049MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0049Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category sets the default constructor visibility.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0050 = new (
+ "RBI0050",
+ new LocalizableResourceString (nameof (Resources.RBI0050Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0050MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0050Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category sets the default constructor visibility.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0051 = new (
+ "RBI0051",
+ new LocalizableResourceString (nameof (Resources.RBI0051Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0051MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0051Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category sets the IntPtr constructor visibility.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0052 = new (
+ "RBI0052",
+ new LocalizableResourceString (nameof (Resources.RBI0052Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0052MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0052Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category sets a model name.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0053 = new (
+ "RBI0053",
+ new LocalizableResourceString (nameof (Resources.RBI0053Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0053MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0053Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
+
+ ///
+ /// Diagnostic descriptor for when a category sets a model name.
+ ///
+ internal static readonly DiagnosticDescriptor RBI0054 = new (
+ "RBI0054",
+ new LocalizableResourceString (nameof (Resources.RBI0054Title), Resources.ResourceManager, typeof (Resources)),
+ new LocalizableResourceString (nameof (Resources.RBI0054MessageFormat), Resources.ResourceManager,
+ typeof (Resources)),
+ "Usage",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: new LocalizableResourceString (nameof (Resources.RBI0054Description), Resources.ResourceManager,
+ typeof (Resources))
+ );
}
diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/CategoryValidator.cs b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/CategoryValidator.cs
index 48499e959a25..dfa66c27289e 100644
--- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/CategoryValidator.cs
+++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Validators/CategoryValidator.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Collections.Immutable;
+using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Context;
@@ -110,6 +111,92 @@ bool ValidMembers (Binding binding, RootContext context,
return diagnostics.Length == 0;
}
+ ///
+ /// Validates the Export attribute data for a category binding, ensuring proper naming conventions,
+ /// type constraints, and constructor visibility settings.
+ ///
+ /// The binding to validate.
+ /// The root context for validation.
+ /// When this method returns, contains diagnostics for any validation failures; otherwise, an empty array.
+ /// The code location to be used for the diagnostics.
+ /// true if the Export attribute data is valid; otherwise, false.
+ bool ValidateExportData (Binding binding, RootContext context, out ImmutableArray diagnostics, Location? location)
+ {
+ var data = (BindingTypeData) binding.BindingInfo;
+ var builder = ImmutableArray.CreateBuilder ();
+
+ // validate the name if specified
+ if (data.Name is not null) {
+ // validate that we do not have any whitespaces in the name
+ if (string.IsNullOrWhiteSpace (data.Name) || data.Name.Contains (' ')) {
+ // the name is not valid
+ builder.Add (Diagnostic.Create (
+ RBI0048, // Category '{0}' name '{1}' is empty an empty string or has white spaces
+ location,
+ binding.Name,
+ data.Name));
+ }
+ }
+ // the category types must be a INativeObject or a NSObject
+ if (!data.CategoryType.IsINativeObject) {
+ // the type is not valid
+ builder.Add (Diagnostic.Create (
+ RBI0049, // Category '{0}' type '{1}' does not implement INativeObject
+ location,
+ binding.Name,
+ data.CategoryType.FullyQualifiedName));
+ }
+ // the default ctor visibility must be the default value, else throw a warning
+ if (data.DefaultCtorVisibility != MethodAttributes.Public) {
+ // warning for the user
+ builder.Add (Diagnostic.Create (
+ RBI0050, // Category '{0}' has DefaultCtorVisibility set to '{1}' but it will be ignored
+ location,
+ binding.Name,
+ data.DefaultCtorVisibility.ToString ()));
+ }
+
+ if (data.ErrorDomain is not null) {
+ // warning for the user
+ builder.Add (Diagnostic.Create (
+ RBI0051, // Category '{0}' has set ErrorDomain to '{1}' but it will be ignored
+ location,
+ binding.Name,
+ data.ErrorDomain));
+ }
+
+ // intptr ctor visibility must be private scope since it will be ignored
+ if (data.IntPtrCtorVisibility != MethodAttributes.PrivateScope) {
+ // warning for the user
+ builder.Add (Diagnostic.Create (
+ RBI0052, // The IntPtr constructor visibility for a category must be PrivateScope.
+ location,
+ binding.Name,
+ data.IntPtrCtorVisibility.ToString ()));
+ }
+
+ if (data.ModelName is not null) {
+ // warning for the user
+ builder.Add (Diagnostic.Create (
+ RBI0053, // Category '{0}' has set ModelName to '{1}' but it will be ignored
+ location,
+ binding.Name,
+ data.ModelName));
+ }
+
+ // string ctor visibility must be private scope since it will be ignored
+ if (data.StringCtorVisibility != MethodAttributes.PrivateScope) {
+ // warning for the user
+ builder.Add (Diagnostic.Create (
+ RBI0054, // Category '{0}' has set StringCtorVisibility to '{1}' but it will be ignored
+ location,
+ binding.Name,
+ data.StringCtorVisibility.ToString ()));
+ }
+
+ diagnostics = builder.ToImmutable ();
+ return diagnostics.Length == 0;
+ }
///
/// Initializes a new instance of the class.
@@ -120,6 +207,10 @@ public CategoryValidator ()
AddGlobalStrategy (RBI0001, IsPartial);
// categories must be static
AddGlobalStrategy (RBI0004, IsStatic);
+ // validate the export attr of the category
+ AddGlobalStrategy (
+ descriptor: [RBI0048, RBI0049, RBI0050, RBI0051, RBI0052, RBI0053, RBI0054],
+ validation: ValidateExportData);
// validate all methods in the category binding
AddGlobalStrategy ([RBI0042, RBI0043, RBI0044], ValidMethods);
// make sure that we do not have constructors, properties, fields or events
diff --git a/src/rgen/Microsoft.Macios.Generator/Attributes/BindingTypeData.cs b/src/rgen/Microsoft.Macios.Generator/Attributes/BindingTypeData.cs
index c24a12c58095..2e0c115bad5c 100644
--- a/src/rgen/Microsoft.Macios.Generator/Attributes/BindingTypeData.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Attributes/BindingTypeData.cs
@@ -127,7 +127,7 @@ public override string ToString ()
///
/// Original name of the ObjC class or protocol.
///
- public string? Name { get; }
+ public string? Name { get; init; }
///
/// The domain of an error enumerator. This has to be used with the SmartEnum flag.
@@ -237,7 +237,6 @@ public static bool TryParse (AttributeData attributeData,
// category related data
TypeInfo categoryType = TypeInfo.Default;
// protocol related data
- string? modelName = null;
// check if we have a category type, we can do that by checking the type of the flag
var isCategory = typeof (T) == typeof (ObjCBindings.Category);
@@ -285,104 +284,102 @@ public static bool TryParse (AttributeData attributeData,
return true;
}
- // the named types are different depending on the type of the flag, if we are dealing with a category or not.
- if (isCategory && TryExtractCategoryNamedParameters (attributeData, out name, ref flags, out categoryType)) {
- data = CreateCategoryBindingData (flags, categoryType);
- return true;
- } else if (isProtocol && TryExtractProtocolNamedParameters (attributeData, out name, ref flags, out modelName)) {
- data = CreateProtocolBindingData (flags, name, modelName);
- return true;
- } else if (TryExtractClassNamedParameters (attributeData, out name, ref flags, out string? errorDomain, out string? libraryName, out MethodAttributes defaultCtorVisibility, out MethodAttributes intPtrCtorVisibility, out MethodAttributes stringCtorVisibility)) {
- data = CreateClassBindingData (flags, name, errorDomain, libraryName, defaultCtorVisibility, intPtrCtorVisibility, stringCtorVisibility);
+ // get all the data from the attribute even when in certain use cases like categories and protocols we do no
+ // need all the data. Later the analyzer/validator will check if the data is correct and will report any issues.
+ if (TryExtractNamedParameters (attributeData, out name, ref flags, out string? modelName, out string? errorDomain, out string? libraryName, out categoryType, out MethodAttributes defaultCtorVisibility, out MethodAttributes intPtrCtorVisibility, out MethodAttributes stringCtorVisibility)) {
+ if (isCategory) {
+ data = flags is not null
+ ? new (categoryType, flags) {
+ Name = name,
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ }
+ : new (categoryType) {
+ Name = name,
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ };
+ } else if (isProtocol) {
+ data = flags is not null ?
+ new (name, flags) {
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ }
+ : new (name) {
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ };
+ } else {
+ data = flags is not null ?
+ new (name, flags) {
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ }
+ : new (name) {
+ ModelName = modelName,
+ ErrorDomain = errorDomain,
+ LibraryPath = libraryName,
+ DefaultCtorVisibility = defaultCtorVisibility,
+ IntPtrCtorVisibility = intPtrCtorVisibility,
+ StringCtorVisibility = stringCtorVisibility,
+ };
+ }
return true;
}
return false;
}
- ///
- /// Creates a new instance of for a class.
- ///
- /// The configuration flags.
- /// The original name of the ObjC class or protocol.
- /// The domain of an error enumerator.
- /// The library name of an error/smart enum.
- /// The visibility of the default constructor.
- /// The visibility of the IntPtr constructor.
- /// The visibility of the string constructor.
- /// A new instance of .
- static BindingTypeData CreateClassBindingData (T? flags, string? name, string? errorDomain,
- string? libraryPath, MethodAttributes defaultCtorVisibility, MethodAttributes intPtrCtorVisibility,
- MethodAttributes stringCtorVisibility)
- {
- return flags is not null
- ? new (name, flags) {
- ErrorDomain = errorDomain,
- LibraryPath = libraryPath,
- DefaultCtorVisibility = defaultCtorVisibility,
- IntPtrCtorVisibility = intPtrCtorVisibility,
- StringCtorVisibility = stringCtorVisibility,
- }
- : new (name) {
- ErrorDomain = errorDomain,
- LibraryPath = libraryPath,
- DefaultCtorVisibility = defaultCtorVisibility,
- IntPtrCtorVisibility = intPtrCtorVisibility,
- StringCtorVisibility = stringCtorVisibility,
- };
- }
-
- ///
- /// Creates a new instance of for a protocol.
- ///
- /// The configuration flags.
- /// The original name of the ObjC protocol.
- /// The name of the model class for the protocol.
- /// A new instance of .
- static BindingTypeData CreateProtocolBindingData (T? flags, string? name, string? modelName)
- {
- return flags is not null
- ? new (name, flags) {
- ModelName = modelName,
- }
- : new (name) {
- ModelName = modelName,
- };
- }
-
- ///
- /// Creates a new instance of for a category.
- ///
- /// The configuration flags.
- /// The type that the category extends.
- /// A new instance of .
- static BindingTypeData CreateCategoryBindingData (T? flags, TypeInfo categoryType)
- {
- return flags is not null
- ? new (categoryType, flags)
- : new (categoryType);
- }
-
///
/// Tries to extract the named parameters for a class from the attribute data.
///
/// The attribute data to be parsed.
/// The original name of the ObjC class or protocol.
/// The configuration flags.
+ /// The name of the model.
/// The domain of an error enumerator.
/// The library name of an error/smart enum.
+ /// The category type that is being extended.
/// The visibility of the default constructor.
/// The visibility of the IntPtr constructor.
/// The visibility of the string constructor.
/// True if the data was parsed.
- static bool TryExtractClassNamedParameters (AttributeData attributeData,
- out string? name, ref T? flags, out string? errorDomain, out string? libraryPath,
- out MethodAttributes defaultCtorVisibility, out MethodAttributes intPtrCtorVisibility,
+ static bool TryExtractNamedParameters (AttributeData attributeData,
+ out string? name,
+ ref T? flags,
+ out string? modelName,
+ out string? errorDomain,
+ out string? libraryPath,
+ out TypeInfo categoryType,
+ out MethodAttributes defaultCtorVisibility,
+ out MethodAttributes intPtrCtorVisibility,
out MethodAttributes stringCtorVisibility)
{
name = null;
+ modelName = null;
errorDomain = null;
libraryPath = null;
+ categoryType = TypeInfo.Default;
defaultCtorVisibility = MethodAttributes.PrivateScope;
intPtrCtorVisibility = MethodAttributes.PrivateScope;
stringCtorVisibility = MethodAttributes.PrivateScope;
@@ -401,6 +398,12 @@ static bool TryExtractClassNamedParameters (AttributeData attributeData,
case "LibraryPath":
libraryPath = (string?) value.Value!;
break;
+ case "ModelName":
+ modelName = (string?) value.Value!;
+ break;
+ case "CategoryType":
+ categoryType = new ((INamedTypeSymbol) value.Value!);
+ break;
case "DefaultCtorVisibility":
defaultCtorVisibility = (MethodAttributes) Convert.ToSingle ((int) value.Value!);
break;
@@ -418,68 +421,6 @@ static bool TryExtractClassNamedParameters (AttributeData attributeData,
return true;
}
- ///
- /// Tries to extract the named parameters for a category from the attribute data.
- ///
- /// The attribute data to be parsed.
- /// The original name of the ObjC class or protocol.
- /// The configuration flags.
- /// The type that the category extends.
- /// True if the data was parsed.
- static bool TryExtractCategoryNamedParameters (AttributeData attributeData, out string? name, ref T? flags, out TypeInfo categoryType)
- {
- name = null;
- categoryType = TypeInfo.Default;
- foreach (var (paramName, value) in attributeData.NamedArguments) {
- switch (paramName) {
- case "Name":
- name = (string?) value.Value!;
- break;
- case "Flags":
- flags = (T) value.Value!;
- break;
- case "CategoryType":
- categoryType = new ((INamedTypeSymbol) value.Value!);
- break;
- default:
- return false;
- }
- }
-
- return true;
- }
-
- ///
- /// Tries to extract the named parameters for a protocol from the attribute data.
- ///
- /// The attribute data to be parsed.
- /// The original name of the ObjC protocol.
- /// The configuration flags.
- /// The name of the model class for the protocol.
- /// True if the data was parsed.
- static bool TryExtractProtocolNamedParameters (AttributeData attributeData, out string? name, ref T? flags, out string? modelName)
- {
- name = null;
- modelName = null;
- foreach (var (paramName, value) in attributeData.NamedArguments) {
- switch (paramName) {
- case "Name":
- name = (string?) value.Value!;
- break;
- case "Flags":
- flags = (T) value.Value!;
- break;
- case "ModelName":
- modelName = (string?) value.Value!;
- break;
- default:
- return false;
- }
- }
-
- return true;
- }
-
///
public bool Equals (BindingTypeData other)
{
diff --git a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/CategoryAnalyzerTests.cs b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/CategoryAnalyzerTests.cs
index fa168375e1c0..32acbe5c0d91 100644
--- a/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/CategoryAnalyzerTests.cs
+++ b/tests/rgen/Microsoft.Macios.Bindings.Analyzer.Tests/CategoryAnalyzerTests.cs
@@ -244,6 +244,237 @@ public partial class TestClass{
DiagnosticSeverity.Error,
"Category 'TestClass' has properties (found 1), but properties are not supported on categories"
];
+
+ // wrong name, is empty spaces
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), Name = "" "")]
+public partial static class TestClass{
+}",
+ "RBI0048",
+ DiagnosticSeverity.Error,
+ "Category 'TestClass' name ' ' is empty an empty string or has white spaces"
+ ];
+
+ // wrong name, contains spaces
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), Name = ""Category Name "")]
+public partial static class TestClass{
+}",
+ "RBI0048",
+ DiagnosticSeverity.Error,
+ "Category 'TestClass' name 'Category Name ' is empty an empty string or has white spaces"
+ ];
+
+ // not INativeObject
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+public class MyClass {}
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (MyClass))]
+public partial static class TestClass{
+}",
+ "RBI0049",
+ DiagnosticSeverity.Error,
+ "Category 'TestClass' type 'TestNamespace.MyClass' does not implement INativeObject"
+ ];
+
+ // DefaultCtorVisibility is ignored
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Reflection;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), DefaultCtorVisibility = MethodAttributes.PrivateScope)]
+public partial static class TestClass{
+}",
+ "RBI0050",
+ DiagnosticSeverity.Warning,
+ "Category 'TestClass' has DefaultCtorVisibility set to 'PrivateScope' but it will be ignored"
+ ];
+
+ // IntPtrCtorVisibility is ignored
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Reflection;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), IntPtrCtorVisibility = MethodAttributes.Public)]
+public partial static class TestClass{
+}",
+ "RBI0052",
+ DiagnosticSeverity.Warning,
+ "Category 'TestClass' has IntPtrCtorVisibility set to 'Public' but it will be ignored"
+ ];
+
+ // StringCtorVisibility is ignored
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Reflection;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), StringCtorVisibility = MethodAttributes.Public)]
+public partial static class TestClass{
+}",
+ "RBI0054",
+ DiagnosticSeverity.Warning,
+ "Category 'TestClass' has StringCtorVisibility set to 'Public' but it will be ignored"
+ ];
+
+ // ErrorDomain is ignored
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Reflection;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), ErrorDomain = ""MyErrorDomain"")]
+public partial static class TestClass{
+}",
+ "RBI0051",
+ DiagnosticSeverity.Warning,
+ "Category 'TestClass' has ErrorDomain set to 'MyErrorDomain' but it will be ignored"
+ ];
+
+ // ModelName is ignored
+ yield return [
+ @"
+#pragma warning disable APL0003
+
+using System;
+using System.Reflection;
+using System.Runtime.Versioning;
+using AVFoundation;
+using CoreGraphics;
+using Foundation;
+using ObjCBindings;
+using ObjCRuntime;
+using nfloat = System.Runtime.InteropServices.NFloat;
+
+namespace TestNamespace;
+
+[SupportedOSPlatform (""macos"")]
+[SupportedOSPlatform (""ios"")]
+[SupportedOSPlatform (""tvos"")]
+[SupportedOSPlatform (""maccatalyst13.1"")]
+[BindingType (typeof (NSObject), ModelName = ""MyModelName"")]
+public partial static class TestClass{
+}",
+ "RBI0053",
+ DiagnosticSeverity.Warning,
+ "Category 'TestClass' has ModelName set to 'MyModelName' but it will be ignored"
+ ];
}
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();