[sgen] Don't trigger collections during allocation of thread objects (#17970)
[mono-project.git] / mcs / tools / corcompare / mono-api-info.cs
blobdf7fb4e6bb0fb2aec39b5baa4f4a86d6116d4d08
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 //
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;
21 using Mono.Cecil;
22 using Mono.Cecil.Cil;
23 using System.IO;
25 namespace Mono.ApiTools {
27 #if !EXCLUDE_DRIVER
28 class Driver
30 public static int Main (string [] args)
32 bool showHelp = false;
33 string output = null;
34 List<string> asms = null;
35 ApiInfoConfig config = new ApiInfoConfig ();
37 var options = new Mono.Options.OptionSet {
38 { "abi",
39 "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
40 v => config.AbiMode = v != null },
41 { "f|follow-forwarders",
42 "Follow type forwarders.",
43 v => config.FollowForwarders = v != null },
44 { "ignore-inherited-interfaces",
45 "Ignore interfaces on the base type.",
46 v => config.IgnoreInheritedInterfaces = v != null },
47 { "ignore-resolution-errors",
48 "Ignore any assemblies that cannot be found.",
49 v => config.IgnoreResolutionErrors = v != null },
50 { "d|L|lib|search-directory=",
51 "Check for assembly references in {DIRECTORY}.",
52 v => config.SearchDirectories.Add (v) },
53 { "r=",
54 "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
55 v => config.ResolveFiles.Add (v) },
56 { "o|out|output=",
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 => config.FullApiSet = v != null },
67 try {
68 asms = options.Parse (args);
69 } catch (Mono.Options.OptionException e) {
70 Console.WriteLine ("Option error: {0}", e.Message);
71 asms = null;
74 if (showHelp || asms == null || asms.Count == 0) {
75 Console.WriteLine ("usage: mono-api-info [OPTIONS+] ASSEMBLY+");
76 Console.WriteLine ();
77 Console.WriteLine ("Expose IL structure of CLR assemblies as XML.");
78 Console.WriteLine ();
79 Console.WriteLine ("Available Options:");
80 Console.WriteLine ();
81 options.WriteOptionDescriptions (Console.Out);
82 Console.WriteLine ();
83 return showHelp ? 0 : 1;
86 TextWriter outputStream = null;
87 try {
88 if (!string.IsNullOrEmpty (output))
89 outputStream = new StreamWriter (output);
91 ApiInfo.Generate (asms, null, outputStream ?? Console.Out, config);
92 } catch (Exception e) {
93 Console.Error.WriteLine (e);
94 return 1;
95 } finally {
96 outputStream?.Dispose ();
98 return 0;
101 #endif
103 class State
105 public bool AbiMode { get; set; } = false;
107 public bool FollowForwarders { get; set; } = false;
109 public bool FullApiSet { get; set; } = false;
111 public bool IgnoreResolutionErrors { get; set; } = false;
113 public bool IgnoreInheritedInterfaces { get; set; } = false;
115 public List<string> SearchDirectories { get; } = new List<string> ();
117 public List<string> ResolveFiles { get; } = new List<string> ();
119 public List<Stream> ResolveStreams { get; } = new List<Stream> ();
121 public TypeHelper TypeHelper { get; private set; }
123 public void ResolveTypes ()
125 TypeHelper = new TypeHelper (IgnoreResolutionErrors, IgnoreInheritedInterfaces);
127 if (SearchDirectories != null) {
128 foreach (var v in SearchDirectories)
129 TypeHelper.Resolver.AddSearchDirectory (v);
131 if (ResolveFiles != null) {
132 foreach (var v in ResolveFiles)
133 TypeHelper.Resolver.ResolveFile (v);
135 if (ResolveStreams != null) {
136 foreach (var v in ResolveStreams)
137 TypeHelper.Resolver.ResolveStream (v);
142 public class ApiInfoConfig
144 public bool AbiMode { get; set; } = false;
146 public bool FollowForwarders { get; set; } = false;
148 public bool FullApiSet { get; set; } = false;
150 public bool IgnoreResolutionErrors { get; set; } = false;
152 public bool IgnoreInheritedInterfaces { get; set; } = false;
154 public List<string> SearchDirectories { get; set; } = new List<string> ();
156 public List<string> ResolveFiles { get; set; } = new List<string> ();
158 public List<Stream> ResolveStreams { get; set; } = new List<Stream> ();
161 public static class ApiInfo
163 public static void Generate (string assemblyPath, TextWriter outStream, ApiInfoConfig config = null)
165 if (assemblyPath == null)
166 throw new ArgumentNullException (nameof (assemblyPath));
168 Generate (new [] { assemblyPath }, null, outStream, config);
171 public static void Generate (Stream assemblyStream, TextWriter outStream, ApiInfoConfig config = null)
173 if (assemblyStream == null)
174 throw new ArgumentNullException (nameof (assemblyStream));
176 Generate (null, new [] { assemblyStream }, outStream, config);
179 public static void Generate (IEnumerable<string> assemblyPaths, TextWriter outStream, ApiInfoConfig config = null)
181 Generate (assemblyPaths, null, outStream, config);
184 public static void Generate (IEnumerable<Stream> assemblyStreams, TextWriter outStream, ApiInfoConfig config = null)
186 Generate (null, assemblyStreams, outStream, config);
189 public static void Generate (IEnumerable<string> assemblyPaths, IEnumerable<Stream> assemblyStreams, TextWriter outStream, ApiInfoConfig config = null)
191 if (outStream == null)
192 throw new ArgumentNullException (nameof (outStream));
194 if (config == null)
195 config = new ApiInfoConfig ();
197 var state = new State {
198 AbiMode = config.AbiMode,
199 FollowForwarders = config.FollowForwarders,
200 FullApiSet = config.FullApiSet,
201 IgnoreResolutionErrors = config.IgnoreResolutionErrors,
202 IgnoreInheritedInterfaces = config.IgnoreInheritedInterfaces,
204 state.SearchDirectories.AddRange (config.SearchDirectories);
205 state.ResolveFiles.AddRange (config.ResolveFiles);
206 state.ResolveStreams.AddRange (config.ResolveStreams);
208 Generate (assemblyPaths, assemblyStreams, outStream, state);
211 internal static void Generate (IEnumerable<string> assemblyFiles, IEnumerable<Stream> assemblyStreams, TextWriter outStream, State state = null)
213 if (outStream == null)
214 throw new ArgumentNullException (nameof (outStream));
216 if (state == null)
217 state = new State ();
219 state.ResolveTypes ();
221 string windir = Environment.GetFolderPath (Environment.SpecialFolder.Windows);
222 string pf = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles);
223 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
225 var acoll = new AssemblyCollection (state);
226 if (assemblyFiles != null) {
227 foreach (string arg in assemblyFiles) {
228 acoll.Add (arg);
230 if (arg.Contains ("v3.0")) {
231 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
232 } else if (arg.Contains ("v3.5")) {
233 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
234 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
235 } else if (arg.Contains ("v4.0")) {
236 if (arg.Contains ("Silverlight")) {
237 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
238 } else {
239 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
240 state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
242 } else {
243 state.TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
247 if (assemblyStreams != null) {
248 foreach (var arg in assemblyStreams) {
249 acoll.Add (arg);
253 var settings = new XmlWriterSettings {
254 Indent = true,
256 using (var textWriter = XmlWriter.Create (outStream, settings)) {
257 var writer = new WellFormedXmlWriter (textWriter);
258 writer.WriteStartDocument ();
259 acoll.Writer = writer;
260 acoll.DoOutput ();
261 writer.WriteEndDocument ();
262 writer.Flush ();
267 class Utils {
268 static char[] CharsToCleanup = new char[] { '<', '>', '/' };
270 public static string CleanupTypeName (TypeReference type)
272 return CleanupTypeName (type.FullName);
275 public static string CleanupTypeName (string t)
277 if (t.IndexOfAny (CharsToCleanup) == -1)
278 return t;
279 var sb = new StringBuilder (t.Length);
280 for (int i = 0; i < t.Length; i++) {
281 var ch = t [i];
282 switch (ch) {
283 case '<':
284 sb.Append ('[');
285 break;
286 case '>':
287 sb.Append (']');
288 break;
289 case '/':
290 sb.Append ('+');
291 break;
292 default:
293 sb.Append (ch);
294 break;
297 return sb.ToString ();
301 class AssemblyCollection
303 XmlWriter writer;
304 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
305 State state;
307 public AssemblyCollection (State state)
309 this.state = state;
312 public bool Add (string name)
314 AssemblyDefinition ass = LoadAssembly (name);
315 assemblies.Add (ass);
316 return true;
319 public bool Add (Stream stream)
321 AssemblyDefinition ass = LoadAssembly (stream);
322 assemblies.Add (ass);
323 return true;
326 public void DoOutput ()
328 if (writer == null)
329 throw new InvalidOperationException ("Document not set");
331 writer.WriteStartElement ("assemblies");
332 foreach (AssemblyDefinition a in assemblies) {
333 AssemblyData data = new AssemblyData (writer, a, state);
334 data.DoOutput ();
336 writer.WriteEndElement ();
339 public XmlWriter Writer {
340 set { writer = value; }
343 AssemblyDefinition LoadAssembly (string assembly)
345 if (File.Exists (assembly))
346 return state.TypeHelper.Resolver.ResolveFile (assembly);
348 return state.TypeHelper.Resolver.Resolve (AssemblyNameReference.Parse (assembly), new ReaderParameters ());
351 AssemblyDefinition LoadAssembly (Stream assembly)
353 return state.TypeHelper.Resolver.ResolveStream (assembly);
357 abstract class BaseData
359 protected XmlWriter writer;
360 protected State state;
362 protected BaseData (XmlWriter writer, State state)
364 this.writer = writer;
365 this.state = state;
368 public abstract void DoOutput ();
370 protected void AddAttribute (string name, string value)
372 writer.WriteAttributeString (name, value);
376 class TypeForwardedToData : BaseData
378 AssemblyDefinition ass;
380 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass, State state)
381 : base (writer, state)
383 this.ass = ass;
386 public override void DoOutput ()
388 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
390 if (((uint)type.Attributes & 0x200000u) == 0)
391 continue;
393 writer.WriteStartElement ("attribute");
394 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
395 writer.WriteStartElement ("properties");
396 writer.WriteStartElement ("property");
397 AddAttribute ("name", "Destination");
398 AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
399 writer.WriteEndElement (); // properties
400 writer.WriteEndElement (); // properties
401 writer.WriteEndElement (); // attribute
405 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass, State state)
407 TypeForwardedToData tftd = new TypeForwardedToData (writer, ass, state);
408 tftd.DoOutput ();
412 class AssemblyData : BaseData
414 AssemblyDefinition ass;
416 public AssemblyData (XmlWriter writer, AssemblyDefinition ass, State state)
417 : base (writer, state)
419 this.ass = ass;
422 public override void DoOutput ()
424 if (writer == null)
425 throw new InvalidOperationException ("Document not set");
427 writer.WriteStartElement ("assembly");
428 AssemblyNameDefinition aname = ass.Name;
429 AddAttribute ("name", aname.Name);
430 AddAttribute ("version", aname.Version.ToString ());
432 AttributeData.OutputAttributes (writer, state, ass);
434 var types = new List<TypeDefinition> ();
435 if (ass.MainModule.Types != null) {
436 types.AddRange (ass.MainModule.Types);
439 if (state.FollowForwarders && ass.MainModule.ExportedTypes != null) {
440 foreach (var t in ass.MainModule.ExportedTypes) {
441 var forwarded = t.Resolve ();
442 if (forwarded == null) {
443 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
445 types.Add (forwarded);
449 if (types.Count == 0) {
450 writer.WriteEndElement (); // assembly
451 return;
454 types.Sort (TypeReferenceComparer.Default);
456 writer.WriteStartElement ("namespaces");
458 string current_namespace = "$%&$&";
459 bool in_namespace = false;
460 foreach (TypeDefinition t in types) {
461 if (string.IsNullOrEmpty (t.Namespace))
462 continue;
464 if (!state.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
465 continue;
467 if (t.DeclaringType != null)
468 continue; // enforce !nested
470 if (t.Namespace != current_namespace) {
471 current_namespace = t.Namespace;
472 if (in_namespace) {
473 writer.WriteEndElement (); // classes
474 writer.WriteEndElement (); // namespace
475 } else {
476 in_namespace = true;
478 writer.WriteStartElement ("namespace");
479 AddAttribute ("name", current_namespace);
480 writer.WriteStartElement ("classes");
483 TypeData bd = new TypeData (writer, t, state);
484 bd.DoOutput ();
488 if (in_namespace) {
489 writer.WriteEndElement (); // classes
490 writer.WriteEndElement (); // namespace
493 writer.WriteEndElement (); // namespaces
495 writer.WriteEndElement (); // assembly
499 abstract class MemberData : BaseData
501 MemberReference [] members;
503 public MemberData (XmlWriter writer, MemberReference [] members, State state)
504 : base (writer, state)
506 this.members = members;
509 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
511 return null;
514 public override void DoOutput ()
516 writer.WriteStartElement (ParentTag);
518 foreach (MemberReference member in members) {
519 writer.WriteStartElement (Tag);
520 AddAttribute ("name", GetName (member));
521 if (!NoMemberAttributes)
522 AddAttribute ("attrib", GetMemberAttributes (member));
523 AddExtraAttributes (member);
525 AttributeData.OutputAttributes (writer, state, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
527 AddExtraData (member);
528 writer.WriteEndElement (); // Tag
531 writer.WriteEndElement (); // ParentTag
534 protected virtual void AddExtraData (MemberReference memberDefenition)
538 protected virtual void AddExtraAttributes (MemberReference memberDefinition)
542 protected virtual string GetName (MemberReference memberDefenition)
544 return "NoNAME";
547 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
549 return null;
552 public virtual bool NoMemberAttributes {
553 get { return false; }
554 set {}
557 public virtual string ParentTag {
558 get { return "NoPARENTTAG"; }
561 public virtual string Tag {
562 get { return "NoTAG"; }
565 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider, State state)
567 if (provider.GenericParameters.Count == 0)
568 return;
570 var gparameters = provider.GenericParameters;
572 writer.WriteStartElement ("generic-parameters");
574 foreach (GenericParameter gp in gparameters) {
575 writer.WriteStartElement ("generic-parameter");
576 writer.WriteAttributeString ("name", gp.Name);
577 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
579 AttributeData.OutputAttributes (writer, state, gp);
581 var constraints = gp.Constraints;
582 if (constraints.Count == 0) {
583 writer.WriteEndElement (); // generic-parameter
584 continue;
587 writer.WriteStartElement ("generic-parameter-constraints");
589 foreach (GenericParameterConstraint constraint in constraints) {
590 writer.WriteStartElement ("generic-parameter-constraint");
591 writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint.ConstraintType));
592 writer.WriteEndElement (); // generic-parameter-constraint
595 writer.WriteEndElement (); // generic-parameter-constraints
597 writer.WriteEndElement (); // generic-parameter
600 writer.WriteEndElement (); // generic-parameters
604 class TypeData : MemberData
606 TypeDefinition type;
608 public TypeData (XmlWriter writer, TypeDefinition type, State state)
609 : base (writer, null, state)
611 this.type = type;
613 public override void DoOutput ()
615 if (writer == null)
616 throw new InvalidOperationException ("Document not set");
618 writer.WriteStartElement ("class");
619 AddAttribute ("name", type.Name);
620 string classType = GetClassType (type);
621 AddAttribute ("type", classType);
623 if (type.BaseType != null)
624 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
626 if (type.IsSealed)
627 AddAttribute ("sealed", "true");
629 if (type.IsAbstract)
630 AddAttribute ("abstract", "true");
632 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
633 AddAttribute ("serializable", "true");
635 string charSet = GetCharSet (type);
636 AddAttribute ("charset", charSet);
638 string layout = GetLayout (type);
639 if (layout != null)
640 AddAttribute ("layout", layout);
642 if (type.PackingSize >= 0) {
643 AddAttribute ("pack", type.PackingSize.ToString ());
646 if (type.ClassSize >= 0) {
647 AddAttribute ("size", type.ClassSize.ToString ());
650 if (type.IsEnum) {
651 var value_type = GetEnumValueField (type);
652 if (value_type == null)
653 throw new NotSupportedException ();
655 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
658 AttributeData.OutputAttributes (writer, state, type);
660 var ifaces = state.TypeHelper.GetInterfaces (type).
661 Where ((iface) => state.TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
662 OrderBy (s => s.FullName, StringComparer.Ordinal);
664 if (ifaces.Any ()) {
665 writer.WriteStartElement ("interfaces");
666 foreach (TypeReference iface in ifaces) {
667 writer.WriteStartElement ("interface");
668 AddAttribute ("name", Utils.CleanupTypeName (iface));
669 writer.WriteEndElement (); // interface
671 writer.WriteEndElement (); // interfaces
674 MemberData.OutputGenericParameters (writer, type, state);
676 ArrayList members = new ArrayList ();
678 FieldDefinition [] fields = GetFields (type);
679 if (fields.Length > 0) {
680 Array.Sort (fields, MemberReferenceComparer.Default);
681 FieldData fd = new FieldData (writer, fields, state);
682 members.Add (fd);
685 if (!state.AbiMode) {
687 MethodDefinition [] ctors = GetConstructors (type);
688 if (ctors.Length > 0) {
689 Array.Sort (ctors, MethodDefinitionComparer.Default);
690 members.Add (new ConstructorData (writer, ctors, state));
693 PropertyDefinition[] properties = GetProperties (type, state.FullApiSet);
694 if (properties.Length > 0) {
695 Array.Sort (properties, PropertyDefinitionComparer.Default);
696 members.Add (new PropertyData (writer, properties, state));
699 EventDefinition [] events = GetEvents (type);
700 if (events.Length > 0) {
701 Array.Sort (events, MemberReferenceComparer.Default);
702 members.Add (new EventData (writer, events, state));
705 MethodDefinition [] methods = GetMethods (type, state.FullApiSet);
706 if (methods.Length > 0) {
707 Array.Sort (methods, MethodDefinitionComparer.Default);
708 members.Add (new MethodData (writer, methods, state));
712 foreach (MemberData md in members)
713 md.DoOutput ();
715 var nested = type.NestedTypes;
716 //remove non public(familiy) and nested in second degree
717 for (int i = nested.Count - 1; i >= 0; i--) {
718 TypeDefinition t = nested [i];
719 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
720 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
721 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
722 // public
723 if (t.DeclaringType == type)
724 continue; // not nested of nested
727 nested.RemoveAt (i);
730 if (nested.Count > 0) {
731 var nestedArray = nested.ToArray ();
732 Array.Sort (nestedArray, TypeReferenceComparer.Default);
734 writer.WriteStartElement ("classes");
735 foreach (TypeDefinition t in nestedArray) {
736 TypeData td = new TypeData (writer, t, state);
737 td.DoOutput ();
739 writer.WriteEndElement (); // classes
742 writer.WriteEndElement (); // class
745 static FieldReference GetEnumValueField (TypeDefinition type)
747 foreach (FieldDefinition field in type.Fields)
748 if (field.IsSpecialName && field.Name == "value__")
749 return field;
751 return null;
754 protected override string GetMemberAttributes (MemberReference member)
756 if (member != type)
757 throw new InvalidOperationException ("odd");
759 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
762 public static bool MustDocumentMethod (MethodDefinition method) {
763 // All other methods
764 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
765 return maskedAccess == MethodAttributes.Public
766 || maskedAccess == MethodAttributes.Family
767 || maskedAccess == MethodAttributes.FamORAssem;
770 string GetClassType (TypeDefinition t)
772 if (t.IsEnum)
773 return "enum";
775 if (t.IsValueType)
776 return "struct";
778 if (t.IsInterface)
779 return "interface";
781 if (state.TypeHelper.IsDelegate(t))
782 return "delegate";
784 if (t.IsPointer)
785 return "pointer";
787 return "class";
790 static string GetCharSet (TypeDefinition type)
792 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
793 if (maskedStringFormat == TypeAttributes.AnsiClass)
794 return CharSet.Ansi.ToString ();
796 if (maskedStringFormat == TypeAttributes.AutoClass)
797 return CharSet.Auto.ToString ();
799 if (maskedStringFormat == TypeAttributes.UnicodeClass)
800 return CharSet.Unicode.ToString ();
802 return CharSet.None.ToString ();
805 static string GetLayout (TypeDefinition type)
807 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
808 if (maskedLayout == TypeAttributes.AutoLayout)
809 return LayoutKind.Auto.ToString ();
811 if (maskedLayout == TypeAttributes.ExplicitLayout)
812 return LayoutKind.Explicit.ToString ();
814 if (maskedLayout == TypeAttributes.SequentialLayout)
815 return LayoutKind.Sequential.ToString ();
817 return null;
820 FieldDefinition [] GetFields (TypeDefinition type) {
821 ArrayList list = new ArrayList ();
823 var fields = type.Fields;
824 foreach (FieldDefinition field in fields) {
825 if (field.IsSpecialName)
826 continue;
828 if (state.AbiMode && field.IsStatic)
829 continue;
831 // we're only interested in public or protected members
832 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
833 if (state.AbiMode && !field.IsNotSerialized) {
834 list.Add (field);
835 } else {
836 if (maskedVisibility == FieldAttributes.Public
837 || maskedVisibility == FieldAttributes.Family
838 || maskedVisibility == FieldAttributes.FamORAssem) {
839 list.Add (field);
844 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
848 internal PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) {
849 var list = new List<PropertyDefinition> ();
851 var t = type;
852 do {
853 var properties = t.Properties;//type.GetProperties (flags);
854 foreach (PropertyDefinition property in properties) {
855 MethodDefinition getMethod = property.GetMethod;
856 MethodDefinition setMethod = property.SetMethod;
858 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
859 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
861 // if neither the getter or setter should be documented, then
862 // skip the property
863 if (hasGetter || hasSetter) {
865 if (t != type && list.Any (l => l.Name == property.Name))
866 continue;
868 list.Add (property);
872 if (!fullAPI)
873 break;
875 if (t.IsInterface || t.IsEnum)
876 break;
878 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
879 t = null;
880 else
881 t = state.TypeHelper.GetBaseType (t);
883 } while (t != null);
885 return list.ToArray ();
888 private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI)
890 var list = new List<MethodDefinition> ();
892 var t = type;
893 do {
894 var methods = t.Methods;//type.GetMethods (flags);
895 foreach (MethodDefinition method in methods) {
896 if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
897 continue;
899 // we're only interested in public or protected members
900 if (!MustDocumentMethod (method))
901 continue;
903 if (t == type && IsFinalizer (method)) {
904 string name = method.DeclaringType.Name;
905 int arity = name.IndexOf ('`');
906 if (arity > 0)
907 name = name.Substring (0, arity);
909 method.Name = "~" + name;
912 if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count &&
913 l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ())))
914 continue;
916 list.Add (method);
919 if (!fullAPI)
920 break;
922 if (t.IsInterface || t.IsEnum)
923 break;
925 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
926 t = null;
927 else
928 t = state.TypeHelper.GetBaseType (t);
930 } while (t != null);
932 return list.ToArray ();
935 sealed class ParameterComparer : IEqualityComparer<ParameterDefinition>
937 public bool Equals (ParameterDefinition x, ParameterDefinition y)
939 return x.ParameterType.Name == y.ParameterType.Name;
942 public int GetHashCode (ParameterDefinition obj)
944 return obj.ParameterType.Name.GetHashCode ();
948 static bool IsFinalizer (MethodDefinition method)
950 if (method.Name != "Finalize")
951 return false;
953 if (!method.IsVirtual)
954 return false;
956 if (method.Parameters.Count != 0)
957 return false;
959 return true;
962 private MethodDefinition [] GetConstructors (TypeDefinition type)
964 ArrayList list = new ArrayList ();
966 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
967 foreach (MethodDefinition constructor in ctors) {
968 // we're only interested in public or protected members
969 if (!MustDocumentMethod(constructor))
970 continue;
972 list.Add (constructor);
975 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
978 private EventDefinition[] GetEvents (TypeDefinition type)
980 ArrayList list = new ArrayList ();
982 var events = type.Events;//type.GetEvents (flags);
983 foreach (EventDefinition eventDef in events) {
984 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
986 if (addMethod == null || !MustDocumentMethod (addMethod))
987 continue;
989 list.Add (eventDef);
992 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
996 class FieldData : MemberData
998 public FieldData (XmlWriter writer, FieldDefinition [] members, State state)
999 : base (writer, members, state)
1003 protected override string GetName (MemberReference memberDefenition)
1005 FieldDefinition field = (FieldDefinition) memberDefenition;
1006 return field.Name;
1009 protected override string GetMemberAttributes (MemberReference memberDefenition)
1011 FieldDefinition field = (FieldDefinition) memberDefenition;
1012 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
1015 protected override void AddExtraAttributes (MemberReference memberDefinition)
1017 base.AddExtraAttributes (memberDefinition);
1019 FieldDefinition field = (FieldDefinition) memberDefinition;
1020 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
1022 if (field.IsLiteral) {
1023 object value = field.Constant;//object value = field.GetValue (null);
1024 string stringValue = null;
1025 //if (value is Enum) {
1026 // // FIXME: when Mono bug #60090 has been
1027 // // fixed, we should just be able to use
1028 // // Convert.ToString
1029 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
1031 //else {
1032 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
1035 if (stringValue != null)
1036 AddAttribute ("value", stringValue);
1040 public override string ParentTag {
1041 get { return "fields"; }
1044 public override string Tag {
1045 get { return "field"; }
1049 class PropertyData : MemberData
1051 public PropertyData (XmlWriter writer, PropertyDefinition [] members, State state)
1052 : base (writer, members, state)
1056 protected override string GetName (MemberReference memberDefenition)
1058 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
1059 return prop.Name;
1062 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
1064 MethodDefinition _get = prop.GetMethod;
1065 MethodDefinition _set = prop.SetMethod;
1066 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
1067 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
1068 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
1069 MethodDefinition [] methods;
1071 if (haveGet && haveSet) {
1072 methods = new MethodDefinition [] { _get, _set };
1073 } else if (haveGet) {
1074 methods = new MethodDefinition [] { _get };
1075 } else if (haveSet) {
1076 methods = new MethodDefinition [] { _set };
1077 } else {
1078 //odd
1079 return null;
1082 return methods;
1085 protected override void AddExtraAttributes (MemberReference memberDefinition)
1087 base.AddExtraAttributes (memberDefinition);
1089 PropertyDefinition prop = (PropertyDefinition) memberDefinition;
1090 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
1092 bool haveParameters;
1093 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
1095 if (methods != null && haveParameters) {
1096 string parms = Parameters.GetSignature (methods [0].Parameters);
1097 if (!string.IsNullOrEmpty (parms))
1098 AddAttribute ("params", parms);
1103 protected override void AddExtraData (MemberReference memberDefenition)
1105 base.AddExtraData (memberDefenition);
1107 bool haveParameters;
1108 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
1110 if (methods == null)
1111 return;
1113 MethodData data = new MethodData (writer, methods, state);
1114 //data.NoMemberAttributes = true;
1115 data.DoOutput ();
1118 protected override string GetMemberAttributes (MemberReference memberDefenition)
1120 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
1121 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
1124 public override string ParentTag {
1125 get { return "properties"; }
1128 public override string Tag {
1129 get { return "property"; }
1133 class EventData : MemberData
1135 public EventData (XmlWriter writer, EventDefinition [] members, State state)
1136 : base (writer, members, state)
1140 protected override string GetName (MemberReference memberDefenition)
1142 EventDefinition evt = (EventDefinition) memberDefenition;
1143 return evt.Name;
1146 protected override string GetMemberAttributes (MemberReference memberDefenition)
1148 EventDefinition evt = (EventDefinition) memberDefenition;
1149 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
1152 protected override void AddExtraAttributes (MemberReference memberDefinition)
1154 base.AddExtraAttributes (memberDefinition);
1156 EventDefinition evt = (EventDefinition) memberDefinition;
1157 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
1160 public override string ParentTag {
1161 get { return "events"; }
1164 public override string Tag {
1165 get { return "event"; }
1169 class MethodData : MemberData
1171 bool noAtts;
1173 public MethodData (XmlWriter writer, MethodDefinition [] members, State state)
1174 : base (writer, members, state)
1178 protected override string GetName (MemberReference memberDefenition)
1180 MethodDefinition method = (MethodDefinition) memberDefenition;
1181 string name = method.Name;
1182 string parms = Parameters.GetSignature (method.Parameters);
1184 return string.Format ("{0}({1})", name, parms);
1187 protected override string GetMemberAttributes (MemberReference memberDefenition)
1189 MethodDefinition method = (MethodDefinition) memberDefenition;
1190 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
1193 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
1195 var mbase = (MethodDefinition) member;
1196 return mbase.MethodReturnType;
1199 protected override void AddExtraAttributes (MemberReference memberDefinition)
1201 base.AddExtraAttributes (memberDefinition);
1203 if (!(memberDefinition is MethodDefinition))
1204 return;
1206 MethodDefinition mbase = (MethodDefinition) memberDefinition;
1208 if (mbase.IsAbstract)
1209 AddAttribute ("abstract", "true");
1210 if (mbase.IsVirtual)
1211 AddAttribute ("virtual", "true");
1212 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
1213 AddAttribute ("sealed", "true");
1214 if (mbase.IsStatic)
1215 AddAttribute ("static", "true");
1216 var baseMethod = state.TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
1217 if (baseMethod != null && baseMethod != mbase) {
1218 // This indicates whether this method is an override of another method.
1219 // This information is not necessarily available in the api info for any
1220 // particular assembly, because a method is only overriding another if
1221 // there is a base virtual function with the same signature, and that
1222 // base method can come from another assembly.
1223 AddAttribute ("is-override", "true");
1225 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
1226 if (rettype != "System.Void" || !mbase.IsConstructor)
1227 AddAttribute ("returntype", (rettype));
1229 // if (mbase.MethodReturnType.HasCustomAttributes)
1230 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1233 protected override void AddExtraData (MemberReference memberDefenition)
1235 base.AddExtraData (memberDefenition);
1237 if (!(memberDefenition is MethodDefinition))
1238 return;
1240 MethodDefinition mbase = (MethodDefinition)memberDefenition;
1242 ParameterData parms = new ParameterData (writer, mbase.Parameters, state) {
1243 HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
1246 parms.DoOutput ();
1248 MemberData.OutputGenericParameters (writer, mbase, state);
1251 public override bool NoMemberAttributes {
1252 get { return noAtts; }
1253 set { noAtts = value; }
1256 public override string ParentTag {
1257 get { return "methods"; }
1260 public override string Tag {
1261 get { return "method"; }
1265 class ConstructorData : MethodData
1267 public ConstructorData (XmlWriter writer, MethodDefinition [] members, State state)
1268 : base (writer, members, state)
1272 public override string ParentTag {
1273 get { return "constructors"; }
1276 public override string Tag {
1277 get { return "constructor"; }
1281 class ParameterData : BaseData
1283 private IList<ParameterDefinition> parameters;
1285 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters, State state)
1286 : base (writer, state)
1288 this.parameters = parameters;
1291 public bool HasExtensionParameter { get; set; }
1293 public override void DoOutput ()
1295 bool first = true;
1296 writer.WriteStartElement ("parameters");
1297 foreach (ParameterDefinition parameter in parameters) {
1298 writer.WriteStartElement ("parameter");
1299 AddAttribute ("name", parameter.Name);
1300 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1301 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1303 string direction = first && HasExtensionParameter ? "this" : "in";
1304 first = false;
1306 var pt = parameter.ParameterType;
1307 var brt = pt as ByReferenceType;
1308 if (brt != null) {
1309 direction = parameter.IsOut ? "out" : "ref";
1310 pt = brt.ElementType;
1313 AddAttribute ("type", Utils.CleanupTypeName (pt));
1315 if (parameter.IsOptional) {
1316 AddAttribute ("optional", "true");
1317 if (parameter.HasConstant)
1318 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1321 if (direction != "in")
1322 AddAttribute ("direction", direction);
1324 AttributeData.OutputAttributes (writer, state, parameter);
1325 writer.WriteEndElement (); // parameter
1327 writer.WriteEndElement (); // parameters
1331 class AttributeData
1333 State state;
1335 public AttributeData (State state)
1337 this.state = state;
1340 public void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1342 if (writer == null)
1343 throw new InvalidOperationException ("Document not set");
1345 if (providers == null || providers.Count == 0)
1346 return;
1348 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1349 return;
1351 writer.WriteStartElement ("attributes");
1353 foreach (var provider in providers) {
1354 if (provider == null)
1355 continue;
1357 if (!provider.HasCustomAttributes)
1358 continue;
1361 var ass = provider as AssemblyDefinition;
1362 if (ass != null && !state.FollowForwarders)
1363 TypeForwardedToData.OutputForwarders (writer, ass, state);
1365 var attributes = provider.CustomAttributes.
1366 Where ((att) => !SkipAttribute (att)).
1367 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1369 foreach (var att in attributes) {
1370 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1372 writer.WriteStartElement ("attribute");
1373 writer.WriteAttributeString ("name", attName);
1375 var attribute_mapping = CreateAttributeMapping (att);
1377 if (attribute_mapping != null) {
1378 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
1379 if (mapping.Any ()) {
1380 writer.WriteStartElement ("properties");
1381 foreach (var kvp in mapping) {
1382 string name = kvp.Key;
1383 object o = kvp.Value;
1385 writer.WriteStartElement ("property");
1386 writer.WriteAttributeString ("name", name);
1388 if (o == null) {
1389 writer.WriteAttributeString ("value", "null");
1390 } else {
1391 string value = o.ToString ();
1392 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1393 value = value.ToUpper ();
1394 writer.WriteAttributeString ("value", value);
1397 writer.WriteEndElement (); // property
1399 writer.WriteEndElement (); // properties
1402 writer.WriteEndElement (); // attribute
1406 writer.WriteEndElement (); // attributes
1409 Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1411 Dictionary<string, object> mapping = null;
1413 if (!state.TypeHelper.TryResolve (attribute))
1414 return mapping;
1416 PopulateMapping (ref mapping, attribute);
1418 var constructor = state.TypeHelper.GetMethod (attribute.Constructor);
1419 if (constructor == null || !constructor.HasParameters)
1420 return mapping;
1422 PopulateMapping (ref mapping, constructor, attribute);
1424 return mapping;
1427 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
1429 if (!attribute.HasProperties)
1430 return;
1432 foreach (var named_argument in attribute.Properties) {
1433 var name = named_argument.Name;
1434 var arg = named_argument.Argument;
1436 if (arg.Value is CustomAttributeArgument)
1437 arg = (CustomAttributeArgument) arg.Value;
1439 if (mapping == null)
1440 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1441 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1445 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1447 Dictionary<FieldReference, int> field_mapping = null;
1449 int? argument = null;
1451 foreach (Instruction instruction in constructor.Body.Instructions) {
1452 switch (instruction.OpCode.Code) {
1453 case Code.Ldarg_1:
1454 argument = 1;
1455 break;
1456 case Code.Ldarg_2:
1457 argument = 2;
1458 break;
1459 case Code.Ldarg_3:
1460 argument = 3;
1461 break;
1462 case Code.Ldarg:
1463 case Code.Ldarg_S:
1464 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1465 break;
1467 case Code.Stfld:
1468 FieldReference field = (FieldReference) instruction.Operand;
1469 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1470 continue;
1472 if (!argument.HasValue)
1473 break;
1475 if (field_mapping == null)
1476 field_mapping = new Dictionary<FieldReference, int> ();
1478 if (!field_mapping.ContainsKey (field))
1479 field_mapping.Add (field, (int) argument - 1);
1481 argument = null;
1482 break;
1486 return field_mapping;
1489 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1491 Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
1493 foreach (PropertyDefinition property in type.Properties) {
1494 if (property.GetMethod == null)
1495 continue;
1496 if (!property.GetMethod.HasBody)
1497 continue;
1499 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1500 if (instruction.OpCode.Code != Code.Ldfld)
1501 continue;
1503 FieldReference field = (FieldReference) instruction.Operand;
1504 if (field.DeclaringType.FullName != type.FullName)
1505 continue;
1507 if (property_mapping == null)
1508 property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1509 property_mapping.Add (property, field);
1510 break;
1514 return property_mapping;
1517 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1519 if (!constructor.HasBody)
1520 return;
1522 // Custom handling for attributes with arguments which cannot be easily extracted
1523 var ca = attribute.ConstructorArguments;
1524 switch (constructor.DeclaringType.FullName) {
1525 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1526 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1527 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1528 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1530 if (mapping == null)
1531 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1532 mapping.Add ("Value", dca.Value);
1533 return;
1534 case "System.ComponentModel.BindableAttribute":
1535 if (ca.Count != 1)
1536 break;
1538 if (mapping == null)
1539 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1541 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1542 mapping.Add ("Bindable", ca[0].Value);
1543 } else if (constructor.Parameters[0].ParameterType.FullName == "System.ComponentModel.BindableSupport") {
1544 if ((int)ca[0].Value == 0)
1545 mapping.Add ("Bindable", false);
1546 else if ((int)ca[0].Value == 1)
1547 mapping.Add ("Bindable", true);
1548 else
1549 throw new NotImplementedException ();
1550 } else {
1551 throw new NotImplementedException ();
1554 return;
1557 var field_mapping = CreateArgumentFieldMapping (constructor);
1558 if (field_mapping != null) {
1559 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1561 if (property_mapping != null) {
1562 foreach (var pair in property_mapping) {
1563 int argument;
1564 if (!field_mapping.TryGetValue (pair.Value, out argument))
1565 continue;
1567 var ca_arg = ca [argument];
1568 if (ca_arg.Value is CustomAttributeArgument)
1569 ca_arg = (CustomAttributeArgument)ca_arg.Value;
1571 if (mapping == null)
1572 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1573 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1579 static object GetArgumentValue (TypeReference reference, object value)
1581 var type = reference.Resolve ();
1582 if (type == null)
1583 return value;
1585 if (type.IsEnum) {
1586 if (IsFlaggedEnum (type))
1587 return GetFlaggedEnumValue (type, value);
1589 return GetEnumValue (type, value);
1592 return value;
1595 static bool IsFlaggedEnum (TypeDefinition type)
1597 if (!type.IsEnum)
1598 return false;
1600 if (!type.HasCustomAttributes)
1601 return false;
1603 foreach (CustomAttribute attribute in type.CustomAttributes)
1604 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1605 return true;
1607 return false;
1610 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1612 if (value is ulong)
1613 return GetFlaggedEnumValue (type, (ulong)value);
1615 long flags = Convert.ToInt64 (value);
1616 var signature = new StringBuilder ();
1618 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1619 FieldDefinition field = type.Fields [i];
1621 if (!field.HasConstant)
1622 continue;
1624 long flag = Convert.ToInt64 (field.Constant);
1626 if (flag == 0)
1627 continue;
1629 if ((flags & flag) == flag) {
1630 if (signature.Length != 0)
1631 signature.Append (", ");
1633 signature.Append (field.Name);
1634 flags -= flag;
1638 return signature.ToString ();
1641 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1643 var signature = new StringBuilder ();
1645 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1646 FieldDefinition field = type.Fields [i];
1648 if (!field.HasConstant)
1649 continue;
1651 ulong flag = Convert.ToUInt64 (field.Constant);
1653 if (flag == 0)
1654 continue;
1656 if ((flags & flag) == flag) {
1657 if (signature.Length != 0)
1658 signature.Append (", ");
1660 signature.Append (field.Name);
1661 flags -= flag;
1665 return signature.ToString ();
1668 static object GetEnumValue (TypeDefinition type, object value)
1670 foreach (FieldDefinition field in type.Fields) {
1671 if (!field.HasConstant)
1672 continue;
1674 if (Comparer.Default.Compare (field.Constant, value) == 0)
1675 return field.Name;
1678 return value;
1681 bool SkipAttribute (CustomAttribute attribute)
1683 if (!state.TypeHelper.IsPublic (attribute))
1684 return true;
1686 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1689 public static void OutputAttributes (XmlWriter writer, State state, params ICustomAttributeProvider[] providers)
1691 var data = new AttributeData (state);
1692 data.DoOutput (writer, providers);
1696 static class Parameters {
1698 public static string GetSignature (IList<ParameterDefinition> infos)
1700 if (infos == null || infos.Count == 0)
1701 return string.Empty;
1703 var signature = new StringBuilder ();
1704 for (int i = 0; i < infos.Count; i++) {
1706 if (i > 0)
1707 signature.Append (", ");
1709 ParameterDefinition info = infos [i];
1711 string modifier = string.Empty;
1712 if (info.ParameterType.IsByReference) {
1713 if ((info.Attributes & ParameterAttributes.In) != 0)
1714 modifier = "in";
1715 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1716 modifier = "out";
1719 if (modifier.Length > 0) {
1720 signature.Append (modifier);
1721 signature.Append (" ");
1724 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1727 return signature.ToString ();
1732 class TypeReferenceComparer : IComparer<TypeReference>
1734 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1736 public int Compare (TypeReference a, TypeReference b)
1738 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1739 if (result != 0)
1740 return result;
1742 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1746 class MemberReferenceComparer : IComparer
1748 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1750 public int Compare (object a, object b)
1752 MemberReference ma = (MemberReference) a;
1753 MemberReference mb = (MemberReference) b;
1754 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1758 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1760 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1762 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1764 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1765 if (res != 0)
1766 return res;
1768 if (!ma.HasParameters && !mb.HasParameters)
1769 return 0;
1771 if (!ma.HasParameters)
1772 return -1;
1774 if (!mb.HasParameters)
1775 return 1;
1777 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1781 class MethodDefinitionComparer : IComparer
1783 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1785 public int Compare (object a, object b)
1787 MethodDefinition ma = (MethodDefinition) a;
1788 MethodDefinition mb = (MethodDefinition) b;
1789 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1790 if (res != 0)
1791 return res;
1793 if (!ma.HasParameters && !mb.HasParameters)
1794 return 0;
1796 if (!ma.HasParameters)
1797 return -1;
1799 if (!mb.HasParameters)
1800 return 1;
1802 res = Compare (ma.Parameters, mb.Parameters);
1803 if (res != 0)
1804 return res;
1806 if (ma.HasGenericParameters != mb.HasGenericParameters)
1807 return ma.HasGenericParameters ? -1 : 1;
1809 if (ma.HasGenericParameters && mb.HasGenericParameters) {
1810 res = ma.GenericParameters.Count - mb.GenericParameters.Count;
1811 if (res != 0)
1812 return res;
1815 // operators can differ by only return type
1816 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1819 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1821 var res = pia.Count - pib.Count;
1822 if (res != 0)
1823 return res;
1825 string siga = Parameters.GetSignature (pia);
1826 string sigb = Parameters.GetSignature (pib);
1827 return String.Compare (siga, sigb, StringComparison.Ordinal);