/Test/Mono.Cecil.Tests/ImportReflectionTests.cs
C# | 428 lines | 339 code | 89 blank | 0 comment | 6 complexity | 5ece7371b06caf0efeb658fb094b4627 MD5 | raw file
1using System; 2using System.Collections.Generic; 3using System.IO; 4using SR = System.Reflection; 5using System.Runtime.CompilerServices; 6 7using Mono.Cecil.Cil; 8 9using NUnit.Framework; 10 11namespace Mono.Cecil.Tests { 12 13 [TestFixture] 14 public class ImportReflectionTests : BaseTestFixture { 15 16 [Test] 17 public void ImportString () 18 { 19 var get_string = Compile<Func<string>> ((_, body) => { 20 var il = body.GetILProcessor (); 21 il.Emit (OpCodes.Ldstr, "yo dawg!"); 22 il.Emit (OpCodes.Ret); 23 }); 24 25 Assert.AreEqual ("yo dawg!", get_string ()); 26 } 27 28 [Test] 29 public void ImportInt () 30 { 31 var add = Compile<Func<int, int, int>> ((_, body) => { 32 var il = body.GetILProcessor (); 33 il.Emit (OpCodes.Ldarg_0); 34 il.Emit (OpCodes.Ldarg_1); 35 il.Emit (OpCodes.Add); 36 il.Emit (OpCodes.Ret); 37 }); 38 39 Assert.AreEqual (42, add (40, 2)); 40 } 41 42 [Test] 43 public void ImportStringByRef () 44 { 45 var get_string = Compile<Func<string, string>> ((module, body) => { 46 var type = module.Types [1]; 47 48 var method_by_ref = new MethodDefinition { 49 Name = "ModifyString", 50 IsPrivate = true, 51 IsStatic = true, 52 }; 53 54 type.Methods.Add (method_by_ref); 55 56 method_by_ref.MethodReturnType.ReturnType = module.ImportReference (typeof (void)); 57 58 method_by_ref.Parameters.Add (new ParameterDefinition (module.ImportReference (typeof (string)))); 59 method_by_ref.Parameters.Add (new ParameterDefinition (module.ImportReference (typeof (string).MakeByRefType ()))); 60 61 var m_il = method_by_ref.Body.GetILProcessor (); 62 m_il.Emit (OpCodes.Ldarg_1); 63 m_il.Emit (OpCodes.Ldarg_0); 64 m_il.Emit (OpCodes.Stind_Ref); 65 m_il.Emit (OpCodes.Ret); 66 67 var v_0 = new VariableDefinition (module.ImportReference (typeof (string))); 68 body.Variables.Add (v_0); 69 70 var il = body.GetILProcessor (); 71 il.Emit (OpCodes.Ldnull); 72 il.Emit (OpCodes.Stloc, v_0); 73 il.Emit (OpCodes.Ldarg_0); 74 il.Emit (OpCodes.Ldloca, v_0); 75 il.Emit (OpCodes.Call, method_by_ref); 76 il.Emit (OpCodes.Ldloc_0); 77 il.Emit (OpCodes.Ret); 78 }); 79 80 Assert.AreEqual ("foo", get_string ("foo")); 81 } 82 83 [Test] 84 public void ImportStringArray () 85 { 86 var identity = Compile<Func<string [,], string [,]>> ((module, body) => { 87 var il = body.GetILProcessor (); 88 il.Emit (OpCodes.Ldarg_0); 89 il.Emit (OpCodes.Ret); 90 }); 91 92 var array = new string [2, 2]; 93 94 Assert.AreEqual (array, identity (array)); 95 } 96 97 [Test] 98 public void ImportFieldStringEmpty () 99 { 100 var get_empty = Compile<Func<string>> ((module, body) => { 101 var il = body.GetILProcessor (); 102 il.Emit (OpCodes.Ldsfld, module.ImportReference (typeof (string).GetField ("Empty"))); 103 il.Emit (OpCodes.Ret); 104 }); 105 106 Assert.AreEqual ("", get_empty ()); 107 } 108 109 [Test] 110 public void ImportStringConcat () 111 { 112 var concat = Compile<Func<string, string, string>> ((module, body) => { 113 var il = body.GetILProcessor (); 114 il.Emit (OpCodes.Ldarg_0); 115 il.Emit (OpCodes.Ldarg_1); 116 il.Emit (OpCodes.Call, module.ImportReference (typeof (string).GetMethod ("Concat", new [] { typeof (string), typeof (string) }))); 117 il.Emit (OpCodes.Ret); 118 }); 119 120 Assert.AreEqual ("FooBar", concat ("Foo", "Bar")); 121 } 122 123 [Test] 124 public void GeneratedAssemblyCulture () 125 { 126 var id = Compile<Func<int, int>> ((module, body) => { 127 var il = body.GetILProcessor (); 128 il.Emit (OpCodes.Ldarg_0); 129 il.Emit (OpCodes.Ret); 130 }); 131 132 Assert.AreEqual ("", id.Method.DeclaringType.Assembly.GetName ().CultureInfo.Name); 133 } 134 135 public class Generic<T> { 136 public T Field; 137 138 public T Method (T t) 139 { 140 return t; 141 } 142 143 public TS GenericMethod<TS> (T t, TS s) 144 { 145 return s; 146 } 147 148 public Generic<TS> ComplexGenericMethod<TS> (T t, TS s) 149 { 150 return new Generic<TS> { Field = s }; 151 } 152 } 153 154 [Test] 155 public void ImportGenericField () 156 { 157 if (Platform.OnCoreClr) 158 return; 159 160 var get_field = Compile<Func<Generic<string>, string>> ((module, body) => { 161 var il = body.GetILProcessor (); 162 il.Emit (OpCodes.Ldarg_0); 163 il.Emit (OpCodes.Ldfld, module.ImportReference (typeof (Generic<string>).GetField ("Field"))); 164 il.Emit (OpCodes.Ret); 165 }); 166 167 var generic = new Generic<string> { 168 Field = "foo", 169 }; 170 171 Assert.AreEqual ("foo", get_field (generic)); 172 } 173 174 [Test] 175 public void ImportGenericMethod () 176 { 177 if (Platform.OnCoreClr) 178 return; 179 180 var generic_identity = Compile<Func<Generic<int>, int, int>> ((module, body) => { 181 var il = body.GetILProcessor (); 182 il.Emit (OpCodes.Ldarg_0); 183 il.Emit (OpCodes.Ldarg_1); 184 il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<int>).GetMethod ("Method"))); 185 il.Emit (OpCodes.Ret); 186 }); 187 188 Assert.AreEqual (42, generic_identity (new Generic<int> (), 42)); 189 } 190 191 [Test] 192 public void ImportGenericMethodSpec () 193 { 194 if (Platform.OnCoreClr) 195 return; 196 197 var gen_spec_id = Compile<Func<Generic<string>, int, int>> ((module, body) => { 198 var il = body.GetILProcessor (); 199 il.Emit (OpCodes.Ldarg_0); 200 il.Emit (OpCodes.Ldnull); 201 il.Emit (OpCodes.Ldarg_1); 202 il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<string>).GetMethod ("GenericMethod").MakeGenericMethod (typeof (int)))); 203 il.Emit (OpCodes.Ret); 204 }); 205 206 Assert.AreEqual (42, gen_spec_id (new Generic<string> (), 42)); 207 } 208 209 [Test] 210 public void ImportComplexGenericMethodSpec () 211 { 212 if (Platform.OnCoreClr) 213 return; 214 215 var gen_spec_id = Compile<Func<Generic<string>, int, int>> ((module, body) => { 216 var il = body.GetILProcessor (); 217 il.Emit (OpCodes.Ldarg_0); 218 il.Emit (OpCodes.Ldnull); 219 il.Emit (OpCodes.Ldarg_1); 220 il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<string>).GetMethod ("ComplexGenericMethod").MakeGenericMethod (typeof (int)))); 221 il.Emit (OpCodes.Ldfld, module.ImportReference (typeof (Generic<int>).GetField ("Field"))); 222 il.Emit (OpCodes.Ret); 223 }); 224 225 Assert.AreEqual (42, gen_spec_id (new Generic<string> (), 42)); 226 } 227 228 public class Foo<TFoo> { 229 public List<TFoo> list; 230 } 231 232 [Test] 233 public void ImportGenericTypeDefOrOpen () 234 { 235 using (var module = typeof (Foo<>).ToDefinition ().Module) { 236 var foo_def = module.ImportReference (typeof (Foo<>)); 237 var foo_open = module.ImportReference (typeof (Foo<>), foo_def); 238 239 Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1", foo_def.FullName); 240 Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>", foo_open.FullName); 241 } 242 } 243 244 [Test] 245 public void ImportGenericTypeFromContext () 246 { 247 var list_foo = typeof (Foo<>).GetField ("list").FieldType; 248 var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); 249 250 var foo_def = typeof (Foo<>).ToDefinition (); 251 using (var module = foo_def.Module) { 252 var generic_foo = module.ImportReference (generic_list_foo_open, foo_def); 253 254 Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>", 255 generic_foo.FullName); 256 } 257 } 258 259 [Test] 260 public void ImportGenericTypeDefFromContext () 261 { 262 var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]); 263 var generic_foo_open = typeof (Generic<>).MakeGenericType (foo_open); 264 265 var foo_def = typeof (Foo<>).ToDefinition (); 266 using (var module = foo_def.Module) { 267 var generic_foo = module.ImportReference (generic_foo_open, foo_def); 268 269 Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1<Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>>", 270 generic_foo.FullName); 271 } 272 } 273 274 [Test] 275 public void ImportArrayTypeDefFromContext () 276 { 277 var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]); 278 var foo_open_array = foo_open.MakeArrayType (); 279 280 var foo_def = typeof (Foo<>).ToDefinition (); 281 using (var module = foo_def.Module) { 282 var array_foo = module.ImportReference (foo_open_array, foo_def); 283 284 Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>[]", 285 array_foo.FullName); 286 } 287 } 288 289 [Test] 290 public void ImportGenericFieldFromContext () 291 { 292 if (Platform.OnCoreClr) 293 return; 294 295 var list_foo = typeof (Foo<>).GetField ("list").FieldType; 296 var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); 297 var generic_list_foo_open_field = generic_list_foo_open.GetField ("Field"); 298 299 var foo_def = typeof (Foo<>).ToDefinition (); 300 using (var module = foo_def.Module) { 301 var generic_field = module.ImportReference (generic_list_foo_open_field, foo_def); 302 303 Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>::Field", 304 generic_field.FullName); 305 } 306 } 307 308 [Test] 309 public void ImportGenericMethodFromContext () 310 { 311 if (Platform.OnCoreClr) 312 return; 313 314 var list_foo = typeof (Foo<>).GetField ("list").FieldType; 315 var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo); 316 var generic_list_foo_open_method = generic_list_foo_open.GetMethod ("Method"); 317 318 var foo_def = typeof (Foo<>).ToDefinition (); 319 using (var module = foo_def.Module) { 320 var generic_method = module.ImportReference (generic_list_foo_open_method, foo_def); 321 322 Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>::Method(T)", 323 generic_method.FullName); 324 } 325 } 326 327 [Test] 328 public void ImportMethodOnOpenGenericType () 329 { 330 using (var module = typeof (Generic<>).ToDefinition ().Module) { 331 var method = module.ImportReference (typeof (Generic<>).GetMethod ("Method")); 332 333 Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::Method(T)", method.FullName); 334 } 335 } 336 337 [Test] 338 public void ImportGenericMethodOnOpenGenericType () 339 { 340 using (var module = typeof (Generic<>).ToDefinition ().Module) { 341 var generic_method = module.ImportReference (typeof (Generic<>).GetMethod ("GenericMethod")); 342 343 Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::GenericMethod(T,TS)", generic_method.FullName); 344 345 generic_method = module.ImportReference (typeof (Generic<>).GetMethod ("GenericMethod"), generic_method); 346 347 Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::GenericMethod<TS>(T,TS)", generic_method.FullName); 348 } 349 } 350 351 delegate void Emitter (ModuleDefinition module, MethodBody body); 352 353 static TDelegate Compile<TDelegate> (Emitter emitter, [CallerMemberName] string testMethodName = null) 354 where TDelegate : class 355 { 356 var name = "ImportReflection_" + testMethodName; 357 358 var module = CreateTestModule<TDelegate> (name, emitter); 359 var assembly = LoadTestModule (module); 360 361 return CreateRunDelegate<TDelegate> (GetTestCase (name, assembly)); 362 } 363 364 static TDelegate CreateRunDelegate<TDelegate> (Type type) 365 where TDelegate : class 366 { 367 return (TDelegate) (object) Delegate.CreateDelegate (typeof (TDelegate), type.GetMethod ("Run")); 368 } 369 370 static Type GetTestCase (string name, SR.Assembly assembly) 371 { 372 return assembly.GetType (name); 373 } 374 375 static SR.Assembly LoadTestModule (ModuleDefinition module) 376 { 377 using (var stream = new MemoryStream ()) { 378 module.Write (stream); 379 File.WriteAllBytes (Path.Combine (Path.Combine (Path.GetTempPath (), "cecil"), module.Name + ".dll"), stream.ToArray ()); 380 return SR.Assembly.Load (stream.ToArray ()); 381 } 382 } 383 384 static ModuleDefinition CreateTestModule<TDelegate> (string name, Emitter emitter) 385 { 386 var module = CreateModule (name); 387 388 var type = new TypeDefinition ( 389 "", 390 name, 391 TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract, 392 module.ImportReference (typeof (object))); 393 394 module.Types.Add (type); 395 396 var method = CreateMethod (type, typeof (TDelegate).GetMethod ("Invoke")); 397 398 emitter (module, method.Body); 399 400 return module; 401 } 402 403 static MethodDefinition CreateMethod (TypeDefinition type, SR.MethodInfo pattern) 404 { 405 var module = type.Module; 406 407 var method = new MethodDefinition { 408 Name = "Run", 409 IsPublic = true, 410 IsStatic = true, 411 }; 412 413 type.Methods.Add (method); 414 415 method.MethodReturnType.ReturnType = module.ImportReference (pattern.ReturnType); 416 417 foreach (var parameter_pattern in pattern.GetParameters ()) 418 method.Parameters.Add (new ParameterDefinition (module.ImportReference (parameter_pattern.ParameterType))); 419 420 return method; 421 } 422 423 static ModuleDefinition CreateModule (string name) 424 { 425 return ModuleDefinition.CreateModule (name, ModuleKind.Dll); 426 } 427 } 428}