[sre] Register a canonical reflected method for a methodspec token. (Fixes #60233...
[mono-project.git] / mcs / class / corlib / Test / System.Reflection.Emit / ILGeneratorTest.cs
blobb31ed2e117ed6e5ed840415c6793650648e37ca4
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
8 using System;
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
19 [TestFixture]
20 public class ILGeneratorTest
22 TypeBuilder tb;
23 ILGenerator il_gen;
25 void DefineBasicMethod ()
27 MethodBuilder mb = tb.DefineMethod("F",
28 MethodAttributes.Public, typeof(string), null);
29 il_gen = mb.GetILGenerator ();
32 [SetUp]
33 public void SetUp ()
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);
45 [Test]
46 public void DeclareLocal_LocalType_Null ()
48 DefineBasicMethod ();
50 try {
51 il_gen.DeclareLocal (null);
52 Assert.Fail ("#A1");
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");
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");
73 [Test]
74 [ExpectedException (typeof (ArgumentException))]
75 public void DefineFilterBodyWithTypeNotNull ()
77 DefineBasicMethod ();
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 ();
87 [Test] // bug #81431
88 public void FilterAndCatchBlock ()
90 DefineBasicMethod ();
91 ILGenerator il = il_gen;
92 il.BeginExceptionBlock ();
93 il.BeginExceptFilterBlock ();
94 il.BeginCatchBlock (null);
95 il.BeginCatchBlock (typeof (SystemException));
98 [Test]
99 [ExpectedException (typeof (InvalidOperationException))]
100 public void InvalidFilterBlock1 ()
102 DefineBasicMethod ();
103 ILGenerator il = il_gen;
104 il.BeginExceptionBlock ();
105 il.BeginExceptFilterBlock ();
106 il.EndExceptionBlock ();
109 [Test]
110 public void ValidFilterBlock1 ()
112 DefineBasicMethod ();
113 ILGenerator il = il_gen;
114 il.BeginExceptionBlock ();
115 il.BeginExceptFilterBlock ();
116 il.BeginFaultBlock ();
117 il.EndExceptionBlock ();
120 [Test]
121 public void ValidFilterBlock2 ()
123 DefineBasicMethod ();
124 ILGenerator il = il_gen;
125 il.BeginExceptionBlock ();
126 il.BeginExceptFilterBlock ();
127 il.BeginFinallyBlock ();
128 il.EndExceptionBlock ();
131 /// <summary>
132 /// Try to emit something like that:
134 /// .method public static bool TestFilter (bool execute_handler)
135 /// {
136 /// .locals init(bool)
137 /// try {
138 /// newobj instance void [mscorlib]System.Exception::.ctor()
139 /// throw
140 /// } filter {
141 /// pop
142 /// ldarg.0
143 /// endfilter
144 /// } {
145 /// ldc.i4.1
146 /// stloc.0
147 /// leave quit
148 /// }
149 /// ldc.i4.0
150 /// stloc.0
151 /// quit:
152 /// ldloc.0
153 /// ret
154 /// }
156 /// It should return true if the handler has been executed
157 /// Otherwise, the exception should not be catched
158 /// </summary>
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 ();
192 try {
193 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
194 Assert.Fail ("#1");
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 ();
208 try {
209 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
210 Assert.Fail ("#1");
211 } catch (NullReferenceException) {
215 [Test] // Emit (OpCode, FieldInfo)
216 public void Emit5_Field_Null ()
218 DefineBasicMethod ();
219 try {
220 il_gen.Emit (OpCodes.Ldsfld, (FieldInfo) null);
221 Assert.Fail ("#1");
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 ();
235 try {
236 il_gen.Emit (OpCodes.Switch, (Label []) null);
237 Assert.Fail ("#1");
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");
247 [Test]
248 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
249 public void Emit10_Labels_Null_MS ()
251 DefineBasicMethod ();
252 try {
253 il_gen.Emit (OpCodes.Switch, (Label []) null);
254 Assert.Fail ("#1");
255 } catch (NullReferenceException) {
259 [Test] // Emit (OpCode, LocalBuilder)
260 public void Emit11_Local_Null ()
262 DefineBasicMethod ();
263 try {
264 il_gen.Emit (OpCodes.Switch, (LocalBuilder) null);
265 Assert.Fail ("#1");
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 ();
279 try {
280 il_gen.Emit (OpCodes.Switch, (MethodInfo) null);
281 Assert.Fail ("#1");
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 ();
295 try {
296 il_gen.Emit (OpCodes.Switch, (SignatureHelper) null);
297 Assert.Fail ("#1");
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 ();
310 try {
311 il_gen.Emit (OpCodes.Switch, (String) null);
312 Assert.Fail ("#1");
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 ();
324 try {
325 il_gen.Emit (OpCodes.Switch, (Type) null);
326 Assert.Fail ("#1");
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");
335 [Test]
336 public void EmitCall_MethodInfo_Null ()
338 DefineBasicMethod ();
339 try {
340 il_gen.EmitCall (OpCodes.Call, (MethodInfo) null, null);
341 Assert.Fail ("#1");
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");
351 [Test]
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 ();
363 static void Foo ()
367 [Test]
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)) });
383 //Test for #509131
384 [Test]
385 public void TestEmitCallIgnoresOptionalArgsForNonVarargMethod ()
387 DefineBasicMethod ();
388 try {
389 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
390 } catch (InvalidOperationException ex) {
391 Assert.Fail ("#1");
395 [Test]
396 [ExpectedException (typeof (Exception))]
397 public void TestFilterEmittingWithoutHandlerExecution ()
399 DefineTestFilterMethod ();
400 Type dynt = tb.CreateType ();
402 MethodInfo tf = dynt.GetMethod ("TestFilter");
403 try {
404 tf.Invoke (null, new object [] { false });
405 } catch (TargetInvocationException tie) {
406 throw tie.InnerException;
410 [Test]
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]));
428 [Test]
429 [ExpectedException (typeof (ArgumentException))]
430 public void LdObjByRef () {
431 DefineBasicMethod ();
432 ILGenerator ig = il_gen;
434 ig.Emit (OpCodes.Ldtoken, typeof (int).MakeByRefType ());
439 [Test] //bug #649017
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 ();
469 The resulting IL is:
470 [ 0] 0x74 token:uint
471 [ 5] 0x74 token:uint
472 [10] 0xd0 token:uint
473 [10] 0xd0 token:uint
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
484 [Test]
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;
498 var il = il_gen;
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> {
528 public int x;
530 public void M () { }
533 public class Derived : Base<string> {
536 [Test]
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;
550 var il = il_gen;
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);
577 [Test]
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
583 // the same.
585 // Regression test for bugzilla #60233
587 var m1 = typeof (Base<string>).GetMethod ("M");
588 var m2 = typeof (Derived).GetMethod ("M");
590 var il = il_gen;
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);