1 // 2 // mono-api-info.cs - Dumps public assembly information to an xml file. 3 // 4 // Authors: 5 // Gonzalo Paniagua Javier (gonzalo@ximian.com) 6 // 7 // Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com) 8 // 9 10 using System; 11 using System.Collections; 12 using System.Collections.Generic; 13 using System.Globalization; 14 using System.Linq; 15 using System.Runtime.CompilerServices; 16 using System.Runtime.InteropServices; 17 using System.Security.Permissions; 18 using System.Text; 19 using System.Xml; 20 21 using Mono.Cecil; 22 using Mono.Cecil.Cil; 23 using System.IO; 24 25 namespace CorCompare 26 { 27 public class Driver 28 { Main(string [] args)29 public static int Main (string [] args) 30 { 31 bool showHelp = false; 32 AbiMode = false; 33 FollowForwarders = false; 34 string output = null; 35 36 var acoll = new AssemblyCollection (); 37 38 var options = new Mono.Options.OptionSet { 39 "usage: mono-api-info [OPTIONS+] ASSEMBLY+", 40 "", 41 "Expose IL structure of CLR assemblies as XML.", 42 "", 43 "Available Options:", 44 { "abi", 45 "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].", 46 v => AbiMode = v != null }, 47 { "f|follow-forwarders", 48 "Follow type forwarders.", 49 v => FollowForwarders = v != null }, 50 { "d|L|lib|search-directory=", 51 "Check for assembly references in {DIRECTORY}.", 52 v => TypeHelper.Resolver.AddSearchDirectory (v) }, 53 { "r=", 54 "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.", 55 v => TypeHelper.Resolver.ResolveFile (v) }, 56 { "o=", 57 "The output file. If not specified the output will be written to stdout.", 58 v => output = v }, 59 { "h|?|help", 60 "Show this message and exit.", 61 v => showHelp = v != null }, 62 { "contract-api", 63 "Produces contract API with all members at each level of inheritance hierarchy", 64 v => FullAPISet = v != null }, 65 }; 66 67 var asms = options.Parse (args); 68 69 if (showHelp || asms.Count == 0) { 70 options.WriteOptionDescriptions (Console.Out); 71 Console.WriteLine (); 72 return showHelp? 0 :1; 73 } 74 75 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows); 76 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); 77 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a")); 78 79 foreach (string arg in asms) { 80 acoll.Add (arg); 81 82 if (arg.Contains ("v3.0")) { 83 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727")); 84 } else if (arg.Contains ("v3.5")) { 85 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727")); 86 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation")); 87 } else if (arg.Contains ("v4.0")) { 88 if (arg.Contains ("Silverlight")) { 89 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0")); 90 } else { 91 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319")); 92 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF")); 93 } 94 } else { 95 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg)); 96 } 97 } 98 99 StreamWriter outputStream = null; 100 if (!string.IsNullOrEmpty (output)) 101 outputStream = new StreamWriter (output); 102 try { 103 TextWriter outStream = outputStream ?? Console.Out; 104 var settings = new XmlWriterSettings (); 105 settings.Indent = true; 106 var textWriter = XmlWriter.Create (outStream, settings); 107 var writer = new WellFormedXmlWriter (textWriter); 108 writer.WriteStartDocument (); 109 acoll.Writer = writer; 110 acoll.DoOutput (); 111 writer.WriteEndDocument (); 112 writer.Flush (); 113 } finally { 114 if (outputStream != null) 115 outputStream.Dispose (); 116 } 117 return 0; 118 } 119 120 internal static bool AbiMode { get; private set; } 121 internal static bool FollowForwarders { get; private set; } 122 internal static bool FullAPISet { get; set; } 123 } 124 125 public class Utils { 126 static char[] CharsToCleanup = new char[] { '<', '>', '/' }; 127 CleanupTypeName(TypeReference type)128 public static string CleanupTypeName (TypeReference type) 129 { 130 return CleanupTypeName (type.FullName); 131 } 132 CleanupTypeName(string t)133 public static string CleanupTypeName (string t) 134 { 135 if (t.IndexOfAny (CharsToCleanup) == -1) 136 return t; 137 var sb = new StringBuilder (t.Length); 138 for (int i = 0; i < t.Length; i++) { 139 var ch = t [i]; 140 switch (ch) { 141 case '<': 142 sb.Append ('['); 143 break; 144 case '>': 145 sb.Append (']'); 146 break; 147 case '/': 148 sb.Append ('+'); 149 break; 150 default: 151 sb.Append (ch); 152 break; 153 } 154 } 155 return sb.ToString (); 156 } 157 } 158 159 class AssemblyCollection 160 { 161 XmlWriter writer; 162 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> (); 163 AssemblyCollection()164 public AssemblyCollection () 165 { 166 } 167 Add(string name)168 public bool Add (string name) 169 { 170 AssemblyDefinition ass = LoadAssembly (name); 171 if (ass == null) { 172 Console.Error.WriteLine ("Cannot load assembly file " + name); 173 return false; 174 } 175 176 assemblies.Add (ass); 177 return true; 178 } 179 DoOutput()180 public void DoOutput () 181 { 182 if (writer == null) 183 throw new InvalidOperationException ("Document not set"); 184 185 writer.WriteStartElement ("assemblies"); 186 foreach (AssemblyDefinition a in assemblies) { 187 AssemblyData data = new AssemblyData (writer, a); 188 data.DoOutput (); 189 } 190 writer.WriteEndElement (); 191 } 192 193 public XmlWriter Writer { 194 set { writer = value; } 195 } 196 LoadAssembly(string assembly)197 AssemblyDefinition LoadAssembly (string assembly) 198 { 199 try { 200 if (File.Exists (assembly)) 201 return TypeHelper.Resolver.ResolveFile (assembly); 202 203 return TypeHelper.Resolver.Resolve (AssemblyNameReference.Parse (assembly), new ReaderParameters ()); 204 } catch (Exception e) { 205 Console.WriteLine (e); 206 return null; 207 } 208 } 209 } 210 211 abstract class BaseData 212 { 213 protected XmlWriter writer; 214 BaseData(XmlWriter writer)215 protected BaseData (XmlWriter writer) 216 { 217 this.writer = writer; 218 } 219 DoOutput()220 public abstract void DoOutput (); 221 AddAttribute(string name, string value)222 protected void AddAttribute (string name, string value) 223 { 224 writer.WriteAttributeString (name, value); 225 } 226 } 227 228 class TypeForwardedToData : BaseData 229 { 230 AssemblyDefinition ass; 231 TypeForwardedToData(XmlWriter writer, AssemblyDefinition ass)232 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass) 233 : base (writer) 234 { 235 this.ass = ass; 236 } 237 DoOutput()238 public override void DoOutput () 239 { 240 foreach (ExportedType type in ass.MainModule.ExportedTypes) { 241 242 if (((uint)type.Attributes & 0x200000u) == 0) 243 continue; 244 245 writer.WriteStartElement ("attribute"); 246 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName); 247 writer.WriteStartElement ("properties"); 248 writer.WriteStartElement ("property"); 249 AddAttribute ("name", "Destination"); 250 AddAttribute ("value", Utils.CleanupTypeName (type.FullName)); 251 writer.WriteEndElement (); // properties 252 writer.WriteEndElement (); // properties 253 writer.WriteEndElement (); // attribute 254 } 255 } 256 OutputForwarders(XmlWriter writer, AssemblyDefinition ass)257 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass) 258 { 259 TypeForwardedToData tftd = new TypeForwardedToData (writer, ass); 260 tftd.DoOutput (); 261 } 262 } 263 264 class AssemblyData : BaseData 265 { 266 AssemblyDefinition ass; 267 AssemblyData(XmlWriter writer, AssemblyDefinition ass)268 public AssemblyData (XmlWriter writer, AssemblyDefinition ass) 269 : base (writer) 270 { 271 this.ass = ass; 272 } 273 DoOutput()274 public override void DoOutput () 275 { 276 if (writer == null) 277 throw new InvalidOperationException ("Document not set"); 278 279 writer.WriteStartElement ("assembly"); 280 AssemblyNameDefinition aname = ass.Name; 281 AddAttribute ("name", aname.Name); 282 AddAttribute ("version", aname.Version.ToString ()); 283 284 AttributeData.OutputAttributes (writer, ass); 285 286 var types = new List<TypeDefinition> (); 287 if (ass.MainModule.Types != null) { 288 types.AddRange (ass.MainModule.Types); 289 } 290 291 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) { 292 foreach (var t in ass.MainModule.ExportedTypes) { 293 var forwarded = t.Resolve (); 294 if (forwarded == null) { 295 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name); 296 } 297 types.Add (forwarded); 298 } 299 } 300 301 if (types.Count == 0) { 302 writer.WriteEndElement (); // assembly 303 return; 304 } 305 306 types.Sort (TypeReferenceComparer.Default); 307 308 writer.WriteStartElement ("namespaces"); 309 310 string current_namespace = "$%&$&"; 311 bool in_namespace = false; 312 foreach (TypeDefinition t in types) { 313 if (string.IsNullOrEmpty (t.Namespace)) 314 continue; 315 316 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)) 317 continue; 318 319 if (t.DeclaringType != null) 320 continue; // enforce !nested 321 322 if (t.Namespace != current_namespace) { 323 current_namespace = t.Namespace; 324 if (in_namespace) { 325 writer.WriteEndElement (); // classes 326 writer.WriteEndElement (); // namespace 327 } else { 328 in_namespace = true; 329 } 330 writer.WriteStartElement ("namespace"); 331 AddAttribute ("name", current_namespace); 332 writer.WriteStartElement ("classes"); 333 } 334 335 TypeData bd = new TypeData (writer, t); 336 bd.DoOutput (); 337 338 } 339 340 if (in_namespace) { 341 writer.WriteEndElement (); // classes 342 writer.WriteEndElement (); // namespace 343 } 344 345 writer.WriteEndElement (); // namespaces 346 347 writer.WriteEndElement (); // assembly 348 } 349 } 350 351 abstract class MemberData : BaseData 352 { 353 MemberReference [] members; 354 MemberData(XmlWriter writer, MemberReference [] members)355 public MemberData (XmlWriter writer, MemberReference [] members) 356 : base (writer) 357 { 358 this.members = members; 359 } 360 GetAdditionalCustomAttributeProvider(MemberReference member)361 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) 362 { 363 return null; 364 } 365 DoOutput()366 public override void DoOutput () 367 { 368 writer.WriteStartElement (ParentTag); 369 370 foreach (MemberReference member in members) { 371 writer.WriteStartElement (Tag); 372 AddAttribute ("name", GetName (member)); 373 if (!NoMemberAttributes) 374 AddAttribute ("attrib", GetMemberAttributes (member)); 375 AddExtraAttributes (member); 376 377 AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member)); 378 379 AddExtraData (member); 380 writer.WriteEndElement (); // Tag 381 } 382 383 writer.WriteEndElement (); // ParentTag 384 } 385 AddExtraData(MemberReference memberDefenition)386 protected virtual void AddExtraData (MemberReference memberDefenition) 387 { 388 } 389 AddExtraAttributes(MemberReference memberDefinition)390 protected virtual void AddExtraAttributes (MemberReference memberDefinition) 391 { 392 } 393 GetName(MemberReference memberDefenition)394 protected virtual string GetName (MemberReference memberDefenition) 395 { 396 return "NoNAME"; 397 } 398 GetMemberAttributes(MemberReference memberDefenition)399 protected virtual string GetMemberAttributes (MemberReference memberDefenition) 400 { 401 return null; 402 } 403 404 public virtual bool NoMemberAttributes { 405 get { return false; } 406 set {} 407 } 408 409 public virtual string ParentTag { 410 get { return "NoPARENTTAG"; } 411 } 412 413 public virtual string Tag { 414 get { return "NoTAG"; } 415 } 416 OutputGenericParameters(XmlWriter writer, IGenericParameterProvider provider)417 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider) 418 { 419 if (provider.GenericParameters.Count == 0) 420 return; 421 422 var gparameters = provider.GenericParameters; 423 424 writer.WriteStartElement ("generic-parameters"); 425 426 foreach (GenericParameter gp in gparameters) { 427 writer.WriteStartElement ("generic-parameter"); 428 writer.WriteAttributeString ("name", gp.Name); 429 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ()); 430 431 AttributeData.OutputAttributes (writer, gp); 432 433 var constraints = gp.Constraints; 434 if (constraints.Count == 0) { 435 writer.WriteEndElement (); // generic-parameter 436 continue; 437 } 438 439 writer.WriteStartElement ("generic-parameter-constraints"); 440 441 foreach (TypeReference constraint in constraints) { 442 writer.WriteStartElement ("generic-parameter-constraint"); 443 writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint)); 444 writer.WriteEndElement (); // generic-parameter-constraint 445 } 446 447 writer.WriteEndElement (); // generic-parameter-constraints 448 449 writer.WriteEndElement (); // generic-parameter 450 } 451 452 writer.WriteEndElement (); // generic-parameters 453 } 454 } 455 456 class TypeData : MemberData 457 { 458 TypeDefinition type; 459 TypeData(XmlWriter writer, TypeDefinition type)460 public TypeData (XmlWriter writer, TypeDefinition type) 461 : base (writer, null) 462 { 463 this.type = type; 464 } DoOutput()465 public override void DoOutput () 466 { 467 if (writer == null) 468 throw new InvalidOperationException ("Document not set"); 469 470 writer.WriteStartElement ("class"); 471 AddAttribute ("name", type.Name); 472 string classType = GetClassType (type); 473 AddAttribute ("type", classType); 474 475 if (type.BaseType != null) 476 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType)); 477 478 if (type.IsSealed) 479 AddAttribute ("sealed", "true"); 480 481 if (type.IsAbstract) 482 AddAttribute ("abstract", "true"); 483 484 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum) 485 AddAttribute ("serializable", "true"); 486 487 string charSet = GetCharSet (type); 488 AddAttribute ("charset", charSet); 489 490 string layout = GetLayout (type); 491 if (layout != null) 492 AddAttribute ("layout", layout); 493 494 if (type.PackingSize >= 0) { 495 AddAttribute ("pack", type.PackingSize.ToString ()); 496 } 497 498 if (type.ClassSize >= 0) { 499 AddAttribute ("size", type.ClassSize.ToString ()); 500 } 501 502 if (type.IsEnum) { 503 var value_type = GetEnumValueField (type); 504 if (value_type == null) 505 throw new NotSupportedException (); 506 507 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType)); 508 } 509 510 AttributeData.OutputAttributes (writer, type); 511 512 var ifaces = TypeHelper.GetInterfaces (type). 513 Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces 514 OrderBy (s => s.FullName, StringComparer.Ordinal); 515 516 if (ifaces.Any ()) { 517 writer.WriteStartElement ("interfaces"); 518 foreach (TypeReference iface in ifaces) { 519 writer.WriteStartElement ("interface"); 520 AddAttribute ("name", Utils.CleanupTypeName (iface)); 521 writer.WriteEndElement (); // interface 522 } 523 writer.WriteEndElement (); // interfaces 524 } 525 526 MemberData.OutputGenericParameters (writer, type); 527 528 ArrayList members = new ArrayList (); 529 530 FieldDefinition [] fields = GetFields (type); 531 if (fields.Length > 0) { 532 Array.Sort (fields, MemberReferenceComparer.Default); 533 FieldData fd = new FieldData (writer, fields); 534 members.Add (fd); 535 } 536 537 if (!Driver.AbiMode) { 538 539 MethodDefinition [] ctors = GetConstructors (type); 540 if (ctors.Length > 0) { 541 Array.Sort (ctors, MethodDefinitionComparer.Default); 542 members.Add (new ConstructorData (writer, ctors)); 543 } 544 545 PropertyDefinition[] properties = GetProperties (type, Driver.FullAPISet); 546 if (properties.Length > 0) { 547 Array.Sort (properties, PropertyDefinitionComparer.Default); 548 members.Add (new PropertyData (writer, properties)); 549 } 550 551 EventDefinition [] events = GetEvents (type); 552 if (events.Length > 0) { 553 Array.Sort (events, MemberReferenceComparer.Default); 554 members.Add (new EventData (writer, events)); 555 } 556 557 MethodDefinition [] methods = GetMethods (type, Driver.FullAPISet); 558 if (methods.Length > 0) { 559 Array.Sort (methods, MethodDefinitionComparer.Default); 560 members.Add (new MethodData (writer, methods)); 561 } 562 } 563 564 foreach (MemberData md in members) 565 md.DoOutput (); 566 567 var nested = type.NestedTypes; 568 //remove non public(familiy) and nested in second degree 569 for (int i = nested.Count - 1; i >= 0; i--) { 570 TypeDefinition t = nested [i]; 571 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic || 572 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily || 573 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) { 574 // public 575 if (t.DeclaringType == type) 576 continue; // not nested of nested 577 } 578 579 nested.RemoveAt (i); 580 } 581 582 if (nested.Count > 0) { 583 var nestedArray = nested.ToArray (); 584 Array.Sort (nestedArray, TypeReferenceComparer.Default); 585 586 writer.WriteStartElement ("classes"); 587 foreach (TypeDefinition t in nestedArray) { 588 TypeData td = new TypeData (writer, t); 589 td.DoOutput (); 590 } 591 writer.WriteEndElement (); // classes 592 } 593 594 writer.WriteEndElement (); // class 595 } 596 GetEnumValueField(TypeDefinition type)597 static FieldReference GetEnumValueField (TypeDefinition type) 598 { 599 foreach (FieldDefinition field in type.Fields) 600 if (field.IsSpecialName && field.Name == "value__") 601 return field; 602 603 return null; 604 } 605 GetMemberAttributes(MemberReference member)606 protected override string GetMemberAttributes (MemberReference member) 607 { 608 if (member != type) 609 throw new InvalidOperationException ("odd"); 610 611 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture); 612 } 613 MustDocumentMethod(MethodDefinition method)614 public static bool MustDocumentMethod (MethodDefinition method) { 615 // All other methods 616 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask; 617 return maskedAccess == MethodAttributes.Public 618 || maskedAccess == MethodAttributes.Family 619 || maskedAccess == MethodAttributes.FamORAssem; 620 } 621 GetClassType(TypeDefinition t)622 static string GetClassType (TypeDefinition t) 623 { 624 if (t.IsEnum) 625 return "enum"; 626 627 if (t.IsValueType) 628 return "struct"; 629 630 if (t.IsInterface) 631 return "interface"; 632 633 if (TypeHelper.IsDelegate(t)) 634 return "delegate"; 635 636 if (t.IsPointer) 637 return "pointer"; 638 639 return "class"; 640 } 641 GetCharSet(TypeDefinition type)642 static string GetCharSet (TypeDefinition type) 643 { 644 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask; 645 if (maskedStringFormat == TypeAttributes.AnsiClass) 646 return CharSet.Ansi.ToString (); 647 648 if (maskedStringFormat == TypeAttributes.AutoClass) 649 return CharSet.Auto.ToString (); 650 651 if (maskedStringFormat == TypeAttributes.UnicodeClass) 652 return CharSet.Unicode.ToString (); 653 654 return CharSet.None.ToString (); 655 } 656 GetLayout(TypeDefinition type)657 static string GetLayout (TypeDefinition type) 658 { 659 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask; 660 if (maskedLayout == TypeAttributes.AutoLayout) 661 return LayoutKind.Auto.ToString (); 662 663 if (maskedLayout == TypeAttributes.ExplicitLayout) 664 return LayoutKind.Explicit.ToString (); 665 666 if (maskedLayout == TypeAttributes.SequentialLayout) 667 return LayoutKind.Sequential.ToString (); 668 669 return null; 670 } 671 GetFields(TypeDefinition type)672 FieldDefinition [] GetFields (TypeDefinition type) { 673 ArrayList list = new ArrayList (); 674 675 var fields = type.Fields; 676 foreach (FieldDefinition field in fields) { 677 if (field.IsSpecialName) 678 continue; 679 680 if (Driver.AbiMode && field.IsStatic) 681 continue; 682 683 // we're only interested in public or protected members 684 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask); 685 if (Driver.AbiMode && !field.IsNotSerialized) { 686 list.Add (field); 687 } else { 688 if (maskedVisibility == FieldAttributes.Public 689 || maskedVisibility == FieldAttributes.Family 690 || maskedVisibility == FieldAttributes.FamORAssem) { 691 list.Add (field); 692 } 693 } 694 } 695 696 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition)); 697 } 698 699 GetProperties(TypeDefinition type, bool fullAPI)700 internal static PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) { 701 var list = new List<PropertyDefinition> (); 702 703 var t = type; 704 do { 705 var properties = t.Properties;//type.GetProperties (flags); 706 foreach (PropertyDefinition property in properties) { 707 MethodDefinition getMethod = property.GetMethod; 708 MethodDefinition setMethod = property.SetMethod; 709 710 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod); 711 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod); 712 713 // if neither the getter or setter should be documented, then 714 // skip the property 715 if (hasGetter || hasSetter) { 716 717 if (t != type && list.Any (l => l.Name == property.Name)) 718 continue; 719 720 list.Add (property); 721 } 722 } 723 724 if (!fullAPI) 725 break; 726 727 if (t.IsInterface || t.IsEnum) 728 break; 729 730 if (t.BaseType == null || t.BaseType.FullName == "System.Object") 731 t = null; 732 else 733 t = t.BaseType.Resolve (); 734 735 } while (t != null); 736 737 return list.ToArray (); 738 } 739 GetMethods(TypeDefinition type, bool fullAPI)740 private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI) 741 { 742 var list = new List<MethodDefinition> (); 743 744 var t = type; 745 do { 746 var methods = t.Methods;//type.GetMethods (flags); 747 foreach (MethodDefinition method in methods) { 748 if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal)) 749 continue; 750 751 // we're only interested in public or protected members 752 if (!MustDocumentMethod (method)) 753 continue; 754 755 if (t == type && IsFinalizer (method)) { 756 string name = method.DeclaringType.Name; 757 int arity = name.IndexOf ('`'); 758 if (arity > 0) 759 name = name.Substring (0, arity); 760 761 method.Name = "~" + name; 762 } 763 764 if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count && 765 l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ()))) 766 continue; 767 768 list.Add (method); 769 } 770 771 if (!fullAPI) 772 break; 773 774 if (t.IsInterface || t.IsEnum) 775 break; 776 777 if (t.BaseType == null || t.BaseType.FullName == "System.Object") 778 t = null; 779 else 780 t = t.BaseType.Resolve (); 781 782 } while (t != null); 783 784 return list.ToArray (); 785 } 786 787 sealed class ParameterComparer : IEqualityComparer<ParameterDefinition> 788 { Equals(ParameterDefinition x, ParameterDefinition y)789 public bool Equals (ParameterDefinition x, ParameterDefinition y) 790 { 791 return x.ParameterType.Name == y.ParameterType.Name; 792 } 793 GetHashCode(ParameterDefinition obj)794 public int GetHashCode (ParameterDefinition obj) 795 { 796 return obj.ParameterType.Name.GetHashCode (); 797 } 798 } 799 IsFinalizer(MethodDefinition method)800 static bool IsFinalizer (MethodDefinition method) 801 { 802 if (method.Name != "Finalize") 803 return false; 804 805 if (!method.IsVirtual) 806 return false; 807 808 if (method.Parameters.Count != 0) 809 return false; 810 811 return true; 812 } 813 GetConstructors(TypeDefinition type)814 private MethodDefinition [] GetConstructors (TypeDefinition type) 815 { 816 ArrayList list = new ArrayList (); 817 818 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags); 819 foreach (MethodDefinition constructor in ctors) { 820 // we're only interested in public or protected members 821 if (!MustDocumentMethod(constructor)) 822 continue; 823 824 list.Add (constructor); 825 } 826 827 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition)); 828 } 829 GetEvents(TypeDefinition type)830 private EventDefinition[] GetEvents (TypeDefinition type) 831 { 832 ArrayList list = new ArrayList (); 833 834 var events = type.Events;//type.GetEvents (flags); 835 foreach (EventDefinition eventDef in events) { 836 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true); 837 838 if (addMethod == null || !MustDocumentMethod (addMethod)) 839 continue; 840 841 list.Add (eventDef); 842 } 843 844 return (EventDefinition []) list.ToArray (typeof (EventDefinition)); 845 } 846 } 847 848 class FieldData : MemberData 849 { FieldData(XmlWriter writer, FieldDefinition [] members)850 public FieldData (XmlWriter writer, FieldDefinition [] members) 851 : base (writer, members) 852 { 853 } 854 GetName(MemberReference memberDefenition)855 protected override string GetName (MemberReference memberDefenition) 856 { 857 FieldDefinition field = (FieldDefinition) memberDefenition; 858 return field.Name; 859 } 860 GetMemberAttributes(MemberReference memberDefenition)861 protected override string GetMemberAttributes (MemberReference memberDefenition) 862 { 863 FieldDefinition field = (FieldDefinition) memberDefenition; 864 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture); 865 } 866 AddExtraAttributes(MemberReference memberDefinition)867 protected override void AddExtraAttributes (MemberReference memberDefinition) 868 { 869 base.AddExtraAttributes (memberDefinition); 870 871 FieldDefinition field = (FieldDefinition) memberDefinition; 872 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType)); 873 874 if (field.IsLiteral) { 875 object value = field.Constant;//object value = field.GetValue (null); 876 string stringValue = null; 877 //if (value is Enum) { 878 // // FIXME: when Mono bug #60090 has been 879 // // fixed, we should just be able to use 880 // // Convert.ToString 881 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture); 882 //} 883 //else { 884 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture); 885 //} 886 887 if (stringValue != null) 888 AddAttribute ("value", stringValue); 889 } 890 } 891 892 public override string ParentTag { 893 get { return "fields"; } 894 } 895 896 public override string Tag { 897 get { return "field"; } 898 } 899 } 900 901 class PropertyData : MemberData 902 { PropertyData(XmlWriter writer, PropertyDefinition [] members)903 public PropertyData (XmlWriter writer, PropertyDefinition [] members) 904 : base (writer, members) 905 { 906 } 907 GetName(MemberReference memberDefenition)908 protected override string GetName (MemberReference memberDefenition) 909 { 910 PropertyDefinition prop = (PropertyDefinition) memberDefenition; 911 return prop.Name; 912 } 913 GetMethods(PropertyDefinition prop, out bool haveParameters)914 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters) 915 { 916 MethodDefinition _get = prop.GetMethod; 917 MethodDefinition _set = prop.SetMethod; 918 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get)); 919 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set)); 920 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1); 921 MethodDefinition [] methods; 922 923 if (haveGet && haveSet) { 924 methods = new MethodDefinition [] { _get, _set }; 925 } else if (haveGet) { 926 methods = new MethodDefinition [] { _get }; 927 } else if (haveSet) { 928 methods = new MethodDefinition [] { _set }; 929 } else { 930 //odd 931 return null; 932 } 933 934 return methods; 935 } 936 AddExtraAttributes(MemberReference memberDefinition)937 protected override void AddExtraAttributes (MemberReference memberDefinition) 938 { 939 base.AddExtraAttributes (memberDefinition); 940 941 PropertyDefinition prop = (PropertyDefinition) memberDefinition; 942 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType)); 943 944 bool haveParameters; 945 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters); 946 947 if (methods != null && haveParameters) { 948 string parms = Parameters.GetSignature (methods [0].Parameters); 949 if (!string.IsNullOrEmpty (parms)) 950 AddAttribute ("params", parms); 951 } 952 953 } 954 AddExtraData(MemberReference memberDefenition)955 protected override void AddExtraData (MemberReference memberDefenition) 956 { 957 base.AddExtraData (memberDefenition); 958 959 bool haveParameters; 960 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters); 961 962 if (methods == null) 963 return; 964 965 MethodData data = new MethodData (writer, methods); 966 //data.NoMemberAttributes = true; 967 data.DoOutput (); 968 } 969 GetMemberAttributes(MemberReference memberDefenition)970 protected override string GetMemberAttributes (MemberReference memberDefenition) 971 { 972 PropertyDefinition prop = (PropertyDefinition) memberDefenition; 973 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture); 974 } 975 976 public override string ParentTag { 977 get { return "properties"; } 978 } 979 980 public override string Tag { 981 get { return "property"; } 982 } 983 } 984 985 class EventData : MemberData 986 { EventData(XmlWriter writer, EventDefinition [] members)987 public EventData (XmlWriter writer, EventDefinition [] members) 988 : base (writer, members) 989 { 990 } 991 GetName(MemberReference memberDefenition)992 protected override string GetName (MemberReference memberDefenition) 993 { 994 EventDefinition evt = (EventDefinition) memberDefenition; 995 return evt.Name; 996 } 997 GetMemberAttributes(MemberReference memberDefenition)998 protected override string GetMemberAttributes (MemberReference memberDefenition) 999 { 1000 EventDefinition evt = (EventDefinition) memberDefenition; 1001 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture); 1002 } 1003 AddExtraAttributes(MemberReference memberDefinition)1004 protected override void AddExtraAttributes (MemberReference memberDefinition) 1005 { 1006 base.AddExtraAttributes (memberDefinition); 1007 1008 EventDefinition evt = (EventDefinition) memberDefinition; 1009 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType)); 1010 } 1011 1012 public override string ParentTag { 1013 get { return "events"; } 1014 } 1015 1016 public override string Tag { 1017 get { return "event"; } 1018 } 1019 } 1020 1021 class MethodData : MemberData 1022 { 1023 bool noAtts; 1024 MethodData(XmlWriter writer, MethodDefinition [] members)1025 public MethodData (XmlWriter writer, MethodDefinition [] members) 1026 : base (writer, members) 1027 { 1028 } 1029 GetName(MemberReference memberDefenition)1030 protected override string GetName (MemberReference memberDefenition) 1031 { 1032 MethodDefinition method = (MethodDefinition) memberDefenition; 1033 string name = method.Name; 1034 string parms = Parameters.GetSignature (method.Parameters); 1035 1036 return string.Format ("{0}({1})", name, parms); 1037 } 1038 GetMemberAttributes(MemberReference memberDefenition)1039 protected override string GetMemberAttributes (MemberReference memberDefenition) 1040 { 1041 MethodDefinition method = (MethodDefinition) memberDefenition; 1042 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture); 1043 } 1044 GetAdditionalCustomAttributeProvider(MemberReference member)1045 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) 1046 { 1047 var mbase = (MethodDefinition) member; 1048 return mbase.MethodReturnType; 1049 } 1050 AddExtraAttributes(MemberReference memberDefinition)1051 protected override void AddExtraAttributes (MemberReference memberDefinition) 1052 { 1053 base.AddExtraAttributes (memberDefinition); 1054 1055 if (!(memberDefinition is MethodDefinition)) 1056 return; 1057 1058 MethodDefinition mbase = (MethodDefinition) memberDefinition; 1059 1060 if (mbase.IsAbstract) 1061 AddAttribute ("abstract", "true"); 1062 if (mbase.IsVirtual) 1063 AddAttribute ("virtual", "true"); 1064 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot) 1065 AddAttribute ("sealed", "true"); 1066 if (mbase.IsStatic) 1067 AddAttribute ("static", "true"); 1068 var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase); 1069 if (baseMethod != null && baseMethod != mbase) { 1070 // This indicates whether this method is an override of another method. 1071 // This information is not necessarily available in the api info for any 1072 // particular assembly, because a method is only overriding another if 1073 // there is a base virtual function with the same signature, and that 1074 // base method can come from another assembly. 1075 AddAttribute ("is-override", "true"); 1076 } 1077 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType); 1078 if (rettype != "System.Void" || !mbase.IsConstructor) 1079 AddAttribute ("returntype", (rettype)); 1080 // 1081 // if (mbase.MethodReturnType.HasCustomAttributes) 1082 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType); 1083 } 1084 AddExtraData(MemberReference memberDefenition)1085 protected override void AddExtraData (MemberReference memberDefenition) 1086 { 1087 base.AddExtraData (memberDefenition); 1088 1089 if (!(memberDefenition is MethodDefinition)) 1090 return; 1091 1092 MethodDefinition mbase = (MethodDefinition)memberDefenition; 1093 1094 ParameterData parms = new ParameterData (writer, mbase.Parameters) { 1095 HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") 1096 }; 1097 1098 parms.DoOutput (); 1099 1100 MemberData.OutputGenericParameters (writer, mbase); 1101 } 1102 1103 public override bool NoMemberAttributes { 1104 get { return noAtts; } 1105 set { noAtts = value; } 1106 } 1107 1108 public override string ParentTag { 1109 get { return "methods"; } 1110 } 1111 1112 public override string Tag { 1113 get { return "method"; } 1114 } 1115 } 1116 1117 class ConstructorData : MethodData 1118 { ConstructorData(XmlWriter writer, MethodDefinition [] members)1119 public ConstructorData (XmlWriter writer, MethodDefinition [] members) 1120 : base (writer, members) 1121 { 1122 } 1123 1124 public override string ParentTag { 1125 get { return "constructors"; } 1126 } 1127 1128 public override string Tag { 1129 get { return "constructor"; } 1130 } 1131 } 1132 1133 class ParameterData : BaseData 1134 { 1135 private IList<ParameterDefinition> parameters; 1136 ParameterData(XmlWriter writer, IList<ParameterDefinition> parameters)1137 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters) 1138 : base (writer) 1139 { 1140 this.parameters = parameters; 1141 } 1142 1143 public bool HasExtensionParameter { get; set; } 1144 DoOutput()1145 public override void DoOutput () 1146 { 1147 bool first = true; 1148 writer.WriteStartElement ("parameters"); 1149 foreach (ParameterDefinition parameter in parameters) { 1150 writer.WriteStartElement ("parameter"); 1151 AddAttribute ("name", parameter.Name); 1152 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture)); 1153 AddAttribute ("attrib", ((int) parameter.Attributes).ToString()); 1154 1155 string direction = first && HasExtensionParameter ? "this" : "in"; 1156 first = false; 1157 1158 var pt = parameter.ParameterType; 1159 var brt = pt as ByReferenceType; 1160 if (brt != null) { 1161 direction = parameter.IsOut ? "out" : "ref"; 1162 pt = brt.ElementType; 1163 } 1164 1165 AddAttribute ("type", Utils.CleanupTypeName (pt)); 1166 1167 if (parameter.IsOptional) { 1168 AddAttribute ("optional", "true"); 1169 if (parameter.HasConstant) 1170 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ()); 1171 } 1172 1173 if (direction != "in") 1174 AddAttribute ("direction", direction); 1175 1176 AttributeData.OutputAttributes (writer, parameter); 1177 writer.WriteEndElement (); // parameter 1178 } 1179 writer.WriteEndElement (); // parameters 1180 } 1181 } 1182 1183 class AttributeData 1184 { DoOutput(XmlWriter writer, IList<ICustomAttributeProvider> providers)1185 public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers) 1186 { 1187 if (writer == null) 1188 throw new InvalidOperationException ("Document not set"); 1189 1190 if (providers == null || providers.Count == 0) 1191 return; 1192 1193 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes)) 1194 return; 1195 1196 writer.WriteStartElement ("attributes"); 1197 1198 foreach (var provider in providers) { 1199 if (provider == null) 1200 continue; 1201 1202 if (!provider.HasCustomAttributes) 1203 continue; 1204 1205 1206 var ass = provider as AssemblyDefinition; 1207 if (ass != null && !Driver.FollowForwarders) 1208 TypeForwardedToData.OutputForwarders (writer, ass); 1209 1210 var attributes = provider.CustomAttributes. 1211 Where ((att) => !SkipAttribute (att)). 1212 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal); 1213 1214 foreach (var att in attributes) { 1215 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType); 1216 1217 writer.WriteStartElement ("attribute"); 1218 writer.WriteAttributeString ("name", attName); 1219 1220 var attribute_mapping = CreateAttributeMapping (att); 1221 1222 if (attribute_mapping != null) { 1223 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId"); 1224 if (mapping.Any ()) { 1225 writer.WriteStartElement ("properties"); 1226 foreach (var kvp in mapping) { 1227 string name = kvp.Key; 1228 object o = kvp.Value; 1229 1230 writer.WriteStartElement ("property"); 1231 writer.WriteAttributeString ("name", name); 1232 1233 if (o == null) { 1234 writer.WriteAttributeString ("value", "null"); 1235 } else { 1236 string value = o.ToString (); 1237 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal)) 1238 value = value.ToUpper (); 1239 writer.WriteAttributeString ("value", value); 1240 } 1241 1242 writer.WriteEndElement (); // property 1243 } 1244 writer.WriteEndElement (); // properties 1245 } 1246 } 1247 writer.WriteEndElement (); // attribute 1248 } 1249 } 1250 1251 writer.WriteEndElement (); // attributes 1252 } 1253 CreateAttributeMapping(CustomAttribute attribute)1254 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute) 1255 { 1256 Dictionary<string, object> mapping = null; 1257 1258 PopulateMapping (ref mapping, attribute); 1259 1260 var constructor = attribute.Constructor.Resolve (); 1261 if (constructor == null || !constructor.HasParameters) 1262 return mapping; 1263 1264 PopulateMapping (ref mapping, constructor, attribute); 1265 1266 return mapping; 1267 } 1268 PopulateMapping(ref Dictionary<string, object> mapping, CustomAttribute attribute)1269 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute) 1270 { 1271 if (!attribute.HasProperties) 1272 return; 1273 1274 foreach (var named_argument in attribute.Properties) { 1275 var name = named_argument.Name; 1276 var arg = named_argument.Argument; 1277 1278 if (arg.Value is CustomAttributeArgument) 1279 arg = (CustomAttributeArgument) arg.Value; 1280 1281 if (mapping == null) 1282 mapping = new Dictionary<string, object> (StringComparer.Ordinal); 1283 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value)); 1284 } 1285 } 1286 CreateArgumentFieldMapping(MethodDefinition constructor)1287 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor) 1288 { 1289 Dictionary<FieldReference, int> field_mapping = null; 1290 1291 int? argument = null; 1292 1293 foreach (Instruction instruction in constructor.Body.Instructions) { 1294 switch (instruction.OpCode.Code) { 1295 case Code.Ldarg_1: 1296 argument = 1; 1297 break; 1298 case Code.Ldarg_2: 1299 argument = 2; 1300 break; 1301 case Code.Ldarg_3: 1302 argument = 3; 1303 break; 1304 case Code.Ldarg: 1305 case Code.Ldarg_S: 1306 argument = ((ParameterDefinition) instruction.Operand).Index + 1; 1307 break; 1308 1309 case Code.Stfld: 1310 FieldReference field = (FieldReference) instruction.Operand; 1311 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName) 1312 continue; 1313 1314 if (!argument.HasValue) 1315 break; 1316 1317 if (field_mapping == null) 1318 field_mapping = new Dictionary<FieldReference, int> (); 1319 1320 if (!field_mapping.ContainsKey (field)) 1321 field_mapping.Add (field, (int) argument - 1); 1322 1323 argument = null; 1324 break; 1325 } 1326 } 1327 1328 return field_mapping; 1329 } 1330 CreatePropertyFieldMapping(TypeDefinition type)1331 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type) 1332 { 1333 Dictionary<PropertyDefinition, FieldReference> property_mapping = null; 1334 1335 foreach (PropertyDefinition property in type.Properties) { 1336 if (property.GetMethod == null) 1337 continue; 1338 if (!property.GetMethod.HasBody) 1339 continue; 1340 1341 foreach (Instruction instruction in property.GetMethod.Body.Instructions) { 1342 if (instruction.OpCode.Code != Code.Ldfld) 1343 continue; 1344 1345 FieldReference field = (FieldReference) instruction.Operand; 1346 if (field.DeclaringType.FullName != type.FullName) 1347 continue; 1348 1349 if (property_mapping == null) 1350 property_mapping = new Dictionary<PropertyDefinition, FieldReference> (); 1351 property_mapping.Add (property, field); 1352 break; 1353 } 1354 } 1355 1356 return property_mapping; 1357 } 1358 PopulateMapping(ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)1359 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute) 1360 { 1361 if (!constructor.HasBody) 1362 return; 1363 1364 // Custom handling for attributes with arguments which cannot be easily extracted 1365 var ca = attribute.ConstructorArguments; 1366 switch (constructor.DeclaringType.FullName) { 1367 case "System.Runtime.CompilerServices.DecimalConstantAttribute": 1368 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ? 1369 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) : 1370 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value); 1371 1372 if (mapping == null) 1373 mapping = new Dictionary<string, object> (StringComparer.Ordinal); 1374 mapping.Add ("Value", dca.Value); 1375 return; 1376 case "System.ComponentModel.BindableAttribute": 1377 if (ca.Count != 1) 1378 break; 1379 1380 if (mapping == null) 1381 mapping = new Dictionary<string, object> (StringComparer.Ordinal); 1382 1383 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) { 1384 mapping.Add ("Bindable", ca[0].Value); 1385 } else if (constructor.Parameters[0].ParameterType.FullName == "System.ComponentModel.BindableSupport") { 1386 if ((int)ca[0].Value == 0) 1387 mapping.Add ("Bindable", false); 1388 else if ((int)ca[0].Value == 1) 1389 mapping.Add ("Bindable", true); 1390 else 1391 throw new NotImplementedException (); 1392 } else { 1393 throw new NotImplementedException (); 1394 } 1395 1396 return; 1397 } 1398 1399 var field_mapping = CreateArgumentFieldMapping (constructor); 1400 if (field_mapping != null) { 1401 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType); 1402 1403 if (property_mapping != null) { 1404 foreach (var pair in property_mapping) { 1405 int argument; 1406 if (!field_mapping.TryGetValue (pair.Value, out argument)) 1407 continue; 1408 1409 var ca_arg = ca [argument]; 1410 if (ca_arg.Value is CustomAttributeArgument) 1411 ca_arg = (CustomAttributeArgument)ca_arg.Value; 1412 1413 if (mapping == null) 1414 mapping = new Dictionary<string, object> (StringComparer.Ordinal); 1415 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value)); 1416 } 1417 } 1418 } 1419 } 1420 GetArgumentValue(TypeReference reference, object value)1421 static object GetArgumentValue (TypeReference reference, object value) 1422 { 1423 var type = reference.Resolve (); 1424 if (type == null) 1425 return value; 1426 1427 if (type.IsEnum) { 1428 if (IsFlaggedEnum (type)) 1429 return GetFlaggedEnumValue (type, value); 1430 1431 return GetEnumValue (type, value); 1432 } 1433 1434 return value; 1435 } 1436 IsFlaggedEnum(TypeDefinition type)1437 static bool IsFlaggedEnum (TypeDefinition type) 1438 { 1439 if (!type.IsEnum) 1440 return false; 1441 1442 if (!type.HasCustomAttributes) 1443 return false; 1444 1445 foreach (CustomAttribute attribute in type.CustomAttributes) 1446 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute") 1447 return true; 1448 1449 return false; 1450 } 1451 GetFlaggedEnumValue(TypeDefinition type, object value)1452 static object GetFlaggedEnumValue (TypeDefinition type, object value) 1453 { 1454 if (value is ulong) 1455 return GetFlaggedEnumValue (type, (ulong)value); 1456 1457 long flags = Convert.ToInt64 (value); 1458 var signature = new StringBuilder (); 1459 1460 for (int i = type.Fields.Count - 1; i >= 0; i--) { 1461 FieldDefinition field = type.Fields [i]; 1462 1463 if (!field.HasConstant) 1464 continue; 1465 1466 long flag = Convert.ToInt64 (field.Constant); 1467 1468 if (flag == 0) 1469 continue; 1470 1471 if ((flags & flag) == flag) { 1472 if (signature.Length != 0) 1473 signature.Append (", "); 1474 1475 signature.Append (field.Name); 1476 flags -= flag; 1477 } 1478 } 1479 1480 return signature.ToString (); 1481 } 1482 GetFlaggedEnumValue(TypeDefinition type, ulong flags)1483 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags) 1484 { 1485 var signature = new StringBuilder (); 1486 1487 for (int i = type.Fields.Count - 1; i >= 0; i--) { 1488 FieldDefinition field = type.Fields [i]; 1489 1490 if (!field.HasConstant) 1491 continue; 1492 1493 ulong flag = Convert.ToUInt64 (field.Constant); 1494 1495 if (flag == 0) 1496 continue; 1497 1498 if ((flags & flag) == flag) { 1499 if (signature.Length != 0) 1500 signature.Append (", "); 1501 1502 signature.Append (field.Name); 1503 flags -= flag; 1504 } 1505 } 1506 1507 return signature.ToString (); 1508 } 1509 GetEnumValue(TypeDefinition type, object value)1510 static object GetEnumValue (TypeDefinition type, object value) 1511 { 1512 foreach (FieldDefinition field in type.Fields) { 1513 if (!field.HasConstant) 1514 continue; 1515 1516 if (Comparer.Default.Compare (field.Constant, value) == 0) 1517 return field.Name; 1518 } 1519 1520 return value; 1521 } 1522 SkipAttribute(CustomAttribute attribute)1523 static bool SkipAttribute (CustomAttribute attribute) 1524 { 1525 if (!TypeHelper.IsPublic (attribute)) 1526 return true; 1527 1528 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal); 1529 } 1530 OutputAttributes(XmlWriter writer, params ICustomAttributeProvider[] providers)1531 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers) 1532 { 1533 AttributeData.DoOutput (writer, providers); 1534 } 1535 } 1536 1537 static class Parameters { 1538 GetSignature(IList<ParameterDefinition> infos)1539 public static string GetSignature (IList<ParameterDefinition> infos) 1540 { 1541 if (infos == null || infos.Count == 0) 1542 return string.Empty; 1543 1544 var signature = new StringBuilder (); 1545 for (int i = 0; i < infos.Count; i++) { 1546 1547 if (i > 0) 1548 signature.Append (", "); 1549 1550 ParameterDefinition info = infos [i]; 1551 1552 string modifier = string.Empty; 1553 if (info.ParameterType.IsByReference) { 1554 if ((info.Attributes & ParameterAttributes.In) != 0) 1555 modifier = "in"; 1556 else if ((info.Attributes & ParameterAttributes.Out) != 0) 1557 modifier = "out"; 1558 } 1559 1560 if (modifier.Length > 0) { 1561 signature.Append (modifier); 1562 signature.Append (" "); 1563 } 1564 1565 signature.Append (Utils.CleanupTypeName (info.ParameterType)); 1566 } 1567 1568 return signature.ToString (); 1569 } 1570 1571 } 1572 1573 class TypeReferenceComparer : IComparer<TypeReference> 1574 { 1575 public static TypeReferenceComparer Default = new TypeReferenceComparer (); 1576 Compare(TypeReference a, TypeReference b)1577 public int Compare (TypeReference a, TypeReference b) 1578 { 1579 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal); 1580 if (result != 0) 1581 return result; 1582 1583 return String.Compare (a.Name, b.Name, StringComparison.Ordinal); 1584 } 1585 } 1586 1587 class MemberReferenceComparer : IComparer 1588 { 1589 public static MemberReferenceComparer Default = new MemberReferenceComparer (); 1590 Compare(object a, object b)1591 public int Compare (object a, object b) 1592 { 1593 MemberReference ma = (MemberReference) a; 1594 MemberReference mb = (MemberReference) b; 1595 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); 1596 } 1597 } 1598 1599 class PropertyDefinitionComparer : IComparer<PropertyDefinition> 1600 { 1601 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer (); 1602 Compare(PropertyDefinition ma, PropertyDefinition mb)1603 public int Compare (PropertyDefinition ma, PropertyDefinition mb) 1604 { 1605 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); 1606 if (res != 0) 1607 return res; 1608 1609 if (!ma.HasParameters && !mb.HasParameters) 1610 return 0; 1611 1612 if (!ma.HasParameters) 1613 return -1; 1614 1615 if (!mb.HasParameters) 1616 return 1; 1617 1618 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters); 1619 } 1620 } 1621 1622 class MethodDefinitionComparer : IComparer 1623 { 1624 public static MethodDefinitionComparer Default = new MethodDefinitionComparer (); 1625 Compare(object a, object b)1626 public int Compare (object a, object b) 1627 { 1628 MethodDefinition ma = (MethodDefinition) a; 1629 MethodDefinition mb = (MethodDefinition) b; 1630 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); 1631 if (res != 0) 1632 return res; 1633 1634 if (!ma.HasParameters && !mb.HasParameters) 1635 return 0; 1636 1637 if (!ma.HasParameters) 1638 return -1; 1639 1640 if (!mb.HasParameters) 1641 return 1; 1642 1643 res = Compare (ma.Parameters, mb.Parameters); 1644 if (res != 0) 1645 return res; 1646 1647 if (ma.HasGenericParameters != mb.HasGenericParameters) 1648 return ma.HasGenericParameters ? -1 : 1; 1649 1650 if (ma.HasGenericParameters && mb.HasGenericParameters) { 1651 res = ma.GenericParameters.Count - mb.GenericParameters.Count; 1652 if (res != 0) 1653 return res; 1654 } 1655 1656 // operators can differ by only return type 1657 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName); 1658 } 1659 Compare(IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)1660 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib) 1661 { 1662 var res = pia.Count - pib.Count; 1663 if (res != 0) 1664 return res; 1665 1666 string siga = Parameters.GetSignature (pia); 1667 string sigb = Parameters.GetSignature (pib); 1668 return String.Compare (siga, sigb, StringComparison.Ordinal); 1669 } 1670 } 1671 } 1672 1673