/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using dnSpy.Debugger.DotNet.Metadata.Impl; namespace dnSpy.Debugger.DotNet.Metadata { /// /// Base class of .NET methods /// public abstract class DmdMethodBase : DmdMemberInfo, IDmdSecurityAttributeProvider, IEquatable { /// /// Gets the method kind /// public virtual DmdSpecialMethodKind SpecialMethodKind => DmdSpecialMethodKind.Metadata; /// /// Gets the AppDomain /// public override DmdAppDomain AppDomain => DeclaringType!.AppDomain; /// /// Gets the method impl flags /// public abstract DmdMethodImplAttributes MethodImplementationFlags { get; } /// /// Gets the method attributes /// public abstract DmdMethodAttributes Attributes { get; } /// /// Gets the calling convention flags /// public DmdCallingConventions CallingConvention { get { // See SignatureNative::SetCallingConvention() in coreclr/src/vm/runtimehandles.h var sig = GetMethodSignature(); DmdCallingConventions res = 0; if ((sig.Flags & DmdSignatureCallingConvention.Mask) == DmdSignatureCallingConvention.VarArg) res |= DmdCallingConventions.VarArgs; else res |= DmdCallingConventions.Standard; if (sig.HasThis) res |= DmdCallingConventions.HasThis; if (sig.ExplicitThis) res |= DmdCallingConventions.ExplicitThis; return res; } } /// /// true if it's a generic method definition /// public abstract bool IsGenericMethodDefinition { get; } /// /// true if it's a generic method /// public abstract bool IsGenericMethod { get; } /// /// true if it's a constructed generic method /// public bool IsConstructedGenericMethod => IsGenericMethod && !IsGenericMethodDefinition; /// /// true if it contains generic parameters /// public abstract bool ContainsGenericParameters { get; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public bool IsIL => (MethodImplementationFlags & DmdMethodImplAttributes.CodeTypeMask) == DmdMethodImplAttributes.IL; public bool IsNative => (MethodImplementationFlags & DmdMethodImplAttributes.CodeTypeMask) == DmdMethodImplAttributes.Native; public bool IsOPTIL => (MethodImplementationFlags & DmdMethodImplAttributes.CodeTypeMask) == DmdMethodImplAttributes.OPTIL; public bool IsRuntime => (MethodImplementationFlags & DmdMethodImplAttributes.CodeTypeMask) == DmdMethodImplAttributes.Runtime; public bool IsUnmanaged => (MethodImplementationFlags & DmdMethodImplAttributes.ManagedMask) == DmdMethodImplAttributes.Unmanaged; public bool IsManaged => (MethodImplementationFlags & DmdMethodImplAttributes.ManagedMask) == DmdMethodImplAttributes.Managed; public bool IsForwardRef => (MethodImplementationFlags & DmdMethodImplAttributes.ForwardRef) != 0; public bool IsPreserveSig => (MethodImplementationFlags & DmdMethodImplAttributes.PreserveSig) != 0; public bool IsInternalCall => (MethodImplementationFlags & DmdMethodImplAttributes.InternalCall) != 0; public bool IsSynchronized => (MethodImplementationFlags & DmdMethodImplAttributes.Synchronized) != 0; public bool IsNoInlining => (MethodImplementationFlags & DmdMethodImplAttributes.NoInlining) != 0; public bool IsAggressiveInlining => (MethodImplementationFlags & DmdMethodImplAttributes.AggressiveInlining) != 0; public bool IsNoOptimization => (MethodImplementationFlags & DmdMethodImplAttributes.NoOptimization) != 0; public bool IsAggressiveOptimization => (MethodImplementationFlags & DmdMethodImplAttributes.AggressiveOptimization) != 0; public bool HasSecurityMitigations => (MethodImplementationFlags & DmdMethodImplAttributes.SecurityMitigations) != 0; public bool IsPublic => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.Public; public bool IsPrivate => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.Private; public bool IsFamily => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.Family; public bool IsAssembly => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.Assembly; public bool IsFamilyAndAssembly => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.FamANDAssem; public bool IsFamilyOrAssembly => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.FamORAssem; public bool IsPrivateScope => (Attributes & DmdMethodAttributes.MemberAccessMask) == DmdMethodAttributes.PrivateScope; public bool IsStatic => (Attributes & DmdMethodAttributes.Static) != 0; public bool IsFinal => (Attributes & DmdMethodAttributes.Final) != 0; public bool IsVirtual => (Attributes & DmdMethodAttributes.Virtual) != 0; public bool IsHideBySig => (Attributes & DmdMethodAttributes.HideBySig) != 0; public bool CheckAccessOnOverride => (Attributes & DmdMethodAttributes.CheckAccessOnOverride) != 0; public bool IsAbstract => (Attributes & DmdMethodAttributes.Abstract) != 0; public bool IsSpecialName => (Attributes & DmdMethodAttributes.SpecialName) != 0; public bool IsPinvokeImpl => (Attributes & DmdMethodAttributes.PinvokeImpl) != 0; public bool IsUnmanagedExport => (Attributes & DmdMethodAttributes.UnmanagedExport) != 0; public bool IsRTSpecialName => (Attributes & DmdMethodAttributes.RTSpecialName) != 0; public bool HasSecurity => (Attributes & DmdMethodAttributes.HasSecurity) != 0; public bool RequireSecObject => (Attributes & DmdMethodAttributes.RequireSecObject) != 0; public bool IsReuseSlot => (Attributes & DmdMethodAttributes.VtableLayoutMask) == DmdMethodAttributes.ReuseSlot; public bool IsNewSlot => (Attributes & DmdMethodAttributes.VtableLayoutMask) == DmdMethodAttributes.NewSlot; #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Gets the RVA of the method body or native code or 0 if none /// public abstract uint RVA { get; } /// /// true if this is an instance constructor /// public bool IsConstructor => this is DmdConstructorInfo && !IsStatic; /// /// Resolves a method reference and throws if it doesn't exist /// /// public DmdMethodBase ResolveMethodBase() => ResolveMethodBase(throwOnError: true)!; /// /// Resolves a method reference and returns null if it doesn't exist /// /// public DmdMethodBase? ResolveMethodBaseNoThrow() => ResolveMethodBase(throwOnError: false); /// /// Resolves a method reference /// /// true to throw if it doesn't exist, false to return null if it doesn't exist /// public abstract DmdMethodBase? ResolveMethodBase(bool throwOnError); /// /// Gets all parameters /// /// public abstract ReadOnlyCollection GetParameters(); /// /// Gets all generic arguments if it's a generic method /// /// public abstract ReadOnlyCollection GetGenericArguments(); /// /// Gets the method body /// /// public abstract DmdMethodBody? GetMethodBody(); /// /// Gets the method signature /// /// public abstract DmdMethodSignature GetMethodSignature(); /// /// Gets the method signature /// /// Generic method arguments /// public abstract DmdMethodSignature GetMethodSignature(IList genericMethodArguments); /// /// Gets the method signature /// /// Generic method arguments /// public DmdMethodSignature GetMethodSignature(IList genericMethodArguments) => GetMethodSignature(genericMethodArguments.ToDmdTypeNoNull(AppDomain)); /// /// Gets the security attributes /// /// public abstract override ReadOnlyCollection GetSecurityAttributesData(); /// /// Calls the method /// /// Evaluation context /// Instance or null if it's a static method /// Parameters /// public object? Invoke(object? context, object? obj, object?[] parameters) => Invoke(context, obj, DmdBindingFlags.Default, parameters); /// /// Calls the method /// /// Evaluation context /// Instance or null if it's a static method /// Binding flags /// Parameters /// public abstract object? Invoke(object? context, object? obj, DmdBindingFlags invokeAttr, object?[]? parameters); #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DmdMethodBase? left, DmdMethodBase? right) => DmdMemberInfoEqualityComparer.DefaultMember.Equals(left, right); public static bool operator !=(DmdMethodBase? left, DmdMethodBase? right) => !DmdMemberInfoEqualityComparer.DefaultMember.Equals(left, right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Equals() /// /// /// public bool Equals(DmdMethodBase? other) => DmdMemberInfoEqualityComparer.DefaultMember.Equals(this, other); /// /// Equals() /// /// /// public abstract override bool Equals(object? obj); /// /// GetHashCode() /// /// public abstract override int GetHashCode(); /// /// ToString() /// /// public sealed override string? ToString() => DmdMemberFormatter.Format(this); } /// /// Special methods created by the CLR /// public enum DmdSpecialMethodKind { /// /// It was read from metadata /// Metadata, /// /// SZArray/MDArray Set method: void Set(int, ..., ElementType) /// Array_Set, /// /// SZArray/MDArray Address method: ElementType& Address(int, ...) /// Array_Address, /// /// SZArray/MDArray Get method: ElementType Get(int, ...) /// Array_Get, /// /// SZArray/MDArray constructor that takes args specifying the sizes of all dimensions. /// Lower bound is assumed to be zero. /// Array_Constructor1, /// /// MDArray constructor that takes args in pairs, one per dimension. The first /// is the lower bound for the dimension and the following is /// the size. /// Array_Constructor2, } }