/Mono.Cecil/MethodDefinition.cs

http://github.com/jbevain/cecil · C# · 559 lines · 429 code · 120 blank · 10 comment · 68 complexity · 324084a600365f4841cc75a38ff9d147 MD5 · raw file

  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Threading;
  12. using Mono.Cecil.Cil;
  13. using Mono.Collections.Generic;
  14. using RVA = System.UInt32;
  15. namespace Mono.Cecil {
  16. public sealed class MethodDefinition : MethodReference, IMemberDefinition, ISecurityDeclarationProvider, ICustomDebugInformationProvider {
  17. ushort attributes;
  18. ushort impl_attributes;
  19. internal volatile bool sem_attrs_ready;
  20. internal MethodSemanticsAttributes sem_attrs;
  21. Collection<CustomAttribute> custom_attributes;
  22. Collection<SecurityDeclaration> security_declarations;
  23. internal RVA rva;
  24. internal PInvokeInfo pinvoke;
  25. Collection<MethodReference> overrides;
  26. internal MethodBody body;
  27. internal MethodDebugInformation debug_info;
  28. internal Collection<CustomDebugInformation> custom_infos;
  29. public override string Name {
  30. get { return base.Name; }
  31. set {
  32. if (IsWindowsRuntimeProjection && value != base.Name)
  33. throw new InvalidOperationException ();
  34. base.Name = value;
  35. }
  36. }
  37. public MethodAttributes Attributes {
  38. get { return (MethodAttributes) attributes; }
  39. set {
  40. if (IsWindowsRuntimeProjection && (ushort) value != attributes)
  41. throw new InvalidOperationException ();
  42. attributes = (ushort) value;
  43. }
  44. }
  45. public MethodImplAttributes ImplAttributes {
  46. get { return (MethodImplAttributes) impl_attributes; }
  47. set {
  48. if (IsWindowsRuntimeProjection && (ushort) value != impl_attributes)
  49. throw new InvalidOperationException ();
  50. impl_attributes = (ushort) value;
  51. }
  52. }
  53. public MethodSemanticsAttributes SemanticsAttributes {
  54. get {
  55. if (sem_attrs_ready)
  56. return sem_attrs;
  57. if (HasImage) {
  58. ReadSemantics ();
  59. return sem_attrs;
  60. }
  61. sem_attrs = MethodSemanticsAttributes.None;
  62. sem_attrs_ready = true;
  63. return sem_attrs;
  64. }
  65. set { sem_attrs = value; }
  66. }
  67. internal new MethodDefinitionProjection WindowsRuntimeProjection {
  68. get { return (MethodDefinitionProjection) projection; }
  69. set { projection = value; }
  70. }
  71. internal void ReadSemantics ()
  72. {
  73. if (sem_attrs_ready)
  74. return;
  75. var module = this.Module;
  76. if (module == null)
  77. return;
  78. if (!module.HasImage)
  79. return;
  80. lock (module.SyncRoot) {
  81. if (sem_attrs_ready)
  82. return;
  83. module.Read (this, (method, reader) => reader.ReadAllSemantics (method));
  84. }
  85. }
  86. public bool HasSecurityDeclarations {
  87. get {
  88. if (security_declarations != null)
  89. return security_declarations.Count > 0;
  90. return this.GetHasSecurityDeclarations (Module);
  91. }
  92. }
  93. public Collection<SecurityDeclaration> SecurityDeclarations {
  94. get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); }
  95. }
  96. public bool HasCustomAttributes {
  97. get {
  98. if (custom_attributes != null)
  99. return custom_attributes.Count > 0;
  100. return this.GetHasCustomAttributes (Module);
  101. }
  102. }
  103. public Collection<CustomAttribute> CustomAttributes {
  104. get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); }
  105. }
  106. public int RVA {
  107. get { return (int) rva; }
  108. }
  109. public bool HasBody {
  110. get {
  111. return (attributes & (ushort) MethodAttributes.Abstract) == 0 &&
  112. (attributes & (ushort) MethodAttributes.PInvokeImpl) == 0 &&
  113. (impl_attributes & (ushort) MethodImplAttributes.InternalCall) == 0 &&
  114. (impl_attributes & (ushort) MethodImplAttributes.Native) == 0 &&
  115. (impl_attributes & (ushort) MethodImplAttributes.Unmanaged) == 0 &&
  116. (impl_attributes & (ushort) MethodImplAttributes.Runtime) == 0;
  117. }
  118. }
  119. public MethodBody Body {
  120. get {
  121. var local = this.body;
  122. if (local != null)
  123. return local;
  124. if (!HasBody)
  125. return null;
  126. if (HasImage && rva != 0)
  127. return Module.Read (ref body, this, (method, reader) => reader.ReadMethodBody (method));
  128. Interlocked.CompareExchange (ref body, new MethodBody (this) , null);
  129. return body;
  130. }
  131. set {
  132. var module = this.Module;
  133. if (module == null) {
  134. body = value;
  135. return;
  136. }
  137. // we reset Body to null in ILSpy to save memory; so we need that operation to be thread-safe
  138. lock (module.SyncRoot) {
  139. body = value;
  140. if (value == null)
  141. this.debug_info = null;
  142. }
  143. }
  144. }
  145. public MethodDebugInformation DebugInformation {
  146. get {
  147. Mixin.Read (Body);
  148. if (debug_info == null) {
  149. Interlocked.CompareExchange (ref debug_info, new MethodDebugInformation (this), null);
  150. }
  151. return debug_info;
  152. }
  153. set {
  154. debug_info = value;
  155. }
  156. }
  157. public bool HasPInvokeInfo {
  158. get {
  159. if (pinvoke != null)
  160. return true;
  161. return IsPInvokeImpl;
  162. }
  163. }
  164. public PInvokeInfo PInvokeInfo {
  165. get {
  166. if (pinvoke != null)
  167. return pinvoke;
  168. if (HasImage && IsPInvokeImpl)
  169. return Module.Read (ref pinvoke, this, (method, reader) => reader.ReadPInvokeInfo (method));
  170. return null;
  171. }
  172. set {
  173. IsPInvokeImpl = true;
  174. pinvoke = value;
  175. }
  176. }
  177. public bool HasOverrides {
  178. get {
  179. if (overrides != null)
  180. return overrides.Count > 0;
  181. return HasImage && Module.Read (this, (method, reader) => reader.HasOverrides (method));
  182. }
  183. }
  184. public Collection<MethodReference> Overrides {
  185. get {
  186. if (overrides != null)
  187. return overrides;
  188. if (HasImage)
  189. return Module.Read (ref overrides, this, (method, reader) => reader.ReadOverrides (method));
  190. Interlocked.CompareExchange (ref overrides, new Collection<MethodReference> (), null);
  191. return overrides;
  192. }
  193. }
  194. public override bool HasGenericParameters {
  195. get {
  196. if (generic_parameters != null)
  197. return generic_parameters.Count > 0;
  198. return this.GetHasGenericParameters (Module);
  199. }
  200. }
  201. public override Collection<GenericParameter> GenericParameters {
  202. get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); }
  203. }
  204. public bool HasCustomDebugInformations {
  205. get {
  206. Mixin.Read (Body);
  207. return !custom_infos.IsNullOrEmpty ();
  208. }
  209. }
  210. public Collection<CustomDebugInformation> CustomDebugInformations {
  211. get {
  212. Mixin.Read (Body);
  213. if (custom_infos == null)
  214. Interlocked.CompareExchange (ref custom_infos, new Collection<CustomDebugInformation> (), null);
  215. return custom_infos;
  216. }
  217. }
  218. #region MethodAttributes
  219. public bool IsCompilerControlled {
  220. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled); }
  221. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled, value); }
  222. }
  223. public bool IsPrivate {
  224. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private); }
  225. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private, value); }
  226. }
  227. public bool IsFamilyAndAssembly {
  228. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem); }
  229. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem, value); }
  230. }
  231. public bool IsAssembly {
  232. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly); }
  233. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly, value); }
  234. }
  235. public bool IsFamily {
  236. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family); }
  237. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family, value); }
  238. }
  239. public bool IsFamilyOrAssembly {
  240. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem); }
  241. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem, value); }
  242. }
  243. public bool IsPublic {
  244. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public); }
  245. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public, value); }
  246. }
  247. public bool IsStatic {
  248. get { return attributes.GetAttributes ((ushort) MethodAttributes.Static); }
  249. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Static, value); }
  250. }
  251. public bool IsFinal {
  252. get { return attributes.GetAttributes ((ushort) MethodAttributes.Final); }
  253. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Final, value); }
  254. }
  255. public bool IsVirtual {
  256. get { return attributes.GetAttributes ((ushort) MethodAttributes.Virtual); }
  257. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Virtual, value); }
  258. }
  259. public bool IsHideBySig {
  260. get { return attributes.GetAttributes ((ushort) MethodAttributes.HideBySig); }
  261. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HideBySig, value); }
  262. }
  263. public bool IsReuseSlot {
  264. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot); }
  265. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot, value); }
  266. }
  267. public bool IsNewSlot {
  268. get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot); }
  269. set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot, value); }
  270. }
  271. public bool IsCheckAccessOnOverride {
  272. get { return attributes.GetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride); }
  273. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride, value); }
  274. }
  275. public bool IsAbstract {
  276. get { return attributes.GetAttributes ((ushort) MethodAttributes.Abstract); }
  277. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Abstract, value); }
  278. }
  279. public bool IsSpecialName {
  280. get { return attributes.GetAttributes ((ushort) MethodAttributes.SpecialName); }
  281. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.SpecialName, value); }
  282. }
  283. public bool IsPInvokeImpl {
  284. get { return attributes.GetAttributes ((ushort) MethodAttributes.PInvokeImpl); }
  285. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.PInvokeImpl, value); }
  286. }
  287. public bool IsUnmanagedExport {
  288. get { return attributes.GetAttributes ((ushort) MethodAttributes.UnmanagedExport); }
  289. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.UnmanagedExport, value); }
  290. }
  291. public bool IsRuntimeSpecialName {
  292. get { return attributes.GetAttributes ((ushort) MethodAttributes.RTSpecialName); }
  293. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.RTSpecialName, value); }
  294. }
  295. public bool HasSecurity {
  296. get { return attributes.GetAttributes ((ushort) MethodAttributes.HasSecurity); }
  297. set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HasSecurity, value); }
  298. }
  299. #endregion
  300. #region MethodImplAttributes
  301. public bool IsIL {
  302. get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL); }
  303. set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL, value); }
  304. }
  305. public bool IsNative {
  306. get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native); }
  307. set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native, value); }
  308. }
  309. public bool IsRuntime {
  310. get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime); }
  311. set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime, value); }
  312. }
  313. public bool IsUnmanaged {
  314. get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged); }
  315. set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged, value); }
  316. }
  317. public bool IsManaged {
  318. get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed); }
  319. set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed, value); }
  320. }
  321. public bool IsForwardRef {
  322. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.ForwardRef); }
  323. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.ForwardRef, value); }
  324. }
  325. public bool IsPreserveSig {
  326. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.PreserveSig); }
  327. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.PreserveSig, value); }
  328. }
  329. public bool IsInternalCall {
  330. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.InternalCall); }
  331. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.InternalCall, value); }
  332. }
  333. public bool IsSynchronized {
  334. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.Synchronized); }
  335. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.Synchronized, value); }
  336. }
  337. public bool NoInlining {
  338. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoInlining); }
  339. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoInlining, value); }
  340. }
  341. public bool NoOptimization {
  342. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoOptimization); }
  343. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoOptimization, value); }
  344. }
  345. public bool AggressiveInlining {
  346. get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.AggressiveInlining); }
  347. set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.AggressiveInlining, value); }
  348. }
  349. #endregion
  350. #region MethodSemanticsAttributes
  351. public bool IsSetter {
  352. get { return this.GetSemantics (MethodSemanticsAttributes.Setter); }
  353. set { this.SetSemantics (MethodSemanticsAttributes.Setter, value); }
  354. }
  355. public bool IsGetter {
  356. get { return this.GetSemantics (MethodSemanticsAttributes.Getter); }
  357. set { this.SetSemantics (MethodSemanticsAttributes.Getter, value); }
  358. }
  359. public bool IsOther {
  360. get { return this.GetSemantics (MethodSemanticsAttributes.Other); }
  361. set { this.SetSemantics (MethodSemanticsAttributes.Other, value); }
  362. }
  363. public bool IsAddOn {
  364. get { return this.GetSemantics (MethodSemanticsAttributes.AddOn); }
  365. set { this.SetSemantics (MethodSemanticsAttributes.AddOn, value); }
  366. }
  367. public bool IsRemoveOn {
  368. get { return this.GetSemantics (MethodSemanticsAttributes.RemoveOn); }
  369. set { this.SetSemantics (MethodSemanticsAttributes.RemoveOn, value); }
  370. }
  371. public bool IsFire {
  372. get { return this.GetSemantics (MethodSemanticsAttributes.Fire); }
  373. set { this.SetSemantics (MethodSemanticsAttributes.Fire, value); }
  374. }
  375. #endregion
  376. public new TypeDefinition DeclaringType {
  377. get { return (TypeDefinition) base.DeclaringType; }
  378. set { base.DeclaringType = value; }
  379. }
  380. public bool IsConstructor {
  381. get {
  382. return this.IsRuntimeSpecialName
  383. && this.IsSpecialName
  384. && (this.Name == ".cctor" || this.Name == ".ctor");
  385. }
  386. }
  387. public override bool IsDefinition {
  388. get { return true; }
  389. }
  390. internal MethodDefinition ()
  391. {
  392. this.token = new MetadataToken (TokenType.Method);
  393. }
  394. public MethodDefinition (string name, MethodAttributes attributes, TypeReference returnType)
  395. : base (name, returnType)
  396. {
  397. this.attributes = (ushort) attributes;
  398. this.HasThis = !this.IsStatic;
  399. this.token = new MetadataToken (TokenType.Method);
  400. }
  401. public override MethodDefinition Resolve ()
  402. {
  403. return this;
  404. }
  405. }
  406. static partial class Mixin {
  407. public static ParameterDefinition GetParameter (this MethodBody self, int index)
  408. {
  409. var method = self.method;
  410. if (method.HasThis) {
  411. if (index == 0)
  412. return self.ThisParameter;
  413. index--;
  414. }
  415. var parameters = method.Parameters;
  416. if (index < 0 || index >= parameters.size)
  417. return null;
  418. return parameters [index];
  419. }
  420. public static VariableDefinition GetVariable (this MethodBody self, int index)
  421. {
  422. var variables = self.Variables;
  423. if (index < 0 || index >= variables.size)
  424. return null;
  425. return variables [index];
  426. }
  427. public static bool GetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics)
  428. {
  429. return (self.SemanticsAttributes & semantics) != 0;
  430. }
  431. public static void SetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics, bool value)
  432. {
  433. if (value)
  434. self.SemanticsAttributes |= semantics;
  435. else
  436. self.SemanticsAttributes &= ~semantics;
  437. }
  438. }
  439. }