Imported Upstream version 5.18.0.142

Former-commit-id: 7467d4b717762eeaf652d77f1486dd11ffb1ff1f
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-10-09 08:20:59 +00:00
parent e52655b4dc
commit 0abdbe5a7d
1547 changed files with 93792 additions and 47893 deletions

View File

@@ -14,6 +14,7 @@ net_4_5_dirs := \
xbuild \
csharp \
corcompare \
mono-api-diff \
mono-api-html \
compiler-tester \
mono-xmltool \
@@ -48,7 +49,7 @@ net_4_5_dirs := \
mono-symbolicate \
linker-analyzer
build_SUBDIRS = resgen gacutil security culevel cil-stringreplacer commoncryptogenerator resx2sr linker cil-strip corcompare mono-api-html
build_SUBDIRS = resgen gacutil security culevel cil-stringreplacer commoncryptogenerator resx2sr linker cil-strip corcompare mono-api-diff mono-api-html
monodroid_tools_SUBDIRS = cil-strip linker-analyzer mkbundle mdoc mono-symbolicate
monodroid_SUBDIRS = nunit-lite
monotouch_SUBDIRS = nunit-lite

View File

@@ -5,7 +5,8 @@ include ../../build/rules.make
PROGRAM = cil-stringreplacer.exe
NO_INSTALL = yes
ifeq ($(PROFILE),basic)
API = $(filter basic build, $(PROFILE))
ifdef API
# It can be run using system .net during boostrap
TARGET_NET_REFERENCE = v4.6
# Trick to make it work during boostrap where it has to run with system

View File

