2 // ILGeneratorTest.cs - NUnit Test Cases for the ILGenerator class
4 // Marek Safar (marek.safar@seznam.cz)
6 // (C) Novell, Inc. http://www.novell.com
9 using System.Collections.Generic;
10 using System.Reflection;
11 using System.Reflection.Emit;
12 using System.Runtime.InteropServices;
13 using System.Threading;
15 using NUnit.Framework;
17 namespace MonoTests.System.Reflection.Emit
20 public class ILGeneratorTest
25 void DefineBasicMethod ()
27 MethodBuilder mb = tb.DefineMethod("F",
28 MethodAttributes.Public, typeof(string), null);
29 il_gen = mb.GetILGenerator ();
35 AssemblyName assemblyName = new AssemblyName ();
36 assemblyName.Name = "MonoTests.System.Reflection.Emit.ILGeneratorTest";
38 AssemblyBuilder assembly = Thread.GetDomain ().DefineDynamicAssembly (
39 assemblyName, AssemblyBuilderAccess.Run);
41 ModuleBuilder module = assembly.DefineDynamicModule ("module1");
42 tb = module.DefineType ("T", TypeAttributes.Public);
46 public void DeclareLocal_LocalType_Null ()
51 il_gen.DeclareLocal (null);
53 } catch (ArgumentNullException ex) {
54 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#A2");
55 Assert.IsNull (ex.InnerException, "#A3");
56 Assert.IsNotNull (ex.Message, "#A4");
57 Assert.IsNotNull (ex.ParamName, "#A5");
58 Assert.AreEqual ("localType", ex.ParamName, "#A");
63 il_gen.DeclareLocal (null, false);
65 } catch (ArgumentNullException ex) {
66 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#B2");
67 Assert.IsNull (ex.InnerException, "#B3");
68 Assert.IsNotNull (ex.Message, "#B4");
69 Assert.IsNotNull (ex.ParamName, "#B5");
70 Assert.AreEqual ("localType", ex.ParamName, "#B6");
76 [ExpectedException (typeof (ArgumentException))]
77 public void DefineFilterBodyWithTypeNotNull ()
80 il_gen.BeginExceptionBlock ();
81 il_gen.EmitWriteLine ("in try");
82 il_gen.BeginExceptFilterBlock ();
83 il_gen.EmitWriteLine ("in filter head");
84 il_gen.BeginCatchBlock (typeof (Exception));
85 il_gen.EmitWriteLine ("in filter body");
86 il_gen.EndExceptionBlock ();
90 public void FilterAndCatchBlock ()
93 ILGenerator il = il_gen;
94 il.BeginExceptionBlock ();
95 il.BeginExceptFilterBlock ();
96 il.BeginCatchBlock (null);
97 il.BeginCatchBlock (typeof (SystemException));
101 [ExpectedException (typeof (InvalidOperationException))]
102 public void InvalidFilterBlock1 ()
104 DefineBasicMethod ();
105 ILGenerator il = il_gen;
106 il.BeginExceptionBlock ();
107 il.BeginExceptFilterBlock ();
108 il.EndExceptionBlock ();
112 public void ValidFilterBlock1 ()
114 DefineBasicMethod ();
115 ILGenerator il = il_gen;
116 il.BeginExceptionBlock ();
117 il.BeginExceptFilterBlock ();
118 il.BeginFaultBlock ();
119 il.EndExceptionBlock ();
123 public void ValidFilterBlock2 ()
125 DefineBasicMethod ();
126 ILGenerator il = il_gen;
127 il.BeginExceptionBlock ();
128 il.BeginExceptFilterBlock ();
129 il.BeginFinallyBlock ();
130 il.EndExceptionBlock ();
134 /// Try to emit something like that:
136 /// .method public static bool TestFilter (bool execute_handler)
138 /// .locals init(bool)
140 /// newobj instance void [mscorlib]System.Exception::.ctor()
158 /// It should return true if the handler has been executed
159 /// Otherwise, the exception should not be catched
161 void DefineTestFilterMethod ()
163 MethodBuilder mb = tb.DefineMethod("TestFilter",
164 MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type [] { typeof (bool) });
166 ConstructorInfo exCtor = typeof (Exception).GetConstructor (new Type [0]);
168 il_gen = mb.GetILGenerator ();
169 il_gen.DeclareLocal (typeof (bool));
170 Label quit = il_gen.DefineLabel ();
171 il_gen.BeginExceptionBlock ();
172 il_gen.Emit (OpCodes.Newobj, exCtor);
173 il_gen.Emit (OpCodes.Throw);
174 il_gen.BeginExceptFilterBlock ();
175 il_gen.Emit (OpCodes.Pop);
176 il_gen.Emit (OpCodes.Ldarg_0);
177 il_gen.BeginCatchBlock (null);
178 il_gen.Emit (OpCodes.Ldc_I4_1);
179 il_gen.Emit (OpCodes.Stloc_0);
180 il_gen.Emit (OpCodes.Leave, quit);
181 il_gen.EndExceptionBlock ();
182 il_gen.Emit (OpCodes.Ldc_I4_0);
183 il_gen.Emit (OpCodes.Stloc_0);
184 il_gen.MarkLabel (quit);
185 il_gen.Emit (OpCodes.Ldloc_0);
186 il_gen.Emit (OpCodes.Ret);
189 [Test] // Emit (OpCode, ConstructorInfo)
191 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
193 public void Emit3_Constructor_Null ()
195 DefineBasicMethod ();
197 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
199 } catch (ArgumentNullException ex) {
200 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
201 Assert.IsNull (ex.InnerException, "#3");
202 Assert.IsNotNull (ex.Message, "#4");
203 Assert.IsNotNull (ex.ParamName, "#5");
208 [Test] // Emit (OpCode, ConstructorInfo)
209 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
210 public void Emit3_Constructor_Null_MS ()
212 DefineBasicMethod ();
214 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
216 } catch (NullReferenceException) {
221 [Test] // Emit (OpCode, FieldInfo)
222 public void Emit5_Field_Null ()
224 DefineBasicMethod ();
226 il_gen.Emit (OpCodes.Ldsfld, (FieldInfo) null);
228 } catch (ArgumentNullException ex) {
229 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
230 Assert.IsNull (ex.InnerException, "#3");
231 Assert.IsNotNull (ex.Message, "#4");
232 Assert.IsNotNull (ex.ParamName, "#5");
236 [Test] // Emit (OpCode, Label [])
237 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
238 public void Emit10_Labels_Null ()
240 DefineBasicMethod ();
242 il_gen.Emit (OpCodes.Switch, (Label []) null);
244 } catch (ArgumentNullException ex) {
245 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
246 Assert.IsNull (ex.InnerException, "#3");
247 Assert.IsNotNull (ex.Message, "#4");
248 Assert.IsNotNull (ex.ParamName, "#5");
249 Assert.AreEqual ("labels", ex.ParamName, "#6");
254 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
255 public void Emit10_Labels_Null_MS ()
257 DefineBasicMethod ();
259 il_gen.Emit (OpCodes.Switch, (Label []) null);
261 } catch (NullReferenceException) {
265 [Test] // Emit (OpCode, LocalBuilder)
266 public void Emit11_Local_Null ()
268 DefineBasicMethod ();
270 il_gen.Emit (OpCodes.Switch, (LocalBuilder) null);
272 } catch (ArgumentNullException ex) {
273 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
274 Assert.IsNull (ex.InnerException, "#3");
275 Assert.IsNotNull (ex.Message, "#4");
276 Assert.IsNotNull (ex.ParamName, "#5");
277 Assert.AreEqual ("local", ex.ParamName, "#6");
281 [Test] // Emit (OpCode, MethodInfo)
282 public void Emit12_Method_Null ()
284 DefineBasicMethod ();
286 il_gen.Emit (OpCodes.Switch, (MethodInfo) null);
288 } catch (ArgumentNullException ex) {
289 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
290 Assert.IsNull (ex.InnerException, "#3");
291 Assert.IsNotNull (ex.Message, "#4");
292 Assert.IsNotNull (ex.ParamName, "#5");
293 Assert.AreEqual ("meth", ex.ParamName, "#6");
297 [Test] // Emit (OpCode, SignatureHelper)
298 public void Emit14_Signature_Null ()
300 DefineBasicMethod ();
302 il_gen.Emit (OpCodes.Switch, (SignatureHelper) null);
304 } catch (ArgumentNullException ex) {
305 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
306 Assert.IsNull (ex.InnerException, "#3");
307 Assert.IsNotNull (ex.Message, "#4");
308 Assert.IsNotNull (ex.ParamName, "#5");
312 [Test] // Emit (OpCode, String)
313 public void Emit16_String_Null ()
315 DefineBasicMethod ();
317 il_gen.Emit (OpCodes.Switch, (String) null);
319 } catch (ArgumentNullException ex) {
320 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
321 Assert.IsNull (ex.InnerException, "#3");
322 Assert.IsNotNull (ex.Message, "#4");
326 [Test] // Emit (OpCode, Type)
327 public void Emit16_Type_Null ()
329 DefineBasicMethod ();
331 il_gen.Emit (OpCodes.Switch, (Type) null);
333 } catch (ArgumentNullException ex) {
334 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
335 Assert.IsNull (ex.InnerException, "#3");
336 Assert.IsNotNull (ex.Message, "#4");
337 Assert.IsNotNull (ex.ParamName, "#5");
342 public void EmitCall_MethodInfo_Null ()
344 DefineBasicMethod ();
346 il_gen.EmitCall (OpCodes.Call, (MethodInfo) null, null);
348 } catch (ArgumentNullException ex) {
349 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
350 Assert.IsNull (ex.InnerException, "#3");
351 Assert.IsNotNull (ex.Message, "#4");
352 Assert.IsNotNull (ex.ParamName, "#5");
353 Assert.AreEqual ("methodInfo", ex.ParamName, "#6");
358 public void TestFilterEmittingWithHandlerExecution ()
360 DefineTestFilterMethod ();
361 Type dynt = tb.CreateType ();
363 MethodInfo tf = dynt.GetMethod ("TestFilter");
364 Assert.IsTrue ((bool) tf.Invoke (null, new object [] { true }));
368 delegate void FooFoo ();
375 public void TestEmitCalliWithNullReturnType ()
377 MethodBuilder mb = tb.DefineMethod ("F",
378 MethodAttributes.Public | MethodAttributes.Static, null, new Type [] { typeof (IntPtr) });
379 mb.SetImplementationFlags (MethodImplAttributes.NoInlining);
380 il_gen = mb.GetILGenerator ();
381 il_gen.Emit (OpCodes.Ldarg_0);
382 il_gen.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, null, Type.EmptyTypes);
383 il_gen.Emit (OpCodes.Ret);
385 Type dynt = tb.CreateType ();
386 dynt.GetMethod ("F", BindingFlags.Public | BindingFlags.Static).Invoke (
387 null, new object [] { Marshal.GetFunctionPointerForDelegate (new FooFoo (Foo)) });
394 public void TestEmitCallIgnoresOptionalArgsForNonVarargMethod ()
396 DefineBasicMethod ();
398 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
399 } catch (InvalidOperationException ex) {
405 public void TestEmitCallThrowsOnOptionalArgsForNonVarargMethod ()
407 DefineBasicMethod ();
409 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
411 } catch (InvalidOperationException ex) {
417 [ExpectedException (typeof (Exception))]
418 public void TestFilterEmittingWithoutHandlerExecution ()
420 DefineTestFilterMethod ();
421 Type dynt = tb.CreateType ();
423 MethodInfo tf = dynt.GetMethod ("TestFilter");
425 tf.Invoke (null, new object [] { false });
426 } catch (TargetInvocationException tie) {
427 throw tie.InnerException;
432 public void TestEmitLocalInfoWithNopOpCode ()
434 var method_builder = tb.DefineMethod ("linop", MethodAttributes.Public | MethodAttributes.Static, typeof (bool), Type.EmptyTypes);
435 il_gen = method_builder.GetILGenerator ();
437 var local = il_gen.DeclareLocal (typeof (int));
438 il_gen.Emit (OpCodes.Nop, local);
439 il_gen.Emit (OpCodes.Ldc_I4_1);
440 il_gen.Emit (OpCodes.Ret);
442 var type = tb.CreateType ();
443 var method = type.GetMethod ("linop");
445 Assert.IsNotNull (method);
446 Assert.IsTrue ((bool) method.Invoke (null, new object [0]));
450 [ExpectedException (typeof (ArgumentException))]
451 public void LdObjByRef () {
452 DefineBasicMethod ();
453 ILGenerator ig = il_gen;
455 ig.Emit (OpCodes.Ldtoken, typeof (int).MakeByRefType ());
461 public void GtdEncodingAsOpenInstance () {
462 AssemblyName asmname = new AssemblyName ();
463 asmname.Name = "test";
464 AssemblyBuilder asmbuild = Thread.GetDomain ().DefineDynamicAssembly (asmname, AssemblyBuilderAccess.RunAndSave);
465 ModuleBuilder modbuild = asmbuild.DefineDynamicModule ("modulename", "test.exe");
467 TypeBuilder myType = modbuild.DefineType ("Sample", TypeAttributes.Public);
469 string[] typeParamNames = { "TFirst" };
470 myType.DefineGenericParameters (typeParamNames);
472 var nested = myType.DefineNestedType ("nested");
473 nested.DefineGenericParameters (typeParamNames);
475 var m = myType.DefineMethod ("test", MethodAttributes.Public);
476 m.SetParameters (myType);
478 var ilgen = m.GetILGenerator ();
479 ilgen.Emit (OpCodes.Castclass, nested);
480 ilgen.Emit (OpCodes.Castclass, typeof (List<>));
481 ilgen.Emit (OpCodes.Ldtoken, nested);
482 ilgen.Emit (OpCodes.Ldtoken, typeof (List<>));
484 var baked = myType.CreateType ();
485 nested.CreateType ();
487 var method = baked.GetMethod ("test");
488 var body = method.GetMethodBody ();
495 The first two tokens must be to typespecs and the last two to typeref/typedef*/
496 var il = body.GetILAsByteArray ();
498 Assert.AreEqual (20, il.Length, "#1");
499 Assert.AreEqual (0x1B, il [4]); //typespec
500 Assert.AreEqual (0x1B, il [9]); //typespec
501 Assert.AreEqual (0x02, il [14]); //typedef
502 Assert.AreEqual (0x01, il [19]); //typeref