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");
62 il_gen
.DeclareLocal (null, false);
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");
74 [ExpectedException (typeof (ArgumentException
))]
75 public void DefineFilterBodyWithTypeNotNull ()
78 il_gen
.BeginExceptionBlock ();
79 il_gen
.EmitWriteLine ("in try");
80 il_gen
.BeginExceptFilterBlock ();
81 il_gen
.EmitWriteLine ("in filter head");
82 il_gen
.BeginCatchBlock (typeof (Exception
));
83 il_gen
.EmitWriteLine ("in filter body");
84 il_gen
.EndExceptionBlock ();
88 public void FilterAndCatchBlock ()
91 ILGenerator il
= il_gen
;
92 il
.BeginExceptionBlock ();
93 il
.BeginExceptFilterBlock ();
94 il
.BeginCatchBlock (null);
95 il
.BeginCatchBlock (typeof (SystemException
));
99 [ExpectedException (typeof (InvalidOperationException
))]
100 public void InvalidFilterBlock1 ()
102 DefineBasicMethod ();
103 ILGenerator il
= il_gen
;
104 il
.BeginExceptionBlock ();
105 il
.BeginExceptFilterBlock ();
106 il
.EndExceptionBlock ();
110 public void ValidFilterBlock1 ()
112 DefineBasicMethod ();
113 ILGenerator il
= il_gen
;
114 il
.BeginExceptionBlock ();
115 il
.BeginExceptFilterBlock ();
116 il
.BeginFaultBlock ();
117 il
.EndExceptionBlock ();
121 public void ValidFilterBlock2 ()
123 DefineBasicMethod ();
124 ILGenerator il
= il_gen
;
125 il
.BeginExceptionBlock ();
126 il
.BeginExceptFilterBlock ();
127 il
.BeginFinallyBlock ();
128 il
.EndExceptionBlock ();
132 /// Try to emit something like that:
134 /// .method public static bool TestFilter (bool execute_handler)
136 /// .locals init(bool)
138 /// newobj instance void [mscorlib]System.Exception::.ctor()
156 /// It should return true if the handler has been executed
157 /// Otherwise, the exception should not be catched
159 void DefineTestFilterMethod ()
161 MethodBuilder mb
= tb
.DefineMethod("TestFilter",
162 MethodAttributes
.Public
| MethodAttributes
.Static
, typeof(bool), new Type
[] { typeof (bool) }
);
164 ConstructorInfo exCtor
= typeof (Exception
).GetConstructor (new Type
[0]);
166 il_gen
= mb
.GetILGenerator ();
167 il_gen
.DeclareLocal (typeof (bool));
168 Label quit
= il_gen
.DefineLabel ();
169 il_gen
.BeginExceptionBlock ();
170 il_gen
.Emit (OpCodes
.Newobj
, exCtor
);
171 il_gen
.Emit (OpCodes
.Throw
);
172 il_gen
.BeginExceptFilterBlock ();
173 il_gen
.Emit (OpCodes
.Pop
);
174 il_gen
.Emit (OpCodes
.Ldarg_0
);
175 il_gen
.BeginCatchBlock (null);
176 il_gen
.Emit (OpCodes
.Ldc_I4_1
);
177 il_gen
.Emit (OpCodes
.Stloc_0
);
178 il_gen
.Emit (OpCodes
.Leave
, quit
);
179 il_gen
.EndExceptionBlock ();
180 il_gen
.Emit (OpCodes
.Ldc_I4_0
);
181 il_gen
.Emit (OpCodes
.Stloc_0
);
182 il_gen
.MarkLabel (quit
);
183 il_gen
.Emit (OpCodes
.Ldloc_0
);
184 il_gen
.Emit (OpCodes
.Ret
);
187 [Test
] // Emit (OpCode, ConstructorInfo)
188 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
189 public void Emit3_Constructor_Null ()
191 DefineBasicMethod ();
193 il_gen
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) null);
195 } catch (ArgumentNullException ex
) {
196 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
197 Assert
.IsNull (ex
.InnerException
, "#3");
198 Assert
.IsNotNull (ex
.Message
, "#4");
199 Assert
.IsNotNull (ex
.ParamName
, "#5");
203 [Test
] // Emit (OpCode, ConstructorInfo)
204 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
205 public void Emit3_Constructor_Null_MS ()
207 DefineBasicMethod ();
209 il_gen
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) null);
211 } catch (NullReferenceException
) {
215 [Test
] // Emit (OpCode, FieldInfo)
216 public void Emit5_Field_Null ()
218 DefineBasicMethod ();
220 il_gen
.Emit (OpCodes
.Ldsfld
, (FieldInfo
) null);
222 } catch (ArgumentNullException ex
) {
223 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
224 Assert
.IsNull (ex
.InnerException
, "#3");
225 Assert
.IsNotNull (ex
.Message
, "#4");
226 Assert
.IsNotNull (ex
.ParamName
, "#5");
230 [Test
] // Emit (OpCode, Label [])
231 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
232 public void Emit10_Labels_Null ()
234 DefineBasicMethod ();
236 il_gen
.Emit (OpCodes
.Switch
, (Label
[]) null);
238 } catch (ArgumentNullException ex
) {
239 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
240 Assert
.IsNull (ex
.InnerException
, "#3");
241 Assert
.IsNotNull (ex
.Message
, "#4");
242 Assert
.IsNotNull (ex
.ParamName
, "#5");
243 Assert
.AreEqual ("labels", ex
.ParamName
, "#6");
248 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
249 public void Emit10_Labels_Null_MS ()
251 DefineBasicMethod ();
253 il_gen
.Emit (OpCodes
.Switch
, (Label
[]) null);
255 } catch (NullReferenceException
) {
259 [Test
] // Emit (OpCode, LocalBuilder)
260 public void Emit11_Local_Null ()
262 DefineBasicMethod ();
264 il_gen
.Emit (OpCodes
.Switch
, (LocalBuilder
) null);
266 } catch (ArgumentNullException ex
) {
267 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
268 Assert
.IsNull (ex
.InnerException
, "#3");
269 Assert
.IsNotNull (ex
.Message
, "#4");
270 Assert
.IsNotNull (ex
.ParamName
, "#5");
271 Assert
.AreEqual ("local", ex
.ParamName
, "#6");
275 [Test
] // Emit (OpCode, MethodInfo)
276 public void Emit12_Method_Null ()
278 DefineBasicMethod ();
280 il_gen
.Emit (OpCodes
.Switch
, (MethodInfo
) null);
282 } catch (ArgumentNullException ex
) {
283 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
284 Assert
.IsNull (ex
.InnerException
, "#3");
285 Assert
.IsNotNull (ex
.Message
, "#4");
286 Assert
.IsNotNull (ex
.ParamName
, "#5");
287 Assert
.AreEqual ("meth", ex
.ParamName
, "#6");
291 [Test
] // Emit (OpCode, SignatureHelper)
292 public void Emit14_Signature_Null ()
294 DefineBasicMethod ();
296 il_gen
.Emit (OpCodes
.Switch
, (SignatureHelper
) null);
298 } catch (ArgumentNullException ex
) {
299 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
300 Assert
.IsNull (ex
.InnerException
, "#3");
301 Assert
.IsNotNull (ex
.Message
, "#4");
302 Assert
.IsNotNull (ex
.ParamName
, "#5");
306 [Test
] // Emit (OpCode, String)
307 public void Emit16_String_Null ()
309 DefineBasicMethod ();
311 il_gen
.Emit (OpCodes
.Switch
, (String
) null);
313 } catch (ArgumentNullException ex
) {
314 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
315 Assert
.IsNull (ex
.InnerException
, "#3");
316 Assert
.IsNotNull (ex
.Message
, "#4");
320 [Test
] // Emit (OpCode, Type)
321 public void Emit16_Type_Null ()
323 DefineBasicMethod ();
325 il_gen
.Emit (OpCodes
.Switch
, (Type
) null);
327 } catch (ArgumentNullException ex
) {
328 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
329 Assert
.IsNull (ex
.InnerException
, "#3");
330 Assert
.IsNotNull (ex
.Message
, "#4");
331 Assert
.IsNotNull (ex
.ParamName
, "#5");
336 public void EmitCall_MethodInfo_Null ()
338 DefineBasicMethod ();
340 il_gen
.EmitCall (OpCodes
.Call
, (MethodInfo
) null, null);
342 } catch (ArgumentNullException ex
) {
343 Assert
.AreEqual (typeof (ArgumentNullException
), ex
.GetType (), "#2");
344 Assert
.IsNull (ex
.InnerException
, "#3");
345 Assert
.IsNotNull (ex
.Message
, "#4");
346 Assert
.IsNotNull (ex
.ParamName
, "#5");
347 Assert
.AreEqual ("methodInfo", ex
.ParamName
, "#6");
352 public void TestFilterEmittingWithHandlerExecution ()
354 DefineTestFilterMethod ();
355 Type dynt
= tb
.CreateType ();
357 MethodInfo tf
= dynt
.GetMethod ("TestFilter");
358 Assert
.IsTrue ((bool) tf
.Invoke (null, new object [] { true }
));
361 delegate void FooFoo ();
368 public void TestEmitCalliWithNullReturnType ()
370 MethodBuilder mb
= tb
.DefineMethod ("F",
371 MethodAttributes
.Public
| MethodAttributes
.Static
, null, new Type
[] { typeof (IntPtr) }
);
372 mb
.SetImplementationFlags (MethodImplAttributes
.NoInlining
);
373 il_gen
= mb
.GetILGenerator ();
374 il_gen
.Emit (OpCodes
.Ldarg_0
);
375 il_gen
.EmitCalli (OpCodes
.Calli
, CallingConvention
.StdCall
, null, Type
.EmptyTypes
);
376 il_gen
.Emit (OpCodes
.Ret
);
378 Type dynt
= tb
.CreateType ();
379 dynt
.GetMethod ("F", BindingFlags
.Public
| BindingFlags
.Static
).Invoke (
380 null, new object [] { Marshal.GetFunctionPointerForDelegate (new FooFoo (Foo)) }
);
385 public void TestEmitCallIgnoresOptionalArgsForNonVarargMethod ()
387 DefineBasicMethod ();
389 il_gen
.EmitCall (OpCodes
.Call
, typeof (object).GetMethod ("GetHashCode"), new Type
[] { typeof (string) }
);
390 } catch (InvalidOperationException ex
) {
396 [ExpectedException (typeof (Exception
))]
397 public void TestFilterEmittingWithoutHandlerExecution ()
399 DefineTestFilterMethod ();
400 Type dynt
= tb
.CreateType ();
402 MethodInfo tf
= dynt
.GetMethod ("TestFilter");
404 tf
.Invoke (null, new object [] { false }
);
405 } catch (TargetInvocationException tie
) {
406 throw tie
.InnerException
;
411 public void TestEmitLocalInfoWithNopOpCode ()
413 var method_builder
= tb
.DefineMethod ("linop", MethodAttributes
.Public
| MethodAttributes
.Static
, typeof (bool), Type
.EmptyTypes
);
414 il_gen
= method_builder
.GetILGenerator ();
416 var local
= il_gen
.DeclareLocal (typeof (int));
417 il_gen
.Emit (OpCodes
.Nop
, local
);
418 il_gen
.Emit (OpCodes
.Ldc_I4_1
);
419 il_gen
.Emit (OpCodes
.Ret
);
421 var type
= tb
.CreateType ();
422 var method
= type
.GetMethod ("linop");
424 Assert
.IsNotNull (method
);
425 Assert
.IsTrue ((bool) method
.Invoke (null, new object [0]));
429 [ExpectedException (typeof (ArgumentException
))]
430 public void LdObjByRef () {
431 DefineBasicMethod ();
432 ILGenerator ig
= il_gen
;
434 ig
.Emit (OpCodes
.Ldtoken
, typeof (int).MakeByRefType ());
440 public void GtdEncodingAsOpenInstance () {
441 AssemblyName asmname
= new AssemblyName ();
442 asmname
.Name
= "test";
443 AssemblyBuilder asmbuild
= Thread
.GetDomain ().DefineDynamicAssembly (asmname
, AssemblyBuilderAccess
.RunAndSave
);
444 ModuleBuilder modbuild
= asmbuild
.DefineDynamicModule ("modulename", "test.exe");
446 TypeBuilder myType
= modbuild
.DefineType ("Sample", TypeAttributes
.Public
);
448 string[] typeParamNames
= { "TFirst" }
;
449 myType
.DefineGenericParameters (typeParamNames
);
451 var nested
= myType
.DefineNestedType ("nested");
452 nested
.DefineGenericParameters (typeParamNames
);
454 var m
= myType
.DefineMethod ("test", MethodAttributes
.Public
);
455 m
.SetParameters (myType
);
457 var ilgen
= m
.GetILGenerator ();
458 ilgen
.Emit (OpCodes
.Castclass
, nested
);
459 ilgen
.Emit (OpCodes
.Castclass
, typeof (List
<>));
460 ilgen
.Emit (OpCodes
.Ldtoken
, nested
);
461 ilgen
.Emit (OpCodes
.Ldtoken
, typeof (List
<>));
463 var baked
= myType
.CreateType ();
464 nested
.CreateType ();
466 var method
= baked
.GetMethod ("test");
467 var body
= method
.GetMethodBody ();
474 The first two tokens must be to typespecs and the last two to typeref/typedef*/
475 var il
= body
.GetILAsByteArray ();
477 Assert
.AreEqual (20, il
.Length
, "#1");
478 Assert
.AreEqual (0x1B, il
[4]); //typespec
479 Assert
.AreEqual (0x1B, il
[9]); //typespec
480 Assert
.AreEqual (0x02, il
[14]); //typedef
481 Assert
.AreEqual (0x01, il
[19]); //typeref
485 public void MethodRefTokenSame () {
486 // Get the same non-virtual method from a base and a derived type so
487 // that the MemberInfo:DeclaredType differs but the tokens are the same.
489 // Regression test for bugzilla #59364
491 DefineBasicMethod ();
493 var m1
= typeof (object).GetMethod ("GetType");
494 var m2
= typeof (string).GetMethod ("GetType");
496 var value_getter
= typeof (RuntimeMethodHandle
).GetProperty ("Value").GetMethod
;
500 var loc
= il
.DeclareLocal (typeof (RuntimeMethodHandle
));
502 // return ((int)(RuntimeMethodHandle (m1).Value == RuntimeMethodHandle (m2).Value)).ToString ()
503 il
.Emit (OpCodes
.Ldtoken
, m1
);
504 il
.Emit (OpCodes
.Stloc
, loc
);
505 il
.Emit (OpCodes
.Ldloca
, loc
);
506 il
.Emit (OpCodes
.Call
, value_getter
);
507 il
.Emit (OpCodes
.Ldtoken
, m2
);
508 il
.Emit (OpCodes
.Stloc
, loc
);
509 il
.Emit (OpCodes
.Ldloca
, loc
);
510 il
.Emit (OpCodes
.Call
, value_getter
);
511 il
.Emit (OpCodes
.Ceq
);
512 il
.Emit (OpCodes
.Box
, typeof (Int32
));
513 il
.Emit (OpCodes
.Callvirt
, typeof (object).GetMethod ("ToString"));
514 il
.Emit (OpCodes
.Ret
);
516 var baked
= tb
.CreateType ();
518 var x
= Activator
.CreateInstance (baked
);
519 var m
= baked
.GetMethod ("F");
521 var s
= m
.Invoke (x
, null);
523 Assert
.AreEqual ("1", s
);
527 public class Base
<T
> {
533 public class Derived
: Base
<string> {
537 public void FieldRefTokenSame () {
538 DefineBasicMethod ();
540 // Get the same field from a base and a derived type so hat
541 // the MemberInfo:DeclaredType differs but the tokens are the same.
543 // Regression test for bugzilla #59364
545 var f1
= typeof (Base
<string>).GetField ("x");
546 var f2
= typeof (Derived
).GetField ("x");
548 var value_getter
= typeof (RuntimeFieldHandle
).GetProperty("Value").GetMethod
;
552 var loc
= il
.DeclareLocal (typeof (RuntimeFieldHandle
));
554 il
.Emit (OpCodes
.Ldtoken
, f1
);
555 il
.Emit (OpCodes
.Stloc
, loc
);
556 il
.Emit (OpCodes
.Ldloca
, loc
);
557 il
.Emit (OpCodes
.Call
, value_getter
);
558 il
.Emit (OpCodes
.Ldtoken
, f2
);
559 il
.Emit (OpCodes
.Stloc
, loc
);
560 il
.Emit (OpCodes
.Ldloca
, loc
);
561 il
.Emit (OpCodes
.Call
, value_getter
);
562 il
.Emit (OpCodes
.Ceq
);
563 il
.Emit (OpCodes
.Box
, typeof (Int32
));
564 il
.Emit (OpCodes
.Callvirt
, typeof (object).GetMethod ("ToString"));
565 il
.Emit (OpCodes
.Ret
);
567 var baked
= tb
.CreateType ();
569 var x
= Activator
.CreateInstance (baked
);
570 var m
= baked
.GetMethod ("F");
572 var s
= m
.Invoke (x
, null);
574 Assert
.AreEqual ("1", s
);
578 public void MethodSpecTokenSame () {
579 DefineBasicMethod ();
580 // Get the same method from a base generic instance and
581 // a type derived from it so that the
582 // MemberInfo:DeclaredType differs but the tokens are
585 // Regression test for bugzilla #60233
587 var m1
= typeof (Base
<string>).GetMethod ("M");
588 var m2
= typeof (Derived
).GetMethod ("M");
592 var loc
= il
.DeclareLocal (typeof (Derived
));
594 il
.Emit (OpCodes
.Newobj
, typeof (Derived
).GetConstructor(new Type
[]{}));
595 il
.Emit (OpCodes
.Stloc
, loc
);
596 il
.Emit (OpCodes
.Ldloc
, loc
);
597 il
.Emit (OpCodes
.Call
, m1
);
598 il
.Emit (OpCodes
.Ldloc
, loc
);
599 il
.Emit (OpCodes
.Call
, m2
);
600 il
.Emit (OpCodes
.Ldstr
, "1");
601 il
.Emit (OpCodes
.Ret
);
603 var baked
= tb
.CreateType ();
605 var x
= Activator
.CreateInstance (baked
);
606 var m
= baked
.GetMethod ("F");
608 var s
= m
.Invoke (x
, null);
610 Assert
.AreEqual ("1", s
);