/Test/Mono.Cecil.Tests/MethodBodyTests.cs

http://github.com/jbevain/cecil · C# · 453 lines · 380 code · 73 blank · 0 comment · 7 complexity · 877606d83fa2d96ef18aed217caf8439 MD5 · raw file

  1. using System;
  2. using System.Linq;
  3. using Mono.Cecil;
  4. using Mono.Cecil.Cil;
  5. using NUnit.Framework;
  6. namespace Mono.Cecil.Tests {
  7. [TestFixture]
  8. public class MethodBodyTests : BaseTestFixture {
  9. [Test]
  10. public void MultiplyMethod ()
  11. {
  12. TestIL ("hello.il", module => {
  13. var foo = module.GetType ("Foo");
  14. Assert.IsNotNull (foo);
  15. var bar = foo.GetMethod ("Bar");
  16. Assert.IsNotNull (bar);
  17. Assert.IsTrue (bar.IsIL);
  18. AssertCode (@"
  19. .locals init (System.Int32 V_0)
  20. IL_0000: ldarg.0
  21. IL_0001: ldarg.1
  22. IL_0002: mul
  23. IL_0003: stloc.0
  24. IL_0004: ldloc.0
  25. IL_0005: call System.Void Foo::Baz(System.Int32)
  26. IL_000a: ret
  27. ", bar);
  28. });
  29. }
  30. [Test]
  31. public void PrintStringEmpty ()
  32. {
  33. TestIL ("hello.il", module => {
  34. var foo = module.GetType ("Foo");
  35. Assert.IsNotNull (foo);
  36. var print_empty = foo.GetMethod ("PrintEmpty");
  37. Assert.IsNotNull (print_empty);
  38. AssertCode (@"
  39. .locals ()
  40. IL_0000: ldsfld System.String System.String::Empty
  41. IL_0005: call System.Void System.Console::WriteLine(System.String)
  42. IL_000a: ret
  43. ", print_empty);
  44. });
  45. }
  46. [Test]
  47. public void Branch ()
  48. {
  49. TestModule ("libhello.dll", module => {
  50. var lib = module.GetType ("Library");
  51. Assert.IsNotNull (lib);
  52. var method = lib.GetMethod ("GetHelloString");
  53. Assert.IsNotNull (method);
  54. AssertCode (@"
  55. .locals init (System.String V_0)
  56. IL_0000: nop
  57. IL_0001: ldstr ""hello world of tomorrow""
  58. IL_0006: stloc.0
  59. IL_0007: br.s IL_0009
  60. IL_0009: ldloc.0
  61. IL_000a: ret
  62. ", method);
  63. });
  64. }
  65. [Test]
  66. public void Switch ()
  67. {
  68. TestModule ("switch.exe", module => {
  69. var program = module.GetType ("Program");
  70. Assert.IsNotNull (program);
  71. var method = program.GetMethod ("Main");
  72. Assert.IsNotNull (method);
  73. AssertCode (@"
  74. .locals init (System.Int32 V_0)
  75. IL_0000: ldarg.0
  76. IL_0001: ldlen
  77. IL_0002: conv.i4
  78. IL_0003: stloc.0
  79. IL_0004: ldloc.0
  80. IL_0005: ldc.i4.8
  81. IL_0006: bgt.s IL_0026
  82. IL_0008: ldloc.0
  83. IL_0009: ldc.i4.1
  84. IL_000a: sub
  85. IL_000b: switch (IL_0032, IL_0034, IL_0038, IL_0034)
  86. IL_0020: ldloc.0
  87. IL_0021: ldc.i4.8
  88. IL_0022: beq.s IL_0036
  89. IL_0024: br.s IL_0038
  90. IL_0026: ldloc.0
  91. IL_0027: ldc.i4.s 16
  92. IL_0029: beq.s IL_0036
  93. IL_002b: ldloc.0
  94. IL_002c: ldc.i4.s 32
  95. IL_002e: beq.s IL_0036
  96. IL_0030: br.s IL_0038
  97. IL_0032: ldc.i4.0
  98. IL_0033: ret
  99. IL_0034: ldc.i4.1
  100. IL_0035: ret
  101. IL_0036: ldc.i4.2
  102. IL_0037: ret
  103. IL_0038: ldc.i4.s 42
  104. IL_003a: ret
  105. ", method);
  106. });
  107. }
  108. [Test]
  109. public void MethodSpec ()
  110. {
  111. TestIL ("methodspecs.il", module => {
  112. var tamtam = module.GetType ("Tamtam");
  113. var bar = tamtam.GetMethod ("Bar");
  114. Assert.IsNotNull (bar);
  115. AssertCode (@"
  116. .locals ()
  117. IL_0000: ldc.i4.2
  118. IL_0001: call System.Void Tamtam::Foo<System.Int32>(TFoo)
  119. IL_0006: ret
  120. ", bar);
  121. });
  122. }
  123. [Test]
  124. public void NestedTryCatchFinally ()
  125. {
  126. TestModule ("catch.exe", module => {
  127. var program = module.GetType ("Program");
  128. var main = program.GetMethod ("Main");
  129. Assert.IsNotNull (main);
  130. AssertCode (@"
  131. .locals ()
  132. IL_0000: call System.Void Program::Foo()
  133. IL_0005: leave.s IL_000d
  134. IL_0007: call System.Void Program::Baz()
  135. IL_000c: endfinally
  136. IL_000d: leave.s IL_001f
  137. IL_000f: pop
  138. IL_0010: call System.Void Program::Bar()
  139. IL_0015: leave.s IL_001f
  140. IL_0017: pop
  141. IL_0018: call System.Void Program::Bar()
  142. IL_001d: leave.s IL_001f
  143. IL_001f: leave.s IL_0027
  144. IL_0021: call System.Void Program::Baz()
  145. IL_0026: endfinally
  146. IL_0027: ret
  147. .try IL_0000 to IL_0007 finally handler IL_0007 to IL_000d
  148. .try IL_0000 to IL_000f catch System.ArgumentException handler IL_000f to IL_0017
  149. .try IL_0000 to IL_000f catch System.Exception handler IL_0017 to IL_001f
  150. .try IL_0000 to IL_0021 finally handler IL_0021 to IL_0027
  151. ", main);
  152. });
  153. }
  154. [Test]
  155. public void FunctionPointersAndCallSites ()
  156. {
  157. TestModule ("fptr.exe", module => {
  158. var type = module.Types [0];
  159. var start = type.GetMethod ("Start");
  160. Assert.IsNotNull (start);
  161. AssertCode (@"
  162. .locals init ()
  163. IL_0000: ldc.i4.1
  164. IL_0001: call method System.Int32 *(System.Int32) MakeDecision::Decide()
  165. IL_0006: calli System.Int32(System.Int32)
  166. IL_000b: call System.Void System.Console::WriteLine(System.Int32)
  167. IL_0010: ldc.i4.1
  168. IL_0011: call method System.Int32 *(System.Int32) MakeDecision::Decide()
  169. IL_0016: calli System.Int32(System.Int32)
  170. IL_001b: call System.Void System.Console::WriteLine(System.Int32)
  171. IL_0020: ldc.i4.1
  172. IL_0021: call method System.Int32 *(System.Int32) MakeDecision::Decide()
  173. IL_0026: calli System.Int32(System.Int32)
  174. IL_002b: call System.Void System.Console::WriteLine(System.Int32)
  175. IL_0030: ret
  176. ", start);
  177. }, verify: false);
  178. }
  179. [Test]
  180. public void ThisParameter ()
  181. {
  182. TestIL ("hello.il", module => {
  183. var type = module.GetType ("Foo");
  184. var method = type.GetMethod ("Gazonk");
  185. Assert.IsNotNull (method);
  186. AssertCode (@"
  187. .locals ()
  188. IL_0000: ldarg 0
  189. IL_0004: pop
  190. IL_0005: ret
  191. ", method);
  192. Assert.AreEqual (method.Body.ThisParameter.ParameterType, type);
  193. Assert.AreEqual (method.Body.ThisParameter, method.Body.Instructions [0].Operand);
  194. });
  195. }
  196. [Test]
  197. public void ThisParameterStaticMethod ()
  198. {
  199. var static_method = typeof (ModuleDefinition).ToDefinition ().Methods.Where (m => m.IsStatic).First ();
  200. Assert.IsNull (static_method.Body.ThisParameter);
  201. }
  202. [Test]
  203. public void ThisParameterPrimitive ()
  204. {
  205. var int32 = typeof (int).ToDefinition ();
  206. var int_to_string = int32.Methods.Where (m => m.Name == "ToString" && m.Parameters.Count == 0).First();
  207. Assert.IsNotNull (int_to_string);
  208. var this_parameter_type = int_to_string.Body.ThisParameter.ParameterType;
  209. Assert.IsTrue (this_parameter_type.IsByReference);
  210. var element_type = ((ByReferenceType) this_parameter_type).ElementType;
  211. Assert.AreEqual (int32, element_type);
  212. }
  213. [Test]
  214. public void ThisParameterValueType ()
  215. {
  216. var token = typeof (MetadataToken).ToDefinition ();
  217. var token_to_string = token.Methods.Where (m => m.Name == "ToString" && m.Parameters.Count == 0).First ();
  218. Assert.IsNotNull (token_to_string);
  219. var this_parameter_type = token_to_string.Body.ThisParameter.ParameterType;
  220. Assert.IsTrue (this_parameter_type.IsByReference);
  221. var element_type = ((ByReferenceType) this_parameter_type).ElementType;
  222. Assert.AreEqual (token, element_type);
  223. }
  224. [Test]
  225. public void ThisParameterObject ()
  226. {
  227. var module = typeof (MethodBodyTests).ToDefinition ().Module;
  228. var @object = module.TypeSystem.Object.Resolve ();
  229. var method = @object.Methods.Where (m => m.HasBody).First ();
  230. var type = method.Body.ThisParameter.ParameterType;
  231. Assert.IsFalse (type.IsValueType);
  232. Assert.IsFalse (type.IsPrimitive);
  233. Assert.IsFalse (type.IsPointer);
  234. }
  235. [Test]
  236. public void FilterMaxStack ()
  237. {
  238. TestIL ("hello.il", module => {
  239. var type = module.GetType ("Foo");
  240. var method = type.GetMethod ("TestFilter");
  241. Assert.IsNotNull (method);
  242. Assert.AreEqual (2, method.Body.MaxStackSize);
  243. });
  244. }
  245. [Test]
  246. public void BranchOutsideMethod ()
  247. {
  248. OnlyOnWindows (); // Mono's ilasm doesn't support branching outside of method
  249. TestIL ("branch-out.il", module => {
  250. var type = module.GetType ("Foo");
  251. var method = type.GetMethod ("BranchOutside");
  252. Assert.IsNotNull (method);
  253. Assert.IsNotNull (method.Body);
  254. var leave = method.Body.Instructions [0];
  255. Assert.AreEqual (OpCodes.Leave, leave.OpCode);
  256. Assert.IsNull (leave.Operand);
  257. Assert.AreEqual ("IL_0000: leave", leave.ToString ());
  258. }, verify: false);
  259. }
  260. [Test]
  261. public void Iterator ()
  262. {
  263. TestModule ("iterator.exe", module => {
  264. var method = module.GetType ("Program").GetMethod ("GetLittleArgs");
  265. Assert.IsNotNull (method.Body);
  266. });
  267. }
  268. [Test]
  269. public void LoadString ()
  270. {
  271. TestCSharp ("CustomAttributes.cs", module => {
  272. var type = module.GetType ("FooAttribute");
  273. var get_fiou = type.GetMethod ("get_Fiou");
  274. Assert.IsNotNull (get_fiou);
  275. var ldstr = get_fiou.Body.Instructions.Where (i => i.OpCode == OpCodes.Ldstr).First ();
  276. Assert.AreEqual ("fiou", ldstr.Operand);
  277. });
  278. }
  279. [Test]
  280. public void UnattachedMethodBody ()
  281. {
  282. var system_void = typeof (void).ToDefinition ();
  283. var method = new MethodDefinition ("NewMethod", MethodAttributes.Assembly | MethodAttributes.Static, system_void);
  284. var body = new MethodBody (method);
  285. var il = body.GetILProcessor ();
  286. il.Emit (OpCodes.Ret);
  287. method.Body = body;
  288. Assert.AreEqual (body, method.Body);
  289. }
  290. [Test]
  291. public void AddInstruction ()
  292. {
  293. var object_ref = new TypeReference ("System", "Object", null, null, false);
  294. var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);
  295. var body = new MethodBody (method);
  296. var il = body.GetILProcessor ();
  297. var first = il.Create (OpCodes.Nop);
  298. var second = il.Create (OpCodes.Nop);
  299. body.Instructions.Add (first);
  300. body.Instructions.Add (second);
  301. Assert.IsNull (first.Previous);
  302. Assert.AreEqual (second, first.Next);
  303. Assert.AreEqual (first, second.Previous);
  304. Assert.IsNull (second.Next);
  305. }
  306. [Test]
  307. public void InsertInstruction ()
  308. {
  309. var object_ref = new TypeReference ("System", "Object", null, null, false);
  310. var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);
  311. var body = new MethodBody (method);
  312. var il = body.GetILProcessor ();
  313. var first = il.Create (OpCodes.Nop);
  314. var second = il.Create (OpCodes.Nop);
  315. var third = il.Create (OpCodes.Nop);
  316. body.Instructions.Add (first);
  317. body.Instructions.Add (third);
  318. Assert.IsNull (first.Previous);
  319. Assert.AreEqual (third, first.Next);
  320. Assert.AreEqual (first, third.Previous);
  321. Assert.IsNull (third.Next);
  322. body.Instructions.Insert (1, second);
  323. Assert.IsNull (first.Previous);
  324. Assert.AreEqual (second, first.Next);
  325. Assert.AreEqual (first, second.Previous);
  326. Assert.AreEqual (third, second.Next);
  327. Assert.AreEqual (second, third.Previous);
  328. Assert.IsNull (third.Next);
  329. }
  330. [Test]
  331. public void InsertAfterLastInstruction ()
  332. {
  333. var object_ref = new TypeReference ("System", "Object", null, null, false);
  334. var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);
  335. var body = new MethodBody (method);
  336. var il = body.GetILProcessor ();
  337. var first = il.Create (OpCodes.Nop);
  338. var second = il.Create (OpCodes.Nop);
  339. var third = il.Create (OpCodes.Nop);
  340. body.Instructions.Add (first);
  341. body.Instructions.Add (second);
  342. Assert.IsNull (first.Previous);
  343. Assert.AreEqual (second, first.Next);
  344. Assert.AreEqual (first, second.Previous);
  345. Assert.IsNull (second.Next);
  346. body.Instructions.Insert (2, third);
  347. Assert.IsNull (first.Previous);
  348. Assert.AreEqual (second, first.Next);
  349. Assert.AreEqual (first, second.Previous);
  350. Assert.AreEqual (third, second.Next);
  351. Assert.AreEqual (second, third.Previous);
  352. Assert.IsNull (third.Next);
  353. }
  354. [Test]
  355. public void RemoveInstruction ()
  356. {
  357. var object_ref = new TypeReference ("System", "Object", null, null, false);
  358. var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);
  359. var body = new MethodBody (method);
  360. var il = body.GetILProcessor ();
  361. var first = il.Create (OpCodes.Nop);
  362. var second = il.Create (OpCodes.Nop);
  363. var third = il.Create (OpCodes.Nop);
  364. body.Instructions.Add (first);
  365. body.Instructions.Add (second);
  366. body.Instructions.Add (third);
  367. Assert.IsNull (first.Previous);
  368. Assert.AreEqual (second, first.Next);
  369. Assert.AreEqual (first, second.Previous);
  370. Assert.AreEqual (third, second.Next);
  371. Assert.AreEqual (second, third.Previous);
  372. Assert.IsNull (third.Next);
  373. body.Instructions.Remove (second);
  374. Assert.IsNull (first.Previous);
  375. Assert.AreEqual (third, first.Next);
  376. Assert.AreEqual (first, third.Previous);
  377. Assert.IsNull (third.Next);
  378. }
  379. }
  380. }