[tests] SRE check that a memberref token is emitted for a gtd
[mono-project.git] / mcs / class / corlib / Test / System.Reflection.Emit / ILGeneratorTest.cs
blob07b8032c6c3723860caf039289607e7e1e8c2fa1
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 ModuleBuilder modulebuilder;
23 TypeBuilder tb;
24 ILGenerator il_gen;
26 void DefineBasicMethod ()
28 MethodBuilder mb = tb.DefineMethod("F",
29 MethodAttributes.Public, typeof(string), null);
30 il_gen = mb.GetILGenerator ();
33 [SetUp]
34 public void SetUp ()
36 AssemblyName assemblyName = new AssemblyName ();
37 assemblyName.Name = "MonoTests.System.Reflection.Emit.ILGeneratorTest";
39 AssemblyBuilder assembly = Thread.GetDomain ().DefineDynamicAssembly (
40 assemblyName, AssemblyBuilderAccess.Run);
42 modulebuilder = assembly.DefineDynamicModule ("module1");
43 tb = modulebuilder.DefineType ("T", TypeAttributes.Public);
46 [Test]
47 public void DeclareLocal_LocalType_Null ()
49 DefineBasicMethod ();
51 try {
52 il_gen.DeclareLocal (null);
53 Assert.Fail ("#A1");
54 } catch (ArgumentNullException ex) {
55 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#A2");
56 Assert.IsNull (ex.InnerException, "#A3");
57 Assert.IsNotNull (ex.Message, "#A4");
58 Assert.IsNotNull (ex.ParamName, "#A5");
59 Assert.AreEqual ("localType", ex.ParamName, "#A");
62 try {
63 il_gen.DeclareLocal (null, false);
64 Assert.Fail ("#B1");
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");
74 [Test]
75 [ExpectedException (typeof (ArgumentException))]
76 public void DefineFilterBodyWithTypeNotNull ()
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 ();
88 [Test] // bug #81431
89 public void FilterAndCatchBlock ()
91 DefineBasicMethod ();
92 ILGenerator il = il_gen;
93 il.BeginExceptionBlock ();
94 il.BeginExceptFilterBlock ();
95 il.BeginCatchBlock (null);
96 il.BeginCatchBlock (typeof (SystemException));
99 [Test]
100 [ExpectedException (typeof (InvalidOperationException))]
101 public void InvalidFilterBlock1 ()
103 DefineBasicMethod ();
104 ILGenerator il = il_gen;
105 il.BeginExceptionBlock ();
106 il.BeginExceptFilterBlock ();
107 il.EndExceptionBlock ();
110 [Test]
111 public void ValidFilterBlock1 ()
113 DefineBasicMethod ();
114 ILGenerator il = il_gen;
115 il.BeginExceptionBlock ();
116 il.BeginExceptFilterBlock ();
117 il.BeginFaultBlock ();
118 il.EndExceptionBlock ();
121 [Test]
122 public void ValidFilterBlock2 ()
124 DefineBasicMethod ();
125 ILGenerator il = il_gen;
126 il.BeginExceptionBlock ();
127 il.BeginExceptFilterBlock ();
128 il.BeginFinallyBlock ();
129 il.EndExceptionBlock ();
132 /// <summary>
133 /// Try to emit something like that:
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 /// }
157 /// It should return true if the handler has been executed
158 /// Otherwise, the exception should not be catched
159 /// </summary>
160 void DefineTestFilterMethod ()
162 MethodBuilder mb = tb.DefineMethod("TestFilter",
163 MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type [] { typeof (bool) });
165 ConstructorInfo exCtor = typeof (Exception).GetConstructor (new Type [0]);
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);
188 [Test] // Emit (OpCode, ConstructorInfo)
189 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
190 public void Emit3_Constructor_Null ()
192 DefineBasicMethod ();
193 try {
194 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
195 Assert.Fail ("#1");
196 } catch (ArgumentNullException ex) {
197 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
198 Assert.IsNull (ex.InnerException, "#3");
199 Assert.IsNotNull (ex.Message, "#4");
200 Assert.IsNotNull (ex.ParamName, "#5");
204 [Test] // Emit (OpCode, ConstructorInfo)
205 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
206 public void Emit3_Constructor_Null_MS ()
208 DefineBasicMethod ();
209 try {
210 il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
211 Assert.Fail ("#1");
212 } catch (NullReferenceException) {
216 [Test] // Emit (OpCode, FieldInfo)
217 public void Emit5_Field_Null ()
219 DefineBasicMethod ();
220 try {
221 il_gen.Emit (OpCodes.Ldsfld, (FieldInfo) null);
222 Assert.Fail ("#1");
223 } catch (ArgumentNullException ex) {
224 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
225 Assert.IsNull (ex.InnerException, "#3");
226 Assert.IsNotNull (ex.Message, "#4");
227 Assert.IsNotNull (ex.ParamName, "#5");
231 [Test] // Emit (OpCode, Label [])
232 [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
233 public void Emit10_Labels_Null ()
235 DefineBasicMethod ();
236 try {
237 il_gen.Emit (OpCodes.Switch, (Label []) null);
238 Assert.Fail ("#1");
239 } catch (ArgumentNullException ex) {
240 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
241 Assert.IsNull (ex.InnerException, "#3");
242 Assert.IsNotNull (ex.Message, "#4");
243 Assert.IsNotNull (ex.ParamName, "#5");
244 Assert.AreEqual ("labels", ex.ParamName, "#6");
248 [Test]
249 [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
250 public void Emit10_Labels_Null_MS ()
252 DefineBasicMethod ();
253 try {
254 il_gen.Emit (OpCodes.Switch, (Label []) null);
255 Assert.Fail ("#1");
256 } catch (NullReferenceException) {
260 [Test] // Emit (OpCode, LocalBuilder)
261 public void Emit11_Local_Null ()
263 DefineBasicMethod ();
264 try {
265 il_gen.Emit (OpCodes.Switch, (LocalBuilder) null);
266 Assert.Fail ("#1");
267 } catch (ArgumentNullException ex) {
268 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
269 Assert.IsNull (ex.InnerException, "#3");
270 Assert.IsNotNull (ex.Message, "#4");
271 Assert.IsNotNull (ex.ParamName, "#5");
272 Assert.AreEqual ("local", ex.ParamName, "#6");
276 [Test] // Emit (OpCode, MethodInfo)
277 public void Emit12_Method_Null ()
279 DefineBasicMethod ();
280 try {
281 il_gen.Emit (OpCodes.Switch, (MethodInfo) null);
282 Assert.Fail ("#1");
283 } catch (ArgumentNullException ex) {
284 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
285 Assert.IsNull (ex.InnerException, "#3");
286 Assert.IsNotNull (ex.Message, "#4");
287 Assert.IsNotNull (ex.ParamName, "#5");
288 Assert.AreEqual ("meth", ex.ParamName, "#6");
292 [Test] // Emit (OpCode, SignatureHelper)
293 public void Emit14_Signature_Null ()
295 DefineBasicMethod ();
296 try {
297 il_gen.Emit (OpCodes.Switch, (SignatureHelper) null);
298 Assert.Fail ("#1");
299 } catch (ArgumentNullException ex) {
300 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
301 Assert.IsNull (ex.InnerException, "#3");
302 Assert.IsNotNull (ex.Message, "#4");
303 Assert.IsNotNull (ex.ParamName, "#5");
307 [Test] // Emit (OpCode, String)
308 public void Emit16_String_Null ()
310 DefineBasicMethod ();
311 try {
312 il_gen.Emit (OpCodes.Switch, (String) null);
313 Assert.Fail ("#1");
314 } catch (ArgumentNullException ex) {
315 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
316 Assert.IsNull (ex.InnerException, "#3");
317 Assert.IsNotNull (ex.Message, "#4");
321 [Test] // Emit (OpCode, Type)
322 public void Emit16_Type_Null ()
324 DefineBasicMethod ();
325 try {
326 il_gen.Emit (OpCodes.Switch, (Type) null);
327 Assert.Fail ("#1");
328 } catch (ArgumentNullException ex) {
329 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
330 Assert.IsNull (ex.InnerException, "#3");
331 Assert.IsNotNull (ex.Message, "#4");
332 Assert.IsNotNull (ex.ParamName, "#5");
336 [Test]
337 public void EmitCall_MethodInfo_Null ()
339 DefineBasicMethod ();
340 try {
341 il_gen.EmitCall (OpCodes.Call, (MethodInfo) null, null);
342 Assert.Fail ("#1");
343 } catch (ArgumentNullException ex) {
344 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
345 Assert.IsNull (ex.InnerException, "#3");
346 Assert.IsNotNull (ex.Message, "#4");
347 Assert.IsNotNull (ex.ParamName, "#5");
348 Assert.AreEqual ("methodInfo", ex.ParamName, "#6");
352 [Test]
353 public void TestFilterEmittingWithHandlerExecution ()
355 DefineTestFilterMethod ();
356 Type dynt = tb.CreateType ();
358 MethodInfo tf = dynt.GetMethod ("TestFilter");
359 Assert.IsTrue ((bool) tf.Invoke (null, new object [] { true }));
362 delegate void FooFoo ();
364 static void Foo ()
368 [Test]
369 public void TestEmitCalliWithNullReturnType ()
371 MethodBuilder mb = tb.DefineMethod ("F",
372 MethodAttributes.Public | MethodAttributes.Static, null, new Type [] { typeof (IntPtr) });
373 mb.SetImplementationFlags (MethodImplAttributes.NoInlining);
374 il_gen = mb.GetILGenerator ();
375 il_gen.Emit (OpCodes.Ldarg_0);
376 il_gen.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, null, Type.EmptyTypes);
377 il_gen.Emit (OpCodes.Ret);
379 Type dynt = tb.CreateType ();
380 dynt.GetMethod ("F", BindingFlags.Public | BindingFlags.Static).Invoke (
381 null, new object [] { Marshal.GetFunctionPointerForDelegate (new FooFoo (Foo)) });
384 //Test for #509131
385 [Test]
386 public void TestEmitCallIgnoresOptionalArgsForNonVarargMethod ()
388 DefineBasicMethod ();
389 try {
390 il_gen.EmitCall (OpCodes.Call, typeof (object).GetMethod ("GetHashCode"), new Type[] { typeof (string) });
391 } catch (InvalidOperationException ex) {
392 Assert.Fail ("#1");
396 [Test]
397 [ExpectedException (typeof (Exception))]
398 public void TestFilterEmittingWithoutHandlerExecution ()
400 DefineTestFilterMethod ();
401 Type dynt = tb.CreateType ();
403 MethodInfo tf = dynt.GetMethod ("TestFilter");
404 try {
405 tf.Invoke (null, new object [] { false });
406 } catch (TargetInvocationException tie) {
407 throw tie.InnerException;
411 [Test]
412 public void TestEmitLocalInfoWithNopOpCode ()
414 var method_builder = tb.DefineMethod ("linop", MethodAttributes.Public | MethodAttributes.Static, typeof (bool), Type.EmptyTypes);
415 il_gen = method_builder.GetILGenerator ();
417 var local = il_gen.DeclareLocal (typeof (int));
418 il_gen.Emit (OpCodes.Nop, local);
419 il_gen.Emit (OpCodes.Ldc_I4_1);
420 il_gen.Emit (OpCodes.Ret);
422 var type = tb.CreateType ();
423 var method = type.GetMethod ("linop");
425 Assert.IsNotNull (method);
426 Assert.IsTrue ((bool) method.Invoke (null, new object [0]));
429 [Test]
430 [ExpectedException (typeof (ArgumentException))]
431 public void LdObjByRef () {
432 DefineBasicMethod ();
433 ILGenerator ig = il_gen;
435 ig.Emit (OpCodes.Ldtoken, typeof (int).MakeByRefType ());
440 [Test] //bug #649017
441 public void GtdEncodingAsOpenInstance () {
442 AssemblyName asmname = new AssemblyName ();
443 asmname.Name = "test";
444 AssemblyBuilder asmbuild = Thread.GetDomain ().DefineDynamicAssembly (asmname, AssemblyBuilderAccess.RunAndSave);
445 ModuleBuilder modbuild = asmbuild.DefineDynamicModule ("modulename", "test.exe");
447 TypeBuilder myType = modbuild.DefineType ("Sample", TypeAttributes.Public);
449 string[] typeParamNames = { "TFirst" };
450 myType.DefineGenericParameters (typeParamNames);
452 var nested = myType.DefineNestedType ("nested");
453 nested.DefineGenericParameters (typeParamNames);
455 var m = myType.DefineMethod ("test", MethodAttributes.Public);
456 m.SetParameters (myType);
458 var ilgen = m.GetILGenerator ();
459 ilgen.Emit (OpCodes.Castclass, nested);
460 ilgen.Emit (OpCodes.Castclass, typeof (List<>));
461 ilgen.Emit (OpCodes.Ldtoken, nested);
462 ilgen.Emit (OpCodes.Ldtoken, typeof (List<>));
464 var baked = myType.CreateType ();
465 nested.CreateType ();
467 var method = baked.GetMethod ("test");
468 var body = method.GetMethodBody ();
470 The resulting IL is:
471 [ 0] 0x74 token:uint
472 [ 5] 0x74 token:uint
473 [10] 0xd0 token:uint
474 [10] 0xd0 token:uint
475 The first two tokens must be to typespecs and the last two to typeref/typedef*/
476 var il = body.GetILAsByteArray ();
478 Assert.AreEqual (20, il.Length, "#1");
479 Assert.AreEqual (0x1B, il [4]); //typespec
480 Assert.AreEqual (0x1B, il [9]); //typespec
481 Assert.AreEqual (0x02, il [14]); //typedef
482 Assert.AreEqual (0x01, il [19]); //typeref
485 [Test]
486 public void MethodRefTokenSame () {
487 // Get the same non-virtual method from a base and a derived type so
488 // that the MemberInfo:DeclaredType differs but the tokens are the same.
490 // Regression test for bugzilla #59364
492 DefineBasicMethod ();
494 var m1 = typeof (object).GetMethod ("GetType");
495 var m2 = typeof (string).GetMethod ("GetType");
497 var value_getter = typeof (RuntimeMethodHandle).GetProperty ("Value").GetMethod;
499 var il = il_gen;
501 var loc = il.DeclareLocal (typeof (RuntimeMethodHandle));
503 // return ((int)(RuntimeMethodHandle (m1).Value == RuntimeMethodHandle (m2).Value)).ToString ()
504 il.Emit (OpCodes.Ldtoken, m1);
505 il.Emit (OpCodes.Stloc, loc);
506 il.Emit (OpCodes.Ldloca, loc);
507 il.Emit (OpCodes.Call, value_getter);
508 il.Emit (OpCodes.Ldtoken, m2);
509 il.Emit (OpCodes.Stloc, loc);
510 il.Emit (OpCodes.Ldloca, loc);
511 il.Emit (OpCodes.Call, value_getter);
512 il.Emit (OpCodes.Ceq);
513 il.Emit (OpCodes.Box, typeof (Int32));
514 il.Emit (OpCodes.Callvirt, typeof (object).GetMethod ("ToString"));
515 il.Emit (OpCodes.Ret);
517 var baked = tb.CreateType ();
519 var x = Activator.CreateInstance (baked);
520 var m = baked.GetMethod ("F");
522 var s = m.Invoke (x, null);
524 Assert.AreEqual ("1", s);
528 public class Base<T> {
529 public int x;
531 public void M () { }
534 public class Derived : Base<string> {
537 [Test]
538 public void FieldRefTokenSame () {
539 DefineBasicMethod ();
541 // Get the same field from a base and a derived type so hat
542 // the MemberInfo:DeclaredType differs but the tokens are the same.
544 // Regression test for bugzilla #59364
546 var f1 = typeof (Base<string>).GetField ("x");
547 var f2 = typeof (Derived).GetField ("x");
549 var value_getter = typeof (RuntimeFieldHandle).GetProperty("Value").GetMethod;
551 var il = il_gen;
553 var loc = il.DeclareLocal (typeof (RuntimeFieldHandle));
555 il.Emit (OpCodes.Ldtoken, f1);
556 il.Emit (OpCodes.Stloc, loc);
557 il.Emit (OpCodes.Ldloca, loc);
558 il.Emit (OpCodes.Call, value_getter);
559 il.Emit (OpCodes.Ldtoken, f2);
560 il.Emit (OpCodes.Stloc, loc);
561 il.Emit (OpCodes.Ldloca, loc);
562 il.Emit (OpCodes.Call, value_getter);
563 il.Emit (OpCodes.Ceq);
564 il.Emit (OpCodes.Box, typeof (Int32));
565 il.Emit (OpCodes.Callvirt, typeof (object).GetMethod ("ToString"));
566 il.Emit (OpCodes.Ret);
568 var baked = tb.CreateType ();
570 var x = Activator.CreateInstance (baked);
571 var m = baked.GetMethod ("F");
573 var s = m.Invoke (x, null);
575 Assert.AreEqual ("1", s);
578 [Test]
579 public void MethodSpecTokenSame () {
580 DefineBasicMethod ();
581 // Get the same method from a base generic instance and
582 // a type derived from it so that the
583 // MemberInfo:DeclaredType differs but the tokens are
584 // the same.
586 // Regression test for bugzilla #60233
588 var m1 = typeof (Base<string>).GetMethod ("M");
589 var m2 = typeof (Derived).GetMethod ("M");
591 var il = il_gen;
593 var loc = il.DeclareLocal (typeof (Derived));
595 il.Emit (OpCodes.Newobj, typeof (Derived).GetConstructor(new Type[]{}));
596 il.Emit (OpCodes.Stloc, loc);
597 il.Emit (OpCodes.Ldloc, loc);
598 il.Emit (OpCodes.Call, m1);
599 il.Emit (OpCodes.Ldloc, loc);
600 il.Emit (OpCodes.Call, m2);
601 il.Emit (OpCodes.Ldstr, "1");
602 il.Emit (OpCodes.Ret);
604 var baked = tb.CreateType ();
606 var x = Activator.CreateInstance (baked);
607 var m = baked.GetMethod ("F");
609 var s = m.Invoke (x, null);
611 Assert.AreEqual ("1", s);