| File: Linker\MethodReferenceExtensions.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using ILLink.Shared.TypeSystemProxy; using Mono.Cecil; namespace Mono.Linker { public static class MethodReferenceExtensions { public static string GetDisplayName(this MethodReference method) { var sb = new System.Text.StringBuilder(); // Match C# syntaxis name if setter or getter #pragma warning disable RS0030 // Cecil's Resolve is banned -- this should be a very cold path and makes calling this method much simpler var methodDefinition = method.Resolve(); #pragma warning restore RS0030 if (methodDefinition != null && (methodDefinition.IsSetter || methodDefinition.IsGetter)) { // Append property name string name = methodDefinition.IsSetter ? string.Concat(methodDefinition.Name.AsSpan(4), ".set") : string.Concat(methodDefinition.Name.AsSpan(4), ".get"); sb.Append(name); // Insert declaring type name and namespace sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); return sb.ToString(); } if (methodDefinition != null && methodDefinition.IsEventMethod()) { // Append event name string name = methodDefinition.SemanticsAttributes switch { MethodSemanticsAttributes.AddOn => string.Concat(methodDefinition.Name.AsSpan(4), ".add"), MethodSemanticsAttributes.RemoveOn => string.Concat(methodDefinition.Name.AsSpan(7), ".remove"), MethodSemanticsAttributes.Fire => string.Concat(methodDefinition.Name.AsSpan(6), ".raise"), _ => throw new NotSupportedException(), }; sb.Append(name); // Insert declaring type name and namespace sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); return sb.ToString(); } // Append parameters sb.Append('('); if (method.HasMetadataParameters()) { #pragma warning disable RS0030 // MethodReference.Parameters is banned -- it's best to leave this as is for now for (int i = 0; i < method.Parameters.Count - 1; i++) sb.Append(method.Parameters[i].ParameterType.GetDisplayNameWithoutNamespace()).Append(", "); sb.Append(method.Parameters[method.Parameters.Count - 1].ParameterType.GetDisplayNameWithoutNamespace()); #pragma warning restore RS0030 // Do not used banned APIs } sb.Append(')'); // Insert generic parameters if (method.HasGenericParameters) { TypeReferenceExtensions.PrependGenericParameters(method.GenericParameters, sb); } // Insert method name if (method.Name == ".ctor") sb.Insert(0, method.DeclaringType.Name); else sb.Insert(0, method.Name); // Insert declaring type name and namespace if (method.DeclaringType != null) sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); return sb.ToString(); } public static TypeReference GetReturnType(this MethodReference method) { if (method.DeclaringType is GenericInstanceType genericInstance) return TypeReferenceExtensions.InflateGenericType(genericInstance, method.ReturnType); return method.ReturnType; } public static bool ReturnsVoid(this IMethodSignature method) { return method.ReturnType.WithoutModifiers().MetadataType == MetadataType.Void; } public static TypeReference GetInflatedParameterType(this MethodReference method, int parameterIndex) { #pragma warning disable RS0030 // MethodReference.Parameters is banned -- it's best to leave this as is for now IGenericInstance? genericInstance = method as IGenericInstance ?? method.DeclaringType as IGenericInstance; if (genericInstance is null) return method.Parameters[parameterIndex].ParameterType; return TypeReferenceExtensions.InflateGenericType(genericInstance, method.Parameters[parameterIndex].ParameterType); #pragma warning restore RS0030 // Do not used banned APIs } /// <summary> /// Gets the number of entries in the 'Parameters' section of a method's metadata (i.e. excludes the implicit 'this' from the count) /// </summary> #pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper public static int GetMetadataParametersCount(this MethodReference method) => method.Parameters.Count; #pragma warning restore RS0030 // Do not used banned APIs /// <summary> /// Returns true if the method has any parameters in the .parameters section of the method's metadata (i.e. excludes the impicit 'this') /// </summary> public static bool HasMetadataParameters(this MethodReference method) => method.GetMetadataParametersCount() != 0; /// <summary> /// Returns the number of the parameters pushed before the method's call (i.e. including the implicit 'this' if present) /// </summary> #pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper public static int GetParametersCount(this MethodReference method) => method.Parameters.Count + (method.HasImplicitThis() ? 1 : 0); #pragma warning restore RS0030 // Do not used banned APIs public static bool IsDeclaredOnType(this MethodReference method, string fullTypeName) { return method.DeclaringType.IsTypeOf(fullTypeName); } public static bool HasImplicitThis(this MethodReference method) { return method.HasThis && !method.ExplicitThis; } /// <summary> /// Returns an IEnumerable of the ReferenceKind of each parameter, with the first being for the implicit 'this' parameter if it exists /// Used for better performance when it's only necessary to get the ReferenceKind of all parameters and nothing else. /// </summary> public static IEnumerable<ReferenceKind> GetParameterReferenceKinds(this MethodReference method) { if (method.HasImplicitThis()) yield return method.DeclaringType.IsValueType ? ReferenceKind.Ref : ReferenceKind.None; #pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper foreach (var parameter in method.Parameters) yield return GetReferenceKind(parameter); #pragma warning restore RS0030 // Do not used banned APIs static ReferenceKind GetReferenceKind(ParameterDefinition param) { if (!param.ParameterType.IsByReference) return ReferenceKind.None; if (param.IsIn) return ReferenceKind.In; if (param.IsOut) return ReferenceKind.Out; return ReferenceKind.Ref; } } } }