< Summary

Information
Class: DotNetApiDiff.ApiExtraction.MemberSignatureBuilder
Assembly: DotNetApiDiff
File(s): /home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/ApiExtraction/MemberSignatureBuilder.cs
Line coverage
43%
Covered lines: 244
Uncovered lines: 318
Coverable lines: 562
Total lines: 880
Line coverage: 43.4%
Branch coverage
38%
Covered branches: 127
Total branches: 326
Branch coverage: 38.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
BuildMethodSignature(...)82.14%362878.68%
BuildPropertySignature(...)60%1604057.81%
BuildFieldSignature(...)87.5%9875.86%
BuildEventSignature(...)45.45%782251.21%
BuildConstructorSignature(...)40.9%582257.89%
BuildTypeSignature(...)0%4692680%
BuildParameterSignature(...)31.25%921633.33%
GetTypeName(...)46.87%5766450%
GetGenericParameterName(...)43.75%711640%
GetAccessibilityString(...)60%171057.89%
GetAccessibilityString(...)10%501026.31%
GetTypeAccessibilityString(...)0%210140%
GetMostAccessible(...)50%6693.33%

File(s)

/home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/ApiExtraction/MemberSignatureBuilder.cs

#LineLine coverage
 1// Copyright DotNet API Diff Project Contributors - SPDX Identifier: MIT
 2using System.Reflection;
 3using System.Text;
 4using DotNetApiDiff.Interfaces;
 5using Microsoft.Extensions.Logging;
 6
 7namespace DotNetApiDiff.ApiExtraction;
 8
 9/// <summary>
 10/// Builds normalized signatures for API members to enable consistent comparison
 11/// </summary>
 12public class MemberSignatureBuilder : IMemberSignatureBuilder
 13{
 14    private readonly ILogger<MemberSignatureBuilder> _logger;
 15
 16    /// <summary>
 17    /// Creates a new instance of the MemberSignatureBuilder
 18    /// </summary>
 19    /// <param name="logger">Logger for diagnostic information</param>
 3020    public MemberSignatureBuilder(ILogger<MemberSignatureBuilder> logger)
 3021    {
 3022        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 2923    }
 24
 25    /// <summary>
 26    /// Builds a normalized signature for a method
 27    /// </summary>
 28    /// <param name="method">Method to build signature for</param>
 29    /// <returns>Normalized method signature</returns>
 30    public string BuildMethodSignature(MethodInfo method)
 731    {
 732        if (method == null)
 133        {
 134            throw new ArgumentNullException(nameof(method));
 35        }
 36
 37        try
 638        {
 639            var signature = new StringBuilder();
 40
 41            // Add accessibility
 642            signature.Append(GetAccessibilityString(method));
 643            signature.Append(' ');
 44
 45            // Add static/virtual/abstract modifiers
 646            if (method.IsStatic)
 147            {
 148                signature.Append("static ");
 149            }
 550            else if (method.IsVirtual && !method.IsFinal)
 151            {
 152                if (method.IsAbstract)
 053                {
 054                    signature.Append("abstract ");
 055                }
 156                else if (method.DeclaringType?.IsInterface == false)
 157                {
 158                    signature.Append("virtual ");
 159                }
 160            }
 461            else if (method.IsFinal && method.IsVirtual)
 062            {
 063                signature.Append("sealed override ");
 064            }
 65
 66            // Add return type
 667            signature.Append(GetTypeName(method.ReturnType));
 668            signature.Append(' ');
 69
 70            // Add method name
 671            signature.Append(method.Name);
 72
 73            // Add generic type parameters if any
 674            if (method.IsGenericMethod)
 175            {
 176                signature.Append('<');
 177                var genericArgs = method.GetGenericArguments();
 478                for (int i = 0; i < genericArgs.Length; i++)
 179                {
 180                    if (i > 0)
 081                    {
 082                        signature.Append(", ");
 083                    }
 84
 185                    signature.Append(GetGenericParameterName(genericArgs[i]));
 186                }
 87
 188                signature.Append('>');
 189            }
 90
 91            // Add parameters
 692            signature.Append('(');
 693            var parameters = method.GetParameters();
 1894            for (int i = 0; i < parameters.Length; i++)
 395            {
 396                if (i > 0)
 197                {
 198                    signature.Append(", ");
 199                }
 100
 3101                signature.Append(BuildParameterSignature(parameters[i]));
 3102            }
 103
 6104            signature.Append(')');
 105
 6106            return signature.ToString();
 107        }
 0108        catch (Exception ex)
 0109        {
 0110            _logger.LogError(ex, "Error building signature for method {MethodName}", method.Name);
 0111            return $"Error: {method.Name}";
 112        }
 6113    }
 114
 115    /// <summary>
 116    /// Builds a normalized signature for a property
 117    /// </summary>
 118    /// <param name="property">Property to build signature for</param>
 119    /// <returns>Normalized property signature</returns>
 120    public string BuildPropertySignature(PropertyInfo property)
 3121    {
 3122        if (property == null)
 1123        {
 1124            throw new ArgumentNullException(nameof(property));
 125        }
 126
 127        try
 2128        {
 2129            var signature = new StringBuilder();
 130
 131            // Get the most accessible accessor between getter and setter
 2132            var getMethod = property.GetMethod;
 2133            var setMethod = property.SetMethod;
 134
 135            // Add accessibility
 2136            if (getMethod != null && setMethod != null)
 1137            {
 138                // Use the most accessible between get and set
 1139                var getAccess = GetAccessibilityString(getMethod);
 1140                var setAccess = GetAccessibilityString(setMethod);
 1141                signature.Append(GetMostAccessible(getAccess, setAccess));
 1142            }
 1143            else if (getMethod != null)
 1144            {
 1145                signature.Append(GetAccessibilityString(getMethod));
 1146            }
 0147            else if (setMethod != null)
 0148            {
 0149                signature.Append(GetAccessibilityString(setMethod));
 0150            }
 151            else
 0152            {
 0153                signature.Append("private");
 0154            }
 155
 2156            signature.Append(' ');
 157
 158            // Add static modifier if applicable
 2159            if ((getMethod != null && getMethod.IsStatic) || (setMethod != null && setMethod.IsStatic))
 0160            {
 0161                signature.Append("static ");
 0162            }
 163
 164            // Add virtual/abstract modifiers
 2165            if (getMethod != null && getMethod.IsVirtual && !getMethod.IsFinal)
 0166            {
 0167                if (getMethod.IsAbstract)
 0168                {
 0169                    signature.Append("abstract ");
 0170                }
 0171                else if (property.DeclaringType?.IsInterface == false)
 0172                {
 0173                    signature.Append("virtual ");
 0174                }
 0175            }
 2176            else if (getMethod != null && getMethod.IsFinal && getMethod.IsVirtual)
 0177            {
 0178                signature.Append("sealed override ");
 0179            }
 180
 181            // Add property type
 2182            signature.Append(GetTypeName(property.PropertyType));
 2183            signature.Append(' ');
 184
 185            // Add property name
 2186            signature.Append(property.Name);
 187
 188            // Add accessors
 2189            signature.Append(" { ");
 2190            if (getMethod != null)
 2191            {
 2192                signature.Append("get; ");
 2193            }
 194
 2195            if (setMethod != null)
 1196            {
 1197                signature.Append("set; ");
 1198            }
 199
 2200            signature.Append('}');
 201
 2202            return signature.ToString();
 203        }
 0204        catch (Exception ex)
 0205        {
 0206            _logger.LogError(ex, "Error building signature for property {PropertyName}", property.Name);
 0207            return $"Error: {property.Name}";
 208        }
 2209    }
 210
 211    /// <summary>
 212    /// Builds a normalized signature for a field
 213    /// </summary>
 214    /// <param name="field">Field to build signature for</param>
 215    /// <returns>Normalized field signature</returns>
 216    public string BuildFieldSignature(FieldInfo field)
 4217    {
 4218        if (field == null)
 1219        {
 1220            throw new ArgumentNullException(nameof(field));
 221        }
 222
 223        try
 3224        {
 3225            var signature = new StringBuilder();
 226
 227            // Add accessibility
 3228            signature.Append(GetAccessibilityString(field));
 3229            signature.Append(' ');
 230
 231            // Add static/readonly/const modifiers
 3232            if (field.IsStatic)
 1233            {
 1234                signature.Append("static ");
 1235            }
 236
 3237            if (field.IsInitOnly)
 1238            {
 1239                signature.Append("readonly ");
 1240            }
 241
 3242            if (field.IsLiteral)
 0243            {
 0244                signature.Append("const ");
 0245            }
 246
 247            // Add field type
 3248            signature.Append(GetTypeName(field.FieldType));
 3249            signature.Append(' ');
 250
 251            // Add field name
 3252            signature.Append(field.Name);
 253
 3254            return signature.ToString();
 255        }
 0256        catch (Exception ex)
 0257        {
 0258            _logger.LogError(ex, "Error building signature for field {FieldName}", field.Name);
 0259            return $"Error: {field.Name}";
 260        }
 3261    }
 262
 263    /// <summary>
 264    /// Builds a normalized signature for an event
 265    /// </summary>
 266    /// <param name="eventInfo">Event to build signature for</param>
 267    /// <returns>Normalized event signature</returns>
 268    public string BuildEventSignature(EventInfo eventInfo)
 2269    {
 2270        if (eventInfo == null)
 1271        {
 1272            throw new ArgumentNullException(nameof(eventInfo));
 273        }
 274
 275        try
 1276        {
 1277            var signature = new StringBuilder();
 278
 279            // Get the add method to determine accessibility
 1280            var addMethod = eventInfo.AddMethod;
 281
 282            // Add accessibility
 1283            if (addMethod != null)
 1284            {
 1285                signature.Append(GetAccessibilityString(addMethod));
 1286                signature.Append(' ');
 287
 288                // Add static modifier if applicable
 1289                if (addMethod.IsStatic)
 0290                {
 0291                    signature.Append("static ");
 0292                }
 293
 294                // Add virtual/abstract modifiers
 1295                if (addMethod.IsVirtual && !addMethod.IsFinal)
 0296                {
 0297                    if (addMethod.IsAbstract)
 0298                    {
 0299                        signature.Append("abstract ");
 0300                    }
 0301                    else if (eventInfo.DeclaringType?.IsInterface == false)
 0302                    {
 0303                        signature.Append("virtual ");
 0304                    }
 0305                }
 1306                else if (addMethod.IsFinal && addMethod.IsVirtual)
 0307                {
 0308                    signature.Append("sealed override ");
 0309                }
 1310            }
 311
 312            // Add event keyword and event handler type
 1313            signature.Append("event ");
 1314            signature.Append(GetTypeName(eventInfo.EventHandlerType ?? typeof(object)));
 1315            signature.Append(' ');
 316
 317            // Add event name
 1318            signature.Append(eventInfo.Name);
 319
 1320            return signature.ToString();
 321        }
 0322        catch (Exception ex)
 0323        {
 0324            _logger.LogError(ex, "Error building signature for event {EventName}", eventInfo.Name);
 0325            return $"Error: {eventInfo.Name}";
 326        }
 1327    }
 328
 329    /// <summary>
 330    /// Builds a normalized signature for a constructor
 331    /// </summary>
 332    /// <param name="constructor">Constructor to build signature for</param>
 333    /// <returns>Normalized constructor signature</returns>
 334    public string BuildConstructorSignature(ConstructorInfo constructor)
 3335    {
 3336        if (constructor == null)
 1337        {
 1338            throw new ArgumentNullException(nameof(constructor));
 339        }
 340
 341        try
 2342        {
 2343            var signature = new StringBuilder();
 344
 345            // Add accessibility
 2346            signature.Append(GetAccessibilityString(constructor));
 2347            signature.Append(' ');
 348
 349            // Add static modifier for static constructors
 2350            if (constructor.IsStatic)
 0351            {
 0352                signature.Append("static ");
 0353            }
 354
 355            // Add constructor name (use declaring type name)
 2356            var typeName = constructor.DeclaringType?.Name ?? "Unknown";
 2357            if (typeName.Contains('`'))
 0358            {
 0359                typeName = typeName.Substring(0, typeName.IndexOf('`'));
 0360            }
 361
 2362            signature.Append(typeName);
 363
 364            // Add parameters
 2365            signature.Append('(');
 2366            var parameters = constructor.GetParameters();
 6367            for (int i = 0; i < parameters.Length; i++)
 1368            {
 1369                if (i > 0)
 0370                {
 0371                    signature.Append(", ");
 0372                }
 373
 1374                signature.Append(BuildParameterSignature(parameters[i]));
 1375            }
 376
 2377            signature.Append(')');
 378
 2379            return signature.ToString();
 380        }
 0381        catch (Exception ex)
 0382        {
 0383            _logger.LogError(
 0384                ex,
 0385                "Error building signature for constructor in type {TypeName}",
 0386                constructor.DeclaringType?.Name ?? "Unknown");
 0387            return $"Error: Constructor in {constructor.DeclaringType?.Name ?? "Unknown"}";
 388        }
 2389    }
 390
 391    /// <summary>
 392    /// Builds a normalized signature for a type
 393    /// </summary>
 394    /// <param name="type">Type to build signature for</param>
 395    /// <returns>Normalized type signature</returns>
 396    public string BuildTypeSignature(Type type)
 0397    {
 0398        if (type == null)
 0399        {
 0400            throw new ArgumentNullException(nameof(type));
 401        }
 402
 403        try
 0404        {
 0405            var signature = new StringBuilder();
 406
 407            // Add accessibility
 0408            signature.Append(GetTypeAccessibilityString(type));
 0409            signature.Append(' ');
 410
 411            // Add sealed/abstract modifiers
 0412            if (type.IsSealed && !type.IsValueType && !type.IsEnum)
 0413            {
 0414                if (type.IsAbstract)
 0415                {
 0416                    signature.Append("static ");
 0417                }
 418                else
 0419                {
 0420                    signature.Append("sealed ");
 0421                }
 0422            }
 0423            else if (type.IsAbstract && !type.IsInterface)
 0424            {
 0425                signature.Append("abstract ");
 0426            }
 427
 428            // Add type kind (class, struct, interface, enum, delegate)
 0429            if (type.IsInterface)
 0430            {
 0431                signature.Append("interface ");
 0432            }
 0433            else if (type.IsEnum)
 0434            {
 0435                signature.Append("enum ");
 0436            }
 0437            else if (type.IsValueType)
 0438            {
 0439                signature.Append("struct ");
 0440            }
 0441            else if (type.IsSubclassOf(typeof(MulticastDelegate)))
 0442            {
 0443                signature.Append("delegate ");
 0444            }
 445            else
 0446            {
 0447                signature.Append("class ");
 0448            }
 449
 450            // Add type name
 0451            signature.Append(type.Name);
 452
 453            // Add generic parameters if any
 0454            if (type.IsGenericType && !type.IsGenericTypeDefinition)
 0455            {
 456                // For constructed generic types, include the type arguments
 0457                var genericArgs = type.GetGenericArguments();
 0458                signature.Append('<');
 0459                for (int i = 0; i < genericArgs.Length; i++)
 0460                {
 0461                    if (i > 0)
 0462                    {
 0463                        signature.Append(", ");
 0464                    }
 465
 0466                    signature.Append(GetTypeName(genericArgs[i]));
 0467                }
 468
 0469                signature.Append('>');
 0470            }
 0471            else if (type.IsGenericTypeDefinition)
 0472            {
 473                // For generic type definitions, include the type parameter names
 0474                var genericArgs = type.GetGenericArguments();
 0475                signature.Append('<');
 0476                for (int i = 0; i < genericArgs.Length; i++)
 0477                {
 0478                    if (i > 0)
 0479                    {
 0480                        signature.Append(", ");
 0481                    }
 482
 0483                    signature.Append(GetGenericParameterName(genericArgs[i]));
 0484                }
 485
 0486                signature.Append('>');
 0487            }
 488
 489            // Add base type if not Object or ValueType
 0490            if (type.BaseType != null && type.BaseType != typeof(object) && type.BaseType != typeof(ValueType) &&
 0491                type.BaseType != typeof(Enum))
 0492            {
 0493                signature.Append(" : ");
 0494                signature.Append(GetTypeName(type.BaseType));
 0495            }
 496
 497            // Add implemented interfaces
 0498            var interfaces = type.GetInterfaces();
 0499            if (interfaces.Length > 0 && !type.IsInterface)
 0500            {
 0501                if (type.BaseType == null || type.BaseType == typeof(object) || type.BaseType == typeof(ValueType) ||
 0502                    type.BaseType == typeof(Enum))
 0503                {
 0504                    signature.Append(" : ");
 0505                }
 506                else
 0507                {
 0508                    signature.Append(", ");
 0509                }
 510
 0511                for (int i = 0; i < interfaces.Length; i++)
 0512                {
 0513                    if (i > 0)
 0514                    {
 0515                        signature.Append(", ");
 0516                    }
 517
 0518                    signature.Append(GetTypeName(interfaces[i]));
 0519                }
 0520            }
 0521            else if (type.IsInterface && interfaces.Length > 0)
 0522            {
 523                // For interfaces, show base interfaces
 0524                signature.Append(" : ");
 0525                for (int i = 0; i < interfaces.Length; i++)
 0526                {
 0527                    if (i > 0)
 0528                    {
 0529                        signature.Append(", ");
 0530                    }
 531
 0532                    signature.Append(GetTypeName(interfaces[i]));
 0533                }
 0534            }
 535
 0536            return signature.ToString();
 537        }
 0538        catch (Exception ex)
 0539        {
 0540            _logger.LogError(ex, "Error building signature for type {TypeName}", type.Name);
 0541            return $"Error: {type.Name}";
 542        }
 0543    }
 544
 545    /// <summary>
 546    /// Builds a signature for a method parameter
 547    /// </summary>
 548    /// <param name="parameter">Parameter to build signature for</param>
 549    /// <returns>Parameter signature</returns>
 550    private string BuildParameterSignature(ParameterInfo parameter)
 4551    {
 4552        var signature = new StringBuilder();
 553
 554        // Add parameter modifiers
 4555        if (parameter.IsOut)
 0556        {
 0557            signature.Append("out ");
 0558        }
 4559        else if (parameter.ParameterType.IsByRef)
 0560        {
 0561            signature.Append("ref ");
 0562        }
 4563        else if (parameter.IsDefined(typeof(ParamArrayAttribute), false))
 0564        {
 0565            signature.Append("params ");
 0566        }
 567
 568        // Add parameter type
 4569        var paramType = parameter.ParameterType;
 4570        if (paramType.IsByRef)
 0571        {
 0572            paramType = paramType.GetElementType() ?? paramType;
 0573        }
 574
 4575        signature.Append(GetTypeName(paramType));
 576
 577        // Add parameter name
 4578        signature.Append(' ');
 4579        signature.Append(parameter.Name);
 580
 581        // Add default value if parameter is optional
 4582        if (parameter.HasDefaultValue)
 0583        {
 0584            signature.Append(" = ");
 0585            if (parameter.DefaultValue == null)
 0586            {
 0587                signature.Append("null");
 0588            }
 0589            else if (parameter.DefaultValue is string stringValue)
 0590            {
 0591                signature.Append($"\"{stringValue}\"");
 0592            }
 593            else
 0594            {
 0595                signature.Append(parameter.DefaultValue);
 0596            }
 0597        }
 598
 4599        return signature.ToString();
 4600    }
 601
 602    /// <summary>
 603    /// Gets a string representation of a type name
 604    /// </summary>
 605    /// <param name="type">Type to get name for</param>
 606    /// <returns>Type name</returns>
 607    private string GetTypeName(Type type)
 16608    {
 16609        if (type == null)
 0610        {
 0611            return "void";
 612        }
 613
 614        // Special type handling based on type characteristics
 16615        switch (true)
 616        {
 16617            case object _ when type == typeof(void):
 5618                return "void";
 619
 11620            case object _ when type.IsByRef:
 0621                return GetTypeName(type.GetElementType() ?? type);
 622
 11623            case object _ when type.IsArray:
 0624                var elementType = type.GetElementType() ?? type;
 0625                var rank = type.GetArrayRank();
 0626                if (rank == 1)
 0627                {
 0628                    return $"{GetTypeName(elementType)}[]";
 629                }
 630                else
 0631                {
 0632                    var commas = new string(',', rank - 1);
 0633                    return $"{GetTypeName(elementType)}[{commas}]";
 634                }
 635
 11636            case object _ when type.IsPointer:
 0637                return $"{GetTypeName(type.GetElementType() ?? type)}*";
 638
 11639            case object _ when type.IsGenericParameter:
 2640                return type.Name;
 641
 9642            case object _ when type.IsGenericType:
 0643                var genericTypeDef = type.GetGenericTypeDefinition();
 0644                var genericArgs = type.GetGenericArguments();
 0645                var typeName = genericTypeDef.Name;
 646
 647                // Remove the `n suffix from generic type names
 0648                if (typeName.Contains('`'))
 0649                {
 0650                    typeName = typeName.Substring(0, typeName.IndexOf('`'));
 0651                }
 652
 653                // Handle common generic collections
 0654                if (genericTypeDef == typeof(Nullable<>))
 0655                {
 0656                    return $"{GetTypeName(genericArgs[0])}?";
 657                }
 658
 659                // For other generic types, use the standard format
 0660                var sb = new StringBuilder();
 0661                sb.Append(typeName);
 0662                sb.Append('<');
 663
 0664                for (int i = 0; i < genericArgs.Length; i++)
 0665                {
 0666                    if (i > 0)
 0667                    {
 0668                        sb.Append(", ");
 0669                    }
 670
 0671                    sb.Append(GetTypeName(genericArgs[i]));
 0672                }
 673
 0674                sb.Append('>');
 0675                return sb.ToString();
 676        }
 677
 678        // Handle primitive types with C# keywords using a direct switch on type
 9679        var primitiveTypeName = type switch
 9680        {
 9681            Type t when t == typeof(bool) => "bool",
 9682            Type t when t == typeof(byte) => "byte",
 9683            Type t when t == typeof(sbyte) => "sbyte",
 9684            Type t when t == typeof(char) => "char",
 9685            Type t when t == typeof(decimal) => "decimal",
 9686            Type t when t == typeof(double) => "double",
 9687            Type t when t == typeof(float) => "float",
 10688            Type t when t == typeof(int) => "int",
 8689            Type t when t == typeof(uint) => "uint",
 8690            Type t when t == typeof(long) => "long",
 8691            Type t when t == typeof(ulong) => "ulong",
 8692            Type t when t == typeof(short) => "short",
 8693            Type t when t == typeof(ushort) => "ushort",
 15694            Type t when t == typeof(string) => "string",
 1695            Type t when t == typeof(object) => "object",
 1696            _ => null // Not a primitive type
 9697        };
 698
 9699        if (primitiveTypeName != null)
 8700        {
 8701            return primitiveTypeName;
 702        }
 703
 704        // For regular types, return the type name directly
 1705        return type.Name;
 16706    }
 707
 708    /// <summary>
 709    /// Gets the name of a generic parameter
 710    /// </summary>
 711    /// <param name="type">Generic parameter type</param>
 712    /// <returns>Generic parameter name</returns>
 713    private string GetGenericParameterName(Type type)
 1714    {
 1715        if (!type.IsGenericParameter)
 0716        {
 0717            return GetTypeName(type);
 718        }
 719
 1720        var constraints = new List<string>();
 721
 722        // Add class/struct constraint
 1723        if (type.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
 0724        {
 0725            constraints.Add("class");
 0726        }
 1727        else if (type.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
 0728        {
 0729            constraints.Add("struct");
 0730        }
 731
 732        // Add new() constraint
 1733        if (type.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint) &&
 1734            !type.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
 0735        {
 0736            constraints.Add("new()");
 0737        }
 738
 739        // Add interface and base class constraints
 3740        foreach (var constraint in type.GetGenericParameterConstraints())
 0741        {
 0742            if (constraint != typeof(object))
 0743            {
 0744                constraints.Add(GetTypeName(constraint));
 0745            }
 0746        }
 747
 1748        if (constraints.Count == 0)
 1749        {
 1750            return type.Name;
 751        }
 752
 0753        return $"{type.Name} : {string.Join(", ", constraints)}";
 1754    }
 755
 756    /// <summary>
 757    /// Gets a string representation of a member's accessibility
 758    /// </summary>
 759    /// <param name="methodBase">Method or constructor to get accessibility for</param>
 760    /// <returns>Accessibility string</returns>
 761    private string GetAccessibilityString(MethodBase methodBase)
 12762    {
 12763        if (methodBase.IsPublic)
 11764        {
 11765            return "public";
 766        }
 1767        else if (methodBase.IsFamily)
 0768        {
 0769            return "protected";
 770        }
 1771        else if (methodBase.IsFamilyOrAssembly)
 0772        {
 0773            return "protected internal";
 774        }
 1775        else if (methodBase.IsFamilyAndAssembly)
 0776        {
 0777            return "private protected";
 778        }
 1779        else if (methodBase.IsAssembly)
 0780        {
 0781            return "internal";
 782        }
 783        else
 1784        {
 1785            return "private";
 786        }
 12787    }
 788
 789    /// <summary>
 790    /// Gets a string representation of a field's accessibility
 791    /// </summary>
 792    /// <param name="field">Field to get accessibility for</param>
 793    /// <returns>Accessibility string</returns>
 794    private string GetAccessibilityString(FieldInfo field)
 3795    {
 3796        if (field.IsPublic)
 3797        {
 3798            return "public";
 799        }
 0800        else if (field.IsFamily)
 0801        {
 0802            return "protected";
 803        }
 0804        else if (field.IsFamilyOrAssembly)
 0805        {
 0806            return "protected internal";
 807        }
 0808        else if (field.IsFamilyAndAssembly)
 0809        {
 0810            return "private protected";
 811        }
 0812        else if (field.IsAssembly)
 0813        {
 0814            return "internal";
 815        }
 816        else
 0817        {
 0818            return "private";
 819        }
 3820    }
 821
 822    /// <summary>
 823    /// Gets a string representation of a type's accessibility
 824    /// </summary>
 825    /// <param name="type">Type to get accessibility for</param>
 826    /// <returns>Accessibility string</returns>
 827    private string GetTypeAccessibilityString(Type type)
 0828    {
 0829        if (type.IsNestedPublic || type.IsPublic)
 0830        {
 0831            return "public";
 832        }
 0833        else if (type.IsNestedFamily)
 0834        {
 0835            return "protected";
 836        }
 0837        else if (type.IsNestedFamORAssem)
 0838        {
 0839            return "protected internal";
 840        }
 0841        else if (type.IsNestedFamANDAssem)
 0842        {
 0843            return "private protected";
 844        }
 0845        else if (type.IsNestedAssembly || type.IsNotPublic)
 0846        {
 0847            return "internal";
 848        }
 849        else
 0850        {
 0851            return "private";
 852        }
 0853    }
 854
 855    /// <summary>
 856    /// Gets the most accessible of two accessibility strings
 857    /// </summary>
 858    /// <param name="access1">First accessibility string</param>
 859    /// <param name="access2">Second accessibility string</param>
 860    /// <returns>Most accessible string</returns>
 861    private string GetMostAccessible(string access1, string access2)
 1862    {
 1863        var accessRank = new Dictionary<string, int>
 1864        {
 1865            { "public", 5 },
 1866            { "protected internal", 4 },
 1867            { "internal", 3 },
 1868            { "protected", 2 },
 1869            { "private protected", 1 },
 1870            { "private", 0 }
 1871        };
 872
 1873        if (accessRank.TryGetValue(access1, out int rank1) && accessRank.TryGetValue(access2, out int rank2))
 1874        {
 1875            return rank1 >= rank2 ? access1 : access2;
 876        }
 877
 0878        return access1; // Default to first if not found
 1879    }
 880}