1 //
2 // MethodDefinition.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 
29 using Mono.Cecil.Cil;
30 using Mono.Collections.Generic;
31 
32 using RVA = System.UInt32;
33 
34 namespace Mono.Cecil {
35 
36 	public sealed class MethodDefinition : MethodReference, IMemberDefinition, ISecurityDeclarationProvider {
37 
38 		ushort attributes;
39 		ushort impl_attributes;
40 		internal volatile bool sem_attrs_ready;
41 		internal MethodSemanticsAttributes sem_attrs;
42 		Collection<CustomAttribute> custom_attributes;
43 		Collection<SecurityDeclaration> security_declarations;
44 
45 		internal RVA rva;
46 		internal PInvokeInfo pinvoke;
47 		Collection<MethodReference> overrides;
48 
49 		internal MethodBody body;
50 
51 		public MethodAttributes Attributes {
52 			get { return (MethodAttributes) attributes; }
53 			set { attributes = (ushort) value; }
54 		}
55 
56 		public MethodImplAttributes ImplAttributes {
57 			get { return (MethodImplAttributes) impl_attributes; }
58 			set { impl_attributes = (ushort) value; }
59 		}
60 
61 		public MethodSemanticsAttributes SemanticsAttributes {
62 			get {
63 				if (sem_attrs_ready)
64 					return sem_attrs;
65 
66 				if (HasImage) {
67 					ReadSemantics ();
68 					return sem_attrs;
69 				}
70 
71 				sem_attrs = MethodSemanticsAttributes.None;
72 				sem_attrs_ready = true;
73 				return sem_attrs;
74 			}
75 			set { sem_attrs = value; }
76 		}
77 
ReadSemantics()78 		internal void ReadSemantics ()
79 		{
80 			if (sem_attrs_ready)
81 				return;
82 
83 			var module = this.Module;
84 			if (module == null)
85 				return;
86 
87 			if (!module.HasImage)
88 				return;
89 
90 			module.Read (this, (method, reader) => reader.ReadAllSemantics (method));
91 		}
92 
93 		public bool HasSecurityDeclarations {
94 			get {
95 				if (security_declarations != null)
96 					return security_declarations.Count > 0;
97 
98 				return this.GetHasSecurityDeclarations (Module);
99 			}
100 		}
101 
102 		public Collection<SecurityDeclaration> SecurityDeclarations {
103 			get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); }
104 		}
105 
106 		public bool HasCustomAttributes {
107 			get {
108 				if (custom_attributes != null)
109 					return custom_attributes.Count > 0;
110 
111 				return this.GetHasCustomAttributes (Module);
112 			}
113 		}
114 
115 		public Collection<CustomAttribute> CustomAttributes {
116 			get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); }
117 		}
118 
119 		public int RVA {
120 			get { return (int) rva; }
121 		}
122 
123 		public bool HasBody {
124 			get {
125 				return (attributes & (ushort) MethodAttributes.Abstract) == 0 &&
126 					(attributes & (ushort) MethodAttributes.PInvokeImpl) == 0 &&
127 					(impl_attributes & (ushort) MethodImplAttributes.InternalCall) == 0 &&
128 					(impl_attributes & (ushort) MethodImplAttributes.Native) == 0 &&
129 					(impl_attributes & (ushort) MethodImplAttributes.Unmanaged) == 0 &&
130 					(impl_attributes & (ushort) MethodImplAttributes.Runtime) == 0;
131 			}
132 		}
133 
134 		public MethodBody Body {
135 			get {
136 				MethodBody localBody = this.body;
137 				if (localBody != null)
138 					return localBody;
139 
140 				if (!HasBody)
141 					return null;
142 
143 				if (HasImage && rva != 0)
144 					return Module.Read (ref body, this, (method, reader) => reader.ReadMethodBody (method));
145 
146 				return body = new MethodBody (this);
147 			}
148 			set {
149 				var module = this.Module;
150 				if (module == null) {
151 					body = value;
152 					return;
153 				}
154 
155 				// we reset Body to null in ILSpy to save memory; so we need that operation to be thread-safe
156 				lock (module.SyncRoot) {
157 					body = value;
158 				}
159 			}
160 		}
161 
162 		public bool HasPInvokeInfo {
163 			get {
164 				if (pinvoke != null)
165 					return true;
166 
167 				return IsPInvokeImpl;
168 			}
169 		}
170 
171 		public PInvokeInfo PInvokeInfo {
172 			get {
173 				if (pinvoke != null)
174 					return pinvoke;
175 
176 				if (HasImage && IsPInvokeImpl)
177 					return Module.Read (ref pinvoke, this, (method, reader) => reader.ReadPInvokeInfo (method));
178 
179 				return null;
180 			}
181 			set {
182 				IsPInvokeImpl = true;
183 				pinvoke = value;
184 			}
185 		}
186 
187 		public bool HasOverrides {
188 			get {
189 				if (overrides != null)
190 					return overrides.Count > 0;
191 
192 				if (HasImage)
193 					return Module.Read (this, (method, reader) => reader.HasOverrides (method));
194 
195 				return false;
196 			}
197 		}
198 
199 		public Collection<MethodReference> Overrides {
200 			get {
201 				if (overrides != null)
202 					return overrides;
203 
204 				if (HasImage)
205 					return Module.Read (ref overrides, this, (method, reader) => reader.ReadOverrides (method));
206 
207 				return overrides = new Collection<MethodReference> ();
208 			}
209 		}
210 
211 		public override bool HasGenericParameters {
212 			get {
213 				if (generic_parameters != null)
214 					return generic_parameters.Count > 0;
215 
216 				return this.GetHasGenericParameters (Module);
217 			}
218 		}
219 
220 		public override Collection<GenericParameter> GenericParameters {
221 			get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); }
222 		}
223 
224 		#region MethodAttributes
225 
226 		public bool IsCompilerControlled {
227 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled); }
228 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.CompilerControlled, value); }
229 		}
230 
231 		public bool IsPrivate {
232 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private); }
233 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Private, value); }
234 		}
235 
236 		public bool IsFamilyAndAssembly {
237 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem); }
238 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamANDAssem, value); }
239 		}
240 
241 		public bool IsAssembly {
242 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly); }
243 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Assembly, value); }
244 		}
245 
246 		public bool IsFamily {
247 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family); }
248 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Family, value); }
249 		}
250 
251 		public bool IsFamilyOrAssembly {
252 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem); }
253 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.FamORAssem, value); }
254 		}
255 
256 		public bool IsPublic {
257 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public); }
258 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.MemberAccessMask, (ushort) MethodAttributes.Public, value); }
259 		}
260 
261 		public bool IsStatic {
262 			get { return attributes.GetAttributes ((ushort) MethodAttributes.Static); }
263 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Static, value); }
264 		}
265 
266 		public bool IsFinal {
267 			get { return attributes.GetAttributes ((ushort) MethodAttributes.Final); }
268 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Final, value); }
269 		}
270 
271 		public bool IsVirtual {
272 			get { return attributes.GetAttributes ((ushort) MethodAttributes.Virtual); }
273 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Virtual, value); }
274 		}
275 
276 		public bool IsHideBySig {
277 			get { return attributes.GetAttributes ((ushort) MethodAttributes.HideBySig); }
278 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HideBySig, value); }
279 		}
280 
281 		public bool IsReuseSlot {
282 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot); }
283 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.ReuseSlot, value); }
284 		}
285 
286 		public bool IsNewSlot {
287 			get { return attributes.GetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot); }
288 			set { attributes = attributes.SetMaskedAttributes ((ushort) MethodAttributes.VtableLayoutMask, (ushort) MethodAttributes.NewSlot, value); }
289 		}
290 
291 		public bool IsCheckAccessOnOverride {
292 			get { return attributes.GetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride); }
293 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.CheckAccessOnOverride, value); }
294 		}
295 
296 		public bool IsAbstract {
297 			get { return attributes.GetAttributes ((ushort) MethodAttributes.Abstract); }
298 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.Abstract, value); }
299 		}
300 
301 		public bool IsSpecialName {
302 			get { return attributes.GetAttributes ((ushort) MethodAttributes.SpecialName); }
303 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.SpecialName, value); }
304 		}
305 
306 		public bool IsPInvokeImpl {
307 			get { return attributes.GetAttributes ((ushort) MethodAttributes.PInvokeImpl); }
308 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.PInvokeImpl, value); }
309 		}
310 
311 		public bool IsUnmanagedExport {
312 			get { return attributes.GetAttributes ((ushort) MethodAttributes.UnmanagedExport); }
313 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.UnmanagedExport, value); }
314 		}
315 
316 		public bool IsRuntimeSpecialName {
317 			get { return attributes.GetAttributes ((ushort) MethodAttributes.RTSpecialName); }
318 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.RTSpecialName, value); }
319 		}
320 
321 		public bool HasSecurity {
322 			get { return attributes.GetAttributes ((ushort) MethodAttributes.HasSecurity); }
323 			set { attributes = attributes.SetAttributes ((ushort) MethodAttributes.HasSecurity, value); }
324 		}
325 
326 		#endregion
327 
328 		#region MethodImplAttributes
329 
330 		public bool IsIL {
331 			get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL); }
332 			set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.IL, value); }
333 		}
334 
335 		public bool IsNative {
336 			get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native); }
337 			set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Native, value); }
338 		}
339 
340 		public bool IsRuntime {
341 			get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime); }
342 			set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.CodeTypeMask, (ushort) MethodImplAttributes.Runtime, value); }
343 		}
344 
345 		public bool IsUnmanaged {
346 			get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged); }
347 			set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Unmanaged, value); }
348 		}
349 
350 		public bool IsManaged {
351 			get { return impl_attributes.GetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed); }
352 			set { impl_attributes = impl_attributes.SetMaskedAttributes ((ushort) MethodImplAttributes.ManagedMask, (ushort) MethodImplAttributes.Managed, value); }
353 		}
354 
355 		public bool IsForwardRef {
356 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.ForwardRef); }
357 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.ForwardRef, value); }
358 		}
359 
360 		public bool IsPreserveSig {
361 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.PreserveSig); }
362 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.PreserveSig, value); }
363 		}
364 
365 		public bool IsInternalCall {
366 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.InternalCall); }
367 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.InternalCall, value); }
368 		}
369 
370 		public bool IsSynchronized {
371 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.Synchronized); }
372 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.Synchronized, value); }
373 		}
374 
375 		public bool NoInlining {
376 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoInlining); }
377 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoInlining, value); }
378 		}
379 
380 		public bool NoOptimization {
381 			get { return impl_attributes.GetAttributes ((ushort) MethodImplAttributes.NoOptimization); }
382 			set { impl_attributes = impl_attributes.SetAttributes ((ushort) MethodImplAttributes.NoOptimization, value); }
383 		}
384 
385 		#endregion
386 
387 		#region MethodSemanticsAttributes
388 
389 		public bool IsSetter {
390 			get { return this.GetSemantics (MethodSemanticsAttributes.Setter); }
391 			set { this.SetSemantics (MethodSemanticsAttributes.Setter, value); }
392 		}
393 
394 		public bool IsGetter {
395 			get { return this.GetSemantics (MethodSemanticsAttributes.Getter); }
396 			set { this.SetSemantics (MethodSemanticsAttributes.Getter, value); }
397 		}
398 
399 		public bool IsOther {
400 			get { return this.GetSemantics (MethodSemanticsAttributes.Other); }
401 			set { this.SetSemantics (MethodSemanticsAttributes.Other, value); }
402 		}
403 
404 		public bool IsAddOn {
405 			get { return this.GetSemantics (MethodSemanticsAttributes.AddOn); }
406 			set { this.SetSemantics (MethodSemanticsAttributes.AddOn, value); }
407 		}
408 
409 		public bool IsRemoveOn {
410 			get { return this.GetSemantics (MethodSemanticsAttributes.RemoveOn); }
411 			set { this.SetSemantics (MethodSemanticsAttributes.RemoveOn, value); }
412 		}
413 
414 		public bool IsFire {
415 			get { return this.GetSemantics (MethodSemanticsAttributes.Fire); }
416 			set { this.SetSemantics (MethodSemanticsAttributes.Fire, value); }
417 		}
418 
419 		#endregion
420 
421 		public new TypeDefinition DeclaringType {
422 			get { return (TypeDefinition) base.DeclaringType; }
423 			set { base.DeclaringType = value; }
424 		}
425 
426 		public bool IsConstructor {
427 			get {
428 				return this.IsRuntimeSpecialName
429 					&& this.IsSpecialName
430 					&& (this.Name == ".cctor" || this.Name == ".ctor");
431 			}
432 		}
433 
434 		public override bool IsDefinition {
435 			get { return true; }
436 		}
437 
MethodDefinition()438 		internal MethodDefinition ()
439 		{
440 			this.token = new MetadataToken (TokenType.Method);
441 		}
442 
MethodDefinition(string name, MethodAttributes attributes, TypeReference returnType)443 		public MethodDefinition (string name, MethodAttributes attributes, TypeReference returnType)
444 			: base (name, returnType)
445 		{
446 			this.attributes = (ushort) attributes;
447 			this.HasThis = !this.IsStatic;
448 			this.token = new MetadataToken (TokenType.Method);
449 		}
450 
Resolve()451 		public override MethodDefinition Resolve ()
452 		{
453 			return this;
454 		}
455 	}
456 
457 	static partial class Mixin {
458 
GetParameter(this MethodBody self, int index)459 		public static ParameterDefinition GetParameter (this MethodBody self, int index)
460 		{
461 			var method = self.method;
462 
463 			if (method.HasThis) {
464 				if (index == 0)
465 					return self.ThisParameter;
466 
467 				index--;
468 			}
469 
470 			var parameters = method.Parameters;
471 
472 			if (index < 0 || index >= parameters.size)
473 				return null;
474 
475 			return parameters [index];
476 		}
477 
GetVariable(this MethodBody self, int index)478 		public static VariableDefinition GetVariable (this MethodBody self, int index)
479 		{
480 			var variables = self.Variables;
481 
482 			if (index < 0 || index >= variables.size)
483 				return null;
484 
485 			return variables [index];
486 		}
487 
GetSemantics(this MethodDefinition self, MethodSemanticsAttributes semantics)488 		public static bool GetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics)
489 		{
490 			return (self.SemanticsAttributes & semantics) != 0;
491 		}
492 
SetSemantics(this MethodDefinition self, MethodSemanticsAttributes semantics, bool value)493 		public static void SetSemantics (this MethodDefinition self, MethodSemanticsAttributes semantics, bool value)
494 		{
495 			if (value)
496 				self.SemanticsAttributes |= semantics;
497 			else
498 				self.SemanticsAttributes &= ~semantics;
499 		}
500 	}
501 }
502