Merge branch 'master' of http://github.com/mono/mono
[mono.git] / mcs / class / corlib / Test / System.Reflection.Emit / MethodBuilderTest.cs
1 //
2 // MethodBuilderTest.cs - NUnit Test Cases for the MethodBuilder class
3 //
4 // Zoltan Varga (vargaz@freemail.hu)
5 //
6 // (C) Ximian, Inc.  http://www.ximian.com
7
8 // TODO:
9 //  - implement 'Signature' (what the hell it does???) and test it
10 //  - implement Equals and test it
11
12 using System;
13 using System.Threading;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.CompilerServices;
17 using System.Security;
18 using System.Security.Permissions;
19 using System.Runtime.InteropServices;
20
21 using NUnit.Framework;
22
23 namespace MonoTests.System.Reflection.Emit
24 {
25         [TestFixture]
26         public class MethodBuilderTest
27         {
28                 private TypeBuilder genClass;
29                 private ModuleBuilder module;
30
31                 [SetUp]
32                 protected void SetUp ()
33                 {
34                         AssemblyName assemblyName = new AssemblyName ();
35                         assemblyName.Name = "MonoTests.System.Reflection.Emit.MethodBuilderTest";
36
37                         AssemblyBuilder assembly = Thread.GetDomain ().DefineDynamicAssembly (
38                                 assemblyName, AssemblyBuilderAccess.Run);
39                         module = assembly.DefineDynamicModule ("module1");
40                         genClass = module.DefineType (genTypeName (), TypeAttributes.Public);
41                 }
42
43                 static int methodIndexer = 0;
44                 static int typeIndexer = 0;
45
46                 // Return a unique method name
47                 private string genMethodName ()
48                 {
49                         return "m" + (methodIndexer++);
50                 }
51
52                 // Return a unique type name
53                 private string genTypeName ()
54                 {
55                         return "class" + (typeIndexer++);
56                 }
57
58                 [Test]
59                 public void TestAttributes ()
60                 {
61                         MethodBuilder mb = genClass.DefineMethod (
62                                 genMethodName (), MethodAttributes.Public, typeof (void), new Type [0]);
63                         Assert.AreEqual (MethodAttributes.Public, mb.Attributes);
64                 }
65
66                 [Test]
67                 public void TestCallingConvention ()
68                 {
69                         MethodBuilder mb = genClass.DefineMethod (
70                                 genMethodName (), 0, typeof (void), new Type [0]);
71                         Assert.AreEqual (CallingConventions.Standard | CallingConventions.HasThis,
72                                 mb.CallingConvention, "CallingConvetion defaults to Standard+HasThis");
73
74                         MethodBuilder mb3 = genClass.DefineMethod (
75                                 genMethodName (), 0, CallingConventions.VarArgs, typeof (void), new Type [0]);
76                         Assert.AreEqual (CallingConventions.VarArgs | CallingConventions.HasThis,
77                                 mb3.CallingConvention, "CallingConvetion works");
78
79                         MethodBuilder mb4 = genClass.DefineMethod (
80                                 genMethodName (), MethodAttributes.Static, CallingConventions.Standard,
81                                 typeof (void), new Type [0]);
82                         Assert.AreEqual (CallingConventions.Standard, mb4.CallingConvention,
83                                 "Static implies !HasThis");
84                 }
85
86                 [Test]
87                 public void TestDeclaringType ()
88                 {
89                         MethodBuilder mb = genClass.DefineMethod (
90                                 genMethodName (), 0, typeof (void), new Type [0]);
91
92                         Assert.AreEqual (genClass, mb.DeclaringType, "DeclaringType works");
93                 }
94
95                 [Test]
96                 public void TestInitLocals ()
97                 {
98                         MethodBuilder mb = genClass.DefineMethod (
99                                 genMethodName (), 0, typeof (void), new Type [0]);
100
101                         Assert.IsTrue (mb.InitLocals, "#1");
102                         mb.InitLocals = false;
103                         Assert.IsFalse (mb.InitLocals, "#2");
104                 }
105
106                 [Test]
107                 [ExpectedException (typeof (NotSupportedException))]
108                 public void TestMethodHandleIncomplete ()
109                 {
110                         MethodBuilder mb = genClass.DefineMethod (
111                                 genMethodName (), 0, typeof (void), new Type [0]);
112
113                         RuntimeMethodHandle handle = mb.MethodHandle;
114                 }
115
116                 [Test]
117                 [ExpectedException (typeof (NotSupportedException))]
118                 public void TestMethodHandleComplete ()
119                 {
120                         MethodBuilder mb = genClass.DefineMethod (
121                                 genMethodName (), 0, typeof (void), new Type [0]);
122                         mb.CreateMethodBody (new byte [2], 1);
123                         genClass.CreateType ();
124
125                         RuntimeMethodHandle handle = mb.MethodHandle;
126                 }
127
128                 [Test]
129                 public void TestName ()
130                 {
131                         string name = genMethodName ();
132                         MethodBuilder mb = genClass.DefineMethod (
133                                 name, 0, typeof (void), new Type [0]);
134
135                         Assert.AreEqual (name, mb.Name);
136                 }
137
138                 [Test]
139                 public void TestReflectedType ()
140                 {
141                         MethodBuilder mb = genClass.DefineMethod (
142                                 genMethodName (), 0, typeof (void), new Type [0]);
143
144                         Assert.AreEqual (genClass, mb.ReflectedType);
145                 }
146
147                 [Test]
148                 public void TestReturnType ()
149                 {
150                         MethodBuilder mb = genClass.DefineMethod (
151                                 genMethodName (), 0, typeof (Console), new Type [0]);
152                         Assert.AreEqual (typeof (Console), mb.ReturnType, "#1");
153
154                         MethodBuilder mb2 = genClass.DefineMethod (
155                                 genMethodName (), 0, null, new Type [0]);
156                         Assert.IsTrue (mb2.ReturnType == null || mb2.ReturnType == typeof (void), "#2");
157                 }
158
159                 [Test]
160                 public void TestReturnTypeCustomAttributes ()
161                 {
162                         MethodBuilder mb = genClass.DefineMethod (
163                                 genMethodName (), 0, typeof (Console), new Type [0]);
164                         Assert.IsNull (mb.ReturnTypeCustomAttributes);
165                 }
166
167                 /*
168                 public void TestSignature () {
169                         MethodBuilder mb = genClass.DefineMethod (
170                                 "m91", 0, typeof (Console), new Type [1] { typeof (Console) });
171
172                         Console.WriteLine (mb.Signature);
173                 }
174                 */
175
176                 [Test]
177                 public void TestCreateMethodBody ()
178                 {
179                         MethodBuilder mb = genClass.DefineMethod (
180                                 genMethodName (), 0, typeof (void), new Type [0]);
181
182                         // Clear body
183                         mb.CreateMethodBody (null, 999);
184
185                         // Check arguments 1.
186                         try {
187                                 mb.CreateMethodBody (new byte [1], -1);
188                                 Assert.Fail ("#1");
189                         } catch (ArgumentOutOfRangeException) {
190                         }
191
192                         // Check arguments 2.
193                         try {
194                                 mb.CreateMethodBody (new byte [1], 2);
195                                 Assert.Fail ("#2");
196                         } catch (ArgumentOutOfRangeException) {
197                         }
198
199                         mb.CreateMethodBody (new byte [2], 1);
200
201                         // Could only be called once
202                         try {
203                                 mb.CreateMethodBody (new byte [2], 1);
204                                 Assert.Fail ("#3");
205                         } catch (InvalidOperationException) {
206                         }
207
208                         // Can not be called on a created type
209                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
210                         MethodBuilder mb2 = tb.DefineMethod (
211                                 genMethodName (), 0, typeof (void), new Type [0]);
212                         ILGenerator ilgen = mb2.GetILGenerator ();
213                         ilgen.Emit (OpCodes.Ret);
214                         tb.CreateType ();
215
216                         try {
217                                 mb2.CreateMethodBody (new byte [2], 1);
218                                 Assert.Fail ("#4");
219                         } catch (InvalidOperationException) {
220                         }
221                 }
222
223                 [Test]
224                 [ExpectedException (typeof (InvalidOperationException))]
225                 public void TestDefineParameterInvalidIndexComplete ()
226                 {
227                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
228                         MethodBuilder mb = tb.DefineMethod (genMethodName (), 0, typeof (void),
229                                 new Type [2] { typeof(int), typeof(int) });
230                         mb.CreateMethodBody (new byte [2], 1);
231                         tb.CreateType ();
232                         mb.DefineParameter (-5, ParameterAttributes.None, "param1");
233                 }
234
235                 [Test]
236                 [ExpectedException (typeof (InvalidOperationException))]
237                 public void TestDefineParameterValidIndexComplete ()
238                 {
239                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
240                         MethodBuilder mb = tb.DefineMethod (genMethodName (), 0, typeof (void),
241                                 new Type [2] { typeof(int), typeof(int) });
242                         mb.CreateMethodBody (new byte [2], 1);
243                         tb.CreateType ();
244                         mb.DefineParameter (1, ParameterAttributes.None, "param1");
245                 }
246
247                 [Test]
248                 public void TestDefineParameter ()
249                 {
250                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
251                         MethodBuilder mb = tb.DefineMethod (
252                                 genMethodName (), 0, typeof (void),
253                                 new Type [2] { typeof (int), typeof (int) });
254
255                         // index out of range
256
257                         // This fails on mono because the mono version accepts a 0 index
258                         /*
259                         try {
260                                 mb.DefineParameter (0, 0, "param1");
261                                 Fail ();
262                         } catch (ArgumentOutOfRangeException) {
263                         }
264                         */
265
266                         try {
267                                 mb.DefineParameter (3, 0, "param1");
268                                 Assert.Fail ("#1");
269                         } catch (ArgumentOutOfRangeException) {
270                         }
271
272                         // Normal usage
273                         mb.DefineParameter (1, 0, "param1");
274                         mb.DefineParameter (1, 0, "param1");
275                         mb.DefineParameter (2, 0, null);
276
277                         mb.CreateMethodBody (new byte [2], 1);
278                         tb.CreateType ();
279                         try {
280                                 mb.DefineParameter (1, 0, "param1");
281                                 Assert.Fail ("#2");
282                         } catch (InvalidOperationException) {
283                         }
284                 }
285
286                 [Test]
287 #if NET_2_0
288                 // MS.NET 2.x no longer allows a zero length method body
289                 // to be emitted
290                 [ExpectedException (typeof (InvalidOperationException))]
291 #endif
292                 public void ZeroLengthBodyTest1 ()
293                 {
294                         MethodBuilder mb = genClass.DefineMethod (
295                                 genMethodName (), 0, typeof (void),
296                                 new Type [2] { typeof (int), typeof (int) });
297                         mb.CreateMethodBody (new byte [2], 0);
298                         genClass.CreateType ();
299                 }
300
301                 // A zero length method body can be created
302                 [Test]
303                 public void ZeroLengthBodyTest2 ()
304                 {
305                         MethodBuilder mb = genClass.DefineMethod (
306                                 genMethodName (), 0, typeof (void),
307                                 new Type [2] { typeof (int), typeof (int) });
308                         mb.CreateMethodBody (new byte [2], 0);
309                 }
310
311                 [Test]
312                 public void TestHashCode ()
313                 {
314                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
315                         string methodName = genMethodName ();
316                         MethodBuilder mb = tb.DefineMethod (methodName, 0, typeof (void),
317                                 new Type [2] { typeof(int), typeof(int) });
318                         Assert.AreEqual (methodName.GetHashCode (), mb.GetHashCode ());
319                 }
320
321                 [Test]
322                 public void TestGetBaseDefinition ()
323                 {
324                         MethodBuilder mb = genClass.DefineMethod (
325                                 genMethodName (), 0, typeof (void), new Type [0]);
326                         Assert.AreEqual (mb.GetBaseDefinition (), mb);
327                 }
328
329                 [Test]
330                 public void TestGetILGenerator ()
331                 {
332                         MethodBuilder mb = genClass.DefineMethod (
333                                 genMethodName (), 0, typeof (void), new Type [0]);
334
335                         // The same instance is returned on the second call
336                         ILGenerator ilgen1 = mb.GetILGenerator ();
337                         ILGenerator ilgen2 = mb.GetILGenerator ();
338
339                         Assert.AreEqual (ilgen1, ilgen2, "#1");
340
341                         // Does not work on unmanaged code
342                         MethodBuilder mb2 = genClass.DefineMethod (
343                                 genMethodName (), 0, typeof (void), new Type [0]);
344                         try {
345                                 mb2.SetImplementationFlags (MethodImplAttributes.Unmanaged);
346                                 mb2.GetILGenerator ();
347                                 Assert.Fail ("#2");
348                         } catch (InvalidOperationException) {
349                         }
350                         try {
351                                 mb2.SetImplementationFlags (MethodImplAttributes.Native);
352                                 mb2.GetILGenerator ();
353                                 Assert.Fail ("#3");
354                         } catch (InvalidOperationException) {
355                         }
356                 }
357
358                 [Test]
359                 public void TestMethodImplementationFlags ()
360                 {
361                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
362                         MethodBuilder mb = tb.DefineMethod (
363                                 genMethodName (), 0, typeof (void), new Type [0]);
364
365                         Assert.AreEqual (MethodImplAttributes.Managed | MethodImplAttributes.IL,
366                                 mb.GetMethodImplementationFlags (), "#1");
367
368                         mb.SetImplementationFlags (MethodImplAttributes.OPTIL);
369
370                         Assert.AreEqual (MethodImplAttributes.OPTIL, mb.GetMethodImplementationFlags (), "#2");
371
372                         mb.CreateMethodBody (new byte [2], 1);
373                         mb.SetImplementationFlags (MethodImplAttributes.Managed);
374                         tb.CreateType ();
375                         try {
376                                 mb.SetImplementationFlags (MethodImplAttributes.OPTIL);
377                                 Assert.Fail ("#3");
378                         } catch (InvalidOperationException) {
379                         }
380                 }
381
382                 [Test]
383                 public void TestGetModule ()
384                 {
385                         MethodBuilder mb = genClass.DefineMethod (
386                                 genMethodName (), 0, typeof (void), new Type [0]);
387                         Assert.AreEqual (module, mb.GetModule ());
388                 }
389
390                 [Test]
391                 public void TestGetParameters ()
392                 {
393                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
394                         MethodBuilder mb = tb.DefineMethod (genMethodName (), 0, typeof (void),
395                                 new Type [1] { typeof (void) });
396
397                         /*
398                          * According to the MSDN docs, this method should fail with a
399                          * NotSupportedException. In reality, it throws an 
400                          * InvalidOperationException under MS .NET, and returns the 
401                          * requested data under mono.
402                          */
403                         /*
404                         try {
405                                 mb.GetParameters ();
406                                 Fail ("#161");
407                         } catch (InvalidOperationException ex) {
408                                 Console.WriteLine (ex);
409                         }
410                         */
411                 }
412
413                 [Test]
414                 public void TestGetToken ()
415                 {
416                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
417                         MethodBuilder mb = tb.DefineMethod (
418                                 genMethodName (), 0, typeof (void), new Type [1] { typeof (void) });
419                         mb.GetToken ();
420                 }
421
422                 [Test]
423                 public void TestInvoke ()
424                 {
425                         MethodBuilder mb = genClass.DefineMethod (
426                                 genMethodName (), 0, typeof (void),
427                                 new Type [1] { typeof (int) });
428
429                         try {
430                                 mb.Invoke (null, new object [1] { 42 });
431                                 Assert.Fail ("#1");
432                         } catch (NotSupportedException) {
433                         }
434
435                         try {
436                                 mb.Invoke (null, 0, null, new object [1] { 42 }, null);
437                                 Assert.Fail ("#2");
438                         } catch (NotSupportedException) {
439                         }
440                 }
441
442                 [Test]
443                 [ExpectedException (typeof (NotSupportedException))]
444                 public void TestIsDefined ()
445                 {
446                         MethodBuilder mb = genClass.DefineMethod (
447                                 genMethodName (), 0, typeof (void),
448                                 new Type [1] { typeof (int) });
449                         mb.IsDefined (null, true);
450                 }
451
452                 [Test]
453                 public void TestGetCustomAttributes_Incomplete ()
454                 {
455                         MethodBuilder mb = genClass.DefineMethod (
456                                 genMethodName (), 0, typeof (void),
457                                 new Type [1] { typeof (int) });
458
459                         try {
460                                 mb.GetCustomAttributes (true);
461                                 Assert.Fail ("#1");
462                         } catch (NotSupportedException) {
463                         }
464
465                         try {
466                                 mb.GetCustomAttributes (null, true);
467                                 Assert.Fail ("#2");
468                         } catch (NotSupportedException) {
469                         }
470                 }
471
472                 [Test]
473                 [Category ("NotWorking")]
474                 public void TestGetCustomAttributes_Complete ()
475                 {
476                         MethodBuilder mb = genClass.DefineMethod (
477                                 genMethodName (), 0, typeof (void),
478                                 new Type [1] { typeof (int) });
479                         mb.GetILGenerator ().Emit (OpCodes.Ret);
480                         genClass.CreateType ();
481
482                         try {
483                                 mb.GetCustomAttributes (true);
484                                 Assert.Fail ("#1");
485                         } catch (NotSupportedException) {
486                         }
487
488                         try {
489                                 mb.GetCustomAttributes (null, true);
490                                 Assert.Fail ("#2");
491                         } catch (NotSupportedException) {
492                         }
493                 }
494
495                 [Test]
496                 public void TestSetCustomAttribute ()
497                 {
498                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
499                         string name = genMethodName ();
500                         MethodBuilder mb = tb.DefineMethod (
501                                 name, MethodAttributes.Public, typeof (void),
502                                 new Type [1] { typeof (int) });
503
504                         // Null argument
505                         try {
506                                 mb.SetCustomAttribute (null);
507                                 Assert.Fail ("#1");
508                         } catch (ArgumentNullException) {
509                         }
510
511                         byte [] custAttrData = { 1, 0, 0, 0, 0 };
512                         Type attrType = Type.GetType
513                                 ("System.Reflection.AssemblyKeyNameAttribute");
514                         Type [] paramTypes = new Type [1];
515                         paramTypes [0] = typeof (String);
516                         ConstructorInfo ctorInfo =
517                                 attrType.GetConstructor (paramTypes);
518
519                         mb.SetCustomAttribute (ctorInfo, custAttrData);
520
521                         // Test MethodImplAttribute
522                         mb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MethodImplAttribute).GetConstructor (new Type [1] { typeof (short) }), new object [1] { (short) MethodImplAttributes.Synchronized }));
523                         mb.GetILGenerator ().Emit (OpCodes.Ret);
524
525                         Type t = tb.CreateType ();
526
527                         Assert.AreEqual (t.GetMethod (name).GetMethodImplementationFlags (),
528                                 MethodImplAttributes.Synchronized, "#2");
529
530                         // Null arguments again
531                         try {
532                                 mb.SetCustomAttribute (null, new byte [2]);
533                                 Assert.Fail ("#3");
534                         } catch (ArgumentNullException) {
535                         }
536
537                         try {
538                                 mb.SetCustomAttribute (ctorInfo, null);
539                                 Assert.Fail ("#4");
540                         } catch (ArgumentNullException) {
541                         }
542                 }
543
544                 [Test]
545                 public void SetCustomAttribute_DllImport_DllName_Empty ()
546                 {
547                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
548                         MethodBuilder mb = tb.DefineMethod (genMethodName (),
549                                 MethodAttributes.Public, typeof (void),
550                                 new Type [1] { typeof (int) });
551
552                         ConstructorInfo ctorInfo = typeof (DllImportAttribute).GetConstructor (
553                                 new Type [] { typeof (string) });
554                         try {
555                                 mb.SetCustomAttribute (new CustomAttributeBuilder (ctorInfo,
556                                         new object [] { string.Empty }));
557                                 Assert.Fail ("#1");
558                         } catch (ArgumentException ex) {
559                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
560                                 Assert.IsNull (ex.InnerException, "#3");
561                                 Assert.IsNotNull (ex.Message, "#4");
562                                 Assert.IsNull (ex.ParamName, "#5");
563                         }
564                 }
565
566                 [Test]
567                 public void SetCustomAttribute_DllImport_DllName_Null ()
568                 {
569                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
570                         MethodBuilder mb = tb.DefineMethod (genMethodName (),
571                                 MethodAttributes.Public, typeof (void),
572                                 new Type [1] { typeof (int) });
573
574                         ConstructorInfo ctorInfo = typeof (DllImportAttribute).GetConstructor (
575                                 new Type [] { typeof (string) });
576                         try {
577                                 mb.SetCustomAttribute (new CustomAttributeBuilder (ctorInfo,
578                                         new object [] { null }));
579                                 Assert.Fail ("#1");
580                         } catch (ArgumentException ex) {
581                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
582                                 Assert.IsNull (ex.InnerException, "#3");
583                                 Assert.IsNotNull (ex.Message, "#4");
584                                 Assert.IsNull (ex.ParamName, "#5");
585                         }
586                 }
587
588                 [Test]
589                 public void SetCustomAttribute_SuppressUnmanagedCodeSecurity ()
590                 {
591                         string mname = genMethodName ();
592
593                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
594                         MethodBuilder mb = tb.DefineMethod (mname, MethodAttributes.Public,
595                                 typeof (void), new Type [] { typeof (int), typeof (string) });
596                         ConstructorInfo attrCtor = typeof (SuppressUnmanagedCodeSecurityAttribute).
597                                 GetConstructor (new Type [0]);
598                         CustomAttributeBuilder caBuilder = new CustomAttributeBuilder (
599                                 attrCtor, new object [0]);
600                         Assert.IsTrue ((mb.Attributes & MethodAttributes.HasSecurity) == 0, "#1");
601                         mb.SetCustomAttribute (caBuilder);
602                         //Assert.IsTrue ((mb.Attributes & MethodAttributes.HasSecurity) == 0, "#2");
603                         mb.GetILGenerator ().Emit (OpCodes.Ret);
604                         Type emittedType = tb.CreateType ();
605                         MethodInfo emittedMethod = emittedType.GetMethod (mname);
606                         Assert.AreEqual (MethodAttributes.HasSecurity, emittedMethod.Attributes & MethodAttributes.HasSecurity, "#3");
607                         //Assert.IsTrue ((mb.Attributes & MethodAttributes.HasSecurity) == 0, "#4");
608                         object [] emittedAttrs = emittedMethod.GetCustomAttributes (typeof (SuppressUnmanagedCodeSecurityAttribute), true);
609                         Assert.AreEqual (1, emittedAttrs.Length, "#5");
610                 }
611
612                 [AttributeUsage (AttributeTargets.Parameter)]
613                 class PrivateAttribute : Attribute
614                 {
615
616                         public PrivateAttribute ()
617                         {
618                         }
619                 }
620
621                 [Test]
622                 public void GetCustomAttributes ()
623                 {
624                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
625                         MethodBuilder mb = tb.DefineMethod ("foo", MethodAttributes.Public,
626                                                                                                 typeof (void),
627                                                                                                 new Type [1] { typeof (int) });
628                         mb.GetILGenerator ().Emit (OpCodes.Ret);
629
630                         Type attrType = typeof (ObsoleteAttribute);
631                         ConstructorInfo ctorInfo =
632                                 attrType.GetConstructor (new Type [] { typeof (String) });
633
634                         mb.SetCustomAttribute (new CustomAttributeBuilder (ctorInfo, new object [] { "FOO" }));
635
636                         // Check that attributes not accessible are not returned
637                         mb.SetCustomAttribute (new CustomAttributeBuilder (typeof (PrivateAttribute).GetConstructor (new Type [0]), new object [] { }));
638
639                         Type t = tb.CreateType ();
640
641                         // Try the created type
642                         {
643                                 MethodInfo mi = t.GetMethod ("foo");
644                                 object [] attrs = mi.GetCustomAttributes (true);
645
646                                 Assert.AreEqual (1, attrs.Length, "#A1");
647                                 Assert.IsTrue (attrs [0] is ObsoleteAttribute, "#A2");
648                                 Assert.AreEqual ("FOO", ((ObsoleteAttribute) attrs [0]).Message, "#A3");
649                         }
650
651                         // Try the type builder
652                         {
653                                 MethodInfo mi = tb.GetMethod ("foo");
654                                 object [] attrs = mi.GetCustomAttributes (true);
655
656                                 Assert.AreEqual (1, attrs.Length, "#B1");
657                                 Assert.IsTrue (attrs [0] is ObsoleteAttribute, "#B2");
658                                 Assert.AreEqual ("FOO", ((ObsoleteAttribute) attrs [0]).Message, "#B3");
659                         }
660                 }
661
662                 [Test]
663                 [ExpectedException (typeof (InvalidOperationException))]
664                 public void TestAddDeclarativeSecurityAlreadyCreated ()
665                 {
666                         MethodBuilder mb = genClass.DefineMethod (
667                                 genMethodName (), MethodAttributes.Public, typeof (void),
668                                 new Type [0]);
669                         ILGenerator ilgen = mb.GetILGenerator ();
670                         ilgen.Emit (OpCodes.Ret);
671                         genClass.CreateType ();
672
673                         PermissionSet set = new PermissionSet (PermissionState.Unrestricted);
674                         mb.AddDeclarativeSecurity (SecurityAction.Demand, set);
675                 }
676
677                 [Test]
678                 [ExpectedException (typeof (ArgumentNullException))]
679                 public void TestAddDeclarativeSecurityNullPermissionSet ()
680                 {
681                         MethodBuilder mb = genClass.DefineMethod (
682                                 genMethodName (), MethodAttributes.Public, typeof (void),
683                                 new Type [0]);
684                         mb.AddDeclarativeSecurity (SecurityAction.Demand, null);
685                 }
686
687                 [Test]
688                 public void TestAddDeclarativeSecurityInvalidAction ()
689                 {
690                         MethodBuilder mb = genClass.DefineMethod (
691                                 genMethodName (), MethodAttributes.Public, typeof (void),
692                                 new Type [0]);
693
694                         SecurityAction [] actions = new SecurityAction [] { 
695                         SecurityAction.RequestMinimum,
696                         SecurityAction.RequestOptional,
697                         SecurityAction.RequestRefuse };
698                         PermissionSet set = new PermissionSet (PermissionState.Unrestricted);
699
700                         foreach (SecurityAction action in actions) {
701                                 try {
702                                         mb.AddDeclarativeSecurity (action, set);
703                                         Assert.Fail ();
704                                 } catch (ArgumentOutOfRangeException) {
705                                 }
706                         }
707                 }
708
709                 [Test]
710                 [ExpectedException (typeof (InvalidOperationException))]
711                 public void TestAddDeclarativeSecurityDuplicateAction ()
712                 {
713                         MethodBuilder mb = genClass.DefineMethod (
714                                 genMethodName (), MethodAttributes.Public, typeof (void),
715                                 new Type [0]);
716                         PermissionSet set = new PermissionSet (PermissionState.Unrestricted);
717                         mb.AddDeclarativeSecurity (SecurityAction.Demand, set);
718                         mb.AddDeclarativeSecurity (SecurityAction.Demand, set);
719                 }
720
721                 [AttributeUsage (AttributeTargets.Parameter)]
722                 class ParamAttribute : Attribute
723                 {
724
725                         public ParamAttribute ()
726                         {
727                         }
728                 }
729
730                 [Test]
731                 public void TestDynamicParams ()
732                 {
733                         string mname = genMethodName ();
734
735                         MethodBuilder mb = genClass.DefineMethod (
736                                 mname, MethodAttributes.Public, typeof (void),
737                                 new Type [] { typeof (int), typeof (string) });
738                         ParameterBuilder pb = mb.DefineParameter (1, ParameterAttributes.In, "foo");
739                         pb.SetConstant (52);
740                         pb.SetCustomAttribute (new CustomAttributeBuilder (typeof (ParamAttribute).GetConstructors () [0], new object [] { }));
741                         ParameterBuilder pb2 = mb.DefineParameter (2, 0, "bar");
742                         pb2.SetConstant ("foo");
743                         mb.GetILGenerator ().Emit (OpCodes.Ret);
744
745                         Type t = genClass.CreateType ();
746                         MethodInfo m = t.GetMethod (mname);
747                         ParameterInfo [] pi = m.GetParameters ();
748
749                         Assert.AreEqual ("foo", pi [0].Name, "#A1");
750                         Assert.IsTrue (pi [0].IsIn, "#A2");
751                         Assert.AreEqual (52, pi [0].DefaultValue, "#A3");
752                         object [] cattrs = pi [0].GetCustomAttributes (true);
753 #if NET_2_0
754                         Assert.AreEqual (1, cattrs.Length, "#A4");
755                         Assert.AreEqual (typeof (InAttribute), cattrs [0].GetType (), "#A5");
756 #else
757                         Assert.AreEqual (0, cattrs.Length, "#A4");
758 #endif
759
760                         cattrs = pi [1].GetCustomAttributes (true);
761                         Assert.AreEqual ("foo", pi [1].DefaultValue, "#B1");
762                 }
763
764                 [Test]
765                 public void SetCustomAttribute_DllImport1 ()
766                 {
767                         string mname = genMethodName ();
768
769                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
770                         MethodBuilder mb = tb.DefineMethod (
771                                 mname, MethodAttributes.Public, typeof (void), 
772                                 new Type [] { typeof (int), typeof (string) });
773
774                         // Create an attribute with default values
775                         mb.SetCustomAttribute (new CustomAttributeBuilder(typeof(DllImportAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { "kernel32" }));
776
777                         Type t = tb.CreateType ();
778
779                         DllImportAttribute attr = (DllImportAttribute)((t.GetMethod (mname).GetCustomAttributes (typeof (DllImportAttribute), true)) [0]);
780
781                         Assert.AreEqual (CallingConvention.Winapi, attr.CallingConvention, "#1");
782                         Assert.AreEqual (mname, attr.EntryPoint, "#2");
783                         Assert.AreEqual ("kernel32", attr.Value, "#3");
784                         Assert.IsFalse (attr.ExactSpelling, "#4");
785                         Assert.IsTrue (attr.PreserveSig, "#5");
786                         Assert.IsFalse (attr.SetLastError, "#6");
787                         Assert.IsFalse (attr.BestFitMapping, "#7");
788                         Assert.IsFalse (attr.ThrowOnUnmappableChar, "#8");
789                 }
790
791                 [Test]
792                 public void SetCustomAttribute_DllImport2 () {
793                         string mname = genMethodName ();
794
795                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
796                         MethodBuilder mb = tb.DefineMethod (
797                                 mname, MethodAttributes.Public, typeof (void), 
798                                 new Type [] { typeof (int), typeof (string) });
799
800                         CustomAttributeBuilder cb = new CustomAttributeBuilder (typeof (DllImportAttribute).GetConstructor (new Type [] {typeof (String)}), new object [] { "foo" }, new FieldInfo [] {typeof (DllImportAttribute).GetField ("EntryPoint"), typeof (DllImportAttribute).GetField ("CallingConvention"), typeof (DllImportAttribute).GetField ("CharSet"), typeof (DllImportAttribute).GetField ("ExactSpelling"), typeof (DllImportAttribute).GetField ("PreserveSig")}, new object [] { "bar", CallingConvention.StdCall, CharSet.Unicode, true, false });
801                         mb.SetCustomAttribute (cb);
802
803                         Type t = tb.CreateType ();
804
805                         DllImportAttribute attr = (DllImportAttribute)((t.GetMethod (mname).GetCustomAttributes (typeof (DllImportAttribute), true)) [0]);
806
807                         Assert.AreEqual (CallingConvention.StdCall, attr.CallingConvention, "#1");
808                         Assert.AreEqual (CharSet.Unicode, attr.CharSet, "#2");
809                         Assert.AreEqual ("bar", attr.EntryPoint, "#3");
810                         Assert.AreEqual ("foo", attr.Value, "#4");
811                         Assert.IsTrue (attr.ExactSpelling, "#5");
812                         Assert.IsFalse (attr.PreserveSig, "#6");
813                         Assert.IsFalse (attr.SetLastError, "#7");
814                         Assert.IsFalse (attr.BestFitMapping, "#8");
815                         Assert.IsFalse (attr.ThrowOnUnmappableChar, "#9");
816                 }
817
818                 [Test]
819                 public void SetCustomAttribute_DllImport3 () {
820                         string mname = genMethodName ();
821
822                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
823                         MethodBuilder mb = tb.DefineMethod (
824                                 mname, MethodAttributes.Public, typeof (void), 
825                                 new Type [] { typeof (int), typeof (string) });
826
827                         // Test attributes with three values (on/off/missing)
828                         CustomAttributeBuilder cb = new CustomAttributeBuilder (typeof (DllImportAttribute).GetConstructor (new Type [] {typeof (String)}), new object [] { "foo" }, new FieldInfo [] { typeof (DllImportAttribute).GetField ("BestFitMapping"), typeof (DllImportAttribute).GetField ("ThrowOnUnmappableChar")}, new object [] { false, false });
829                         mb.SetCustomAttribute (cb);
830
831                         Type t = tb.CreateType ();
832
833                         DllImportAttribute attr = (DllImportAttribute)((t.GetMethod (mname).GetCustomAttributes (typeof (DllImportAttribute), true)) [0]);
834
835                         Assert.IsFalse (attr.BestFitMapping, "#1");
836                         Assert.IsFalse (attr.ThrowOnUnmappableChar, "#2");
837                 }
838
839                 [Test]
840                 public void SetCustomAttribute_DllImport4 ()
841                 {
842                         string mname = genMethodName ();
843
844                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
845                         MethodBuilder mb = tb.DefineMethod (
846                                 mname, MethodAttributes.Public, typeof (void), 
847                                 new Type [] { typeof (int), typeof (string) });
848
849                         CustomAttributeBuilder cb = new CustomAttributeBuilder (typeof (DllImportAttribute).GetConstructor (new Type [] {typeof (String)}), new object [] { "foo" }, new FieldInfo [] { typeof (DllImportAttribute).GetField ("SetLastError"), typeof (DllImportAttribute).GetField ("BestFitMapping"), typeof (DllImportAttribute).GetField ("ThrowOnUnmappableChar")}, new object [] { true, true, true });
850                         mb.SetCustomAttribute (cb);
851
852                         Type t = tb.CreateType ();
853
854                         DllImportAttribute attr = (DllImportAttribute)((t.GetMethod (mname).GetCustomAttributes (typeof (DllImportAttribute), true)) [0]);
855
856                         Assert.IsTrue (attr.SetLastError, "#1");
857                         Assert.IsTrue (attr.BestFitMapping, "#2");
858                         Assert.IsTrue (attr.ThrowOnUnmappableChar, "#3");
859                 }
860
861                 public class GenericFoo <T> {
862                         public static T field;
863                 }
864
865                 [Test]
866                 public void ILGen_GenericTypeParameterBuilder ()
867                 {
868                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
869                         MethodBuilder mb = tb.DefineMethod ("box_int", 
870                                                                                                 MethodAttributes.Public|MethodAttributes.Static, typeof (object), new Type [] { typeof (int) });
871
872                         GenericTypeParameterBuilder[] pars = mb.DefineGenericParameters (new string [] { "foo" });
873
874                         ILGenerator ilgen = mb.GetILGenerator ();
875                         ilgen.Emit (OpCodes.Ldarg_0);
876                         ilgen.Emit (OpCodes.Box, pars [0]);
877                         ilgen.Emit (OpCodes.Ret);
878
879                         Type t = tb.CreateType ();
880                         MethodInfo mi = t.GetMethod ("box_int");
881                         MethodInfo mi2 = mi.MakeGenericMethod (new Type [] { typeof (int) });
882                         Assert.AreEqual (1, mi2.Invoke (null, new object [] { 1 }));
883                 }
884
885                 public void ILGen_InstantiatedGenericType ()
886                 {
887                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
888                         MethodBuilder mb = tb.DefineMethod ("return_type", 
889                                                                                                 MethodAttributes.Public|MethodAttributes.Static, typeof (object), new Type [] { });
890
891                         GenericTypeParameterBuilder[] pars = mb.DefineGenericParameters (new string [] { "foo" });
892
893                         ILGenerator ilgen = mb.GetILGenerator ();
894
895                         Type genericFoo = typeof (GenericFoo<int>).GetGenericTypeDefinition ().MakeGenericType (new Type [] { pars [0] });
896
897                         ilgen.Emit (OpCodes.Ldtoken, genericFoo);
898                         ilgen.Emit (OpCodes.Call, typeof (Type).GetMethod ("GetTypeFromHandle"));
899                         ilgen.Emit (OpCodes.Ret);
900
901                         Type t = tb.CreateType ();
902                         MethodInfo mi = t.GetMethod ("box_int");
903                         MethodInfo mi2 = mi.MakeGenericMethod (new Type [] { typeof (int) });
904                         Assert.AreEqual (typeof (GenericFoo<int>), mi2.Invoke (null, new object [] { 1 }));
905                 }
906
907                 public void ILGen_InstantiatedTypeBuilder ()
908                 {
909                         TypeBuilder genericTb = module.DefineType (genTypeName (), TypeAttributes.Public);
910                         genericTb.DefineGenericParameters (new string [] { "foo" });
911                         Type generatedGenericType = genericTb.CreateType ();
912
913                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
914                         MethodBuilder mb = tb.DefineMethod ("return_type", 
915                                                                                                 MethodAttributes.Public|MethodAttributes.Static, typeof (object), new Type [] { });
916
917                         GenericTypeParameterBuilder[] pars = mb.DefineGenericParameters (new string [] { "foo" });
918
919                         ILGenerator ilgen = mb.GetILGenerator ();
920
921                         ilgen.Emit (OpCodes.Ldtoken, genericTb.MakeGenericType (new Type [] { pars [0] }));
922                         ilgen.Emit (OpCodes.Call, typeof (Type).GetMethod ("GetTypeFromHandle"));
923                         ilgen.Emit (OpCodes.Ret);
924
925                         Type t = tb.CreateType ();
926                         MethodInfo mi = t.GetMethod ("return_type");
927                         MethodInfo mi2 = mi.MakeGenericMethod (new Type [] { typeof (int) });
928                         Assert.AreEqual (generatedGenericType.MakeGenericType (new Type [] { typeof (int) }), mi2.Invoke (null, new object [] { 1 }));
929                 }
930
931                 [Test]
932                 public void Bug354757 ()
933                 {
934                         TypeBuilder gtb = module.DefineType (genTypeName (), TypeAttributes.Public);
935                         gtb.DefineGenericParameters ("T");
936                         MethodBuilder mb = gtb.DefineMethod ("foo", MethodAttributes.Public);
937                         mb.DefineGenericParameters ("S");
938                         Assert.IsTrue (mb.IsGenericMethodDefinition);
939
940                         Type gt = gtb.MakeGenericType (typeof (object));
941                         MethodInfo m = TypeBuilder.GetMethod (gt, mb);
942                         Assert.IsTrue (m.IsGenericMethodDefinition);
943
944                         MethodInfo mopen = m.MakeGenericMethod (m.GetGenericArguments ());
945                         Assert.IsFalse (mopen.IsGenericMethodDefinition);
946                 }
947
948                 [Test]
949                 public void DefineGenericParameters_Names_Empty ()
950                 {
951                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
952                         MethodBuilder mb = tb.DefineMethod ("foo", MethodAttributes.Public);
953
954                         try {
955                                 mb.DefineGenericParameters (new string [0]);
956                                 Assert.Fail ("#1");
957                         } catch (ArgumentException ex) {
958                                 // Value does not fall within the expected range
959                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
960                                 Assert.IsNull (ex.InnerException, "#3");
961                                 Assert.IsNotNull (ex.Message, "#4");
962                                 Assert.IsNull (ex.ParamName, "#5");
963                         }
964                 }
965
966
967
968                 [Test]
969                 public void DefineGenericParameters_Names_Null ()
970                 {
971                         TypeBuilder tb = module.DefineType (genTypeName (), TypeAttributes.Public);
972                         MethodBuilder mb = tb.DefineMethod ("foo", MethodAttributes.Public);
973
974                         try {
975                                 mb.DefineGenericParameters ((string []) null);
976                                 Assert.Fail ("#A1");
977                         } catch (ArgumentNullException ex) {
978                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#A2");
979                                 Assert.IsNull (ex.InnerException, "#A3");
980                                 Assert.IsNotNull (ex.Message, "#A4");
981                                 Assert.AreEqual ("names", ex.ParamName, "#A5");
982                         }
983
984                         try {
985                                 mb.DefineGenericParameters ("K", null, "V");
986                                 Assert.Fail ("#B1");
987                         } catch (ArgumentNullException ex) {
988                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#B2");
989                                 Assert.IsNull (ex.InnerException, "#B3");
990                                 Assert.IsNotNull (ex.Message, "#B4");
991                                 Assert.AreEqual ("names", ex.ParamName, "#B5");
992                         }
993                 }
994
995
996                 public static int Foo<T> (T a, T b) {
997                         return 99;
998                 }
999
1000                 [Test]//bug #591226
1001                 public void GenericMethodIsProperlyInflated ()
1002                 {
1003                         var tb = module.DefineType ("foo");
1004                         var met = typeof (MethodBuilderTest).GetMethod ("Foo");
1005
1006                         var mb = tb.DefineMethod ("myFunc", MethodAttributes.Public | MethodAttributes.Static, typeof (int), Type.EmptyTypes);
1007                         var garg = mb.DefineGenericParameters ("a") [0];
1008                         mb.SetParameters (garg, garg);
1009
1010                         var ilgen = mb.GetILGenerator ();
1011                         ilgen.Emit (OpCodes.Ldarg_0);
1012                         ilgen.Emit (OpCodes.Ldarg_1);
1013                         ilgen.Emit (OpCodes.Call, met.MakeGenericMethod (garg));
1014                         ilgen.Emit (OpCodes.Ret);
1015
1016                         var res = tb.CreateType ();
1017                         var mm = res.GetMethod ("myFunc").MakeGenericMethod (typeof (int));
1018
1019                         var rt = mm.Invoke (null, new object[] { 10, 20 });
1020                         Assert.AreEqual (99, rt, "#1");
1021                 }
1022
1023             public static void VarargMethod (string headline, __arglist) {
1024                 ArgIterator ai = new ArgIterator (__arglist);
1025         
1026                 Console.Write (headline);
1027                 while (ai.GetRemainingCount () > 0)
1028                     Console.Write (TypedReference.ToObject (ai.GetNextArg ()));
1029                 Console.WriteLine ();
1030             }
1031
1032                 [Test]//bug #626441
1033                 public void CanCallVarargMethods ()
1034                 {
1035                         var tb = module.DefineType ("foo");
1036                         MethodBuilder mb = tb.DefineMethod ("CallVarargMethod", 
1037                                 MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
1038                                 typeof (void), Type.EmptyTypes);
1039
1040                         ILGenerator il = mb.GetILGenerator ();
1041                         MethodInfo miVarargMethod = typeof (MethodBuilderTest).GetMethod ("VarargMethod");
1042                         
1043                         il.Emit (OpCodes.Ldstr, "Hello world from ");
1044                         il.Emit (OpCodes.Call, typeof(Assembly).GetMethod ("GetExecutingAssembly"));
1045                         il.EmitCall (OpCodes.Call, miVarargMethod, new Type[] { typeof(Assembly) });
1046                         
1047                         il.Emit (OpCodes.Ldstr, "Current time: ");
1048                         il.Emit (OpCodes.Call, typeof(DateTime).GetMethod("get_Now"));
1049                         il.Emit (OpCodes.Ldstr, " (UTC ");
1050                         il.Emit (OpCodes.Call, typeof(DateTime).GetMethod("get_UtcNow"));
1051                         il.Emit (OpCodes.Ldstr, ")");
1052                         il.EmitCall (OpCodes.Call, miVarargMethod, new Type[] { typeof (DateTime), typeof (string), typeof (DateTime), typeof (string) });
1053                         il.Emit (OpCodes.Ret);
1054
1055                         Type type = tb.CreateType ();
1056                         type.GetMethod ("CallVarargMethod").Invoke (null, null);
1057                 }
1058         }
1059 }