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