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