|
// 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;
}
}
}
}
|