/Test/Mono.Cecil.Tests/ImportReflectionTests.cs

http://github.com/jbevain/cecil · C# · 428 lines · 339 code · 89 blank · 0 comment · 6 complexity · 5ece7371b06caf0efeb658fb094b4627 MD5 · raw file

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