@@ -41,6 +41,7 @@ public class Program
public bool Verbose { get; set; }
public List<string> ResourcesStrings { get; }
public string ILFile { get; set; }
public bool MonoMscorlib { get; set; }
public CmdOptions ()
{
@@ -61,6 +62,8 @@ public class Program
v => options.Verbose = v != null },
{ "ilreplace=", "File with IL code to be used instead",
v => options.ILFile = v },
{ "mscorlib-debug", "IL customizations for Mono's mscorlib",
v => options.MonoMscorlib = v != null },
};
List<string> extra;
@@ -130,6 +133,10 @@ public class Program
using (var assembly = AssemblyDefinition.ReadAssembly (assemblyLocation, readerParameters)) {
foreach (var module in assembly.Modules) {
foreach (var type in module.GetTypes ()) {
if (options.MonoMscorlib && type.Name == "Debug" && type.Namespace == "System.Diagnostics") {
type.Name = "DebugPrivate";
}
foreach (var method in type.Methods) {
if (!method.HasBody)
continue;

View File

@@ -32,16 +32,11 @@ using System.IO;
using Mono.Cecil;
namespace GuiCompare {
namespace Mono.ApiTools {
public class AssemblyResolver : DefaultAssemblyResolver {
class AssemblyResolver : DefaultAssemblyResolver {
public AssemblyDefinition ResolveFile (string file)
{
return ProcessFile (file);
}
AssemblyDefinition ProcessFile (string file)
{
AddSearchDirectory (Path.GetDirectoryName (file));
var assembly = AssemblyDefinition.ReadAssembly (file, new ReaderParameters { AssemblyResolver = this, InMemory = true });
@@ -49,5 +44,13 @@ namespace GuiCompare {
return assembly;
}
public AssemblyDefinition ResolveStream (Stream stream)
{
var assembly = AssemblyDefinition.ReadAssembly (stream, new ReaderParameters { AssemblyResolver = this, InMemory = true });
RegisterAssembly (assembly);
return assembly;
}
}
}

View File

@@ -3,32 +3,57 @@ using System.Collections.Generic;
using System.Text;
using Mono.Cecil;
using GuiCompare;
namespace Mono.ApiTools {
namespace CorCompare {
class TypeHelper {
static class TypeHelper {
public TypeHelper (bool ignoreResolutionErrors, bool ignoreInheritedInterfaces)
{
IgnoreResolutionErrors = ignoreResolutionErrors;
IgnoreInheritedInterfaces = ignoreInheritedInterfaces;
}
public static AssemblyResolver Resolver = new AssemblyResolver ();
public bool IgnoreResolutionErrors { get; }
internal static bool IsPublic (TypeReference typeref)
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");
TypeDefinition td = typeref.Resolve ();
if (td == null)
return false;
try {
var td = typeref.Resolve ();
if (td == null)
return false;
return td.IsPublic;
return td.IsPublic || (td.IsNestedPublic && IsPublic (td.DeclaringType));
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return true;
}
}
internal static bool IsDelegate (TypeReference typeref)
internal bool IsDelegate (TypeReference typeref)
{
return IsDerivedFrom (typeref, "System.MulticastDelegate");
}
internal static bool IsDerivedFrom (TypeReference type, string derivedFrom)
internal bool IsDerivedFrom (TypeReference type, string derivedFrom)
{
bool first = true;
foreach (var def in WalkHierarchy (type)) {
@@ -44,52 +69,71 @@ namespace CorCompare {
return false;
}
internal static IEnumerable<TypeDefinition> WalkHierarchy (TypeReference type)
internal IEnumerable<TypeDefinition> WalkHierarchy (TypeReference type)
{
for (var def = type.Resolve (); def != null; def = GetBaseType (def))
yield return def;
}
internal static IEnumerable<TypeReference> GetInterfaces (TypeReference type)
internal IEnumerable<TypeReference> GetInterfaces (TypeReference type)
{
var ifaces = new Dictionary<string, TypeReference> ();
foreach (var def in WalkHierarchy (type))
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 static TypeDefinition GetBaseType (TypeDefinition child)
internal TypeDefinition GetBaseType (TypeDefinition child)
{
if (child.BaseType == null)
return null;
return child.BaseType.Resolve ();
try {
return child.BaseType.Resolve ();
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return null;
}
}
internal static bool IsPublic (CustomAttribute att)
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 static string GetFullName (CustomAttribute att)
internal string GetFullName (CustomAttribute att)
{
return att.AttributeType.FullName;
}
internal static TypeDefinition GetTypeDefinition (CustomAttribute att)
internal TypeDefinition GetTypeDefinition (CustomAttribute att)
{
return att.AttributeType.Resolve ();
}
static bool IsOverride (MethodDefinition method)
bool IsOverride (MethodDefinition method)
{
return method.IsVirtual && !method.IsNewSlot;
}
public static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
public MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
{
if (!IsOverride (method))
return method;
@@ -106,7 +150,7 @@ namespace CorCompare {
return method;
}
static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
{
if (!type.HasMethods)
return null;
@@ -118,7 +162,7 @@ namespace CorCompare {
return null;
}
static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
{
if (!candidate.IsVirtual)
return false;
@@ -139,7 +183,7 @@ namespace CorCompare {
return true;
}
public static bool TypeMatch (IModifierType a, IModifierType b)
public bool TypeMatch (IModifierType a, IModifierType b)
{
if (!TypeMatch (a.ModifierType, b.ModifierType))
return false;
@@ -147,7 +191,7 @@ namespace CorCompare {
return TypeMatch (a.ElementType, b.ElementType);
}
public static bool TypeMatch (TypeSpecification a, TypeSpecification b)
public bool TypeMatch (TypeSpecification a, TypeSpecification b)
{
if (a is GenericInstanceType)
return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b);
@@ -158,7 +202,7 @@ namespace CorCompare {
return TypeMatch (a.ElementType, b.ElementType);
}
public static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
public bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
{
if (!TypeMatch (a.ElementType, b.ElementType))
return false;
@@ -176,7 +220,7 @@ namespace CorCompare {
return true;
}
public static bool TypeMatch (TypeReference a, TypeReference b)
public bool TypeMatch (TypeReference a, TypeReference b)
{
if (a is GenericParameter)
return true;

View File

@@ -11,9 +11,9 @@ using System.Globalization;
using System.Collections;
using System.Xml;
namespace CorCompare {
namespace Mono.ApiTools {
public class WellFormedXmlWriter : DefaultXmlWriter
class WellFormedXmlWriter : DefaultXmlWriter
{
public static bool IsInvalid (int ch)
{
@@ -110,7 +110,7 @@ namespace CorCompare {
}
public class DefaultXmlWriter : XmlWriter
class DefaultXmlWriter : XmlWriter
{
XmlWriter writer;

File diff suppressed because it is too large Load Diff

View File

@@ -8,20 +8,35 @@ LIB_REFS = System System.Core System.Xml Mono.Cecil
TEST_CASES := \
mscorlib/test-array.cs \
mscorlib/test-remoting.cs \
mscorlib/test-exception-01.cs \
mscorlib/test-locale-01.cs \
mscorlib/test-reflection-01.cs \
mscorlib/test-string-01.cs \
mscorlib/test-string-02.cs \
mscorlib/test-string-03.cs \
mscorlib/test-task-01.cs \
System/test-security.cs
ifdef MOBILE_PROFILE
TEST_CASES += \
# Requires linker fix
# mscorlib/test-crypto-01.cs
endif
ifndef AOT_FRIENDLY_PROFILE
TEST_CASES += \
mscorlib/test-remoting.cs \
mscorlib/test-reflection.cs
endif
TESTS_COMPILER = $(MCS) -nologo -noconfig -debug:portable -r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll
SIZE_TEST_CASES :=
TESTS_COMPILER = $(MCS) -nologo -noconfig -unsafe -debug:portable -r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll
check: compile-tests
$(MAKE) run-tests
compile-tests: $(TEST_CASES)
compile-tests: $(TEST_CASES) $(SIZE_TEST_CASES)
mscorlib/test-%.cs:
$(TESTS_COMPILER) Tests/$@ /out:Tests/$(@:.cs=.exe)
@@ -46,4 +61,40 @@ System/test-%.exe mscorlib/test-%.exe:
$(TEST_EXEC) $(LINKER_OUTPUT)/$(@F)
@rm -rf $(LINKER_OUTPUT)
BCL_ASSEMBLIES_CORE=mscorlib.dll System.dll System.Core.dll System.Xml.dll
BCL_ASSEMBLIES=$(BCL_ASSEMBLIES_CORE) $(sort $(filter-out $(BCL_ASSEMBLIES_CORE), $(notdir $(wildcard $(PROFILE_PATH)/System.*.dll)) ))
COMMA=,
REPORT_FILE=$(PROFILE)-linked-size.csv
bcl-size-current: compile-tests
@echo "App,$$(echo '$(BCL_ASSEMBLIES)' | tr ' ' ',')" > $(REPORT_FILE)
@for app in $(sort $(SIZE_TEST_CASES:.cs=.exe) $(TEST_CASES:.cs=.exe)); do \
rm -rf $(LINKER_OUTPUT); \
mkdir $(LINKER_OUTPUT); \
echo Checking linked BCL size for $$app; \
$(LINKER) -a Tests/$$app; \
sizes=""; \
for asm in $(BCL_ASSEMBLIES); do \
if [ -f "$(LINKER_OUTPUT)/$$asm" ]; then size=$$(wc -c < "$(LINKER_OUTPUT)/$$asm" | tr -d "[:space:]"); else size="0"; fi; \
sizes="$$sizes,$$size"; \
done; \
echo "$$app$$sizes" >> $(REPORT_FILE); \
rm -rf $(LINKER_OUTPUT); \
done;
bcl-size-diff:
@echo "Regenerating BCL Linked Size diff..."
$(Q) $(MAKE) bcl-size-current PROFILE=net_4_x || true
$(Q) $(MAKE) bcl-size-current PROFILE=monotouch || true
$(Q) $(MAKE) bcl-size-current PROFILE=monodroid || true
@echo "Checking size differences..."
@mkdir -p sizediff
$(Q) git diff HEAD "*.csv" > temp.patch
$(Q) git show HEAD:./net_4_x-linked-size.csv > net_4_x-linked-size.old.csv
$(Q) git show HEAD:./monotouch-linked-size.csv > monotouch-linked-size.old.csv
$(Q) git show HEAD:./monodroid-linked-size.csv > monodroid-linked-size.old.csv
$(Q) sed -e "/@diffdata@/r temp.patch" -e "/@diffdata@/d" -e "/@olddata-net_4_x@/r net_4_x-linked-size.old.csv" -e "/@olddata-net_4_x@/d" -e "/@olddata-monotouch@/r monotouch-linked-size.old.csv" -e "/@olddata-monotouch@/d" -e "/@olddata-monodroid@/r monodroid-linked-size.old.csv" -e "/@olddata-monodroid@/d" -e "/@newdata-net_4_x@/r net_4_x-linked-size.csv" -e "/@newdata-net_4_x@/d" -e "/@newdata-monotouch@/r monotouch-linked-size.csv" -e "/@newdata-monotouch@/d" -e "/@newdata-monodroid@/r monodroid-linked-size.csv" -e "/@newdata-monodroid@/d" linked-size-diff.html.in > sizediff/index.html
$(Q) if [ -s temp.patch ]; then echo "Error: Found BCL Linked Size differences, see mcs/tools/linker/sizediff/index.html."; rm -f temp.patch *.old.csv; exit 1; else echo "No differences found."; rm -f temp.patch *.old.csv; fi
include ../../build/executable.make

View File

@@ -0,0 +1,10 @@
thisdir = tools/mono-api-diff
SUBDIRS =
include ../../build/rules.make
LIB_REFS = System.Xml System.Core System
LOCAL_MCS_FLAGS =
PROGRAM = mono-api-diff.exe
include ../../build/executable.make

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
mono-api-diff.cs
../../class/Mono.Options/Mono.Options/Options.cs

View File

@@ -4,9 +4,9 @@ using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Xamarin.ApiDiff
{
public class ApiChange
namespace Mono.ApiTools {
class ApiChange
{
public string Header;
public StringBuilder Member = new StringBuilder ();
@@ -14,10 +14,12 @@ namespace Xamarin.ApiDiff
public bool AnyChange;
public bool HasIgnoredChanges;
public string SourceDescription;
public State State;
public ApiChange (string sourceDescription)
public ApiChange (string sourceDescription, State state)
{
SourceDescription = sourceDescription;
State = state;
}
public ApiChange Append (string text)
@@ -28,7 +30,7 @@ namespace Xamarin.ApiDiff
public ApiChange AppendAdded (string text, bool breaking = false)
{
Formatter.Current.DiffAddition (Member, text, breaking);
State.Formatter.DiffAddition (Member, text, breaking);
Breaking |= breaking;
AnyChange = true;
return this;
@@ -36,7 +38,7 @@ namespace Xamarin.ApiDiff
public ApiChange AppendRemoved (string text, bool breaking = true)
{
Formatter.Current.DiffRemoval (Member, text, breaking);
State.Formatter.DiffRemoval (Member, text, breaking);
Breaking |= breaking;
AnyChange = true;
return this;
@@ -44,14 +46,22 @@ namespace Xamarin.ApiDiff
public ApiChange AppendModified (string old, string @new, bool breaking = true)
{
Formatter.Current.DiffModification (Member, old, @new, breaking);
State.Formatter.DiffModification (Member, old, @new, breaking);
Breaking |= breaking;
AnyChange = true;
return this;
}
}
public class ApiChanges : Dictionary<string, List<ApiChange>> {
class ApiChanges : Dictionary<string, List<ApiChange>> {
public State State;
public ApiChanges (State state)
{
State = state;
}
public void Add (XElement source, XElement target, ApiChange change)
{
if (!change.AnyChange) {
@@ -59,9 +69,9 @@ namespace Xamarin.ApiDiff
if (!change.HasIgnoredChanges) {
var isField = source.Name.LocalName == "field";
if (isField) {
Console.WriteLine ("Comparison resulting in no changes (src: {2} dst: {3}) :\n{0}\n{1}\n\n", source.ToString (), target.ToString (), source.GetFieldAttributes (), target.GetFieldAttributes ());
State.LogDebugMessage ($"Comparison resulting in no changes (src: {source.GetFieldAttributes ()} dst: {target.GetFieldAttributes ()}) :\n{source}\n{target}\n\n");
} else {
Console.WriteLine ("Comparison resulting in no changes (src: {2} dst: {3}) :\n{0}\n{1}\n\n", source.ToString (), target.ToString (), source.GetMethodAttributes (), target.GetMethodAttributes ());
State.LogDebugMessage ($"Comparison resulting in no changes (src: {source.GetMethodAttributes ()} dst: {target.GetMethodAttributes ()}) :\n{source}\n{target}\n\n");
}
}
return;

View File

@@ -37,63 +37,39 @@ using System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Mono.Options;
namespace Mono.ApiTools {
namespace Xamarin.ApiDiff {
class State {
public TextWriter Output { get; set; }
public Formatter Formatter { get; set; }
public string Assembly { get; set; }
public string Namespace { get; set; }
public string Type { get; set; }
public string BaseType { get; set; }
public string Parent { get; set; }
public int Indent { get; set; }
public List<Regex> IgnoreAdded { get; } = new List<Regex> ();
public List<Regex> IgnoreNew { get; } = new List<Regex> ();
public List<Regex> IgnoreRemoved { get; } = new List<Regex> ();
public bool IgnoreParameterNameChanges { get; set; }
public bool IgnoreVirtualChanges { get; set; }
public bool IgnoreAddedPropertySetters { get; set; }
public bool IgnoreNonbreaking { get; set; }
public bool Lax { get; set; }
public bool Colorize { get; set; } = true;
public int Verbosity { get; set; }
public static class State {
static TextWriter output;
public static TextWriter Output {
get {
if (output == null)
output = Console.Out;
return output;
}
set { output = value; }
}
public static string Assembly { get; set; }
public static string Namespace { get; set; }
public static string Type { get; set; }
public static string BaseType { get; set; }
public static string Parent { get; set; }
public static int Indent { get; set; }
static List<Regex> ignoreAdded = new List<Regex> ();
public static List<Regex> IgnoreAdded {
get { return ignoreAdded; }
}
static List<Regex> ignoreNew = new List<Regex> ();
public static List<Regex> IgnoreNew {
get { return ignoreNew; }
}
static List<Regex> ignoreRemoved = new List<Regex> ();
public static List<Regex> IgnoreRemoved {
get { return ignoreRemoved; }
}
public static bool IgnoreParameterNameChanges { get; set; }
public static bool IgnoreVirtualChanges { get; set; }
public static bool IgnoreAddedPropertySetters { get; set; }
public static bool IgnoreNonbreaking { get; set; }
public static bool Lax;
public static bool Colorize = true;
public static int Verbosity;
public static void LogDebugMessage (string value)
public void LogDebugMessage (string value)
{
#if !EXCLUDE_DRIVER
if (Verbosity == 0)
return;
Console.WriteLine (value);
#endif
}
}
#if !EXCLUDE_DRIVER
class Program {
public static int Main (string[] args)
@@ -101,61 +77,51 @@ namespace Xamarin.ApiDiff {
var showHelp = false;
string diff = null;
List<string> extra = null;
var config = new ApiDiffFormattedConfig ();
var options = new OptionSet {
var options = new Mono.Options.OptionSet {
{ "h|help", "Show this help", v => showHelp = true },
{ "d|diff=", "HTML diff file out output (omit for stdout)", v => diff = v },
{ "d|o|out=|output=|diff=", "HTML diff file out output (omit for stdout)", v => diff = v },
{ "i|ignore=", "Ignore new, added, and removed members whose description matches a given C# regular expression (see below).",
v => {
var r = new Regex (v);
State.IgnoreAdded.Add (r);
State.IgnoreRemoved.Add (r);
State.IgnoreNew.Add (r);
config.IgnoreAdded.Add (r);
config.IgnoreRemoved.Add (r);
config.IgnoreNew.Add (r);
}
},
{ "a|ignore-added=", "Ignore added members whose description matches a given C# regular expression (see below).",
v => State.IgnoreAdded.Add (new Regex (v))
v => config.IgnoreAdded.Add (new Regex (v))
},
{ "r|ignore-removed=", "Ignore removed members whose description matches a given C# regular expression (see below).",
v => State.IgnoreRemoved.Add (new Regex (v))
v => config.IgnoreRemoved.Add (new Regex (v))
},
{ "n|ignore-new=", "Ignore new namespaces and types whose description matches a given C# regular expression (see below).",
v => State.IgnoreNew.Add (new Regex (v))
v => config.IgnoreNew.Add (new Regex (v))
},
{ "ignore-changes-parameter-names", "Ignore changes to parameter names for identically prototyped methods.",
v => State.IgnoreParameterNameChanges = v != null
v => config.IgnoreParameterNameChanges = v != null
},
{ "ignore-changes-property-setters", "Ignore adding setters to properties.",
v => State.IgnoreAddedPropertySetters = v != null
v => config.IgnoreAddedPropertySetters = v != null
},
{ "ignore-changes-virtual", "Ignore changing non-`virtual` to `virtual` or adding `override`.",
v => State.IgnoreVirtualChanges = v != null
v => config.IgnoreVirtualChanges = v != null
},
{ "c|colorize:", "Colorize HTML output", v => State.Colorize = string.IsNullOrEmpty (v) ? true : bool.Parse (v) },
{ "x|lax", "Ignore duplicate XML entries", v => State.Lax = true },
{ "ignore-nonbreaking", "Ignore all nonbreaking changes", v => State.IgnoreNonbreaking = true },
{ "c|colorize:", "Colorize HTML output", v => config.Colorize = string.IsNullOrEmpty (v) ? true : bool.Parse (v) },
{ "x|lax", "Ignore duplicate XML entries", v => config.IgnoreDuplicateXml = true },
{ "ignore-nonbreaking", "Ignore all nonbreaking changes", v => config.IgnoreNonbreaking = true },
{ "v|verbose:", "Verbosity level; when set, will print debug messages",
(int? v) => State.Verbosity = v ?? (State.Verbosity + 1)},
{ "md|markdown", "Output markdown instead of HTML", v => Formatter.Current = new MarkdownFormatter () },
new ResponseFileSource (),
(int? v) => config.Verbosity = v ?? (config.Verbosity + 1)},
{ "md|markdown", "Output markdown instead of HTML", v => config.Formatter = ApiDiffFormatter.Markdown },
new Mono.Options.ResponseFileSource (),
};
try {
extra = options.Parse (args);
} catch (OptionException e) {
} catch (Mono.Options.OptionException e) {
Console.WriteLine ("Option error: {0}", e.Message);
showHelp = true;
}
// unless specified default to HTML
if (Formatter.Current == null)
Formatter.Current = new HtmlFormatter ();
if (State.IgnoreNonbreaking) {
State.IgnoreAddedPropertySetters = true;
State.IgnoreVirtualChanges = true;
State.IgnoreNew.Add (new Regex (".*"));
State.IgnoreAdded.Add (new Regex (".*"));
extra = null;
}
if (showHelp || extra == null || extra.Count < 2 || extra.Count > 3) {
@@ -177,7 +143,7 @@ namespace Xamarin.ApiDiff {
Console.WriteLine (" The regular expressions will match any member description ending with");
Console.WriteLine (" 'INSCopying' or 'INSCoding'.");
Console.WriteLine ();
return 1;
return showHelp ? 0 : 1;
}
var input = extra [0];
@@ -185,37 +151,136 @@ namespace Xamarin.ApiDiff {
if (extra.Count == 3 && diff == null)
diff = extra [2];
TextWriter outputStream = null;
try {
var ac = new AssemblyComparer (input, output);
if (diff != null) {
string diffHtml = String.Empty;
using (var writer = new StringWriter ()) {
State.Output = writer;
ac.Compare ();
diffHtml = State.Output.ToString ();
}
if (diffHtml.Length > 0) {
using (var file = new StreamWriter (diff)) {
var title = $"{ac.SourceAssembly}.dll";
if (ac.SourceAssembly != ac.TargetAssembly)
title += $" vs {ac.TargetAssembly}.dll";
Formatter.Current.BeginDocument (file, $"API diff: {title}");
Formatter.Current.BeginAssembly (file);
file.Write (diffHtml);
Formatter.Current.EndAssembly (file);
Formatter.Current.EndDocument (file);
}
}
} else {
State.Output = Console.Out;
ac.Compare ();
}
}
catch (Exception e) {
if (!string.IsNullOrEmpty (diff))
outputStream = new StreamWriter (diff);
ApiDiffFormatted.Generate (input, output, outputStream ?? Console.Out, config);
} catch (Exception e) {
Console.WriteLine (e);
return 1;
} finally {
outputStream?.Dispose ();
}
return 0;
}
}
#endif
public enum ApiDiffFormatter {
Html,
Markdown,
}
public class ApiDiffFormattedConfig {
public ApiDiffFormatter Formatter { get; set; }
public List<Regex> IgnoreAdded { get; set; } = new List<Regex> ();
public List<Regex> IgnoreNew { get; set; } = new List<Regex> ();
public List<Regex> IgnoreRemoved { get; set; } = new List<Regex> ();
public bool IgnoreParameterNameChanges { get; set; }
public bool IgnoreVirtualChanges { get; set; }
public bool IgnoreAddedPropertySetters { get; set; }
public bool IgnoreNonbreaking { get; set; }
public bool IgnoreDuplicateXml { get; set; }
public bool Colorize { get; set; } = true;
internal int Verbosity { get; set; }
}
public static class ApiDiffFormatted {
public static void Generate (Stream firstInfo, Stream secondInfo, TextWriter outStream, ApiDiffFormattedConfig config = null)
{
var state = CreateState (config);
Generate (firstInfo, secondInfo, outStream, state);
}
public static void Generate (string firstInfo, string secondInfo, TextWriter outStream, ApiDiffFormattedConfig config = null)
{
var state = CreateState (config);
Generate (firstInfo, secondInfo, outStream, state);
}
internal static void Generate (string firstInfo, string secondInfo, TextWriter outStream, State state)
{
var ac = new AssemblyComparer (firstInfo, secondInfo, state);
Generate (ac, outStream, state);
}
internal static void Generate (Stream firstInfo, Stream secondInfo, TextWriter outStream, State state)
{
var ac = new AssemblyComparer (firstInfo, secondInfo, state);
Generate (ac, outStream, state);
}
static void Generate (AssemblyComparer ac, TextWriter outStream, State state)
{
var diffHtml = String.Empty;
using (var writer = new StringWriter ()) {
state.Output = writer;
ac.Compare ();
diffHtml = state.Output.ToString ();
}
if (diffHtml.Length > 0) {
var title = $"{ac.SourceAssembly}.dll";
if (ac.SourceAssembly != ac.TargetAssembly)
title += $" vs {ac.TargetAssembly}.dll";
state.Formatter.BeginDocument (outStream, $"API diff: {title}");
state.Formatter.BeginAssembly (outStream);
outStream.Write (diffHtml);
state.Formatter.EndAssembly (outStream);
state.Formatter.EndDocument (outStream);
}
}
static State CreateState (ApiDiffFormattedConfig config)
{
if (config == null)
config = new ApiDiffFormattedConfig ();
var state = new State {
Colorize = config.Colorize,
Formatter = null,
IgnoreAddedPropertySetters = config.IgnoreAddedPropertySetters,
IgnoreVirtualChanges = config.IgnoreVirtualChanges,
IgnoreNonbreaking = config.IgnoreNonbreaking,
IgnoreParameterNameChanges = config.IgnoreParameterNameChanges,
Lax = config.IgnoreDuplicateXml,
Verbosity = config.Verbosity
};
state.IgnoreAdded.AddRange (config.IgnoreAdded);
state.IgnoreNew.AddRange (config.IgnoreNew);
state.IgnoreRemoved.AddRange (config.IgnoreRemoved);
switch (config.Formatter)
{
case ApiDiffFormatter.Html:
state.Formatter = new HtmlFormatter(state);
break;
case ApiDiffFormatter.Markdown:
state.Formatter = new MarkdownFormatter(state);
break;
default:
throw new ArgumentException("Invlid formatter specified.");
}
// unless specified default to HTML
if (state.Formatter == null)
state.Formatter = new HtmlFormatter (state);
if (state.IgnoreNonbreaking) {
state.IgnoreAddedPropertySetters = true;
state.IgnoreVirtualChanges = true;
state.IgnoreNew.Add (new Regex (".*"));
state.IgnoreAdded.Add (new Regex (".*"));
}
return state;
}
}
}

View File

@@ -26,21 +26,33 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public class AssemblyComparer : Comparer {
class AssemblyComparer : Comparer {
XDocument source;
XDocument target;
NamespaceComparer comparer;
public AssemblyComparer (string sourceFile, string targetFile)
public AssemblyComparer (string sourceFile, string targetFile, State state)
: this (XDocument.Load(sourceFile), XDocument.Load(targetFile), state)
{
source = XDocument.Load (sourceFile);
target = XDocument.Load (targetFile);
comparer = new NamespaceComparer ();
}
public AssemblyComparer (Stream sourceFile, Stream targetFile, State state)
: this (XDocument.Load(sourceFile), XDocument.Load(targetFile), state)
{
}
public AssemblyComparer (XDocument sourceFile, XDocument targetFile, State state)
: base (state)
{
source = sourceFile;
target = targetFile;
comparer = new NamespaceComparer (state);
}
public string SourceAssembly { get; private set; }

View File

@@ -30,9 +30,9 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public class ClassComparer : Comparer {
class ClassComparer : Comparer {
InterfaceComparer icomparer;
ConstructorComparer ccomparer;
@@ -42,14 +42,15 @@ namespace Xamarin.ApiDiff {
MethodComparer mcomparer;
ClassComparer kcomparer;
public ClassComparer ()
public ClassComparer (State state)
: base (state)
{
icomparer = new InterfaceComparer ();
ccomparer = new ConstructorComparer ();
fcomparer = new FieldComparer ();
pcomparer = new PropertyComparer ();
ecomparer = new EventComparer ();
mcomparer = new MethodComparer ();
icomparer = new InterfaceComparer (state);
ccomparer = new ConstructorComparer (state);
fcomparer = new FieldComparer (state);
pcomparer = new PropertyComparer (state);
ecomparer = new EventComparer (state);
mcomparer = new MethodComparer (state);
}
public override void SetContext (XElement current)
@@ -190,7 +191,7 @@ namespace Xamarin.ApiDiff {
Output.WriteLine ();
Indent ().WriteLine ("// inner types");
State.Parent = State.Type;
kcomparer = new NestedClassComparer ();
kcomparer = new NestedClassComparer (State);
foreach (var inner in t.Elements ("class"))
kcomparer.AddedInner (inner);
State.Type = State.Parent;
@@ -227,7 +228,7 @@ namespace Xamarin.ApiDiff {
!State.IgnoreRemoved.Any (re => re.IsMatch (rm)) &&
!(State.IgnoreNonbreaking && IsBaseChangeCompatible (sb, tb))) {
Formatter.BeginMemberModification (Output, "Modified base type");
var apichange = new ApiChange ($"{State.Namespace}.{State.Type}").AppendModified (sb, tb, true);
var apichange = new ApiChange ($"{State.Namespace}.{State.Type}", State).AppendModified (sb, tb, true);
Formatter.Diff (Output, apichange);
Formatter.EndMemberModification (Output);
}
@@ -242,7 +243,7 @@ namespace Xamarin.ApiDiff {
var si = source.Element ("classes");
if (si != null) {
var ti = target.Element ("classes");
kcomparer = new NestedClassComparer ();
kcomparer = new NestedClassComparer (State);
State.Parent = State.Type;
kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
State.Type = State.Parent;
@@ -280,7 +281,12 @@ namespace Xamarin.ApiDiff {
}
}
public class NestedClassComparer : ClassComparer {
class NestedClassComparer : ClassComparer {
public NestedClassComparer (State state)
: base (state)
{
}
public override void SetContext (XElement current)
{

View File

@@ -30,19 +30,28 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public abstract class Comparer {
abstract class Comparer {
protected List<XElement> removed = new List<XElement> ();
protected ApiChanges modified = new ApiChanges ();
protected List<XElement> removed;
protected ApiChanges modified;
public Comparer (State state)
{
State = state;
removed = new List<XElement> ();
modified = new ApiChanges (state);
}
public State State { get; }
public TextWriter Output {
get { return State.Output; }
}
public Formatter Formatter {
get { return Formatter.Current; }
get { return State.Formatter; }
}
protected TextWriter Indent ()

View File

@@ -30,10 +30,15 @@ using System.Reflection;
using System.Text;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
// MethodComparer inherits from this one
public class ConstructorComparer : MemberComparer {
class ConstructorComparer : MemberComparer {
public ConstructorComparer (State state)
: base (state)
{
}
public override string GroupName {
get { return "constructors"; }
@@ -50,8 +55,8 @@ namespace Xamarin.ApiDiff {
void RenderReturnType (XElement source, XElement target, ApiChange change)
{
var srcType = source.GetTypeName ("returntype");
var tgtType = target.GetTypeName ("returntype");
var srcType = source.GetTypeName ("returntype", State);
var tgtType = target.GetTypeName ("returntype", State);
if (srcType != tgtType) {
change.AppendModified (srcType, tgtType, true);
@@ -68,7 +73,7 @@ namespace Xamarin.ApiDiff {
if (base.Equals (source, target, changes))
return true;
var change = new ApiChange (GetDescription (source));
var change = new ApiChange (GetDescription (source), State);
change.Header = "Modified " + GroupName;
RenderMethodAttributes (source, target, change);
RenderReturnType (source, target, change);
@@ -106,7 +111,7 @@ namespace Xamarin.ApiDiff {
string name = e.GetAttribute ("name");
var r = e.GetTypeName ("returntype");
var r = e.GetTypeName ("returntype", State);
if (r != null) {
// ctor dont' have a return type
sb.Append (r).Append (' ');
@@ -123,7 +128,7 @@ namespace Xamarin.ApiDiff {
if (genericp != null) {
var list = new List<string> ();
foreach (var p in genericp.Elements ("generic-parameter")) {
list.Add (p.GetTypeName ("name"));
list.Add (p.GetTypeName ("name", State));
}
sb.Append (Formatter.LesserThan).Append (String.Join (", ", list)).Append (Formatter.GreaterThan);
}
@@ -133,7 +138,7 @@ namespace Xamarin.ApiDiff {
if (parameters != null) {
var list = new List<string> ();
foreach (var p in parameters.Elements ("parameter")) {
var param = p.GetTypeName ("type");
var param = p.GetTypeName ("type", State);
if (!State.IgnoreParameterNameChanges)
param += " " + p.GetAttribute ("name");

View File

@@ -28,9 +28,14 @@ using System;
using System.Text;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public class EventComparer : MemberComparer {
class EventComparer : MemberComparer {
public EventComparer (State state)
: base (state)
{
}
public override string GroupName {
get { return "events"; }
@@ -45,12 +50,12 @@ namespace Xamarin.ApiDiff {
if (base.Equals (source, target, changes))
return true;
var change = new ApiChange (GetDescription (source));
var change = new ApiChange (GetDescription (source), State);
change.Header = "Modified " + GroupName;
change.Append ("public event ");
var srcEventType = source.GetTypeName ("eventtype");
var tgtEventType = target.GetTypeName ("eventtype");
var srcEventType = source.GetTypeName ("eventtype", State);
var tgtEventType = target.GetTypeName ("eventtype", State);
if (srcEventType != tgtEventType) {
change.AppendModified (srcEventType, tgtEventType, true);
@@ -67,7 +72,7 @@ namespace Xamarin.ApiDiff {
StringBuilder sb = new StringBuilder ();
// TODO: attribs
sb.Append ("public event ");
sb.Append (e.GetTypeName ("eventtype")).Append (' ');
sb.Append (e.GetTypeName ("eventtype", State)).Append (' ');
sb.Append (e.GetAttribute ("name")).Append (';');
return sb.ToString ();
}

View File

@@ -31,9 +31,14 @@ using System.Reflection;
using System.Text;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public class FieldComparer : MemberComparer {
class FieldComparer : MemberComparer {
public FieldComparer (State state)
: base (state)
{
}
public override string GroupName {
get { return "fields"; }
@@ -109,7 +114,7 @@ namespace Xamarin.ApiDiff {
var name = source.GetAttribute ("name");
var srcValue = source.GetAttribute ("value");
var tgtValue = target.GetAttribute ("value");
var change = new ApiChange (GetDescription (source));
var change = new ApiChange (GetDescription (source), State);
change.Header = "Modified " + GroupName;
if (State.BaseType == "System.Enum") {
@@ -122,8 +127,8 @@ namespace Xamarin.ApiDiff {
} else {
RenderFieldAttributes (source.GetFieldAttributes (), target.GetFieldAttributes (), change);
var srcType = source.GetTypeName ("fieldtype");
var tgtType = target.GetTypeName ("fieldtype");
var srcType = source.GetTypeName ("fieldtype", State);
var tgtType = target.GetTypeName ("fieldtype", State);
if (srcType != tgtType) {
change.AppendModified (srcType, tgtType, true);
@@ -184,7 +189,7 @@ namespace Xamarin.ApiDiff {
sb.Append ("const ");
}
string ftype = e.GetTypeName ("fieldtype");
string ftype = e.GetTypeName ("fieldtype", State);
sb.Append (ftype).Append (' ');
sb.Append (name);
if (ftype == "string" && e.Attribute ("value") != null) {

View File

@@ -30,11 +30,16 @@ using System.Collections.Generic;
using System.Xml.Linq;
using System.Text;
namespace Xamarin.ApiDiff {
namespace Mono.ApiTools {
public abstract class Formatter {
abstract class Formatter {
public static Formatter Current { get; set; }
public Formatter(State state)
{
State = state;
}
public State State { get; }
public abstract string LesserThan { get; }
public abstract string GreaterThan { get; }

Some files were not shown because too many files have changed in this diff Show More