diff --git a/corcompare/AssemblyResolver.cs b/corcompare/AssemblyResolver.cs new file mode 100644 index 0000000..decd20e --- /dev/null +++ b/corcompare/AssemblyResolver.cs @@ -0,0 +1,56 @@ +// +// AssemblyResolver.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.IO; + +using Mono.Cecil; + +namespace Mono.ApiTools { + + class AssemblyResolver : DefaultAssemblyResolver { + + public AssemblyDefinition ResolveFile (string file) + { + AddSearchDirectory (Path.GetDirectoryName (file)); + var assembly = AssemblyDefinition.ReadAssembly (file, new ReaderParameters { AssemblyResolver = this, InMemory = true }); + RegisterAssembly (assembly); + + return assembly; + } + + public AssemblyDefinition ResolveStream (Stream stream) + { + var assembly = AssemblyDefinition.ReadAssembly (stream, new ReaderParameters { AssemblyResolver = this, InMemory = true }); + RegisterAssembly (assembly); + + return assembly; + } + } +} diff --git a/corcompare/Makefile b/corcompare/Makefile new file mode 100644 index 0000000..2f4a664 --- /dev/null +++ b/corcompare/Makefile @@ -0,0 +1,10 @@ +thisdir = tools/corcompare +SUBDIRS = +include ../../build/rules.make + +LIB_REFS = Mono.Cecil System.Xml System.Core System +LOCAL_MCS_FLAGS = + +PROGRAM = mono-api-info.exe + +include ../../build/executable.make diff --git a/corcompare/Util.cs b/corcompare/Util.cs new file mode 100644 index 0000000..107c721 --- /dev/null +++ b/corcompare/Util.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Mono.Cecil; + +namespace Mono.ApiTools { + + class TypeHelper { + + public TypeHelper (bool ignoreResolutionErrors, bool ignoreInheritedInterfaces) + { + IgnoreResolutionErrors = ignoreResolutionErrors; + IgnoreInheritedInterfaces = ignoreInheritedInterfaces; + } + + public bool IgnoreResolutionErrors { get; } + + public bool IgnoreInheritedInterfaces { get; } + + public AssemblyResolver Resolver { get; } = new AssemblyResolver(); + + internal bool TryResolve (CustomAttribute attribute) + { + if (attribute == null) + throw new ArgumentNullException (nameof (attribute)); + + try { + var has = attribute.HasProperties; + return true; + } catch (AssemblyResolutionException) when (IgnoreResolutionErrors) { + return false; + } + } + + internal bool IsPublic (TypeReference typeref) + { + if (typeref == null) + throw new ArgumentNullException ("typeref"); + + try { + var td = typeref.Resolve (); + if (td == null) + return false; + + return td.IsPublic || (td.IsNestedPublic && IsPublic (td.DeclaringType)); + } catch (AssemblyResolutionException) when (IgnoreResolutionErrors) { + return true; + } + } + + internal bool IsDelegate (TypeReference typeref) + { + return IsDerivedFrom (typeref, "System.MulticastDelegate"); + } + + internal bool IsDerivedFrom (TypeReference type, string derivedFrom) + { + bool first = true; + foreach (var def in WalkHierarchy (type)) { + if (first) { + first = false; + continue; + } + + if (def.FullName == derivedFrom) + return true; + } + + return false; + } + + internal IEnumerable WalkHierarchy (TypeReference type) + { + for (var def = type.Resolve (); def != null; def = GetBaseType (def)) + yield return def; + } + + internal IEnumerable GetInterfaces (TypeReference type) + { + var ifaces = new Dictionary (); + + foreach (var def in WalkHierarchy (type)) { + foreach (var iface in def.Interfaces) + ifaces [iface.InterfaceType.FullName] = iface.InterfaceType; + if (IgnoreInheritedInterfaces) + break; + } + + return ifaces.Values; + } + + internal TypeDefinition GetBaseType (TypeDefinition child) + { + if (child.BaseType == null) + return null; + + try { + return child.BaseType.Resolve (); + } catch (AssemblyResolutionException) when (IgnoreResolutionErrors) { + return null; + } + } + + internal MethodDefinition GetMethod (MethodReference method) + { + if (method == null) + throw new ArgumentNullException (nameof (method)); + + try { + return method.Resolve (); + } catch (AssemblyResolutionException) when (IgnoreResolutionErrors) { + return null; + } + } + + internal bool IsPublic (CustomAttribute att) + { + return IsPublic (att.AttributeType); + } + + internal string GetFullName (CustomAttribute att) + { + return att.AttributeType.FullName; + } + + internal TypeDefinition GetTypeDefinition (CustomAttribute att) + { + return att.AttributeType.Resolve (); + } + + bool IsOverride (MethodDefinition method) + { + return method.IsVirtual && !method.IsNewSlot; + } + + public MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method) + { + if (!IsOverride (method)) + return method; + + var @base = GetBaseType (method.DeclaringType); + while (@base != null) { + MethodDefinition base_method = TryMatchMethod (@base.Resolve (), method); + if (base_method != null) + return GetBaseMethodInTypeHierarchy (base_method) ?? base_method; + + @base = GetBaseType (@base); + } + + return method; + } + + MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method) + { + if (!type.HasMethods) + return null; + + foreach (MethodDefinition candidate in type.Methods) + if (MethodMatch (candidate, method)) + return candidate; + + return null; + } + + bool MethodMatch (MethodDefinition candidate, MethodDefinition method) + { + if (!candidate.IsVirtual) + return false; + + if (candidate.Name != method.Name) + return false; + + if (!TypeMatch (candidate.ReturnType, method.ReturnType)) + return false; + + if (candidate.Parameters.Count != method.Parameters.Count) + return false; + + for (int i = 0; i < candidate.Parameters.Count; i++) + if (!TypeMatch (candidate.Parameters [i].ParameterType, method.Parameters [i].ParameterType)) + return false; + + return true; + } + + public bool TypeMatch (IModifierType a, IModifierType b) + { + if (!TypeMatch (a.ModifierType, b.ModifierType)) + return false; + + return TypeMatch (a.ElementType, b.ElementType); + } + + public bool TypeMatch (TypeSpecification a, TypeSpecification b) + { + if (a is GenericInstanceType) + return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b); + + if (a is IModifierType) + return TypeMatch ((IModifierType) a, (IModifierType) b); + + return TypeMatch (a.ElementType, b.ElementType); + } + + public bool TypeMatch (GenericInstanceType a, GenericInstanceType b) + { + if (!TypeMatch (a.ElementType, b.ElementType)) + return false; + + if (a.GenericArguments.Count != b.GenericArguments.Count) + return false; + + if (a.GenericArguments.Count == 0) + return true; + + for (int i = 0; i < a.GenericArguments.Count; i++) + if (!TypeMatch (a.GenericArguments [i], b.GenericArguments [i])) + return false; + + return true; + } + + public bool TypeMatch (TypeReference a, TypeReference b) + { + if (a is GenericParameter) + return true; + + if (a is TypeSpecification || b is TypeSpecification) { + if (a.GetType () != b.GetType ()) + return false; + + return TypeMatch ((TypeSpecification) a, (TypeSpecification) b); + } + + return a.FullName == b.FullName; + } + } +} diff --git a/corcompare/WellFormedXmlWriter.cs b/corcompare/WellFormedXmlWriter.cs new file mode 100644 index 0000000..dbc5847 --- /dev/null +++ b/corcompare/WellFormedXmlWriter.cs @@ -0,0 +1,289 @@ +// +// WellFormedXmlWriter.cs +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2006 Novell, Inc. http://www.novell.com +// +using System; +using System.Globalization; +using System.Collections; +using System.Xml; + +namespace Mono.ApiTools { + + class WellFormedXmlWriter : DefaultXmlWriter + { + public static bool IsInvalid (int ch) + { + switch (ch) { + case 9: + case 10: + case 13: + return false; + } + if (ch < 32) + return true; + if (ch < 0xD800) + return false; + if (ch < 0xE000) + return true; + if (ch < 0xFFFE) + return false; + if (ch < 0x10000) + return true; + if (ch < 0x110000) + return false; + else + return true; + } + + public static int IndexOfInvalid (string s, bool allowSurrogate) + { + for (int i = 0; i < s.Length; i++) + if (IsInvalid (s [i])) { + if (!allowSurrogate || + i + 1 == s.Length || + s [i] < '\uD800' || + s [i] >= '\uDC00' || + s [i + 1] < '\uDC00' || + s [i + 1] >= '\uE000') + return i; + i++; + } + return -1; + } + + public static int IndexOfInvalid (char [] s, int start, int length, bool allowSurrogate) + { + int end = start + length; + if (s.Length < end) + throw new ArgumentOutOfRangeException ("length"); + for (int i = start; i < end; i++) + if (IsInvalid (s [i])) { + if (!allowSurrogate || + i + 1 == end || + s [i] < '\uD800' || + s [i] >= '\uDC00' || + s [i + 1] < '\uDC00' || + s [i + 1] >= '\uE000') + return i; + i++; + } + return -1; + } + + public WellFormedXmlWriter (XmlWriter writer) : base (writer) + { + } + + public override void WriteString (string text) + { + int i = IndexOfInvalid (text, true); + if (i >= 0) { + char [] arr = text.ToCharArray (); + Writer.WriteChars (arr, 0, i); + WriteChars (arr, i, arr.Length - i); + } else { + // no invalid character. + Writer.WriteString (text); + } + } + + public override void WriteChars (char [] text, int idx, int length) + { + int start = idx; + int end = idx + length; + while ((idx = IndexOfInvalid (text, start, length, true)) >= 0) { + if (start < idx) + Writer.WriteChars (text, start, idx - start); + Writer.WriteString (String.Format (CultureInfo.InvariantCulture, + text [idx] < 0x80 ? "\\x{0:X02}" : "\\u{0:X04}", + (int) text [idx])); + length -= idx - start + 1; + start = idx + 1; + } + if (start < end) + Writer.WriteChars (text, start, end - start); + } + + } + + class DefaultXmlWriter : XmlWriter + { + XmlWriter writer; + + public DefaultXmlWriter (XmlWriter writer) + { + this.writer = writer; + } + + protected XmlWriter Writer { + get { return writer; } + } + + public override void Close () + { + writer.Close (); + } + + public override void Flush () + { + writer.Flush (); + } + + public override string LookupPrefix (string ns) + { + return writer.LookupPrefix (ns); + } + + public override void WriteBase64 (byte [] buffer, int index, int count) + { + writer.WriteBase64 (buffer, index, count); + } + + public override void WriteBinHex (byte [] buffer, int index, int count) + { + writer.WriteBinHex (buffer, index, count); + } + + public override void WriteCData (string text) + { + writer.WriteCData (text); + } + + public override void WriteCharEntity (char ch) + { + writer.WriteCharEntity (ch); + } + + public override void WriteChars (char [] buffer, int index, int count) + { + writer.WriteChars (buffer, index, count); + } + + public override void WriteComment (string text) + { + writer.WriteComment (text); + } + + public override void WriteDocType (string name, string pubid, string sysid, string subset) + { + writer.WriteDocType (name, pubid, sysid, subset); + } + + public override void WriteEndAttribute () + { + writer.WriteEndAttribute (); + } + + public override void WriteEndDocument () + { + writer.WriteEndDocument (); + } + + public override void WriteEndElement () + { + writer.WriteEndElement (); + } + + public override void WriteEntityRef (string name) + { + writer.WriteEntityRef (name); + } + + public override void WriteFullEndElement () + { + writer.WriteFullEndElement (); + } + + public override void WriteName (string name) + { + writer.WriteName (name); + } + + public override void WriteNmToken (string name) + { + writer.WriteNmToken (name); + } + + public override void WriteNode (XmlReader reader, bool defattr) + { + writer.WriteNode (reader, defattr); + } + + public override void WriteProcessingInstruction (string name, string text) + { + writer.WriteProcessingInstruction (name, text); + } + + public override void WriteQualifiedName (string localName, string ns) + { + writer.WriteQualifiedName (localName, ns); + } + + public override void WriteRaw (string data) + { + writer.WriteRaw (data); + } + + public override void WriteRaw (char [] buffer, int index, int count) + { + writer.WriteRaw (buffer, index, count); + } + + public override void WriteStartAttribute (string prefix, string localName, string ns) + { + writer.WriteStartAttribute (prefix, localName, ns); + } + + public override void WriteStartDocument (bool standalone) + { + writer.WriteStartDocument (standalone); + } + + public override void WriteStartDocument () + { + writer.WriteStartDocument (); + } + + public override void WriteStartElement (string prefix, string localName, string ns) + { + writer.WriteStartElement (prefix, localName, ns); + } + + public override void WriteString (string text) + { + writer.WriteString (text); + } + + public override void WriteSurrogateCharEntity (char lowChar, char highChar) + { + writer.WriteSurrogateCharEntity (lowChar, highChar); + } + + public override void WriteWhitespace (string ws) + { + writer.WriteWhitespace (ws); + } + + public override WriteState WriteState { + get { + return writer.WriteState; + } + } + + public override string XmlLang { + get { + return writer.XmlLang; + } + } + + public override XmlSpace XmlSpace { + get { + return writer.XmlSpace; + } + } + } +} \ No newline at end of file diff --git a/corcompare/gen-infos.rb b/corcompare/gen-infos.rb new file mode 100755 index 0000000..e87bb7f --- /dev/null +++ b/corcompare/gen-infos.rb @@ -0,0 +1,525 @@ +#!/usr/bin/env ruby + +require 'ftools' + +$gac = 'C:/WINDOWS/assembly/GAC_MSIL' +$fx = 'C:/WINDOWS/Microsoft.NET/Framework' + +$fx1_1 = File.join $fx, "v1.1.4322" +$fx2_0 = File.join $fx, "v2.0.50727" +$fx3_0 = 'C:/Program Files/Reference Assemblies/Microsoft/Framework/v3.0' +$fx3_5 = 'C:/Program Files/Reference Assemblies/Microsoft/Framework/v3.5' +$fx4_0 = File.join $fx, "v4.0.30319" +$fx4_0_wpf = File.join $fx4_0, "WPF" +$fx4_5 = File.join $fx, "v4.0.30319" +$fx4_5_wpf = File.join $fx4_0, "WPF" +$sl2_0 = 'C:/Program Files/Microsoft Silverlight/2.0.40115.0' +$sl2_0sdk = 'C:/Program Files/Microsoft SDKs/Silverlight/v2.0/Libraries/Client/' +$sl4 = 'C:/Program Files/Microsoft Silverlight/4.0.51204.0' +$sl4_sdk = 'C:/Program Files/Microsoft SDKs/Silverlight/v4.0/Libraries/Client' + +$net_1_1 = [ + "mscorlib", + "System", + "System.Data", + "System.Data.OracleClient", + "System.DirectoryServices", + "System.Drawing", + "System.Runtime.Remoting", + "System.Runtime.Serialization.Formatters.Soap", + "System.Security", + "System.ServiceProcess", + "System.Web", + "System.Web.Services", + "System.Windows.Forms", + "System.Xml", + "cscompmgd", + "Microsoft.VisualBasic", + "", + "System.Configuration.Install", + "System.Design", + "System.Drawing.Design", + "System.EnterpriseServices", + "System.Management", + "System.Messaging" +] + +$net_2_0 = [ + "mscorlib", + "System", + "System.Configuration", + "System.Data", + "System.Data.OracleClient", + "System.DirectoryServices", + "System.Drawing", + "System.Runtime.Remoting", + "System.Runtime.Serialization.Formatters.Soap", + "System.Security", + "System.ServiceProcess", + "System.Transactions", + "System.Web", + "System.Web.Services", + "System.Windows.Forms", + "System.Xml", + "cscompmgd", + "Microsoft.VisualBasic", + "", + "Microsoft.Build.Engine", + "Microsoft.Build.Framework", + "Microsoft.Build.Tasks", + "Microsoft.Build.Utilities", + "", + "System.Configuration.Install", + "System.Design", + "System.Drawing.Design", + "System.EnterpriseServices", + "System.Management", + "System.Messaging", +] + +$net_3_0 = [ + "PresentationCore", + + "PresentationFramework", + "System.Speech", + "WindowsBase", + "", + "System.IdentityModel", + "System.IdentityModel.Selectors", + "System.IO.Log", + "System.Runtime.Serialization", + "System.ServiceModel", + "", + "System.Workflow.Activities", + "System.Workflow.ComponentModel", + "System.Workflow.Runtime", + "", + "PresentationBuildTasks", + "", + "PresentationFramework.Aero", + "PresentationFramework.Classic", + "PresentationFramework.Luna", + "PresentationFramework.Royale", + "ReachFramework", + "", + "System.Printing", +] + +$net_3_5 = [ + "mscorlib", + "System", + "System.AddIn", + "System.AddIn.Contract", + "System.ComponentModel.DataAnnotations", + "System.Configuration", + "System.Core", + "System.Configuration.Install", + "System.Data", + "System.Data.Linq", + "System.Data.OracleClient", + "System.DirectoryServices", + # "System.DirectoryServices.AccountManagement", + # "System.DirectoryServices.Protocols", + "System.Drawing", + "System.Net", + "System.Runtime.Remoting", + "System.Security", + "System.ServiceProcess", + "System.Transactions", + "System.Web", + "System.Web.Extensions", + "System.Web.Extensions.Design", + "System.Web.Mobile", + "System.Web.RegularExpressions", + "System.Web.Services", + "System.Windows.Forms", + "System.Xml", + "System.Xml.Linq", + "", + "System.Runtime.Serialization.Formatters.Soap", + "cscompmgd", + "Microsoft.VisualBasic", + "", + "Microsoft.Build.Engine", + "Microsoft.Build.Framework", + "Microsoft.Build.Tasks", + "Microsoft.Build.Utilities", + "Microsoft.Build.Conversion.v3.5", + "Microsoft.Build.Utilities.v3.5", + "", + "System.Configuration.Install", + "System.Design", + "System.Drawing.Design", + "System.EnterpriseServices", + "System.Management", + "System.Management.Instrumentation", + "System.Messaging", +] + +$net_4_0 = [ + "mscorlib", + + "Microsoft.Build.Conversion.v4.0", + "Microsoft.Build", + "Microsoft.Build.Engine", + "Microsoft.Build.Framework", + "Microsoft.Build.Tasks.v4.0", + "Microsoft.Build.Utilities.v4.0", + "Microsoft.CSharp", + "Microsoft.Data.Entity.Build.Tasks", + "Microsoft.JScript", + "Microsoft.VisualBasic.Compatibility.Data", + "Microsoft.VisualBasic.Compatibility", + "Microsoft.VisualBasic", +# "Microsoft.VisualC.STLCLR", + + "PresentationBuildTasks", + "PresentationCore", + "PresentationFramework.Aero", + "PresentationFramework.Classic", + "PresentationFramework", + "PresentationFramework.Luna", + "PresentationFramework.Royale", + "PresentationUI", + "ReachFramework", + + "System.Activities", + "System.Activities.Core.Presentation", + "System.Activities.DurableInstancing", + "System.Activities.Presentation", + "System.AddIn.Contract", + "System.AddIn", + "System.ComponentModel.Composition", + "System.ComponentModel.DataAnnotations", + "System.configuration", + "System.Configuration.Install", + "System.Core", + "System.Data.DataSetExtensions", + "System.Data", + "System.Data.Entity.Design", + "System.Data.Entity", + "System.Data.Linq", + "System.Data.OracleClient", + "System.Data.Services.Client", + "System.Data.Services.Design", + "System.Data.Services", + "System.Data.SqlXml", + "System.Deployment", + "System.Design", + "System.Device", + "System.DirectoryServices.AccountManagement", + "System.DirectoryServices", + "System.DirectoryServices.Protocols", + "System", + "System.Drawing.Design", + "System.Drawing", + "System.Dynamic", + "System.EnterpriseServices", + "System.EnterpriseServices.Thunk", + "System.EnterpriseServices.Wrapper", + "System.IdentityModel", + "System.IdentityModel.Selectors", + "System.IO.Log", + "System.Management", + "System.Management.Instrumentation", + "System.Messaging", + "System.Net", + "System.Numerics", + "System.Printing", + "System.Runtime.Caching", + "System.Runtime.Remoting", + "System.Runtime.Serialization", + "System.Runtime.Serialization.Formatters.Soap", + "System.Security", + "System.ServiceModel.Activation", + "System.ServiceModel.Activities", + "System.ServiceModel.Channels", + "System.ServiceModel.Discovery", + "System.ServiceModel", + "System.ServiceModel.Routing", + "System.ServiceModel.Web", + "System.ServiceProcess", + "System.Speech", + "System.Transactions", + "System.Web.Abstractions", + "System.Web.ApplicationServices", + "System.Web.DataVisualization.Design", + "System.Web.DataVisualization", + "System.Web", + "System.Web.DynamicData.Design", + "System.Web.DynamicData", + "System.Web.Entity.Design", + "System.Web.Entity", + "System.Web.Extensions.Design", + "System.Web.Extensions", + "System.Web.Mobile", + "System.Web.RegularExpressions", + "System.Web.Routing", + "System.Web.Services", + "System.Windows.Forms.DataVisualization.Design", + "System.Windows.Forms.DataVisualization", + "System.Windows.Forms", + "System.Windows.Presentation", + "System.Workflow.Activities", + "System.Workflow.ComponentModel", + "System.Workflow.Runtime", + "System.WorkflowServices", + "System.Xaml", + "System.Xaml.Hosting", + "System.Xml", + "System.Xml.Linq", + + "WindowsBase", + "XamlBuildTask" +] + +$net_4_5 = [ + "mscorlib", + + "Microsoft.Activities.Build", + "Microsoft.Build.Conversion.v4.0", + "Microsoft.Build", + "Microsoft.Build.Engine", + "Microsoft.Build.Framework", + "Microsoft.Build.Tasks.v4.0", + "Microsoft.Build.Utilities.v4.0", + "Microsoft.CSharp", + "Microsoft.Data.Entity.Build.Tasks", + "Microsoft.JScript", + "Microsoft.VisualBasic.Activities.Compiler", + "Microsoft.VisualBasic.Compatibility.Data", + "Microsoft.VisualBasic.Compatibility", + "Microsoft.VisualBasic", + "Microsoft.Windows.ApplicationServer.Applications", + + "PresentationBuildTasks", + "PresentationCore", + "PresentationFramework.Aero", + "PresentationFramework.Classic", + "PresentationFramework", + "PresentationFramework.Luna", + "PresentationFramework.Royale", + "PresentationUI", + "ReachFramework", + "System.Printing", + "System.Speech", + "WindowsBase", + "XamlBuildTask", + + "System.Activities", + "System.Activities.Core.Presentation", + "System.Activities.DurableInstancing", + "System.Activities.Presentation", + "System.AddIn.Contract", + "System.AddIn", + "System.ComponentModel.Composition", + "System.ComponentModel.DataAnnotations", + "System.Configuration", + "System.Configuration.Install", + "System.Core", + "System.Data.DataSetExtensions", + "System.Data", + "System.Data.Entity.Design", + "System.Data.Entity", + "System.Data.Linq", + "System.Data.OracleClient", + "System.Data.Services.Client", + "System.Data.Services.Design", + "System.Data.Services", + "System.Data.SqlXml", + "System.Deployment", + "System.Design", + "System.Device", + "System.DirectoryServices.AccountManagement", + "System.DirectoryServices", + "System.DirectoryServices.Protocols", + "System", + "System.Drawing.Design", + "System.Drawing", + "System.Dynamic", + "System.EnterpriseServices", + "System.EnterpriseServices.Thunk", + "System.EnterpriseServices.Wrapper", + "System.IdentityModel", + "System.IdentityModel.Selectors", + "System.IdentityModel.Services", + "System.IO.Compression", + "System.IO.Compression.FileSystem", + "System.IO.Log", + "System.Management", + "System.Management.Instrumentation", + "System.Messaging", + "System.Net", + "System.Net.Http", + "System.Net.Http.WebRequest", + "System.Numerics", + "System.Reflection.context", + "System.Runtime.Caching", + "System.Runtime.Remoting", + "System.Runtime.Serialization", + "System.Runtime.Serialization.Formatters.Soap", + "System.Security", + "System.ServiceModel.Activation", + "System.ServiceModel.Activities", + "System.ServiceModel.Channels", + "System.ServiceModel.Discovery", + "System.ServiceModel", + "System.ServiceModel.Routing", + "System.ServiceModel.Web", + "System.ServiceProcess", + "System.Threading.Tasks.Dataflow", + "System.Transactions", + "System.Web.Abstractions", + "System.Web.ApplicationServices", + "System.Web.DataVisualization.Design", + "System.Web.DataVisualization", + "System.Web", + "System.Web.DynamicData.Design", + "System.Web.DynamicData", + "System.Web.Entity.Design", + "System.Web.Entity", + "System.Web.Extensions.Design", + "System.Web.Extensions", + "System.Web.Mobile", + "System.Web.RegularExpressions", + "System.Web.Services", + "System.Windows.Forms.DataVisualization.Design", + "System.Windows.Forms.DataVisualization", + "System.Windows.Forms", + "System.Windows.Presentation", + "System.Workflow.Activities", + "System.Workflow.ComponentModel", + "System.Workflow.Runtime", + "System.WorkflowServices", + "System.Xaml", + "System.Xaml.Hosting", + "System.Xml", + "System.Xml.Linq" +] + +$sl_2_0 = [ + "mscorlib", + "System.Windows", + "Microsoft.VisualBasic", + "System", + "System.Core", + "System.Net", + "System.Runtime.Serialization", + "System.ServiceModel", + "System.Windows.Browser", + "System.Xml", + "", + "System.Xml.Linq", + "System.Windows.Controls", + "System.Windows.Controls.Data", +] + +$sl_4 = [ + "mscorlib", + "Microsoft.VisualBasic", + "System", + "System.Core", + "System.Net", + "System.Runtime.Serialization", + "System.ServiceModel", + "System.ServiceModel.Web", + "System.Windows", + "System.Windows.Browser", + "System.Xml", + "", + "Microsoft.CSharp", + "System.ComponentModel.Composition", + "System.ComponentModel.Composition.Initialization", + "System.ComponentModel.DataAnnotations", + "System.Data.Services.Client", + "System.Json", + "System.Numerics", + "System.Runtime.Serialization.Json", + "System.ServiceModel.Extensions", + "System.ServiceModel.NetTcp", + "System.ServiceModel.PollingDuplex", + "System.ServiceModel.Syndication", + "System.ServiceModel.Web.Extensions", + "System.Windows.Controls.Data", + "System.Windows.Controls.Data.Input", + "System.Windows.Controls", + "System.Windows.Controls.Input", + "System.Windows.Controls.Navigation", + "System.Windows.Data", + "System.Xml.Linq", + "System.Xml.Serialization", + "System.Xml.Utils", + "System.Xml.XPath" +] + +def locate(assembly, fxs = nil) + if fxs + fxs.each do |fx| + file = File.join fx, assembly + ".dll" + return file if File.file?(file) + end + end + + gac = File.join $gac, assembly, "**", "*.dll" + + glob = Dir.glob gac + + return glob.first if glob and glob.length > 0 +end + +def delete(glob) + Dir.glob(glob).each do |file| + File.delete file + end +end + +def clean(pattern, allow_create = false) + if allow_create and not File.directory? "masterinfos" + Dir.mkdir("masterinfos") + return + end + + delete(File.join("masterinfos", pattern)) +end + +def generate(location, assembly) + out = File.join "masterinfos", assembly + ".xml" + system("./mono-api-info.exe \"#{location}\" > #{out}") +end + +def process(profile, assemblies, fxs = nil) + clean("*", true) + + assemblies.each do |assembly| + if assembly != nil and assembly.length > 0 + puts assembly + location = locate(assembly, fxs) + if location + generate(location, assembly) + else + puts "fail to locate " + assembly + end + #puts " " + location if location + end + end + + clean("*.dll") + + file = "masterinfos-#{profile}.tar" + + system("tar -cf #{file} masterinfos") + system("gzip #{file}") + + clean("*") + + Dir.delete("masterinfos") +end + +delete("*.tar.gz") + +process("2.0", $net_2_0, [$fx2_0]) +process("3.0", $net_3_0, [$fx3_0, $fx2_0]) +process("3.5", $net_3_5, [$fx3_5, $fx2_0]) +process("4.0", $net_4_0, [$fx4_0, $fx4_0_wpf]) +process("4.5", $net_4_5, [$fx4_5, $fx4_5_wpf]) +process("SL4", $sl_4, [$sl4, $sl4_sdk]) diff --git a/corcompare/mono-api-info.cs b/corcompare/mono-api-info.cs new file mode 100644 index 0000000..df7fb4e --- /dev/null +++ b/corcompare/mono-api-info.cs @@ -0,0 +1,1831 @@ +// +// mono-api-info.cs - Dumps public assembly information to an xml file. +// +// Authors: +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com) +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Text; +using System.Xml; + +using Mono.Cecil; +using Mono.Cecil.Cil; +using System.IO; + +namespace Mono.ApiTools { + +#if !EXCLUDE_DRIVER + class Driver + { + public static int Main (string [] args) + { + bool showHelp = false; + string output = null; + List asms = null; + ApiInfoConfig config = new ApiInfoConfig (); + + var options = new Mono.Options.OptionSet { + { "abi", + "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].", + v => config.AbiMode = v != null }, + { "f|follow-forwarders", + "Follow type forwarders.", + v => config.FollowForwarders = v != null }, + { "ignore-inherited-interfaces", + "Ignore interfaces on the base type.", + v => config.IgnoreInheritedInterfaces = v != null }, + { "ignore-resolution-errors", + "Ignore any assemblies that cannot be found.", + v => config.IgnoreResolutionErrors = v != null }, + { "d|L|lib|search-directory=", + "Check for assembly references in {DIRECTORY}.", + v => config.SearchDirectories.Add (v) }, + { "r=", + "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.", + v => config.ResolveFiles.Add (v) }, + { "o|out|output=", + "The output file. If not specified the output will be written to stdout.", + v => output = v }, + { "h|?|help", + "Show this message and exit.", + v => showHelp = v != null }, + { "contract-api", + "Produces contract API with all members at each level of inheritance hierarchy", + v => config.FullApiSet = v != null }, + }; + + try { + asms = options.Parse (args); + } catch (Mono.Options.OptionException e) { + Console.WriteLine ("Option error: {0}", e.Message); + asms = null; + } + + if (showHelp || asms == null || asms.Count == 0) { + Console.WriteLine ("usage: mono-api-info [OPTIONS+] ASSEMBLY+"); + Console.WriteLine (); + Console.WriteLine ("Expose IL structure of CLR assemblies as XML."); + Console.WriteLine (); + Console.WriteLine ("Available Options:"); + Console.WriteLine (); + options.WriteOptionDescriptions (Console.Out); + Console.WriteLine (); + return showHelp ? 0 : 1; + } + + TextWriter outputStream = null; + try { + if (!string.IsNullOrEmpty (output)) + outputStream = new StreamWriter (output); + + ApiInfo.Generate (asms, null, outputStream ?? Console.Out, config); + } catch (Exception e) { + Console.Error.WriteLine (e); + return 1; + } finally { + outputStream?.Dispose (); + } + return 0; + } + } +#endif + + class State + { + public bool AbiMode { get; set; } = false; + + public bool FollowForwarders { get; set; } = false; + + public bool FullApiSet { get; set; } = false; + + public bool IgnoreResolutionErrors { get; set; } = false; + + public bool IgnoreInheritedInterfaces { get; set; } = false; + + public List SearchDirectories { get; } = new List (); + + public List ResolveFiles { get; } = new List (); + + public List ResolveStreams { get; } = new List (); + + public TypeHelper TypeHelper { get; private set; } + + public void ResolveTypes () + { + TypeHelper = new TypeHelper (IgnoreResolutionErrors, IgnoreInheritedInterfaces); + + if (SearchDirectories != null) { + foreach (var v in SearchDirectories) + TypeHelper.Resolver.AddSearchDirectory (v); + } + if (ResolveFiles != null) { + foreach (var v in ResolveFiles) + TypeHelper.Resolver.ResolveFile (v); + } + if (ResolveStreams != null) { + foreach (var v in ResolveStreams) + TypeHelper.Resolver.ResolveStream (v); + } + } + } + + public class ApiInfoConfig + { + public bool AbiMode { get; set; } = false; + + public bool FollowForwarders { get; set; } = false; + + public bool FullApiSet { get; set; } = false; + + public bool IgnoreResolutionErrors { get; set; } = false; + + public bool IgnoreInheritedInterfaces { get; set; } = false; + + public List SearchDirectories { get; set; } = new List (); + + public List ResolveFiles { get; set; } = new List (); + + public List ResolveStreams { get; set; } = new List (); + } + + public static class ApiInfo + { + public static void Generate (string assemblyPath, TextWriter outStream, ApiInfoConfig config = null) + { + if (assemblyPath == null) + throw new ArgumentNullException (nameof (assemblyPath)); + + Generate (new [] { assemblyPath }, null, outStream, config); + } + + public static void Generate (Stream assemblyStream, TextWriter outStream, ApiInfoConfig config = null) + { + if (assemblyStream == null) + throw new ArgumentNullException (nameof (assemblyStream)); + + Generate (null, new [] { assemblyStream }, outStream, config); + } + + public static void Generate (IEnumerable assemblyPaths, TextWriter outStream, ApiInfoConfig config = null) + { + Generate (assemblyPaths, null, outStream, config); + } + + public static void Generate (IEnumerable assemblyStreams, TextWriter outStream, ApiInfoConfig config = null) + { + Generate (null, assemblyStreams, outStream, config); + } + + public static void Generate (IEnumerable assemblyPaths, IEnumerable assemblyStreams, TextWriter outStream, ApiInfoConfig config = null) + { + if (outStream == null) + throw new ArgumentNullException (nameof (outStream)); + + if (config == null) + config = new ApiInfoConfig (); + + var state = new State { + AbiMode = config.AbiMode, + FollowForwarders = config.FollowForwarders, + FullApiSet = config.FullApiSet, + IgnoreResolutionErrors = config.IgnoreResolutionErrors, + IgnoreInheritedInterfaces = config.IgnoreInheritedInterfaces, + }; + state.SearchDirectories.AddRange (config.SearchDirectories); + state.ResolveFiles.AddRange (config.ResolveFiles); + state.ResolveStreams.AddRange (config.ResolveStreams); + + Generate (assemblyPaths, assemblyStreams, outStream, state); + } + + internal static void Generate (IEnumerable assemblyFiles, IEnumerable assemblyStreams, TextWriter outStream, State state = null) + { + if (outStream == null) + throw new ArgumentNullException (nameof (outStream)); + + if (state == null) + state = new State (); + + state.ResolveTypes (); + + string windir = Environment.GetFolderPath (Environment.SpecialFolder.Windows); + string pf = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles); + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a")); + + var acoll = new AssemblyCollection (state); + if (assemblyFiles != null) { + foreach (string arg in assemblyFiles) { + acoll.Add (arg); + + if (arg.Contains ("v3.0")) { + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727")); + } else if (arg.Contains ("v3.5")) { + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727")); + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation")); + } else if (arg.Contains ("v4.0")) { + if (arg.Contains ("Silverlight")) { + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0")); + } else { + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319")); + state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF")); + } + } else { + state.TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg)); + } + } + } + if (assemblyStreams != null) { + foreach (var arg in assemblyStreams) { + acoll.Add (arg); + } + } + + var settings = new XmlWriterSettings { + Indent = true, + }; + using (var textWriter = XmlWriter.Create (outStream, settings)) { + var writer = new WellFormedXmlWriter (textWriter); + writer.WriteStartDocument (); + acoll.Writer = writer; + acoll.DoOutput (); + writer.WriteEndDocument (); + writer.Flush (); + } + } + } + + class Utils { + static char[] CharsToCleanup = new char[] { '<', '>', '/' }; + + public static string CleanupTypeName (TypeReference type) + { + return CleanupTypeName (type.FullName); + } + + public static string CleanupTypeName (string t) + { + if (t.IndexOfAny (CharsToCleanup) == -1) + return t; + var sb = new StringBuilder (t.Length); + for (int i = 0; i < t.Length; i++) { + var ch = t [i]; + switch (ch) { + case '<': + sb.Append ('['); + break; + case '>': + sb.Append (']'); + break; + case '/': + sb.Append ('+'); + break; + default: + sb.Append (ch); + break; + } + } + return sb.ToString (); + } + } + + class AssemblyCollection + { + XmlWriter writer; + List assemblies = new List (); + State state; + + public AssemblyCollection (State state) + { + this.state = state; + } + + public bool Add (string name) + { + AssemblyDefinition ass = LoadAssembly (name); + assemblies.Add (ass); + return true; + } + + public bool Add (Stream stream) + { + AssemblyDefinition ass = LoadAssembly (stream); + assemblies.Add (ass); + return true; + } + + public void DoOutput () + { + if (writer == null) + throw new InvalidOperationException ("Document not set"); + + writer.WriteStartElement ("assemblies"); + foreach (AssemblyDefinition a in assemblies) { + AssemblyData data = new AssemblyData (writer, a, state); + data.DoOutput (); + } + writer.WriteEndElement (); + } + + public XmlWriter Writer { + set { writer = value; } + } + + AssemblyDefinition LoadAssembly (string assembly) + { + if (File.Exists (assembly)) + return state.TypeHelper.Resolver.ResolveFile (assembly); + + return state.TypeHelper.Resolver.Resolve (AssemblyNameReference.Parse (assembly), new ReaderParameters ()); + } + + AssemblyDefinition LoadAssembly (Stream assembly) + { + return state.TypeHelper.Resolver.ResolveStream (assembly); + } + } + + abstract class BaseData + { + protected XmlWriter writer; + protected State state; + + protected BaseData (XmlWriter writer, State state) + { + this.writer = writer; + this.state = state; + } + + public abstract void DoOutput (); + + protected void AddAttribute (string name, string value) + { + writer.WriteAttributeString (name, value); + } + } + + class TypeForwardedToData : BaseData + { + AssemblyDefinition ass; + + public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass, State state) + : base (writer, state) + { + this.ass = ass; + } + + public override void DoOutput () + { + foreach (ExportedType type in ass.MainModule.ExportedTypes) { + + if (((uint)type.Attributes & 0x200000u) == 0) + continue; + + writer.WriteStartElement ("attribute"); + AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName); + writer.WriteStartElement ("properties"); + writer.WriteStartElement ("property"); + AddAttribute ("name", "Destination"); + AddAttribute ("value", Utils.CleanupTypeName (type.FullName)); + writer.WriteEndElement (); // properties + writer.WriteEndElement (); // properties + writer.WriteEndElement (); // attribute + } + } + + public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass, State state) + { + TypeForwardedToData tftd = new TypeForwardedToData (writer, ass, state); + tftd.DoOutput (); + } + } + + class AssemblyData : BaseData + { + AssemblyDefinition ass; + + public AssemblyData (XmlWriter writer, AssemblyDefinition ass, State state) + : base (writer, state) + { + this.ass = ass; + } + + public override void DoOutput () + { + if (writer == null) + throw new InvalidOperationException ("Document not set"); + + writer.WriteStartElement ("assembly"); + AssemblyNameDefinition aname = ass.Name; + AddAttribute ("name", aname.Name); + AddAttribute ("version", aname.Version.ToString ()); + + AttributeData.OutputAttributes (writer, state, ass); + + var types = new List (); + if (ass.MainModule.Types != null) { + types.AddRange (ass.MainModule.Types); + } + + if (state.FollowForwarders && ass.MainModule.ExportedTypes != null) { + foreach (var t in ass.MainModule.ExportedTypes) { + var forwarded = t.Resolve (); + if (forwarded == null) { + throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name); + } + types.Add (forwarded); + } + } + + if (types.Count == 0) { + writer.WriteEndElement (); // assembly + return; + } + + types.Sort (TypeReferenceComparer.Default); + + writer.WriteStartElement ("namespaces"); + + string current_namespace = "$%&$&"; + bool in_namespace = false; + foreach (TypeDefinition t in types) { + if (string.IsNullOrEmpty (t.Namespace)) + continue; + + if (!state.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)) + continue; + + if (t.DeclaringType != null) + continue; // enforce !nested + + if (t.Namespace != current_namespace) { + current_namespace = t.Namespace; + if (in_namespace) { + writer.WriteEndElement (); // classes + writer.WriteEndElement (); // namespace + } else { + in_namespace = true; + } + writer.WriteStartElement ("namespace"); + AddAttribute ("name", current_namespace); + writer.WriteStartElement ("classes"); + } + + TypeData bd = new TypeData (writer, t, state); + bd.DoOutput (); + + } + + if (in_namespace) { + writer.WriteEndElement (); // classes + writer.WriteEndElement (); // namespace + } + + writer.WriteEndElement (); // namespaces + + writer.WriteEndElement (); // assembly + } + } + + abstract class MemberData : BaseData + { + MemberReference [] members; + + public MemberData (XmlWriter writer, MemberReference [] members, State state) + : base (writer, state) + { + this.members = members; + } + + protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) + { + return null; + } + + public override void DoOutput () + { + writer.WriteStartElement (ParentTag); + + foreach (MemberReference member in members) { + writer.WriteStartElement (Tag); + AddAttribute ("name", GetName (member)); + if (!NoMemberAttributes) + AddAttribute ("attrib", GetMemberAttributes (member)); + AddExtraAttributes (member); + + AttributeData.OutputAttributes (writer, state, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member)); + + AddExtraData (member); + writer.WriteEndElement (); // Tag + } + + writer.WriteEndElement (); // ParentTag + } + + protected virtual void AddExtraData (MemberReference memberDefenition) + { + } + + protected virtual void AddExtraAttributes (MemberReference memberDefinition) + { + } + + protected virtual string GetName (MemberReference memberDefenition) + { + return "NoNAME"; + } + + protected virtual string GetMemberAttributes (MemberReference memberDefenition) + { + return null; + } + + public virtual bool NoMemberAttributes { + get { return false; } + set {} + } + + public virtual string ParentTag { + get { return "NoPARENTTAG"; } + } + + public virtual string Tag { + get { return "NoTAG"; } + } + + public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider, State state) + { + if (provider.GenericParameters.Count == 0) + return; + + var gparameters = provider.GenericParameters; + + writer.WriteStartElement ("generic-parameters"); + + foreach (GenericParameter gp in gparameters) { + writer.WriteStartElement ("generic-parameter"); + writer.WriteAttributeString ("name", gp.Name); + writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ()); + + AttributeData.OutputAttributes (writer, state, gp); + + var constraints = gp.Constraints; + if (constraints.Count == 0) { + writer.WriteEndElement (); // generic-parameter + continue; + } + + writer.WriteStartElement ("generic-parameter-constraints"); + + foreach (GenericParameterConstraint constraint in constraints) { + writer.WriteStartElement ("generic-parameter-constraint"); + writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint.ConstraintType)); + writer.WriteEndElement (); // generic-parameter-constraint + } + + writer.WriteEndElement (); // generic-parameter-constraints + + writer.WriteEndElement (); // generic-parameter + } + + writer.WriteEndElement (); // generic-parameters + } + } + + class TypeData : MemberData + { + TypeDefinition type; + + public TypeData (XmlWriter writer, TypeDefinition type, State state) + : base (writer, null, state) + { + this.type = type; + } + public override void DoOutput () + { + if (writer == null) + throw new InvalidOperationException ("Document not set"); + + writer.WriteStartElement ("class"); + AddAttribute ("name", type.Name); + string classType = GetClassType (type); + AddAttribute ("type", classType); + + if (type.BaseType != null) + AddAttribute ("base", Utils.CleanupTypeName (type.BaseType)); + + if (type.IsSealed) + AddAttribute ("sealed", "true"); + + if (type.IsAbstract) + AddAttribute ("abstract", "true"); + + if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum) + AddAttribute ("serializable", "true"); + + string charSet = GetCharSet (type); + AddAttribute ("charset", charSet); + + string layout = GetLayout (type); + if (layout != null) + AddAttribute ("layout", layout); + + if (type.PackingSize >= 0) { + AddAttribute ("pack", type.PackingSize.ToString ()); + } + + if (type.ClassSize >= 0) { + AddAttribute ("size", type.ClassSize.ToString ()); + } + + if (type.IsEnum) { + var value_type = GetEnumValueField (type); + if (value_type == null) + throw new NotSupportedException (); + + AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType)); + } + + AttributeData.OutputAttributes (writer, state, type); + + var ifaces = state.TypeHelper.GetInterfaces (type). + Where ((iface) => state.TypeHelper.IsPublic (iface)). // we're only interested in public interfaces + OrderBy (s => s.FullName, StringComparer.Ordinal); + + if (ifaces.Any ()) { + writer.WriteStartElement ("interfaces"); + foreach (TypeReference iface in ifaces) { + writer.WriteStartElement ("interface"); + AddAttribute ("name", Utils.CleanupTypeName (iface)); + writer.WriteEndElement (); // interface + } + writer.WriteEndElement (); // interfaces + } + + MemberData.OutputGenericParameters (writer, type, state); + + ArrayList members = new ArrayList (); + + FieldDefinition [] fields = GetFields (type); + if (fields.Length > 0) { + Array.Sort (fields, MemberReferenceComparer.Default); + FieldData fd = new FieldData (writer, fields, state); + members.Add (fd); + } + + if (!state.AbiMode) { + + MethodDefinition [] ctors = GetConstructors (type); + if (ctors.Length > 0) { + Array.Sort (ctors, MethodDefinitionComparer.Default); + members.Add (new ConstructorData (writer, ctors, state)); + } + + PropertyDefinition[] properties = GetProperties (type, state.FullApiSet); + if (properties.Length > 0) { + Array.Sort (properties, PropertyDefinitionComparer.Default); + members.Add (new PropertyData (writer, properties, state)); + } + + EventDefinition [] events = GetEvents (type); + if (events.Length > 0) { + Array.Sort (events, MemberReferenceComparer.Default); + members.Add (new EventData (writer, events, state)); + } + + MethodDefinition [] methods = GetMethods (type, state.FullApiSet); + if (methods.Length > 0) { + Array.Sort (methods, MethodDefinitionComparer.Default); + members.Add (new MethodData (writer, methods, state)); + } + } + + foreach (MemberData md in members) + md.DoOutput (); + + var nested = type.NestedTypes; + //remove non public(familiy) and nested in second degree + for (int i = nested.Count - 1; i >= 0; i--) { + TypeDefinition t = nested [i]; + if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic || + (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily || + (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) { + // public + if (t.DeclaringType == type) + continue; // not nested of nested + } + + nested.RemoveAt (i); + } + + if (nested.Count > 0) { + var nestedArray = nested.ToArray (); + Array.Sort (nestedArray, TypeReferenceComparer.Default); + + writer.WriteStartElement ("classes"); + foreach (TypeDefinition t in nestedArray) { + TypeData td = new TypeData (writer, t, state); + td.DoOutput (); + } + writer.WriteEndElement (); // classes + } + + writer.WriteEndElement (); // class + } + + static FieldReference GetEnumValueField (TypeDefinition type) + { + foreach (FieldDefinition field in type.Fields) + if (field.IsSpecialName && field.Name == "value__") + return field; + + return null; + } + + protected override string GetMemberAttributes (MemberReference member) + { + if (member != type) + throw new InvalidOperationException ("odd"); + + return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture); + } + + public static bool MustDocumentMethod (MethodDefinition method) { + // All other methods + MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask; + return maskedAccess == MethodAttributes.Public + || maskedAccess == MethodAttributes.Family + || maskedAccess == MethodAttributes.FamORAssem; + } + + string GetClassType (TypeDefinition t) + { + if (t.IsEnum) + return "enum"; + + if (t.IsValueType) + return "struct"; + + if (t.IsInterface) + return "interface"; + + if (state.TypeHelper.IsDelegate(t)) + return "delegate"; + + if (t.IsPointer) + return "pointer"; + + return "class"; + } + + static string GetCharSet (TypeDefinition type) + { + TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask; + if (maskedStringFormat == TypeAttributes.AnsiClass) + return CharSet.Ansi.ToString (); + + if (maskedStringFormat == TypeAttributes.AutoClass) + return CharSet.Auto.ToString (); + + if (maskedStringFormat == TypeAttributes.UnicodeClass) + return CharSet.Unicode.ToString (); + + return CharSet.None.ToString (); + } + + static string GetLayout (TypeDefinition type) + { + TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask; + if (maskedLayout == TypeAttributes.AutoLayout) + return LayoutKind.Auto.ToString (); + + if (maskedLayout == TypeAttributes.ExplicitLayout) + return LayoutKind.Explicit.ToString (); + + if (maskedLayout == TypeAttributes.SequentialLayout) + return LayoutKind.Sequential.ToString (); + + return null; + } + + FieldDefinition [] GetFields (TypeDefinition type) { + ArrayList list = new ArrayList (); + + var fields = type.Fields; + foreach (FieldDefinition field in fields) { + if (field.IsSpecialName) + continue; + + if (state.AbiMode && field.IsStatic) + continue; + + // we're only interested in public or protected members + FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask); + if (state.AbiMode && !field.IsNotSerialized) { + list.Add (field); + } else { + if (maskedVisibility == FieldAttributes.Public + || maskedVisibility == FieldAttributes.Family + || maskedVisibility == FieldAttributes.FamORAssem) { + list.Add (field); + } + } + } + + return (FieldDefinition []) list.ToArray (typeof (FieldDefinition)); + } + + + internal PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) { + var list = new List (); + + var t = type; + do { + var properties = t.Properties;//type.GetProperties (flags); + foreach (PropertyDefinition property in properties) { + MethodDefinition getMethod = property.GetMethod; + MethodDefinition setMethod = property.SetMethod; + + bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod); + bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod); + + // if neither the getter or setter should be documented, then + // skip the property + if (hasGetter || hasSetter) { + + if (t != type && list.Any (l => l.Name == property.Name)) + continue; + + list.Add (property); + } + } + + if (!fullAPI) + break; + + if (t.IsInterface || t.IsEnum) + break; + + if (t.BaseType == null || t.BaseType.FullName == "System.Object") + t = null; + else + t = state.TypeHelper.GetBaseType (t); + + } while (t != null); + + return list.ToArray (); + } + + private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI) + { + var list = new List (); + + var t = type; + do { + var methods = t.Methods;//type.GetMethods (flags); + foreach (MethodDefinition method in methods) { + if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal)) + continue; + + // we're only interested in public or protected members + if (!MustDocumentMethod (method)) + continue; + + if (t == type && IsFinalizer (method)) { + string name = method.DeclaringType.Name; + int arity = name.IndexOf ('`'); + if (arity > 0) + name = name.Substring (0, arity); + + method.Name = "~" + name; + } + + if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count && + l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ()))) + continue; + + list.Add (method); + } + + if (!fullAPI) + break; + + if (t.IsInterface || t.IsEnum) + break; + + if (t.BaseType == null || t.BaseType.FullName == "System.Object") + t = null; + else + t = state.TypeHelper.GetBaseType (t); + + } while (t != null); + + return list.ToArray (); + } + + sealed class ParameterComparer : IEqualityComparer + { + public bool Equals (ParameterDefinition x, ParameterDefinition y) + { + return x.ParameterType.Name == y.ParameterType.Name; + } + + public int GetHashCode (ParameterDefinition obj) + { + return obj.ParameterType.Name.GetHashCode (); + } + } + + static bool IsFinalizer (MethodDefinition method) + { + if (method.Name != "Finalize") + return false; + + if (!method.IsVirtual) + return false; + + if (method.Parameters.Count != 0) + return false; + + return true; + } + + private MethodDefinition [] GetConstructors (TypeDefinition type) + { + ArrayList list = new ArrayList (); + + var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags); + foreach (MethodDefinition constructor in ctors) { + // we're only interested in public or protected members + if (!MustDocumentMethod(constructor)) + continue; + + list.Add (constructor); + } + + return (MethodDefinition []) list.ToArray (typeof (MethodDefinition)); + } + + private EventDefinition[] GetEvents (TypeDefinition type) + { + ArrayList list = new ArrayList (); + + var events = type.Events;//type.GetEvents (flags); + foreach (EventDefinition eventDef in events) { + MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true); + + if (addMethod == null || !MustDocumentMethod (addMethod)) + continue; + + list.Add (eventDef); + } + + return (EventDefinition []) list.ToArray (typeof (EventDefinition)); + } + } + + class FieldData : MemberData + { + public FieldData (XmlWriter writer, FieldDefinition [] members, State state) + : base (writer, members, state) + { + } + + protected override string GetName (MemberReference memberDefenition) + { + FieldDefinition field = (FieldDefinition) memberDefenition; + return field.Name; + } + + protected override string GetMemberAttributes (MemberReference memberDefenition) + { + FieldDefinition field = (FieldDefinition) memberDefenition; + return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture); + } + + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); + + FieldDefinition field = (FieldDefinition) memberDefinition; + AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType)); + + if (field.IsLiteral) { + object value = field.Constant;//object value = field.GetValue (null); + string stringValue = null; + //if (value is Enum) { + // // FIXME: when Mono bug #60090 has been + // // fixed, we should just be able to use + // // Convert.ToString + // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture); + //} + //else { + stringValue = Convert.ToString (value, CultureInfo.InvariantCulture); + //} + + if (stringValue != null) + AddAttribute ("value", stringValue); + } + } + + public override string ParentTag { + get { return "fields"; } + } + + public override string Tag { + get { return "field"; } + } + } + + class PropertyData : MemberData + { + public PropertyData (XmlWriter writer, PropertyDefinition [] members, State state) + : base (writer, members, state) + { + } + + protected override string GetName (MemberReference memberDefenition) + { + PropertyDefinition prop = (PropertyDefinition) memberDefenition; + return prop.Name; + } + + MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters) + { + MethodDefinition _get = prop.GetMethod; + MethodDefinition _set = prop.SetMethod; + bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get)); + bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set)); + haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1); + MethodDefinition [] methods; + + if (haveGet && haveSet) { + methods = new MethodDefinition [] { _get, _set }; + } else if (haveGet) { + methods = new MethodDefinition [] { _get }; + } else if (haveSet) { + methods = new MethodDefinition [] { _set }; + } else { + //odd + return null; + } + + return methods; + } + + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); + + PropertyDefinition prop = (PropertyDefinition) memberDefinition; + AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType)); + + bool haveParameters; + MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters); + + if (methods != null && haveParameters) { + string parms = Parameters.GetSignature (methods [0].Parameters); + if (!string.IsNullOrEmpty (parms)) + AddAttribute ("params", parms); + } + + } + + protected override void AddExtraData (MemberReference memberDefenition) + { + base.AddExtraData (memberDefenition); + + bool haveParameters; + MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters); + + if (methods == null) + return; + + MethodData data = new MethodData (writer, methods, state); + //data.NoMemberAttributes = true; + data.DoOutput (); + } + + protected override string GetMemberAttributes (MemberReference memberDefenition) + { + PropertyDefinition prop = (PropertyDefinition) memberDefenition; + return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture); + } + + public override string ParentTag { + get { return "properties"; } + } + + public override string Tag { + get { return "property"; } + } + } + + class EventData : MemberData + { + public EventData (XmlWriter writer, EventDefinition [] members, State state) + : base (writer, members, state) + { + } + + protected override string GetName (MemberReference memberDefenition) + { + EventDefinition evt = (EventDefinition) memberDefenition; + return evt.Name; + } + + protected override string GetMemberAttributes (MemberReference memberDefenition) + { + EventDefinition evt = (EventDefinition) memberDefenition; + return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture); + } + + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); + + EventDefinition evt = (EventDefinition) memberDefinition; + AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType)); + } + + public override string ParentTag { + get { return "events"; } + } + + public override string Tag { + get { return "event"; } + } + } + + class MethodData : MemberData + { + bool noAtts; + + public MethodData (XmlWriter writer, MethodDefinition [] members, State state) + : base (writer, members, state) + { + } + + protected override string GetName (MemberReference memberDefenition) + { + MethodDefinition method = (MethodDefinition) memberDefenition; + string name = method.Name; + string parms = Parameters.GetSignature (method.Parameters); + + return string.Format ("{0}({1})", name, parms); + } + + protected override string GetMemberAttributes (MemberReference memberDefenition) + { + MethodDefinition method = (MethodDefinition) memberDefenition; + return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture); + } + + protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) + { + var mbase = (MethodDefinition) member; + return mbase.MethodReturnType; + } + + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); + + if (!(memberDefinition is MethodDefinition)) + return; + + MethodDefinition mbase = (MethodDefinition) memberDefinition; + + if (mbase.IsAbstract) + AddAttribute ("abstract", "true"); + if (mbase.IsVirtual) + AddAttribute ("virtual", "true"); + if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot) + AddAttribute ("sealed", "true"); + if (mbase.IsStatic) + AddAttribute ("static", "true"); + var baseMethod = state.TypeHelper.GetBaseMethodInTypeHierarchy (mbase); + if (baseMethod != null && baseMethod != mbase) { + // This indicates whether this method is an override of another method. + // This information is not necessarily available in the api info for any + // particular assembly, because a method is only overriding another if + // there is a base virtual function with the same signature, and that + // base method can come from another assembly. + AddAttribute ("is-override", "true"); + } + string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType); + if (rettype != "System.Void" || !mbase.IsConstructor) + AddAttribute ("returntype", (rettype)); +// +// if (mbase.MethodReturnType.HasCustomAttributes) +// AttributeData.OutputAttributes (writer, mbase.MethodReturnType); + } + + protected override void AddExtraData (MemberReference memberDefenition) + { + base.AddExtraData (memberDefenition); + + if (!(memberDefenition is MethodDefinition)) + return; + + MethodDefinition mbase = (MethodDefinition)memberDefenition; + + ParameterData parms = new ParameterData (writer, mbase.Parameters, state) { + HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") + }; + + parms.DoOutput (); + + MemberData.OutputGenericParameters (writer, mbase, state); + } + + public override bool NoMemberAttributes { + get { return noAtts; } + set { noAtts = value; } + } + + public override string ParentTag { + get { return "methods"; } + } + + public override string Tag { + get { return "method"; } + } + } + + class ConstructorData : MethodData + { + public ConstructorData (XmlWriter writer, MethodDefinition [] members, State state) + : base (writer, members, state) + { + } + + public override string ParentTag { + get { return "constructors"; } + } + + public override string Tag { + get { return "constructor"; } + } + } + + class ParameterData : BaseData + { + private IList parameters; + + public ParameterData (XmlWriter writer, IList parameters, State state) + : base (writer, state) + { + this.parameters = parameters; + } + + public bool HasExtensionParameter { get; set; } + + public override void DoOutput () + { + bool first = true; + writer.WriteStartElement ("parameters"); + foreach (ParameterDefinition parameter in parameters) { + writer.WriteStartElement ("parameter"); + AddAttribute ("name", parameter.Name); + AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture)); + AddAttribute ("attrib", ((int) parameter.Attributes).ToString()); + + string direction = first && HasExtensionParameter ? "this" : "in"; + first = false; + + var pt = parameter.ParameterType; + var brt = pt as ByReferenceType; + if (brt != null) { + direction = parameter.IsOut ? "out" : "ref"; + pt = brt.ElementType; + } + + AddAttribute ("type", Utils.CleanupTypeName (pt)); + + if (parameter.IsOptional) { + AddAttribute ("optional", "true"); + if (parameter.HasConstant) + AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ()); + } + + if (direction != "in") + AddAttribute ("direction", direction); + + AttributeData.OutputAttributes (writer, state, parameter); + writer.WriteEndElement (); // parameter + } + writer.WriteEndElement (); // parameters + } + } + + class AttributeData + { + State state; + + public AttributeData (State state) + { + this.state = state; + } + + public void DoOutput (XmlWriter writer, IList providers) + { + if (writer == null) + throw new InvalidOperationException ("Document not set"); + + if (providers == null || providers.Count == 0) + return; + + if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes)) + return; + + writer.WriteStartElement ("attributes"); + + foreach (var provider in providers) { + if (provider == null) + continue; + + if (!provider.HasCustomAttributes) + continue; + + + var ass = provider as AssemblyDefinition; + if (ass != null && !state.FollowForwarders) + TypeForwardedToData.OutputForwarders (writer, ass, state); + + var attributes = provider.CustomAttributes. + Where ((att) => !SkipAttribute (att)). + OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal); + + foreach (var att in attributes) { + string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType); + + writer.WriteStartElement ("attribute"); + writer.WriteAttributeString ("name", attName); + + var attribute_mapping = CreateAttributeMapping (att); + + if (attribute_mapping != null) { + var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId"); + if (mapping.Any ()) { + writer.WriteStartElement ("properties"); + foreach (var kvp in mapping) { + string name = kvp.Key; + object o = kvp.Value; + + writer.WriteStartElement ("property"); + writer.WriteAttributeString ("name", name); + + if (o == null) { + writer.WriteAttributeString ("value", "null"); + } else { + string value = o.ToString (); + if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal)) + value = value.ToUpper (); + writer.WriteAttributeString ("value", value); + } + + writer.WriteEndElement (); // property + } + writer.WriteEndElement (); // properties + } + } + writer.WriteEndElement (); // attribute + } + } + + writer.WriteEndElement (); // attributes + } + + Dictionary CreateAttributeMapping (CustomAttribute attribute) + { + Dictionary mapping = null; + + if (!state.TypeHelper.TryResolve (attribute)) + return mapping; + + PopulateMapping (ref mapping, attribute); + + var constructor = state.TypeHelper.GetMethod (attribute.Constructor); + if (constructor == null || !constructor.HasParameters) + return mapping; + + PopulateMapping (ref mapping, constructor, attribute); + + return mapping; + } + + static void PopulateMapping (ref Dictionary mapping, CustomAttribute attribute) + { + if (!attribute.HasProperties) + return; + + foreach (var named_argument in attribute.Properties) { + var name = named_argument.Name; + var arg = named_argument.Argument; + + if (arg.Value is CustomAttributeArgument) + arg = (CustomAttributeArgument) arg.Value; + + if (mapping == null) + mapping = new Dictionary (StringComparer.Ordinal); + mapping.Add (name, GetArgumentValue (arg.Type, arg.Value)); + } + } + + static Dictionary CreateArgumentFieldMapping (MethodDefinition constructor) + { + Dictionary field_mapping = null; + + int? argument = null; + + foreach (Instruction instruction in constructor.Body.Instructions) { + switch (instruction.OpCode.Code) { + case Code.Ldarg_1: + argument = 1; + break; + case Code.Ldarg_2: + argument = 2; + break; + case Code.Ldarg_3: + argument = 3; + break; + case Code.Ldarg: + case Code.Ldarg_S: + argument = ((ParameterDefinition) instruction.Operand).Index + 1; + break; + + case Code.Stfld: + FieldReference field = (FieldReference) instruction.Operand; + if (field.DeclaringType.FullName != constructor.DeclaringType.FullName) + continue; + + if (!argument.HasValue) + break; + + if (field_mapping == null) + field_mapping = new Dictionary (); + + if (!field_mapping.ContainsKey (field)) + field_mapping.Add (field, (int) argument - 1); + + argument = null; + break; + } + } + + return field_mapping; + } + + static Dictionary CreatePropertyFieldMapping (TypeDefinition type) + { + Dictionary property_mapping = null; + + foreach (PropertyDefinition property in type.Properties) { + if (property.GetMethod == null) + continue; + if (!property.GetMethod.HasBody) + continue; + + foreach (Instruction instruction in property.GetMethod.Body.Instructions) { + if (instruction.OpCode.Code != Code.Ldfld) + continue; + + FieldReference field = (FieldReference) instruction.Operand; + if (field.DeclaringType.FullName != type.FullName) + continue; + + if (property_mapping == null) + property_mapping = new Dictionary (); + property_mapping.Add (property, field); + break; + } + } + + return property_mapping; + } + + static void PopulateMapping (ref Dictionary mapping, MethodDefinition constructor, CustomAttribute attribute) + { + if (!constructor.HasBody) + return; + + // Custom handling for attributes with arguments which cannot be easily extracted + var ca = attribute.ConstructorArguments; + switch (constructor.DeclaringType.FullName) { + case "System.Runtime.CompilerServices.DecimalConstantAttribute": + var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ? + new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) : + new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value); + + if (mapping == null) + mapping = new Dictionary (StringComparer.Ordinal); + mapping.Add ("Value", dca.Value); + return; + case "System.ComponentModel.BindableAttribute": + if (ca.Count != 1) + break; + + if (mapping == null) + mapping = new Dictionary (StringComparer.Ordinal); + + if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) { + mapping.Add ("Bindable", ca[0].Value); + } else if (constructor.Parameters[0].ParameterType.FullName == "System.ComponentModel.BindableSupport") { + if ((int)ca[0].Value == 0) + mapping.Add ("Bindable", false); + else if ((int)ca[0].Value == 1) + mapping.Add ("Bindable", true); + else + throw new NotImplementedException (); + } else { + throw new NotImplementedException (); + } + + return; + } + + var field_mapping = CreateArgumentFieldMapping (constructor); + if (field_mapping != null) { + var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType); + + if (property_mapping != null) { + foreach (var pair in property_mapping) { + int argument; + if (!field_mapping.TryGetValue (pair.Value, out argument)) + continue; + + var ca_arg = ca [argument]; + if (ca_arg.Value is CustomAttributeArgument) + ca_arg = (CustomAttributeArgument)ca_arg.Value; + + if (mapping == null) + mapping = new Dictionary (StringComparer.Ordinal); + mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value)); + } + } + } + } + + static object GetArgumentValue (TypeReference reference, object value) + { + var type = reference.Resolve (); + if (type == null) + return value; + + if (type.IsEnum) { + if (IsFlaggedEnum (type)) + return GetFlaggedEnumValue (type, value); + + return GetEnumValue (type, value); + } + + return value; + } + + static bool IsFlaggedEnum (TypeDefinition type) + { + if (!type.IsEnum) + return false; + + if (!type.HasCustomAttributes) + return false; + + foreach (CustomAttribute attribute in type.CustomAttributes) + if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute") + return true; + + return false; + } + + static object GetFlaggedEnumValue (TypeDefinition type, object value) + { + if (value is ulong) + return GetFlaggedEnumValue (type, (ulong)value); + + long flags = Convert.ToInt64 (value); + var signature = new StringBuilder (); + + for (int i = type.Fields.Count - 1; i >= 0; i--) { + FieldDefinition field = type.Fields [i]; + + if (!field.HasConstant) + continue; + + long flag = Convert.ToInt64 (field.Constant); + + if (flag == 0) + continue; + + if ((flags & flag) == flag) { + if (signature.Length != 0) + signature.Append (", "); + + signature.Append (field.Name); + flags -= flag; + } + } + + return signature.ToString (); + } + + static object GetFlaggedEnumValue (TypeDefinition type, ulong flags) + { + var signature = new StringBuilder (); + + for (int i = type.Fields.Count - 1; i >= 0; i--) { + FieldDefinition field = type.Fields [i]; + + if (!field.HasConstant) + continue; + + ulong flag = Convert.ToUInt64 (field.Constant); + + if (flag == 0) + continue; + + if ((flags & flag) == flag) { + if (signature.Length != 0) + signature.Append (", "); + + signature.Append (field.Name); + flags -= flag; + } + } + + return signature.ToString (); + } + + static object GetEnumValue (TypeDefinition type, object value) + { + foreach (FieldDefinition field in type.Fields) { + if (!field.HasConstant) + continue; + + if (Comparer.Default.Compare (field.Constant, value) == 0) + return field.Name; + } + + return value; + } + + bool SkipAttribute (CustomAttribute attribute) + { + if (!state.TypeHelper.IsPublic (attribute)) + return true; + + return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal); + } + + public static void OutputAttributes (XmlWriter writer, State state, params ICustomAttributeProvider[] providers) + { + var data = new AttributeData (state); + data.DoOutput (writer, providers); + } + } + + static class Parameters { + + public static string GetSignature (IList infos) + { + if (infos == null || infos.Count == 0) + return string.Empty; + + var signature = new StringBuilder (); + for (int i = 0; i < infos.Count; i++) { + + if (i > 0) + signature.Append (", "); + + ParameterDefinition info = infos [i]; + + string modifier = string.Empty; + if (info.ParameterType.IsByReference) { + if ((info.Attributes & ParameterAttributes.In) != 0) + modifier = "in"; + else if ((info.Attributes & ParameterAttributes.Out) != 0) + modifier = "out"; + } + + if (modifier.Length > 0) { + signature.Append (modifier); + signature.Append (" "); + } + + signature.Append (Utils.CleanupTypeName (info.ParameterType)); + } + + return signature.ToString (); + } + + } + + class TypeReferenceComparer : IComparer + { + public static TypeReferenceComparer Default = new TypeReferenceComparer (); + + public int Compare (TypeReference a, TypeReference b) + { + int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal); + if (result != 0) + return result; + + return String.Compare (a.Name, b.Name, StringComparison.Ordinal); + } + } + + class MemberReferenceComparer : IComparer + { + public static MemberReferenceComparer Default = new MemberReferenceComparer (); + + public int Compare (object a, object b) + { + MemberReference ma = (MemberReference) a; + MemberReference mb = (MemberReference) b; + return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); + } + } + + class PropertyDefinitionComparer : IComparer + { + public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer (); + + public int Compare (PropertyDefinition ma, PropertyDefinition mb) + { + int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); + if (res != 0) + return res; + + if (!ma.HasParameters && !mb.HasParameters) + return 0; + + if (!ma.HasParameters) + return -1; + + if (!mb.HasParameters) + return 1; + + return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters); + } + } + + class MethodDefinitionComparer : IComparer + { + public static MethodDefinitionComparer Default = new MethodDefinitionComparer (); + + public int Compare (object a, object b) + { + MethodDefinition ma = (MethodDefinition) a; + MethodDefinition mb = (MethodDefinition) b; + int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal); + if (res != 0) + return res; + + if (!ma.HasParameters && !mb.HasParameters) + return 0; + + if (!ma.HasParameters) + return -1; + + if (!mb.HasParameters) + return 1; + + res = Compare (ma.Parameters, mb.Parameters); + if (res != 0) + return res; + + if (ma.HasGenericParameters != mb.HasGenericParameters) + return ma.HasGenericParameters ? -1 : 1; + + if (ma.HasGenericParameters && mb.HasGenericParameters) { + res = ma.GenericParameters.Count - mb.GenericParameters.Count; + if (res != 0) + return res; + } + + // operators can differ by only return type + return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName); + } + + public static int Compare (IList pia, IList pib) + { + var res = pia.Count - pib.Count; + if (res != 0) + return res; + + string siga = Parameters.GetSignature (pia); + string sigb = Parameters.GetSignature (pib); + return String.Compare (siga, sigb, StringComparison.Ordinal); + } + } +} + diff --git a/corcompare/mono-api-info.exe.sources b/corcompare/mono-api-info.exe.sources new file mode 100644 index 0000000..9ae6cd0 --- /dev/null +++ b/corcompare/mono-api-info.exe.sources @@ -0,0 +1,5 @@ +AssemblyResolver.cs +Util.cs +WellFormedXmlWriter.cs +mono-api-info.cs +../../class/Mono.Options/Mono.Options/Options.cs diff --git a/corcompare/upload.rb b/corcompare/upload.rb new file mode 100755 index 0000000..6b19f8b --- /dev/null +++ b/corcompare/upload.rb @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +CURRENT = "2.8" + +Dir["*.tar.gz"].each { |file| + system("scp #{file} mono-web@go-mono.com:go-mono/masterinfos/#{CURRENT}") +}