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