copied mono-api-diff.cs from mono-2-2 branch so new patch can be applied and history...
[mono.git] / mcs / class / corlib / Test / System.Reflection.Emit / ILGeneratorTest.cs
1 //
2 // ILGeneratorTest.cs - NUnit Test Cases for the ILGenerator class
3 //
4 // Marek Safar (marek.safar@seznam.cz)
5 //
6 // (C) Novell, Inc.  http://www.novell.com
7
8 using System;
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Runtime.InteropServices;
12 using System.Threading;
13
14 using NUnit.Framework;
15
16 namespace MonoTests.System.Reflection.Emit
17 {
18         [TestFixture]
19         public class ILGeneratorTest
20         {
21                 TypeBuilder tb;
22                 ILGenerator il_gen;
23
24                 void DefineBasicMethod ()
25                 {
26                         MethodBuilder mb = tb.DefineMethod("F",
27                                 MethodAttributes.Public, typeof(string), null);
28                         il_gen = mb.GetILGenerator ();
29                 }
30
31                 [SetUp]
32                 public void SetUp ()
33                 {
34                         AssemblyName assemblyName = new AssemblyName ();
35                         assemblyName.Name = "MonoTests.System.Reflection.Emit.ILGeneratorTest";
36
37                         AssemblyBuilder assembly = Thread.GetDomain ().DefineDynamicAssembly (
38                                 assemblyName, AssemblyBuilderAccess.Run);
39
40                         ModuleBuilder module = assembly.DefineDynamicModule ("module1");
41                         tb = module.DefineType ("T", TypeAttributes.Public);
42                 }
43
44                 [Test]
45                 public void DeclareLocal_LocalType_Null ()
46                 {
47                         DefineBasicMethod ();
48
49                         try {
50                                 il_gen.DeclareLocal (null);
51                                 Assert.Fail ("#A1");
52                         } catch (ArgumentNullException ex) {
53                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#A2");
54                                 Assert.IsNull (ex.InnerException, "#A3");
55                                 Assert.IsNotNull (ex.Message, "#A4");
56                                 Assert.IsNotNull (ex.ParamName, "#A5");
57                                 Assert.AreEqual ("localType", ex.ParamName, "#A");
58                         }
59
60 #if NET_2_0
61                         try {
62                                 il_gen.DeclareLocal (null, false);
63                                 Assert.Fail ("#B1");
64                         } catch (ArgumentNullException ex) {
65                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#B2");
66                                 Assert.IsNull (ex.InnerException, "#B3");
67                                 Assert.IsNotNull (ex.Message, "#B4");
68                                 Assert.IsNotNull (ex.ParamName, "#B5");
69                                 Assert.AreEqual ("localType", ex.ParamName, "#B6");
70                         }
71 #endif
72                 }
73
74                 [Test]
75                 [ExpectedException (typeof (ArgumentException))]
76                 public void DefineFilterBodyWithTypeNotNull ()
77                 {
78                         DefineBasicMethod ();
79                         il_gen.BeginExceptionBlock ();
80                         il_gen.EmitWriteLine ("in try");
81                         il_gen.BeginExceptFilterBlock ();
82                         il_gen.EmitWriteLine ("in filter head");
83                         il_gen.BeginCatchBlock (typeof (Exception));
84                         il_gen.EmitWriteLine ("in filter body");
85                         il_gen.EndExceptionBlock ();
86                 }
87
88                 [Test] // bug #81431
89                 public void FilterAndCatchBlock ()
90                 {
91                         DefineBasicMethod ();
92                         ILGenerator il = il_gen;
93                         il.BeginExceptionBlock ();
94                         il.BeginExceptFilterBlock ();
95                         il.BeginCatchBlock (null);
96                         il.BeginCatchBlock (typeof (SystemException));
97                 }
98                 
99                 [Test]
100                 [ExpectedException (typeof (InvalidOperationException))]
101                 public void InvalidFilterBlock1 ()
102                 {
103                         DefineBasicMethod ();
104                         ILGenerator il = il_gen;
105                         il.BeginExceptionBlock ();
106                         il.BeginExceptFilterBlock ();
107                         il.EndExceptionBlock ();
108                 }
109                 
110                 [Test]
111                 public void ValidFilterBlock1 ()
112                 {
113                         DefineBasicMethod ();
114                         ILGenerator il = il_gen;
115                         il.BeginExceptionBlock ();
116                         il.BeginExceptFilterBlock ();
117                         il.BeginFaultBlock ();
118                         il.EndExceptionBlock ();
119                 }
120                 
121                 [Test]
122                 public void ValidFilterBlock2 ()
123                 {
124                         DefineBasicMethod ();
125                         ILGenerator il = il_gen;
126                         il.BeginExceptionBlock ();
127                         il.BeginExceptFilterBlock ();
128                         il.BeginFinallyBlock ();
129                         il.EndExceptionBlock ();
130                 }
131                 
132                 /// <summary>
133                 /// Try to emit something like that:
134                 ///
135                 /// .method public static bool TestFilter (bool execute_handler)
136                 /// {
137                 ///     .locals init(bool)
138                 ///     try {
139                 ///             newobj  instance void [mscorlib]System.Exception::.ctor()
140                 ///             throw
141                 ///     } filter {
142                 ///             pop
143                 ///             ldarg.0
144                 ///             endfilter
145                 ///     } {
146                 ///             ldc.i4.1
147                 ///             stloc.0
148                 ///             leave quit
149                 ///     }
150                 ///     ldc.i4.0
151                 ///     stloc.0
152                 /// quit:
153                 ///     ldloc.0
154                 ///     ret
155                 /// }
156                 ///
157                 /// It should return true if the handler has been executed
158                 /// Otherwise, the exception should not be catched
159                 /// </summary>
160                 void DefineTestFilterMethod ()
161                 {
162                         MethodBuilder mb = tb.DefineMethod("TestFilter",
163                                 MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type [] { typeof (bool) });
164
165                         ConstructorInfo exCtor = typeof (Exception).GetConstructor (new Type [0]);
166
167                         il_gen = mb.GetILGenerator ();
168                         il_gen.DeclareLocal (typeof (bool));
169                         Label quit = il_gen.DefineLabel ();
170                         il_gen.BeginExceptionBlock ();
171                         il_gen.Emit (OpCodes.Newobj, exCtor);
172                         il_gen.Emit (OpCodes.Throw);
173                         il_gen.BeginExceptFilterBlock ();
174                         il_gen.Emit (OpCodes.Pop);
175                         il_gen.Emit (OpCodes.Ldarg_0);
176                         il_gen.BeginCatchBlock (null);
177                         il_gen.Emit (OpCodes.Ldc_I4_1);
178                         il_gen.Emit (OpCodes.Stloc_0);
179                         il_gen.Emit (OpCodes.Leave, quit);
180                         il_gen.EndExceptionBlock ();
181                         il_gen.Emit (OpCodes.Ldc_I4_0);
182                         il_gen.Emit (OpCodes.Stloc_0);
183                         il_gen.MarkLabel (quit);
184                         il_gen.Emit (OpCodes.Ldloc_0);
185                         il_gen.Emit (OpCodes.Ret);
186                 }
187
188                 [Test] // Emit (OpCode, ConstructorInfo)
189 #if NET_2_0
190                 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
191 #endif
192                 public void Emit3_Constructor_Null ()
193                 {
194                         DefineBasicMethod ();
195                         try {
196                                 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
197                                 Assert.Fail ("#1");
198                         } catch (ArgumentNullException ex) {
199                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
200                                 Assert.IsNull (ex.InnerException, "#3");
201                                 Assert.IsNotNull (ex.Message, "#4");
202                                 Assert.IsNotNull (ex.ParamName, "#5");
203                         }
204                 }
205
206 #if NET_2_0
207                 [Test] // Emit (OpCode, ConstructorInfo)
208                 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
209                 public void Emit3_Constructor_Null_MS ()
210                 {
211                         DefineBasicMethod ();
212                         try {
213                                 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
214                                 Assert.Fail ("#1");
215                         } catch (NullReferenceException) {
216                         }
217                 }
218 #endif
219
220                 [Test] // Emit (OpCode, FieldInfo)
221                 public void Emit5_Field_Null ()
222                 {
223                         DefineBasicMethod ();
224                         try {
225                                 il_gen.Emit (OpCodes.Ldsfld, (FieldInfo) null);
226                                 Assert.Fail ("#1");
227                         } catch (ArgumentNullException ex) {
228                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
229                                 Assert.IsNull (ex.InnerException, "#3");
230                                 Assert.IsNotNull (ex.Message, "#4");
231                                 Assert.IsNotNull (ex.ParamName, "#5");
232                         }
233                 }
234
235                 [Test] // Emit (OpCode, Label [])
236                 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
237                 public void Emit10_Labels_Null ()
238                 {
239                         DefineBasicMethod ();
240                         try {
241                                 il_gen.Emit (OpCodes.Switch, (Label []) null);
242                                 Assert.Fail ("#1");
243                         } catch (ArgumentNullException ex) {
244                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
245                                 Assert.IsNull (ex.InnerException, "#3");
246                                 Assert.IsNotNull (ex.Message, "#4");
247                                 Assert.IsNotNull (ex.ParamName, "#5");
248                                 Assert.AreEqual ("labels", ex.ParamName, "#6");
249                         }
250                 }
251
252                 [Test]
253                 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
254                 public void Emit10_Labels_Null_MS ()
255                 {
256                         DefineBasicMethod ();
257                         try {
258                                 il_gen.Emit (OpCodes.Switch, (Label []) null);
259                                 Assert.Fail ("#1");
260                         } catch (NullReferenceException) {
261                         }
262                 }
263
264                 [Test] // Emit (OpCode, LocalBuilder)
265                 public void Emit11_Local_Null ()
266                 {
267                         DefineBasicMethod ();
268                         try {
269                                 il_gen.Emit (OpCodes.Switch, (LocalBuilder) null);
270                                 Assert.Fail ("#1");
271                         } catch (ArgumentNullException ex) {
272                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
273                                 Assert.IsNull (ex.InnerException, "#3");
274                                 Assert.IsNotNull (ex.Message, "#4");
275                                 Assert.IsNotNull (ex.ParamName, "#5");
276                                 Assert.AreEqual ("local", ex.ParamName, "#6");
277                         }
278                 }
279
280                 [Test] // Emit (OpCode, MethodInfo)
281                 public void Emit12_Method_Null ()
282                 {
283                         DefineBasicMethod ();
284                         try {
285                                 il_gen.Emit (OpCodes.Switch, (MethodInfo) null);
286                                 Assert.Fail ("#1");
287                         } catch (ArgumentNullException ex) {
288                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
289                                 Assert.IsNull (ex.InnerException, "#3");
290                                 Assert.IsNotNull (ex.Message, "#4");
291                                 Assert.IsNotNull (ex.ParamName, "#5");
292                                 Assert.AreEqual ("meth", ex.ParamName, "#6");
293                         }
294                 }
295
296                 [Test] // Emit (OpCode, SignatureHelper)
297                 public void Emit14_Signature_Null ()
298                 {
299                         DefineBasicMethod ();
300                         try {
301                                 il_gen.Emit (OpCodes.Switch, (SignatureHelper) null);
302                                 Assert.Fail ("#1");
303                         } catch (ArgumentNullException ex) {
304                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
305                                 Assert.IsNull (ex.InnerException, "#3");
306                                 Assert.IsNotNull (ex.Message, "#4");
307                                 Assert.IsNotNull (ex.ParamName, "#5");
308                         }
309                 }
310
311                 [Test] // Emit (OpCode, String)
312                 public void Emit16_String_Null ()
313                 {
314                         DefineBasicMethod ();
315                         try {
316                                 il_gen.Emit (OpCodes.Switch, (String) null);
317                                 Assert.Fail ("#1");
318                         } catch (ArgumentNullException ex) {
319                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
320                                 Assert.IsNull (ex.InnerException, "#3");
321                                 Assert.IsNotNull (ex.Message, "#4");
322                         }
323                 }
324
325                 [Test] // Emit (OpCode, Type)
326                 public void Emit16_Type_Null ()
327                 {
328                         DefineBasicMethod ();
329                         try {
330                                 il_gen.Emit (OpCodes.Switch, (Type) null);
331                                 Assert.Fail ("#1");
332                         } catch (ArgumentNullException ex) {
333                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
334                                 Assert.IsNull (ex.InnerException, "#3");
335                                 Assert.IsNotNull (ex.Message, "#4");
336                                 Assert.IsNotNull (ex.ParamName, "#5");
337                         }
338                 }
339
340                 [Test]
341                 public void EmitCall_MethodInfo_Null ()
342                 {
343                         DefineBasicMethod ();
344                         try {
345                                 il_gen.EmitCall (OpCodes.Call, (MethodInfo) null, null);
346                                 Assert.Fail ("#1");
347                         } catch (ArgumentNullException ex) {
348                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
349                                 Assert.IsNull (ex.InnerException, "#3");
350                                 Assert.IsNotNull (ex.Message, "#4");
351                                 Assert.IsNotNull (ex.ParamName, "#5");
352                                 Assert.AreEqual ("methodInfo", ex.ParamName, "#6");
353                         }
354                 }
355
356                 [Test]
357                 public void TestFilterEmittingWithHandlerExecution ()
358                 {
359                         DefineTestFilterMethod ();
360                         Type dynt = tb.CreateType ();
361                         
362                         MethodInfo tf = dynt.GetMethod ("TestFilter");
363                         Assert.IsTrue ((bool) tf.Invoke (null, new object [] { true }));
364                 }
365
366 #if NET_2_0
367                 delegate void FooFoo ();
368
369                 static void Foo ()
370                 {
371                 }
372
373                 [Test]
374                 public void TestEmitCalliWithNullReturnType ()
375                 {
376                         MethodBuilder mb = tb.DefineMethod ("F",
377                                 MethodAttributes.Public | MethodAttributes.Static, null, new Type [] { typeof (IntPtr) });
378                         mb.SetImplementationFlags (MethodImplAttributes.NoInlining);
379                         il_gen = mb.GetILGenerator ();
380                         il_gen.Emit (OpCodes.Ldarg_0);
381                         il_gen.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, null, Type.EmptyTypes);
382                         il_gen.Emit (OpCodes.Ret);
383         
384                         Type dynt = tb.CreateType ();
385                         dynt.GetMethod ("F", BindingFlags.Public | BindingFlags.Static).Invoke (
386                                 null, new object [] { Marshal.GetFunctionPointerForDelegate (new FooFoo (Foo)) });
387                 }
388 #endif
389
390 #if NET_2_0
391                 //Test for #509131
392                 [Test]
393                 public void TestEmitCallIgnoresOptionalArgsForNonVarargMethod ()
394                 {
395                         DefineBasicMethod ();
396                         try {
397                                 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
398                         } catch (InvalidOperationException ex) {
399                                 Assert.Fail ("#1");
400                         }
401                 }
402 #else
403                 [Test]
404                 public void TestEmitCallThrowsOnOptionalArgsForNonVarargMethod ()
405                 {
406                         DefineBasicMethod ();
407                         try {
408                                 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
409                                 Assert.Fail ("#1");
410                         } catch (InvalidOperationException ex) {
411                         }
412                 }
413 #endif
414
415                 [Test]
416                 [ExpectedException (typeof (Exception))]
417                 public void TestFilterEmittingWithoutHandlerExecution ()
418                 {
419                         DefineTestFilterMethod ();
420                         Type dynt = tb.CreateType ();
421                         
422                         MethodInfo tf = dynt.GetMethod ("TestFilter");
423                         try {
424                                 tf.Invoke (null, new object [] { false });
425                         } catch (TargetInvocationException tie) {
426                                 throw tie.InnerException;
427                         }
428                 }
429
430                 [Test]
431                 public void TestEmitLocalInfoWithNopOpCode ()
432                 {
433                         var method_builder = tb.DefineMethod ("linop", MethodAttributes.Public | MethodAttributes.Static, typeof (bool), Type.EmptyTypes);
434                         il_gen = method_builder.GetILGenerator ();
435
436                         var local = il_gen.DeclareLocal (typeof (int));
437                         il_gen.Emit (OpCodes.Nop, local);
438                         il_gen.Emit (OpCodes.Ldc_I4_1);
439                         il_gen.Emit (OpCodes.Ret);
440
441                         var type = tb.CreateType ();
442                         var method = type.GetMethod ("linop");
443
444                         Assert.IsNotNull (method);
445                         Assert.IsTrue ((bool) method.Invoke (null, new object [0]));
446                 }
447
448                 [Test]
449                 [ExpectedException (typeof (ArgumentException))]
450                 public void LdObjByRef () {
451                         DefineBasicMethod ();
452                         ILGenerator ig = il_gen;
453
454                         ig.Emit (OpCodes.Ldtoken, typeof (int).MakeByRefType ());
455                 }
456         }
457 }