1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.Generic; 6 using Xunit; 7 8 namespace System.Reflection.Emit.Tests 9 { 10 public class TypeBuilderDefineMethodTests 11 { TestData()12 public static IEnumerable<object[]> TestData() 13 { 14 yield return new object[] { "Name", MethodAttributes.Abstract, CallingConventions.Standard, null, null }; 15 yield return new object[] { "Name", MethodAttributes.Assembly, CallingConventions.Standard, null, null }; 16 yield return new object[] { "Name", MethodAttributes.CheckAccessOnOverride, CallingConventions.Standard, null, null }; 17 yield return new object[] { "Name", MethodAttributes.FamANDAssem, CallingConventions.Standard, null, null }; 18 yield return new object[] { "Name", MethodAttributes.Family, CallingConventions.Standard, null, null }; 19 yield return new object[] { "Name", MethodAttributes.FamORAssem, CallingConventions.Standard, null, null }; 20 yield return new object[] { "Name", MethodAttributes.Final, CallingConventions.Standard, null, null }; 21 yield return new object[] { "Name", MethodAttributes.HasSecurity, CallingConventions.Standard, null, null }; 22 yield return new object[] { "Name", MethodAttributes.HideBySig, CallingConventions.Standard, null, null }; 23 yield return new object[] { "Name", MethodAttributes.MemberAccessMask, CallingConventions.Standard, null, null }; 24 yield return new object[] { "Name", MethodAttributes.NewSlot, CallingConventions.Standard, null, null }; 25 yield return new object[] { "Name", MethodAttributes.PinvokeImpl, CallingConventions.Standard, null, null }; 26 yield return new object[] { "Name", MethodAttributes.Private, CallingConventions.Standard, null, null }; 27 yield return new object[] { "Name", MethodAttributes.PrivateScope, CallingConventions.Standard, null, null }; 28 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.Standard, null, null }; 29 yield return new object[] { "Name", MethodAttributes.RequireSecObject, CallingConventions.Standard, null, null }; 30 yield return new object[] { "Name", MethodAttributes.ReuseSlot, CallingConventions.Standard, null, null }; 31 yield return new object[] { "Name", MethodAttributes.RTSpecialName, CallingConventions.Standard, null, null }; 32 yield return new object[] { "Name", MethodAttributes.SpecialName, CallingConventions.Standard, null, null }; 33 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.Standard, null, null }; 34 yield return new object[] { "Name", MethodAttributes.UnmanagedExport, CallingConventions.Standard, null, null }; 35 yield return new object[] { "Name", MethodAttributes.Virtual, CallingConventions.Standard, null, null }; 36 yield return new object[] { "Name", MethodAttributes.VtableLayoutMask, CallingConventions.Standard, null, null }; 37 yield return new object[] { "Name", MethodAttributes.Abstract | MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual, CallingConventions.Standard, null, null }; 38 yield return new object[] { "Name", MethodAttributes.Final | MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.Static, CallingConventions.Standard, null, null }; 39 40 // Static 41 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.Any, null, null }; 42 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.ExplicitThis, null, null }; 43 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.HasThis, null, null }; 44 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.Standard, null, null }; 45 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.VarArgs, null, null }; 46 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.Any | CallingConventions.Standard, null, null }; 47 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.Any | CallingConventions.VarArgs, null, null }; 48 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.HasThis | CallingConventions.Standard, null, null }; 49 yield return new object[] { "Name", MethodAttributes.Static, CallingConventions.HasThis | CallingConventions.ExplicitThis, null, null }; 50 yield return new object[] { "Name", MethodAttributes.Static, (CallingConventions)(-1), null, null }; 51 52 // Instance 53 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.Any, null, null }; 54 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.ExplicitThis, null, null }; 55 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.HasThis, null, null }; 56 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.Standard, null, null }; 57 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.VarArgs, null, null }; 58 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.Any | CallingConventions.Standard, null, null }; 59 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.Any | CallingConventions.VarArgs, null, null }; 60 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.HasThis | CallingConventions.Standard, null, null }; 61 yield return new object[] { "Name", MethodAttributes.Public, CallingConventions.HasThis | CallingConventions.ExplicitThis, null, null }; 62 yield return new object[] { "Name", MethodAttributes.Public, (CallingConventions)(-1), null, null }; 63 } 64 65 [Theory] 66 [MemberData(nameof(TestData))] DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)67 public void DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes) 68 { 69 bool defaultReturnTypeAndParameters = returnType == null && parameterTypes == null; 70 if (callingConvention == CallingConventions.Standard) 71 { 72 if (defaultReturnTypeAndParameters) 73 { 74 // Use DefineMethod(string, MethodAttributes) 75 TypeBuilder type1 = Helpers.DynamicType(TypeAttributes.Public); 76 MethodBuilder method1 = type1.DefineMethod(name, attributes); 77 VerifyMethod(type1, method1, name, attributes, callingConvention, returnType, parameterTypes); 78 } 79 // Use DefineMethod(string, MethodAttributes, Type, Type[]) 80 TypeBuilder type2 = Helpers.DynamicType(TypeAttributes.Public); 81 MethodBuilder method2 = type2.DefineMethod(name, attributes, returnType, parameterTypes); 82 VerifyMethod(type2, method2, name, attributes, callingConvention, returnType, parameterTypes); 83 } 84 if (defaultReturnTypeAndParameters) 85 { 86 // Use DefineMethod(string, MethodAttributes, CallingConventions) 87 TypeBuilder type3 = Helpers.DynamicType(TypeAttributes.Public); 88 MethodBuilder method3 = type3.DefineMethod(name, attributes, callingConvention); 89 VerifyMethod(type3, method3, name, attributes, callingConvention, returnType, parameterTypes); 90 } 91 // Use DefineMethod(string, MethodAttributes, CallingConventions, Type, Type[]) 92 TypeBuilder type4 = Helpers.DynamicType(TypeAttributes.Public); 93 MethodBuilder method4 = type4.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes); 94 VerifyMethod(type4, method4, name, attributes, callingConvention, returnType, parameterTypes); 95 } 96 97 [Fact] DefineMethod_MultipleOverloads_Works()98 public void DefineMethod_MultipleOverloads_Works() 99 { 100 const string Name = "Name"; 101 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); 102 MethodBuilder method1 = type.DefineMethod(Name, MethodAttributes.Public); 103 Assert.Equal(Name, method1.Name); 104 105 MethodBuilder method2 = type.DefineMethod(Name, MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(int) }); 106 Assert.Equal(Name, method2.Name); 107 } 108 VerifyMethod(TypeBuilder type, MethodBuilder method, string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)109 private static void VerifyMethod(TypeBuilder type, MethodBuilder method, string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes) 110 { 111 CallingConventions expectedCallingConvention = callingConvention; 112 if ((attributes & MethodAttributes.Static) == 0) 113 { 114 expectedCallingConvention |= CallingConventions.HasThis; 115 } 116 117 Assert.Equal(type.AsType(), method.DeclaringType); 118 Assert.Equal(name, method.Name); 119 Assert.Equal(attributes, method.Attributes); 120 Assert.Equal(expectedCallingConvention, method.CallingConvention); 121 Assert.Equal(returnType, method.ReturnType); 122 } 123 } 124 } 125