diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..8e7d7a9
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,183 @@
+###############################
+# Core EditorConfig Options #
+###############################
+
+root = true
+
+# All files
+[*]
+indent_style = space
+charset = utf-8
+# Unix-style newlines with a newline ending every file
+end_of_line = lf
+insert_final_newline = true
+
+# Protobuf, XML, YAML and project files
+[*.{proto,xml,yaml,yml,csproj}]
+indent_size = 2
+insert_final_newline = true
+
+# Code files
+[*.{cs,csx}]
+indent_size = 4
+insert_final_newline = true
+
+###############################
+# .NET Coding Conventions #
+###############################
+
+[*.{cs}]
+# Organize usings
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# this. preferences
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_readonly_field = true:suggestion
+
+# Expression-level preferences
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+
+###############################
+# Naming Conventions #
+###############################
+
+# Style Definitions
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# Use PascalCase for constant fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+
+###############################
+# C# Code Style Rules #
+###############################
+
+[*.cs]
+# var preferences
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+csharp_style_var_elsewhere = false:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+
+# Pattern-matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+
+# Null-checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+
+# Expression-level preferences
+csharp_prefer_braces = true:silent
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+###############################
+# C# Formatting Rules #
+###############################
+
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+
+# Wrapping preferences
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
+
+# CA1305: Specify IFormatProvider
+dotnet_diagnostic.CA1305.severity = none
+
+# CA1307: Specify StringComparison
+dotnet_diagnostic.CA1307.severity = none
+
+# CA1308: Normalize strings to uppercase
+dotnet_diagnostic.CA1308.severity = none
+
+# CA1304: Specify CultureInfo
+dotnet_diagnostic.CA1304.severity = none
+
+dotnet_diagnostic.CA1802.severity = none
+dotnet_diagnostic.CA1303.severity = none
+dotnet_diagnostic.SA1005.severity = none
+dotnet_diagnostic.SA1101.severity = none
+dotnet_diagnostic.SA1108.severity = none
+dotnet_diagnostic.SA1124.severity = none
+dotnet_diagnostic.SA1128.severity = none
+dotnet_diagnostic.SA1200.severity = none
+dotnet_diagnostic.SA1201.severity = none
+dotnet_diagnostic.SA1202.severity = none
+dotnet_diagnostic.SA1204.severity = none
+dotnet_diagnostic.SA1214.severity = none
+dotnet_diagnostic.SA1309.severity = none
+dotnet_diagnostic.SA1413.severity = none
+dotnet_diagnostic.SA1502.severity = none
+dotnet_diagnostic.SA1512.severity = none
+dotnet_diagnostic.SA1633.severity = none
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..eac873f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+ - package-ecosystem: nuget
+ directory: /
+ open-pull-requests-limit: 10
+ schedule:
+ interval: monthly
diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml
new file mode 100644
index 0000000..6087802
--- /dev/null
+++ b/.github/workflows/build-test.yaml
@@ -0,0 +1,32 @@
+name: Build.NET
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 7.0.x
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --nologo --no-restore
+
+ - name: Test
+ run: dotnet test --nologo --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings
diff --git a/.gitignore b/.gitignore
index eb080c3..3c18b7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,16 @@ TestResults/
*.sln.ide/
*.user
*.suo
+.vs/
+MigrationBackup/
+*.dll
+*.zip
+
+# IDEs
+.vscode
+.idea
+*.iml
+
+# MacOS
+.DS_Store
+packed/
diff --git a/CompatibilityCheckExample/App.config b/CompatibilityCheckExample/App.config
deleted file mode 100644
index 8e15646..0000000
--- a/CompatibilityCheckExample/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CompatibilityCheckExample/CompatibilityCheckExample.csproj b/CompatibilityCheckExample/CompatibilityCheckExample.csproj
deleted file mode 100644
index 8558995..0000000
--- a/CompatibilityCheckExample/CompatibilityCheckExample.csproj
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {69E70F61-27CA-46A2-8017-A2F66B1D4AAA}
- Exe
- Properties
- CompatibilityCheckExample
- CompatibilityCheckExample
- v4.5
- 512
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll
-
-
- False
- ..\packages\NuGet.Core.2.8.3\lib\net40-Client\NuGet.Core.dll
-
-
-
- False
- ..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
-
-
-
- ..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {c3d7fce7-0fed-462f-a4a6-bafc6aa91ef2}
- CompatibilityChecker
-
-
-
-
-
\ No newline at end of file
diff --git a/CompatibilityCheckExample/Program.cs b/CompatibilityCheckExample/Program.cs
deleted file mode 100644
index 4826f40..0000000
--- a/CompatibilityCheckExample/Program.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-namespace CompatibilityCheckExample
-{
- using System;
- using System.Reflection.PortableExecutable;
- using CompatibilityChecker;
- using NuGet;
- using Directory = System.IO.Directory;
- using File = System.IO.File;
- using Path = System.IO.Path;
-
- internal class Program
- {
- private static void Main(string[] args)
- {
- bool removeDirectory;
- string temporaryDirectory = GetTemporaryDirectory(out removeDirectory);
- Console.WriteLine("Working directory: {0}", temporaryDirectory);
-
- try
- {
- IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository("https://www.nuget.org/api/v2/");
- PackageManager packageManager = new PackageManager(sourceRepository, temporaryDirectory);
- packageManager.PackageInstalled += HandlePackageInstalled;
- packageManager.InstallPackage("Microsoft.Bcl.Immutable", SemanticVersion.Parse("1.0.34"));
- packageManager.InstallPackage("System.Collections.Immutable", SemanticVersion.Parse("1.1.33-beta"));
-
- using (PEReader referenceAssembly = new PEReader(File.OpenRead(Path.Combine(temporaryDirectory, "Microsoft.Bcl.Immutable.1.0.34", "lib", "portable-net45+win8+wp8+wpa81", "System.Collections.Immutable.dll"))))
- {
- using (PEReader newAssembly = new PEReader(File.OpenRead(Path.Combine(temporaryDirectory, "System.Collections.Immutable.1.1.33-beta", "lib", "portable-net45+win8+wp8+wpa81", "System.Collections.Immutable.dll"))))
- {
- Analyzer analyzer = new Analyzer(referenceAssembly, newAssembly, null);
- analyzer.Run();
- }
- }
- }
- finally
- {
- if (removeDirectory)
- Directory.Delete(temporaryDirectory, true);
- }
- }
-
- private static void HandlePackageInstalled(object sender, PackageOperationEventArgs e)
- {
- Console.WriteLine("Installed package: {0}", e.Package.GetFullName());
- }
-
- private static string GetTemporaryDirectory(out bool removeDirectory)
- {
- string packagesPath = Path.GetFullPath(@"..\..\..");
- if (Directory.Exists(Path.Combine(packagesPath, "packages")))
- {
- removeDirectory = false;
- return Path.Combine(packagesPath, "packages");
- }
-
- string path = Path.Combine(Path.GetTempPath(), "CompatibilityChecker-" + Path.GetRandomFileName());
- Directory.CreateDirectory(path);
- removeDirectory = true;
- return path;
- }
- }
-}
diff --git a/CompatibilityCheckExample/Properties/AssemblyInfo.cs b/CompatibilityCheckExample/Properties/AssemblyInfo.cs
deleted file mode 100644
index d4b2dba..0000000
--- a/CompatibilityCheckExample/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("CompatibilityCheckExample")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft")]
-[assembly: AssemblyProduct("CompatibilityCheckExample")]
-[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("69e70f61-27ca-46a2-8017-a2f66b1d4aaa")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/CompatibilityCheckExample/packages.config b/CompatibilityCheckExample/packages.config
deleted file mode 100644
index f22dc22..0000000
--- a/CompatibilityCheckExample/packages.config
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CompatibilityChecker/Analyzer.cs b/CompatibilityChecker.Library/Analyzer.cs
similarity index 50%
rename from CompatibilityChecker/Analyzer.cs
rename to CompatibilityChecker.Library/Analyzer.cs
index 3134a08..458f64a 100644
--- a/CompatibilityChecker/Analyzer.cs
+++ b/CompatibilityChecker.Library/Analyzer.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System;
using System.Collections.Generic;
@@ -7,36 +7,44 @@
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
- using CompatibilityChecker.Descriptors;
+ using CompatibilityChecker.Library.Descriptors;
public class Analyzer
{
- private readonly PEReader _referenceAssembly;
- private readonly PEReader _newAssembly;
- private readonly IMessageLogger _logger;
+ private readonly PEReader referenceAssembly;
+ private readonly PEReader newAssembly;
+ private readonly IMessageReporter reporter;
- private MetadataReader _referenceMetadata;
- private MetadataReader _newMetadata;
+ private MetadataReader referenceMetadata;
+ private MetadataReader newMetadata;
private MetadataMapping _referenceToNewMapping;
- private MetadataMapping _newToReferenceMapping;
+ private MetadataMapping newToReferenceMapping;
- public Analyzer(PEReader referenceAssembly, PEReader newAssembly, IMessageLogger logger)
+ private bool _hasRun = false;
+
+ public bool HasRun => _hasRun;
+
+ public IEnumerable Results => reporter.ReportedMessages;
+
+ public IReportStatistics ResultStatistics => reporter.Statistics;
+
+ public Analyzer(PEReader referenceAssembly, PEReader newAssembly, IMessageReporter reporter, IMessageLogger logger)
{
- _referenceAssembly = referenceAssembly;
- _newAssembly = newAssembly;
- _logger = logger ?? new ConsoleMessageLogger();
+ this.referenceAssembly = referenceAssembly;
+ this.newAssembly = newAssembly;
+ this.reporter = reporter ?? new BasicListingReporter(logger ?? new ConsoleMessageLogger());
}
public void Run()
{
- _referenceMetadata = _referenceAssembly.GetMetadataReader();
- _newMetadata = _newAssembly.GetMetadataReader();
- var referenceMetadata = _referenceMetadata;
- var newMetadata = _newMetadata;
+ this.referenceMetadata = referenceAssembly.GetMetadataReader();
+ this.newMetadata = newAssembly.GetMetadataReader();
+ var referenceMetadata = this.referenceMetadata;
+ var newMetadata = this.newMetadata;
_referenceToNewMapping = new MetadataMapping(referenceMetadata, newMetadata);
- _newToReferenceMapping = new MetadataMapping(newMetadata, referenceMetadata);
+ newToReferenceMapping = new MetadataMapping(newMetadata, referenceMetadata);
CheckAssemblyProperties(referenceMetadata, newMetadata);
@@ -45,17 +53,21 @@ public void Run()
TypeDefinition typeDefinition = referenceMetadata.GetTypeDefinition(typeDefinitionHandle);
if (!IsPubliclyVisible(referenceMetadata, typeDefinition))
+ {
continue;
+ }
if (IsMarkedPreliminary(referenceMetadata, typeDefinition))
+ {
continue;
+ }
Mapping typeMapping = _referenceToNewMapping.MapTypeDefinition(typeDefinitionHandle);
// make sure the type still exists
if (typeMapping.Target.IsNil)
{
- _logger.Report(TypeMustNotBeRemoved.CreateMessage());
+ reporter.Report(TypeMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition)));
continue;
}
@@ -65,7 +77,7 @@ public void Run()
if ((newTypeDefinition.Attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed
&& HasVisibleConstructors(newMetadata, newTypeDefinition))
{
- _logger.Report(SealedMustNotBeAddedToType.CreateMessage());
+ reporter.Report(SealedMustNotBeAddedToType.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition)));
}
}
@@ -74,16 +86,20 @@ public void Run()
if ((newTypeDefinition.Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract
&& HasVisibleConstructors(newMetadata, newTypeDefinition))
{
- _logger.Report(AbstractMustNotBeAddedToType.CreateMessage());
+ reporter.Report(AbstractMustNotBeAddedToType.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition)));
}
}
TypeAttributes uncheckedAttributesMask = ~(TypeAttributes.Sealed | TypeAttributes.Abstract);
if ((typeDefinition.Attributes & uncheckedAttributesMask) != (newTypeDefinition.Attributes & uncheckedAttributesMask))
- throw new NotImplementedException("Attributes of publicly visible type changed.");
+ {
+ reporter.Report(PublicAttributesMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition)));
+ }
if (IsMarkedPreliminary(newMetadata, newTypeDefinition))
- throw new NotImplementedException("Publicly visible type changed from stable to preliminary.");
+ {
+ reporter.Report(TypeMustNotBeMadePreliminaryFromStable.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition)));
+ }
// check base type
Handle baseTypeHandle = typeDefinition.BaseType;
@@ -91,31 +107,35 @@ public void Run()
{
Handle newBaseTypeHandle = newTypeDefinition.BaseType;
if (newBaseTypeHandle.IsNil)
- throw new NotImplementedException("Base type changed.");
+ {
+ reporter.Report(BaseTypeMustNotChange.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition))); // throw new NotImplementedException("Base type changed.");
+ }
if (baseTypeHandle.Kind != newBaseTypeHandle.Kind)
- throw new NotImplementedException("Base type changed.");
+ {
+ reporter.Report(BaseTypeMustNotChange.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition))); // throw new NotImplementedException("Base type changed.");
+ }
switch (baseTypeHandle.Kind)
{
- case HandleKind.TypeDefinition:
- CheckBaseType(referenceMetadata, newMetadata, (TypeDefinitionHandle)baseTypeHandle, (TypeDefinitionHandle)newBaseTypeHandle);
- break;
+ case HandleKind.TypeDefinition:
+ CheckBaseType(referenceMetadata, newMetadata, (TypeDefinitionHandle)baseTypeHandle, (TypeDefinitionHandle)newBaseTypeHandle);
+ break;
- case HandleKind.TypeReference:
- TypeReference referenceBaseTypeReference = referenceMetadata.GetTypeReference((TypeReferenceHandle)baseTypeHandle);
- TypeReference newBaseTypeReference = newMetadata.GetTypeReference((TypeReferenceHandle)newBaseTypeHandle);
- CheckBaseType(referenceMetadata, newMetadata, referenceBaseTypeReference, newBaseTypeReference);
- break;
+ case HandleKind.TypeReference:
+ TypeReference referenceBaseTypeReference = referenceMetadata.GetTypeReference((TypeReferenceHandle)baseTypeHandle);
+ TypeReference newBaseTypeReference = newMetadata.GetTypeReference((TypeReferenceHandle)newBaseTypeHandle);
+ CheckBaseType(referenceMetadata, newMetadata, referenceBaseTypeReference, newBaseTypeReference);
+ break;
- case HandleKind.TypeSpecification:
- TypeSpecification referenceBaseTypeSpecification = referenceMetadata.GetTypeSpecification((TypeSpecificationHandle)baseTypeHandle);
- TypeSpecification newBaseTypeSpecification = newMetadata.GetTypeSpecification((TypeSpecificationHandle)newBaseTypeHandle);
- CheckBaseType(referenceMetadata, newMetadata, referenceBaseTypeSpecification, newBaseTypeSpecification);
- break;
+ case HandleKind.TypeSpecification:
+ TypeSpecification referenceBaseTypeSpecification = referenceMetadata.GetTypeSpecification((TypeSpecificationHandle)baseTypeHandle);
+ TypeSpecification newBaseTypeSpecification = newMetadata.GetTypeSpecification((TypeSpecificationHandle)newBaseTypeHandle);
+ CheckBaseType(referenceMetadata, newMetadata, referenceBaseTypeSpecification, newBaseTypeSpecification);
+ break;
- default:
- throw new InvalidOperationException("Unrecognized base type handle kind.");
+ default:
+ throw new InvalidOperationException("Unrecognized base type handle kind.");
}
}
@@ -126,7 +146,9 @@ public void Run()
{
TypeDefinition interfaceImplementationTypeDefinition = referenceMetadata.GetTypeDefinition((TypeDefinitionHandle)interfaceImplementation.Interface);
if (!IsPubliclyVisible(referenceMetadata, interfaceImplementationTypeDefinition))
+ {
continue;
+ }
}
bool foundMatchingInterface = false;
@@ -134,11 +156,15 @@ public void Run()
{
foundMatchingInterface = IsSameType(referenceMetadata, newMetadata, interfaceImplementation.Interface, newInterfaceImplementation.Interface);
if (foundMatchingInterface)
+ {
break;
+ }
}
if (!foundMatchingInterface)
- throw new NotImplementedException("Implemented interface was removed from a type.");
+ {
+ reporter.Report(ImplementedInterfaceMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition), GetMetadataName(referenceMetadata, interfaceImplementation))); // throw new NotImplementedException("Implemented interface was removed from a type.");
+ }
}
// check fields
@@ -146,38 +172,53 @@ public void Run()
{
var fieldDefinition = referenceMetadata.GetFieldDefinition(fieldDefinitionHandle);
if (!IsPubliclyVisible(referenceMetadata, fieldDefinition))
+ {
continue;
+ }
Mapping fieldMapping = _referenceToNewMapping.MapFieldDefinition(fieldDefinitionHandle);
if (fieldMapping.Target.IsNil)
{
if (fieldMapping.CandidateTargets.IsDefaultOrEmpty)
- throw new NotImplementedException(string.Format("Publicly-visible field '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, fieldDefinition)));
+ {
+ reporter.Report(FieldMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, fieldDefinition))); //throw new NotImplementedException(string.Format("Publicly-visible field '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, fieldDefinition)));
+ }
- throw new NotImplementedException();
+ //throw new NotImplementedException();
+ continue; // TODO test
}
FieldDefinition newFieldDefinition = newMetadata.GetFieldDefinition(fieldMapping.Target);
if (fieldDefinition.Attributes != newFieldDefinition.Attributes)
- throw new NotImplementedException("Attributes of publicly-visible field changed.");
+ {
+ reporter.Report(FieldAttributesMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, fieldDefinition))); // throw new NotImplementedException("Attributes of publicly-visible field changed.");
+ }
if (!IsSameFieldSignature(referenceMetadata, newMetadata, referenceMetadata.GetSignature(fieldDefinition), newMetadata.GetSignature(newFieldDefinition)))
- throw new NotImplementedException("Signature of publicly-accessible field changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of publicly-accessible field '{0}' changed.", GetMetadataName(referenceMetadata, fieldDefinition)))); // throw new NotImplementedException("Signature of publicly-accessible field changed.");
+ }
if (!fieldDefinition.GetDefaultValue().IsNil)
{
if (newFieldDefinition.GetDefaultValue().IsNil)
- throw new NotImplementedException("Constant value of a field was removed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Constant value of field '{0}' was removed.", GetMetadataName(referenceMetadata, fieldDefinition)))); // throw new NotImplementedException("Constant value of a field was removed.");
+ }
Constant constant = referenceMetadata.GetConstant(fieldDefinition.GetDefaultValue());
Constant newConstant = newMetadata.GetConstant(newFieldDefinition.GetDefaultValue());
if (constant.TypeCode != newConstant.TypeCode)
- throw new NotImplementedException("Constant value of a field changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Constant value's type of field '{0}' changed from '{1}' to '{2}'.", GetMetadataName(referenceMetadata, fieldDefinition), constant.TypeCode, newConstant.TypeCode))); // throw new NotImplementedException("Constant value of a field changed.");
+ }
var referenceValue = referenceMetadata.GetBlobContent(constant.Value);
var newValue = referenceMetadata.GetBlobContent(constant.Value);
if (!referenceValue.SequenceEqual(newValue))
- throw new NotImplementedException("Constant value of a field changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Constant value of field '{0}'.", GetMetadataName(referenceMetadata, fieldDefinition)))); // throw new NotImplementedException("Constant value of a field changed.");
+ }
}
}
@@ -185,30 +226,41 @@ public void Run()
foreach (var methodDefinition in typeDefinition.GetMethods().Select(referenceMetadata.GetMethodDefinition))
{
if (!IsPubliclyVisible(referenceMetadata, methodDefinition))
+ {
continue;
+ }
string referenceName = referenceMetadata.GetString(methodDefinition.Name);
- List newMethodDefinitions = new List();
+ List newMethodDefinitions = new ();
foreach (var newMethodDefinition in newTypeDefinition.GetMethods().Select(newMetadata.GetMethodDefinition))
{
string newName = newMetadata.GetString(newMethodDefinition.Name);
if (!string.Equals(referenceName, newName, StringComparison.Ordinal))
+ {
continue;
+ }
// filter on number of generic parameters
if (methodDefinition.GetGenericParameters().Count != newMethodDefinition.GetGenericParameters().Count)
+ {
continue;
+ }
// filter on number of parameters
if (methodDefinition.GetParameters().Count != newMethodDefinition.GetParameters().Count)
+ {
continue;
+ }
newMethodDefinitions.Add(newMethodDefinition);
}
if (newMethodDefinitions.Count == 0)
- throw new NotImplementedException(string.Format("Publicly-visible method '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, methodDefinition)));
+ {
+ reporter.Report(MethodMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, methodDefinition))); //throw new NotImplementedException(string.Format("Publicly-visible method '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, methodDefinition)));
+ continue;
+ }
bool foundMethodDefinition = false;
foreach (var newMethodDefinition in newMethodDefinitions)
@@ -216,24 +268,71 @@ public void Run()
MethodSignature referenceSignatureReader = referenceMetadata.GetSignature(methodDefinition);
MethodSignature newSignatureReader = newMetadata.GetSignature(newMethodDefinition);
if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceSignatureReader, newSignatureReader))
+ {
continue;
+ }
if (methodDefinition.Attributes != newMethodDefinition.Attributes)
- throw new NotImplementedException("Attributes of publicly-visible method changed.");
+ {
+ reporter.Report(MethodAttributesMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, methodDefinition))); // throw new NotImplementedException("Attributes of publicly-visible method changed.");
+ }
foundMethodDefinition = true;
break;
}
if (!foundMethodDefinition)
- throw new NotImplementedException(string.Format("Publicly-visible method '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, methodDefinition)));
+ {
+ reporter.Report(MethodMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, methodDefinition))); //throw new NotImplementedException(string.Format("Publicly-visible method '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, methodDefinition)));
+ }
}
// If the type is an interface, additionally make sure the number of methods did not change.
if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
{
- if (typeDefinition.GetMethods().Count != newTypeDefinition.GetMethods().Count)
- throw new NotImplementedException("Method was added to an interface.");
+ if (typeDefinition.GetMethods().Count < newTypeDefinition.GetMethods().Count)
+ {
+ List addedMethods = new ();
+ foreach (var newMethodDefinition in newTypeDefinition.GetMethods().Select(newMetadata.GetMethodDefinition))
+ {
+ string newName = newMetadata.GetString(newMethodDefinition.Name);
+
+ List methodDefinitions = new ();
+ foreach (var methodDefinition in typeDefinition.GetMethods().Select(referenceMetadata.GetMethodDefinition))
+ {
+ string referenceName = referenceMetadata.GetString(methodDefinition.Name);
+ if (!string.Equals(newName, referenceName, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ // filter on number of generic parameters
+ if (methodDefinition.GetGenericParameters().Count != newMethodDefinition.GetGenericParameters().Count)
+ {
+ continue;
+ }
+
+ // filter on number of parameters
+ if (methodDefinition.GetParameters().Count != newMethodDefinition.GetParameters().Count)
+ {
+ continue;
+ }
+
+ methodDefinitions.Add(methodDefinition);
+ }
+
+ if (methodDefinitions.Count == 0)
+ {
+ addedMethods.Add(newMethodDefinition);
+ continue;
+ }
+ }
+
+ foreach (var addedMethod in addedMethods)
+ {
+ reporter.Report(MethodMustNotBeAddedToInterface.CreateMessage(GetMetadataName(referenceMetadata, typeDefinition), GetMetadataName(newMetadata, addedMethod))); // throw new NotImplementedException("Method was added to an interface.");
+ }
+ }
}
// check events
@@ -241,18 +340,27 @@ public void Run()
{
var eventDefinition = referenceMetadata.GetEventDefinition(eventDefinitionHandle);
if (!IsPubliclyVisible(referenceMetadata, eventDefinition))
+ {
continue;
+ }
Mapping eventDefinitionMapping = _referenceToNewMapping.MapEventDefinition(eventDefinitionHandle);
if (eventDefinitionMapping.Target.IsNil)
- throw new NotImplementedException(string.Format("Publicly-visible event '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, eventDefinition, typeDefinition)));
+ {
+ reporter.Report(EventMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); //throw new NotImplementedException(string.Format("Publicly-visible event '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, eventDefinition, typeDefinition)));
+ continue; // TODO test
+ }
EventDefinition newEventDefinition = newMetadata.GetEventDefinition(eventDefinitionMapping.Target);
if (eventDefinition.Attributes != newEventDefinition.Attributes)
- throw new NotImplementedException("Attributes of publicly-visible event changed.");
+ {
+ reporter.Report(EventAttributesMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); // throw new NotImplementedException("Attributes of publicly-visible event changed.");
+ }
if (!IsSameType(referenceMetadata, newMetadata, eventDefinition.Type, newEventDefinition.Type))
- throw new NotImplementedException("Signature of publicly-visible event changed.");
+ {
+ reporter.Report(EventSignatureMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); // throw new NotImplementedException("Signature of publicly-visible event changed.");
+ }
EventAccessors eventAccessors = eventDefinition.GetAccessors();
@@ -263,19 +371,25 @@ public void Run()
{
EventAccessors newEventAccessors = newEventDefinition.GetAccessors();
if (newEventAccessors.Adder.IsNil)
- throw new NotImplementedException("Event adder was removed.");
+ {
+ reporter.Report(EventAdderMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); // throw new NotImplementedException("Event adder was removed.");
+ }
MethodDefinition newAdderMethodDefinition = newMetadata.GetMethodDefinition(newEventAccessors.Adder);
string referenceAdderName = referenceMetadata.GetString(referenceAdderMethodDefinition.Name);
string newAdderName = newMetadata.GetString(newAdderMethodDefinition.Name);
if (!string.Equals(referenceAdderName, newAdderName, StringComparison.Ordinal))
- throw new NotImplementedException("Signature of event adder changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Name of event adder '{0}' changed.", referenceAdderName))); // throw new NotImplementedException("Signature of event adder changed.");
+ }
MethodSignature referenceSignatureReader = referenceMetadata.GetSignature(referenceAdderMethodDefinition);
MethodSignature newSignatureReader = newMetadata.GetSignature(newAdderMethodDefinition);
if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceSignatureReader, newSignatureReader))
- throw new NotImplementedException("Signature of event adder changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of event adder '{0}' changed.", referenceAdderName))); // throw new NotImplementedException("Signature of event adder changed.");
+ }
}
}
@@ -286,19 +400,25 @@ public void Run()
{
EventAccessors newEventAccessors = newEventDefinition.GetAccessors();
if (newEventAccessors.Remover.IsNil)
- throw new NotImplementedException("Event remover was removed.");
+ {
+ reporter.Report(EventRemoverMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); // throw new NotImplementedException("Event remover was removed.");
+ }
MethodDefinition newRemoverMethodDefinition = newMetadata.GetMethodDefinition(newEventAccessors.Remover);
string referenceRemoverName = referenceMetadata.GetString(referenceRemoverMethodDefinition.Name);
string newRemoverName = newMetadata.GetString(newRemoverMethodDefinition.Name);
if (!string.Equals(referenceRemoverName, newRemoverName, StringComparison.Ordinal))
- throw new NotImplementedException("Signature of event remover changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Name of event remover '{0}' changed.", referenceRemoverName))); // throw new NotImplementedException("Signature of event remover changed.");
+ }
MethodSignature referenceSignatureReader = referenceMetadata.GetSignature(referenceRemoverMethodDefinition);
MethodSignature newSignatureReader = newMetadata.GetSignature(newRemoverMethodDefinition);
if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceSignatureReader, newSignatureReader))
- throw new NotImplementedException("Signature of event remover changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of event remover '{0}' changed.", referenceRemoverName))); // throw new NotImplementedException("Signature of event remover changed.");
+ }
}
}
@@ -309,19 +429,27 @@ public void Run()
{
EventAccessors newEventAccessors = newEventDefinition.GetAccessors();
if (newEventAccessors.Raiser.IsNil)
- throw new NotImplementedException("Event raiser was removed.");
-
- MethodDefinition newRaiserMethodDefinition = newMetadata.GetMethodDefinition(newEventAccessors.Raiser);
-
- string referenceRaiserName = referenceMetadata.GetString(referenceRaiserMethodDefinition.Name);
- string newRaiserName = newMetadata.GetString(newRaiserMethodDefinition.Name);
- if (!string.Equals(referenceRaiserName, newRaiserName, StringComparison.Ordinal))
- throw new NotImplementedException("Signature of event raiser changed.");
-
- MethodSignature referenceSignatureReader = referenceMetadata.GetSignature(referenceRaiserMethodDefinition);
- MethodSignature newSignatureReader = newMetadata.GetSignature(newRaiserMethodDefinition);
- if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceSignatureReader, newSignatureReader))
- throw new NotImplementedException("Signature of event raiser changed.");
+ {
+ reporter.Report(EventRaiserMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, eventDefinition, typeDefinition))); // throw new NotImplementedException("Event raiser was removed.");
+ }
+ else
+ {
+ MethodDefinition newRaiserMethodDefinition = newMetadata.GetMethodDefinition(newEventAccessors.Raiser);
+
+ string referenceRaiserName = referenceMetadata.GetString(referenceRaiserMethodDefinition.Name);
+ string newRaiserName = newMetadata.GetString(newRaiserMethodDefinition.Name);
+ if (!string.Equals(referenceRaiserName, newRaiserName, StringComparison.Ordinal))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Name of event raiser '{0}' changed.", referenceRaiserName))); // throw new NotImplementedException("Signature of event raiser changed.");
+ }
+
+ MethodSignature referenceSignatureReader = referenceMetadata.GetSignature(referenceRaiserMethodDefinition);
+ MethodSignature newSignatureReader = newMetadata.GetSignature(newRaiserMethodDefinition);
+ if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceSignatureReader, newSignatureReader))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of event raiser '{0}' changed.", referenceRaiserName))); // throw new NotImplementedException("Signature of event raiser changed.");
+ }
+ }
}
}
}
@@ -330,7 +458,9 @@ public void Run()
foreach (var propertyDefinition in typeDefinition.GetProperties().Select(referenceMetadata.GetPropertyDefinition))
{
if (!IsPubliclyVisible(referenceMetadata, propertyDefinition))
+ {
continue;
+ }
string referenceName = referenceMetadata.GetString(propertyDefinition.Name);
@@ -346,16 +476,23 @@ public void Run()
}
if (newPropertyDefinitionHandle.IsNil)
- throw new NotImplementedException(string.Format("Publicly-visible property '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)));
+ {
+ reporter.Report(PropertyMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition))); //throw new NotImplementedException(string.Format("Publicly-visible property '{0}' was renamed or removed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)));
+ continue; // TODO test
+ }
PropertyDefinition newPropertyDefinition = newMetadata.GetPropertyDefinition(newPropertyDefinitionHandle);
if (propertyDefinition.Attributes != newPropertyDefinition.Attributes)
- throw new NotImplementedException("Attributes of publicly-visible property changed.");
+ {
+ reporter.Report(PropertyAttributesMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition))); // throw new NotImplementedException("Attributes of publicly-visible property changed.");
+ }
PropertySignature referenceSignature = referenceMetadata.GetSignature(propertyDefinition);
PropertySignature newSignature = newMetadata.GetSignature(newPropertyDefinition);
if (!IsSamePropertySignature(referenceMetadata, newMetadata, referenceSignature, newSignature))
- throw new NotImplementedException("Signature of publicly-visible property changed.");
+ {
+ reporter.Report(PropertySignatureMustNotBeChanged.CreateMessage(GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition))); // throw new NotImplementedException("Signature of publicly-visible property changed.");
+ }
PropertyAccessors propertyAccessors = propertyDefinition.GetAccessors();
if (!propertyAccessors.Getter.IsNil)
@@ -365,19 +502,27 @@ public void Run()
{
PropertyAccessors newPropertyAccessors = newPropertyDefinition.GetAccessors();
if (newPropertyAccessors.Getter.IsNil)
- throw new NotImplementedException("Property getter was removed.");
-
- MethodDefinition newGetterMethodDefinition = newMetadata.GetMethodDefinition(newPropertyAccessors.Getter);
-
- string referenceGetterName = referenceMetadata.GetString(referenceGetterMethodDefinition.Name);
- string newGetterName = newMetadata.GetString(newGetterMethodDefinition.Name);
- if (!string.Equals(referenceGetterName, newGetterName, StringComparison.Ordinal))
- throw new NotImplementedException("Signature of property getter changed.");
-
- MethodSignature referenceAccessorSignatureReader = referenceMetadata.GetSignature(referenceGetterMethodDefinition);
- MethodSignature newAccessorSignatureReader = newMetadata.GetSignature(newGetterMethodDefinition);
- if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceAccessorSignatureReader, newAccessorSignatureReader))
- throw new NotImplementedException("Signature of property getter changed.");
+ {
+ reporter.Report(PropertyGetterMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition))); // throw new NotImplementedException("Property getter was removed.");
+ }
+ else
+ {
+ MethodDefinition newGetterMethodDefinition = newMetadata.GetMethodDefinition(newPropertyAccessors.Getter);
+
+ string referenceGetterName = referenceMetadata.GetString(referenceGetterMethodDefinition.Name);
+ string newGetterName = newMetadata.GetString(newGetterMethodDefinition.Name);
+ if (!string.Equals(referenceGetterName, newGetterName, StringComparison.Ordinal))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Name of property getter for '{0}' changed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)))); // throw new NotImplementedException("Signature of property getter changed.");
+ }
+
+ MethodSignature referenceAccessorSignatureReader = referenceMetadata.GetSignature(referenceGetterMethodDefinition);
+ MethodSignature newAccessorSignatureReader = newMetadata.GetSignature(newGetterMethodDefinition);
+ if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceAccessorSignatureReader, newAccessorSignatureReader))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of property getter for '{0}' changed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)))); // throw new NotImplementedException("Signature of property getter changed.");
+ }
+ }
}
}
@@ -388,23 +533,33 @@ public void Run()
{
PropertyAccessors newPropertyAccessors = newPropertyDefinition.GetAccessors();
if (newPropertyAccessors.Setter.IsNil)
- throw new NotImplementedException("Property setter was removed.");
-
- MethodDefinition newSetterMethodDefinition = newMetadata.GetMethodDefinition(newPropertyAccessors.Setter);
-
- string referenceSetterName = referenceMetadata.GetString(referenceSetterMethodDefinition.Name);
- string newSetterName = newMetadata.GetString(newSetterMethodDefinition.Name);
- if (!string.Equals(referenceSetterName, newSetterName, StringComparison.Ordinal))
- throw new NotImplementedException("Signature of property setter changed.");
-
- MethodSignature referenceAccessorSignatureReader = referenceMetadata.GetSignature(referenceSetterMethodDefinition);
- MethodSignature newAccessorSignatureReader = newMetadata.GetSignature(newSetterMethodDefinition);
- if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceAccessorSignatureReader, newAccessorSignatureReader))
- throw new NotImplementedException("Signature of property setter changed.");
+ {
+ reporter.Report(PropertySetterMustNotBeRemoved.CreateMessage(GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition))); // throw new NotImplementedException("Property setter was removed.");
+ }
+ else
+ {
+ MethodDefinition newSetterMethodDefinition = newMetadata.GetMethodDefinition(newPropertyAccessors.Setter);
+
+ string referenceSetterName = referenceMetadata.GetString(referenceSetterMethodDefinition.Name);
+ string newSetterName = newMetadata.GetString(newSetterMethodDefinition.Name);
+ if (!string.Equals(referenceSetterName, newSetterName, StringComparison.Ordinal))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Name of property setter for '{0}' changed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)))); // throw new NotImplementedException("Signature of property setter changed.");
+ }
+
+ MethodSignature referenceAccessorSignatureReader = referenceMetadata.GetSignature(referenceSetterMethodDefinition);
+ MethodSignature newAccessorSignatureReader = newMetadata.GetSignature(newSetterMethodDefinition);
+ if (!IsSameMethodSignature(referenceMetadata, newMetadata, referenceAccessorSignatureReader, newAccessorSignatureReader))
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Signature of property setter for '{0}' changed.", GetMetadataName(referenceMetadata, propertyDefinition, typeDefinition)))); // throw new NotImplementedException("Signature of property setter changed.");
+ }
+ }
}
}
}
}
+
+ _hasRun = true;
}
private void CheckAssemblyProperties(MetadataReader referenceMetadata, MetadataReader newMetadata)
@@ -415,12 +570,16 @@ private void CheckAssemblyProperties(MetadataReader referenceMetadata, MetadataR
string referenceName = referenceMetadata.GetString(referenceAssemblyDefinition.Name);
string newName = newMetadata.GetString(newAssemblyDefinition.Name);
if (!string.Equals(referenceName, newName, StringComparison.Ordinal))
- _logger.Report(AssemblyNameMustNotBeChanged.CreateMessage());
+ {
+ reporter.Report(AssemblyNameMustNotBeChanged.CreateMessage(referenceName));
+ }
string referenceCulture = referenceMetadata.GetString(referenceAssemblyDefinition.Culture);
string newCulture = referenceMetadata.GetString(newAssemblyDefinition.Culture);
if (!string.Equals(referenceCulture, newCulture, StringComparison.Ordinal))
- throw new NotImplementedException("Assembly culture changed.");
+ {
+ reporter.Report(OtherError.CreateMessage(string.Format("Assembly culture changed from '{0}' to '{1}'.", referenceCulture, newCulture))); // throw new NotImplementedException("Assembly culture changed.");
+ }
if (!referenceAssemblyDefinition.PublicKey.IsNil)
{
@@ -428,7 +587,9 @@ private void CheckAssemblyProperties(MetadataReader referenceMetadata, MetadataR
var referencePublicKey = referenceMetadata.GetBlobContent(referenceAssemblyDefinition.PublicKey);
var newPublicKey = newMetadata.GetBlobContent(newAssemblyDefinition.PublicKey);
if (!referencePublicKey.SequenceEqual(newPublicKey))
- _logger.Report(PublicKeyMustNotBeChanged.CreateMessage());
+ {
+ reporter.Report(PublicKeyMustNotBeChanged.CreateMessage(referenceName));
+ }
}
}
@@ -438,6 +599,11 @@ private bool HasVisibleConstructors(MetadataReader metadataReader, TypeDefinitio
return true;
}
+ private string GetMetadataName(MetadataReader metadataReader, AssemblyDefinition assemblyDefinition)
+ {
+ return metadataReader.GetString(assemblyDefinition.Name);
+ }
+
private string GetMetadataName(MetadataReader metadataReader, TypeDefinition typeDefinition)
{
if (typeDefinition.GetDeclaringType().IsNil)
@@ -455,6 +621,37 @@ private string GetMetadataName(MetadataReader metadataReader, TypeDefinition typ
}
}
+ private string GetMetadataName(MetadataReader metadataReader, InterfaceImplementation interfaceImplementation)
+ {
+ var interfaceNamespaceName = "Unknown";
+ var interfaceName = "Interface";
+ if (interfaceImplementation.Interface.Kind == HandleKind.TypeDefinition)
+ {
+ TypeDefinition interfaceImplementationTypeDefinition = metadataReader.GetTypeDefinition((TypeDefinitionHandle)interfaceImplementation.Interface);
+
+ interfaceNamespaceName = metadataReader.GetString(interfaceImplementationTypeDefinition.Namespace);
+ interfaceName = metadataReader.GetString(interfaceImplementationTypeDefinition.Name);
+ }
+ else if (interfaceImplementation.Interface.Kind == HandleKind.TypeSpecification)
+ {
+ TypeSpecification interfaceImplementationTypeSpecification = metadataReader.GetTypeSpecification((TypeSpecificationHandle)interfaceImplementation.Interface);
+ TypeSpecificationSignature referenceSignature = metadataReader.GetSignature(interfaceImplementationTypeSpecification);
+
+ if (HandleKind.TypeReference == referenceSignature.TypeHandle.Kind)
+ {
+ TypeReference interfaceImplementationTypeReference = metadataReader.GetTypeReference((TypeReferenceHandle)referenceSignature.TypeHandle);
+ interfaceNamespaceName = metadataReader.GetString(interfaceImplementationTypeReference.Namespace);
+ interfaceName = metadataReader.GetString(interfaceImplementationTypeReference.Name);
+ }
+ else
+ {
+ interfaceNamespaceName = "TypeSpecificationHandleNotImplemented";
+ }
+ }
+
+ return string.Format("{0}.{1}", interfaceNamespaceName, interfaceName);
+ }
+
private string GetMetadataName(MetadataReader metadataReader, FieldDefinition fieldDefinition)
{
TypeDefinition declaringTypeDefinition = metadataReader.GetTypeDefinition(fieldDefinition.GetDeclaringType());
@@ -489,10 +686,14 @@ private void CheckBaseType(MetadataReader referenceMetadata, MetadataReader newM
{
Mapping mappedTypeDefinitionHandle = _referenceToNewMapping.MapTypeDefinition(referenceBaseTypeHandle);
if (mappedTypeDefinitionHandle.Target.IsNil)
- throw new NotImplementedException("Base type no longer in assembly.");
+ {
+ reporter.Report(BaseTypeMustStayInAssembly.CreateMessage(GetMetadataName(referenceMetadata, referenceMetadata.GetTypeDefinition(mappedTypeDefinitionHandle.Target)))); // throw new NotImplementedException("Base type no longer in assembly.");
+ }
if (mappedTypeDefinitionHandle.Target != newBaseTypeDefinitionHandle)
- throw new NotImplementedException("Base type changed.");
+ {
+ reporter.Report(BaseTypeMustNotChange.CreateMessage(GetMetadataName(referenceMetadata, referenceMetadata.GetTypeDefinition(mappedTypeDefinitionHandle.Target)))); // throw new NotImplementedException("Base type changed.");
+ }
}
private void CheckBaseType(MetadataReader referenceMetadata, MetadataReader newMetadata, TypeReference referenceBaseTypeReference, TypeReference newBaseTypeReference)
@@ -502,12 +703,16 @@ private void CheckBaseType(MetadataReader referenceMetadata, MetadataReader newM
string referenceName = referenceMetadata.GetString(referenceBaseTypeReference.Name);
string newName = newMetadata.GetString(newBaseTypeReference.Name);
if (!string.Equals(referenceName, newName, StringComparison.Ordinal))
- throw new NotImplementedException("Base type changed.");
+ {
+ reporter.Report(BaseTypeMustNotChange.CreateMessage(referenceName)); // throw new NotImplementedException("Base type changed."); // throw new NotImplementedException("Base type changed.");
+ }
string referenceNamespace = referenceMetadata.GetString(referenceBaseTypeReference.Namespace);
string newNamespace = newMetadata.GetString(newBaseTypeReference.Namespace);
if (!string.Equals(referenceNamespace, newNamespace, StringComparison.Ordinal))
- throw new NotImplementedException("Base type changed.");
+ {
+ reporter.Report(BaseTypeMustNotChange.CreateMessage(string.Format("{0}.{1}", referenceNamespace, referenceName))); // throw new NotImplementedException("Base type changed.");
+ }
}
private void CheckBaseType(MetadataReader referenceMetadata, MetadataReader newMetadata, TypeSpecification referenceBaseTypeSpecification, TypeSpecification newBaseTypeSpecification)
@@ -518,49 +723,61 @@ private void CheckBaseType(MetadataReader referenceMetadata, MetadataReader newM
private bool IsSameType(MetadataReader referenceMetadata, MetadataReader newMetadata, Handle referenceTypeHandle, Handle newTypeHandle)
{
if (referenceTypeHandle.IsNil != newTypeHandle.IsNil)
+ {
return false;
+ }
if (referenceTypeHandle.Kind != newTypeHandle.Kind)
+ {
return false;
+ }
switch (referenceTypeHandle.Kind)
{
- case HandleKind.TypeDefinition:
- Mapping mappedTypeDefinitionHandle = _referenceToNewMapping.MapTypeDefinition((TypeDefinitionHandle)referenceTypeHandle);
- if (mappedTypeDefinitionHandle.Target.IsNil)
- return false;
+ case HandleKind.TypeDefinition:
+ Mapping mappedTypeDefinitionHandle = _referenceToNewMapping.MapTypeDefinition((TypeDefinitionHandle)referenceTypeHandle);
+ if (mappedTypeDefinitionHandle.Target.IsNil)
+ {
+ return false;
+ }
- return mappedTypeDefinitionHandle.Target == (TypeDefinitionHandle)newTypeHandle;
+ return mappedTypeDefinitionHandle.Target == (TypeDefinitionHandle)newTypeHandle;
- case HandleKind.TypeReference:
- TypeReference referenceTypeReference = referenceMetadata.GetTypeReference((TypeReferenceHandle)referenceTypeHandle);
- TypeReference newTypeReference = newMetadata.GetTypeReference((TypeReferenceHandle)newTypeHandle);
- return IsSameType(referenceMetadata, newMetadata, referenceTypeReference, newTypeReference);
+ case HandleKind.TypeReference:
+ TypeReference referenceTypeReference = referenceMetadata.GetTypeReference((TypeReferenceHandle)referenceTypeHandle);
+ TypeReference newTypeReference = newMetadata.GetTypeReference((TypeReferenceHandle)newTypeHandle);
+ return IsSameType(referenceMetadata, newMetadata, referenceTypeReference, newTypeReference);
- case HandleKind.TypeSpecification:
- TypeSpecification referenceTypeSpecification = referenceMetadata.GetTypeSpecification((TypeSpecificationHandle)referenceTypeHandle);
- TypeSpecification newTypeSpecification = newMetadata.GetTypeSpecification((TypeSpecificationHandle)newTypeHandle);
- return IsSameType(referenceMetadata, newMetadata, referenceTypeSpecification, newTypeSpecification);
+ case HandleKind.TypeSpecification:
+ TypeSpecification referenceTypeSpecification = referenceMetadata.GetTypeSpecification((TypeSpecificationHandle)referenceTypeHandle);
+ TypeSpecification newTypeSpecification = newMetadata.GetTypeSpecification((TypeSpecificationHandle)newTypeHandle);
+ return IsSameType(referenceMetadata, newMetadata, referenceTypeSpecification, newTypeSpecification);
- default:
- throw new InvalidOperationException("Invalid type handle.");
+ default:
+ throw new InvalidOperationException("Invalid type handle.");
}
}
private bool IsSameType(MetadataReader referenceMetadata, MetadataReader newMetadata, TypeReference referenceTypeReference, TypeReference newTypeReference)
{
if (!IsSameResolutionScope(referenceMetadata, newMetadata, referenceTypeReference.ResolutionScope, newTypeReference.ResolutionScope))
+ {
return false;
+ }
string referenceName = referenceMetadata.GetString(referenceTypeReference.Name);
string newName = newMetadata.GetString(newTypeReference.Name);
if (!string.Equals(referenceName, newName, StringComparison.Ordinal))
+ {
return false;
+ }
string referenceNamespace = referenceMetadata.GetString(referenceTypeReference.Namespace);
string newNamespace = newMetadata.GetString(newTypeReference.Namespace);
if (!string.Equals(referenceNamespace, newNamespace, StringComparison.Ordinal))
+ {
return false;
+ }
return true;
}
@@ -573,52 +790,62 @@ private bool IsSameType(MetadataReader referenceMetadata, MetadataReader newMeta
SignatureTypeCode referenceTypeCode = referenceSignature.TypeCode;
SignatureTypeCode newTypeCode = newSignature.TypeCode;
if (referenceTypeCode != newTypeCode)
+ {
return false;
+ }
switch (referenceTypeCode)
{
- case SignatureTypeCode.Pointer:
- Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
- return true;
-
- case SignatureTypeCode.FunctionPointer:
- Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
- return true;
+ case SignatureTypeCode.Pointer:
+ Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
+ return true;
- case SignatureTypeCode.Array:
- Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
- return true;
+ case SignatureTypeCode.FunctionPointer:
+ Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
+ return true;
- case SignatureTypeCode.SZArray:
- Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
- return true;
+ case SignatureTypeCode.Array:
+ Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
+ return true;
- case SignatureTypeCode.GenericTypeInstance:
- if (!IsSameType(referenceMetadata, newMetadata, referenceSignature.TypeHandle, newSignature.TypeHandle))
- return false;
+ case SignatureTypeCode.SZArray:
+ Console.WriteLine("IsSameType not yet implemented for {0}.", referenceTypeCode);
+ return true;
- ImmutableArray referenceGenericArguments = referenceSignature.GenericTypeArguments;
- ImmutableArray newGenericArguments = newSignature.GenericTypeArguments;
- if (referenceGenericArguments.Length != newGenericArguments.Length)
- return false;
+ case SignatureTypeCode.GenericTypeInstance:
+ if (!IsSameType(referenceMetadata, newMetadata, referenceSignature.TypeHandle, newSignature.TypeHandle))
+ {
+ return false;
+ }
- for (int i = 0; i < referenceGenericArguments.Length; i++)
- {
- if (!IsSameTypeSignature(referenceMetadata, newMetadata, referenceGenericArguments[i], newGenericArguments[i]))
+ ImmutableArray referenceGenericArguments = referenceSignature.GenericTypeArguments;
+ ImmutableArray newGenericArguments = newSignature.GenericTypeArguments;
+ if (referenceGenericArguments.Length != newGenericArguments.Length)
+ {
return false;
- }
+ }
- return true;
+ for (int i = 0; i < referenceGenericArguments.Length; i++)
+ {
+ if (!IsSameTypeSignature(referenceMetadata, newMetadata, referenceGenericArguments[i], newGenericArguments[i]))
+ {
+ return false;
+ }
+ }
- default:
- return false;
+ return true;
+
+ default:
+ return false;
}
}
private bool IsSameFieldSignature(MetadataReader referenceMetadata, MetadataReader newMetadata, FieldSignature referenceSignature, FieldSignature newSignature)
{
if (!referenceSignature.CustomModifiers.IsEmpty || !newSignature.CustomModifiers.IsEmpty)
+ {
throw new NotImplementedException();
+ }
return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignature.Type, newSignature.Type);
}
@@ -628,29 +855,41 @@ private bool IsSameMethodSignature(MetadataReader referenceMetadata, MetadataRea
SignatureHeader referenceHeader = referenceSignatureReader.Header;
SignatureHeader newHeader = newSignatureReader.Header;
if (referenceHeader.Kind != SignatureKind.Method || newHeader.Kind != SignatureKind.Method)
+ {
throw new InvalidOperationException("Expected method signatures.");
+ }
if (referenceHeader.RawValue != newHeader.RawValue)
+ {
return false;
+ }
if (referenceHeader.IsGeneric)
{
if (referenceSignatureReader.GenericParameterCount != newSignatureReader.GenericParameterCount)
+ {
return false;
+ }
}
if (!IsSameReturnTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.ReturnType, newSignatureReader.ReturnType))
+ {
return false;
+ }
var referenceParameters = referenceSignatureReader.Parameters;
var newParameters = newSignatureReader.Parameters;
if (referenceParameters.Length != newParameters.Length)
+ {
return false;
+ }
for (int i = 0; i < referenceParameters.Length; i++)
{
if (!IsSameParameterSignature(referenceMetadata, newMetadata, referenceParameters[i], newParameters[i]))
+ {
return false;
+ }
}
return true;
@@ -661,26 +900,38 @@ private bool IsSamePropertySignature(MetadataReader referenceMetadata, MetadataR
SignatureHeader referenceHeader = referenceSignatureReader.Header;
SignatureHeader newHeader = newSignatureReader.Header;
if (referenceHeader.Kind != SignatureKind.Property || newHeader.Kind != SignatureKind.Property)
+ {
throw new InvalidOperationException("Expected property signatures.");
+ }
if (referenceHeader.IsInstance != newHeader.IsInstance)
+ {
return false;
+ }
ImmutableArray referenceParameters = referenceSignatureReader.Parameters;
ImmutableArray newParameters = newSignatureReader.Parameters;
if (referenceParameters.Length != newParameters.Length)
+ {
return false;
+ }
if (!referenceSignatureReader.CustomModifiers.IsEmpty || !newSignatureReader.CustomModifiers.IsEmpty)
+ {
throw new NotImplementedException();
+ }
if (!IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.PropertyType, newSignatureReader.PropertyType))
+ {
return false;
+ }
for (int i = 0; i < referenceParameters.Length; i++)
{
if (!IsSameParameterSignature(referenceMetadata, newMetadata, referenceParameters[i], newParameters[i]))
+ {
return false;
+ }
}
return true;
@@ -689,148 +940,174 @@ private bool IsSamePropertySignature(MetadataReader referenceMetadata, MetadataR
private bool IsSameParameterSignature(MetadataReader referenceMetadata, MetadataReader newMetadata, ParameterSignature referenceSignatureReader, ParameterSignature newSignatureReader)
{
if (!referenceSignatureReader.CustomModifiers.IsEmpty || !newSignatureReader.CustomModifiers.IsEmpty)
+ {
throw new NotImplementedException();
+ }
if (referenceSignatureReader.TypeCode != newSignatureReader.TypeCode)
+ {
return false;
+ }
switch (referenceSignatureReader.TypeCode)
{
- case SignatureTypeCode.TypedReference:
- return true;
+ case SignatureTypeCode.TypedReference:
+ return true;
- default:
- if (referenceSignatureReader.IsByRef != newSignatureReader.IsByRef)
- return false;
+ default:
+ if (referenceSignatureReader.IsByRef != newSignatureReader.IsByRef)
+ {
+ return false;
+ }
- return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.Type, newSignatureReader.Type);
+ return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.Type, newSignatureReader.Type);
}
}
private bool IsSameReturnTypeSignature(MetadataReader referenceMetadata, MetadataReader newMetadata, ReturnTypeSignature referenceSignatureReader, ReturnTypeSignature newSignatureReader)
{
if (!referenceSignatureReader.CustomModifiers.IsEmpty || !newSignatureReader.CustomModifiers.IsEmpty)
+ {
throw new NotImplementedException();
+ }
if (referenceSignatureReader.TypeCode != newSignatureReader.TypeCode)
+ {
return false;
+ }
switch (referenceSignatureReader.TypeCode)
{
- case SignatureTypeCode.TypedReference:
- case SignatureTypeCode.Void:
- return true;
+ case SignatureTypeCode.TypedReference:
+ case SignatureTypeCode.Void:
+ return true;
- default:
- if (referenceSignatureReader.IsByRef != newSignatureReader.IsByRef)
- return false;
+ default:
+ if (referenceSignatureReader.IsByRef != newSignatureReader.IsByRef)
+ {
+ return false;
+ }
- return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.Type, newSignatureReader.Type);
+ return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignatureReader.Type, newSignatureReader.Type);
}
}
private bool IsSameTypeSignature(MetadataReader referenceMetadata, MetadataReader newMetadata, TypeSignature referenceSignature, TypeSignature newSignature)
{
if (referenceSignature.TypeCode != newSignature.TypeCode)
+ {
return false;
+ }
switch (referenceSignature.TypeCode)
{
- case SignatureTypeCode.Boolean:
- case SignatureTypeCode.Char:
- case SignatureTypeCode.SByte:
- case SignatureTypeCode.Byte:
- case SignatureTypeCode.Int16:
- case SignatureTypeCode.UInt16:
- case SignatureTypeCode.Int32:
- case SignatureTypeCode.UInt32:
- case SignatureTypeCode.Int64:
- case SignatureTypeCode.UInt64:
- case SignatureTypeCode.IntPtr:
- case SignatureTypeCode.UIntPtr:
- case SignatureTypeCode.Single:
- case SignatureTypeCode.Double:
- return true;
-
- case SignatureTypeCode.Object:
- case SignatureTypeCode.String:
- return true;
-
- case SignatureTypeCode.Array:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
-
- case SignatureTypeCode.FunctionPointer:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
-
- case SignatureTypeCode.GenericTypeInstance:
- if (!IsSameType(referenceMetadata, newMetadata, referenceSignature.TypeHandle, newSignature.TypeHandle))
- return false;
+ case SignatureTypeCode.Boolean:
+ case SignatureTypeCode.Char:
+ case SignatureTypeCode.SByte:
+ case SignatureTypeCode.Byte:
+ case SignatureTypeCode.Int16:
+ case SignatureTypeCode.UInt16:
+ case SignatureTypeCode.Int32:
+ case SignatureTypeCode.UInt32:
+ case SignatureTypeCode.Int64:
+ case SignatureTypeCode.UInt64:
+ case SignatureTypeCode.IntPtr:
+ case SignatureTypeCode.UIntPtr:
+ case SignatureTypeCode.Single:
+ case SignatureTypeCode.Double:
+ return true;
- ImmutableArray referenceGenericArguments = referenceSignature.GenericTypeArguments;
- ImmutableArray newGenericArguments = newSignature.GenericTypeArguments;
- if (referenceGenericArguments.Length != newGenericArguments.Length)
- return false;
+ case SignatureTypeCode.Object:
+ case SignatureTypeCode.String:
+ return true;
- for (int i = 0; i < referenceGenericArguments.Length; i++)
- {
- if (!IsSameTypeSignature(referenceMetadata, newMetadata, referenceGenericArguments[i], newGenericArguments[i]))
+ case SignatureTypeCode.Array:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
+
+ case SignatureTypeCode.FunctionPointer:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
+
+ case SignatureTypeCode.GenericTypeInstance:
+ if (!IsSameType(referenceMetadata, newMetadata, referenceSignature.TypeHandle, newSignature.TypeHandle))
+ {
return false;
- }
+ }
+
+ ImmutableArray referenceGenericArguments = referenceSignature.GenericTypeArguments;
+ ImmutableArray newGenericArguments = newSignature.GenericTypeArguments;
+ if (referenceGenericArguments.Length != newGenericArguments.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < referenceGenericArguments.Length; i++)
+ {
+ if (!IsSameTypeSignature(referenceMetadata, newMetadata, referenceGenericArguments[i], newGenericArguments[i]))
+ {
+ return false;
+ }
+ }
- return true;
+ return true;
- case SignatureTypeCode.GenericMethodParameter:
- case SignatureTypeCode.GenericTypeParameter:
- return referenceSignature.GenericParameterIndex == newSignature.GenericParameterIndex;
+ case SignatureTypeCode.GenericMethodParameter:
+ case SignatureTypeCode.GenericTypeParameter:
+ return referenceSignature.GenericParameterIndex == newSignature.GenericParameterIndex;
- case SignatureTypeCode.TypeHandle:
- Handle referenceTypeHandle = referenceSignature.TypeHandle;
- Handle newTypeHandle = newSignature.TypeHandle;
- return IsSameType(referenceMetadata, newMetadata, referenceTypeHandle, newTypeHandle);
+ case SignatureTypeCode.TypeHandle:
+ Handle referenceTypeHandle = referenceSignature.TypeHandle;
+ Handle newTypeHandle = newSignature.TypeHandle;
+ return IsSameType(referenceMetadata, newMetadata, referenceTypeHandle, newTypeHandle);
- case SignatureTypeCode.Pointer:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
+ case SignatureTypeCode.Pointer:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", referenceSignature.TypeCode));
- case SignatureTypeCode.SZArray:
- if (!referenceSignature.CustomModifiers.IsEmpty || !newSignature.CustomModifiers.IsEmpty)
- throw new NotImplementedException();
+ case SignatureTypeCode.SZArray:
+ if (!referenceSignature.CustomModifiers.IsEmpty || !newSignature.CustomModifiers.IsEmpty)
+ {
+ throw new NotImplementedException();
+ }
- return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignature.ElementType, newSignature.ElementType);
+ return IsSameTypeSignature(referenceMetadata, newMetadata, referenceSignature.ElementType, newSignature.ElementType);
- default:
- throw new InvalidOperationException("Invalid signature type code.");
+ default:
+ throw new InvalidOperationException("Invalid signature type code.");
}
}
private bool IsSameResolutionScope(MetadataReader referenceMetadata, MetadataReader newMetadata, Handle referenceResolutionScope, Handle newResolutionScope)
{
if (referenceResolutionScope.IsNil != newResolutionScope.IsNil)
+ {
return false;
+ }
if (referenceResolutionScope.Kind != newResolutionScope.Kind)
+ {
return false;
+ }
switch (referenceResolutionScope.Kind)
{
- case HandleKind.ModuleDefinition:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
+ case HandleKind.ModuleDefinition:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
- case HandleKind.ModuleReference:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
+ case HandleKind.ModuleReference:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
- case HandleKind.AssemblyReference:
- AssemblyReference referenceResolutionScopeAssemblyReference = referenceMetadata.GetAssemblyReference((AssemblyReferenceHandle)referenceResolutionScope);
- AssemblyReference newResolutionScopeAssemblyReference = newMetadata.GetAssemblyReference((AssemblyReferenceHandle)newResolutionScope);
- return IsSameResolutionScope(referenceMetadata, newMetadata, referenceResolutionScopeAssemblyReference, newResolutionScopeAssemblyReference);
+ case HandleKind.AssemblyReference:
+ AssemblyReference referenceResolutionScopeAssemblyReference = referenceMetadata.GetAssemblyReference((AssemblyReferenceHandle)referenceResolutionScope);
+ AssemblyReference newResolutionScopeAssemblyReference = newMetadata.GetAssemblyReference((AssemblyReferenceHandle)newResolutionScope);
+ return IsSameResolutionScope(referenceMetadata, newMetadata, referenceResolutionScopeAssemblyReference, newResolutionScopeAssemblyReference);
- case HandleKind.TypeReference:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
+ case HandleKind.TypeReference:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
- default:
- throw new InvalidOperationException("Invalid ResolutionScope kind.");
+ default:
+ throw new InvalidOperationException("Invalid ResolutionScope kind.");
}
return true;
@@ -844,40 +1121,46 @@ private bool IsSameResolutionScope(MetadataReader referenceMetadata, MetadataRea
private void CheckResolutionScope(MetadataReader referenceMetadata, MetadataReader newMetadata, Handle referenceResolutionScope, Handle newResolutionScope)
{
if (referenceResolutionScope.IsNil != newResolutionScope.IsNil)
- throw new NotImplementedException("ResolutionScope changed.");
+ {
+ reporter.Report(OtherError.CreateMessage("ResolutionScope changed.")); // throw new NotImplementedException("ResolutionScope changed.");
+ }
if (referenceResolutionScope.Kind != newResolutionScope.Kind)
- throw new NotImplementedException("ResolutionScope changed.");
+ {
+ reporter.Report(OtherError.CreateMessage("ResolutionScope changed.")); // throw new NotImplementedException("ResolutionScope changed.");
+ }
switch (referenceResolutionScope.Kind)
{
- case HandleKind.ModuleDefinition:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
-
- case HandleKind.ModuleReference:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
-
- case HandleKind.AssemblyReference:
- AssemblyReference referenceResolutionScopeAssemblyReference = referenceMetadata.GetAssemblyReference((AssemblyReferenceHandle)referenceResolutionScope);
- AssemblyReference newResolutionScopeAssemblyReference = newMetadata.GetAssemblyReference((AssemblyReferenceHandle)newResolutionScope);
- CheckResolutionScope(referenceMetadata, newMetadata, referenceResolutionScopeAssemblyReference, newResolutionScopeAssemblyReference);
- break;
-
- case HandleKind.TypeReference:
- Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
- break;
-
- default:
- throw new InvalidOperationException("Invalid ResolutionScope kind.");
+ case HandleKind.ModuleDefinition:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
+
+ case HandleKind.ModuleReference:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
+
+ case HandleKind.AssemblyReference:
+ AssemblyReference referenceResolutionScopeAssemblyReference = referenceMetadata.GetAssemblyReference((AssemblyReferenceHandle)referenceResolutionScope);
+ AssemblyReference newResolutionScopeAssemblyReference = newMetadata.GetAssemblyReference((AssemblyReferenceHandle)newResolutionScope);
+ CheckResolutionScope(referenceMetadata, newMetadata, referenceResolutionScopeAssemblyReference, newResolutionScopeAssemblyReference);
+ break;
+
+ case HandleKind.TypeReference:
+ Console.WriteLine("ResolutionScope:{0} checking not yet implemented.", referenceResolutionScope.Kind);
+ break;
+
+ default:
+ throw new InvalidOperationException("Invalid ResolutionScope kind.");
}
}
private void CheckResolutionScope(MetadataReader referenceMetadata, MetadataReader newMetadata, AssemblyReference referenceResolutionScope, AssemblyReference newResolutionScope)
{
if (!IsSameAssembly(referenceMetadata, newMetadata, referenceResolutionScope, newResolutionScope))
- throw new NotImplementedException("ResolutionScope assembly reference changed.");
+ {
+ reporter.Report(ResolutionScopeAssemblyReferenceMustNotChange.CreateMessage(referenceMetadata.GetString(referenceResolutionScope.Name))); // throw new NotImplementedException("ResolutionScope assembly reference changed.");
+ }
}
private bool IsSameAssembly(MetadataReader referenceMetadata, MetadataReader newMetadata, AssemblyReference referenceAssemblyReference, AssemblyReference newAssemblyReference)
@@ -885,29 +1168,39 @@ private bool IsSameAssembly(MetadataReader referenceMetadata, MetadataReader new
string referenceName = referenceMetadata.GetString(referenceAssemblyReference.Name);
string newName = newMetadata.GetString(newAssemblyReference.Name);
if (!string.Equals(referenceName, newName, StringComparison.Ordinal))
+ {
return false;
+ }
string referenceCulture = referenceMetadata.GetString(referenceAssemblyReference.Culture);
string newCulture = newMetadata.GetString(newAssemblyReference.Culture);
if (!string.Equals(referenceCulture, newCulture, StringComparison.Ordinal))
+ {
return false;
+ }
Version referenceVersion = referenceAssemblyReference.Version;
Version newVersion = newAssemblyReference.Version;
if (referenceVersion != newVersion)
+ {
return false;
+ }
byte[] referencePublicKeyOrToken = referenceMetadata.GetBlobBytes(referenceAssemblyReference.PublicKeyOrToken);
byte[] newPublicKeyOrToken = newMetadata.GetBlobBytes(newAssemblyReference.PublicKeyOrToken);
if (referencePublicKeyOrToken != null)
{
if (newPublicKeyOrToken == null || referencePublicKeyOrToken.Length != newPublicKeyOrToken.Length)
+ {
return false;
+ }
for (int i = 0; i < referencePublicKeyOrToken.Length; i++)
{
if (referencePublicKeyOrToken[i] != newPublicKeyOrToken[i])
+ {
return false;
+ }
}
}
else if (newPublicKeyOrToken != null)
@@ -922,20 +1215,20 @@ private bool IsPubliclyVisible(MetadataReader metadataReader, TypeDefinition typ
{
switch (typeDefinition.Attributes & TypeAttributes.VisibilityMask)
{
- case TypeAttributes.Public:
- return true;
-
- case TypeAttributes.NestedPublic:
- case TypeAttributes.NestedFamORAssem:
- case TypeAttributes.NestedFamily:
- TypeDefinition declaringType = metadataReader.GetTypeDefinition(typeDefinition.GetDeclaringType());
- return IsPubliclyVisible(metadataReader, declaringType);
-
- case TypeAttributes.NestedFamANDAssem:
- case TypeAttributes.NestedPrivate:
- case TypeAttributes.NotPublic:
- default:
- return false;
+ case TypeAttributes.Public:
+ return true;
+
+ case TypeAttributes.NestedPublic:
+ case TypeAttributes.NestedFamORAssem:
+ case TypeAttributes.NestedFamily:
+ TypeDefinition declaringType = metadataReader.GetTypeDefinition(typeDefinition.GetDeclaringType());
+ return IsPubliclyVisible(metadataReader, declaringType);
+
+ case TypeAttributes.NestedFamANDAssem:
+ case TypeAttributes.NestedPrivate:
+ case TypeAttributes.NotPublic:
+ default:
+ return false;
}
}
@@ -943,24 +1236,26 @@ private bool IsPubliclyVisible(MetadataReader referenceMetadata, FieldDefinition
{
switch (fieldDefinition.Attributes & FieldAttributes.FieldAccessMask)
{
- case FieldAttributes.Public:
- case FieldAttributes.Family:
- case FieldAttributes.FamORAssem:
- break;
-
- case FieldAttributes.FamANDAssem:
- case FieldAttributes.Assembly:
- case FieldAttributes.Private:
- case FieldAttributes.PrivateScope:
- default:
- return false;
+ case FieldAttributes.Public:
+ case FieldAttributes.Family:
+ case FieldAttributes.FamORAssem:
+ break;
+
+ case FieldAttributes.FamANDAssem:
+ case FieldAttributes.Assembly:
+ case FieldAttributes.Private:
+ case FieldAttributes.PrivateScope:
+ default:
+ return false;
}
if (checkDeclaringType)
{
TypeDefinition declaringTypeDefinition = referenceMetadata.GetTypeDefinition(fieldDefinition.GetDeclaringType());
if (!IsPubliclyVisible(referenceMetadata, declaringTypeDefinition))
+ {
return false;
+ }
}
return true;
@@ -970,24 +1265,26 @@ private bool IsPubliclyVisible(MetadataReader referenceMetadata, MethodDefinitio
{
switch (methodDefinition.Attributes & MethodAttributes.MemberAccessMask)
{
- case MethodAttributes.Public:
- case MethodAttributes.Family:
- case MethodAttributes.FamORAssem:
- break;
-
- case MethodAttributes.FamANDAssem:
- case MethodAttributes.Assembly:
- case MethodAttributes.Private:
- case MethodAttributes.PrivateScope:
- default:
- return false;
+ case MethodAttributes.Public:
+ case MethodAttributes.Family:
+ case MethodAttributes.FamORAssem:
+ break;
+
+ case MethodAttributes.FamANDAssem:
+ case MethodAttributes.Assembly:
+ case MethodAttributes.Private:
+ case MethodAttributes.PrivateScope:
+ default:
+ return false;
}
if (checkDeclaringType)
{
TypeDefinition declaringTypeDefinition = referenceMetadata.GetTypeDefinition(methodDefinition.GetDeclaringType());
if (!IsPubliclyVisible(referenceMetadata, declaringTypeDefinition))
+ {
return false;
+ }
}
return true;
@@ -1000,21 +1297,27 @@ private bool IsPubliclyVisible(MetadataReader referenceMetadata, EventDefinition
{
MethodDefinition adderMethodDefinition = referenceMetadata.GetMethodDefinition(eventAccessors.Adder);
if (IsPubliclyVisible(referenceMetadata, adderMethodDefinition, checkDeclaringType))
+ {
return true;
+ }
}
if (!eventAccessors.Remover.IsNil)
{
MethodDefinition removerMethodDefinition = referenceMetadata.GetMethodDefinition(eventAccessors.Remover);
if (IsPubliclyVisible(referenceMetadata, removerMethodDefinition, checkDeclaringType))
+ {
return true;
+ }
}
if (!eventAccessors.Raiser.IsNil)
{
MethodDefinition raiserMethodDefinition = referenceMetadata.GetMethodDefinition(eventAccessors.Raiser);
if (IsPubliclyVisible(referenceMetadata, raiserMethodDefinition, checkDeclaringType))
+ {
return true;
+ }
}
return false;
@@ -1027,14 +1330,18 @@ private bool IsPubliclyVisible(MetadataReader referenceMetadata, PropertyDefinit
{
MethodDefinition getterMethodDefinition = referenceMetadata.GetMethodDefinition(propertyAccessors.Getter);
if (IsPubliclyVisible(referenceMetadata, getterMethodDefinition, checkDeclaringType))
+ {
return true;
+ }
}
if (!propertyAccessors.Setter.IsNil)
{
MethodDefinition setterMethodDefinition = referenceMetadata.GetMethodDefinition(propertyAccessors.Setter);
if (IsPubliclyVisible(referenceMetadata, setterMethodDefinition, checkDeclaringType))
+ {
return true;
+ }
}
return false;
diff --git a/CompatibilityChecker/ArrayShapeSignature.cs b/CompatibilityChecker.Library/ArrayShapeSignature.cs
similarity index 81%
rename from CompatibilityChecker/ArrayShapeSignature.cs
rename to CompatibilityChecker.Library/ArrayShapeSignature.cs
index a1dbb57..49e8fc0 100644
--- a/CompatibilityChecker/ArrayShapeSignature.cs
+++ b/CompatibilityChecker.Library/ArrayShapeSignature.cs
@@ -1,22 +1,22 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Collections.Immutable;
using System.Reflection.Metadata;
public struct ArrayShapeSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public ArrayShapeSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public int Rank
{
get
{
- return _reader.ReadCompressedInteger();
+ return reader.ReadCompressedInteger();
}
}
@@ -24,7 +24,7 @@ public ImmutableArray Lengths
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
// rank
reader.ReadCompressedInteger();
@@ -33,7 +33,9 @@ public ImmutableArray Lengths
int numSizes = reader.ReadCompressedInteger();
var builder = ImmutableArray.CreateBuilder(numSizes);
for (int i = 0; i < numSizes; i++)
+ {
builder.Add(reader.ReadCompressedInteger());
+ }
return builder.ToImmutable();
}
@@ -43,7 +45,7 @@ public ImmutableArray LowerBounds
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
// rank
reader.ReadCompressedInteger();
@@ -51,13 +53,17 @@ public ImmutableArray LowerBounds
// sizes
int numSizes = reader.ReadCompressedInteger();
for (int i = 0; i < numSizes; i++)
+ {
reader.ReadCompressedInteger();
+ }
// bounds
int numBounds = reader.ReadCompressedInteger();
var builder = ImmutableArray.CreateBuilder(numBounds);
for (int i = 0; i < numBounds; i++)
+ {
builder.Add(reader.ReadCompressedSignedInteger());
+ }
return builder.ToImmutable();
}
@@ -65,7 +71,7 @@ public ImmutableArray LowerBounds
public BlobReader Skip()
{
- BlobReader reader = _reader;
+ var reader = this.reader;
// rank
reader.ReadCompressedInteger();
@@ -73,12 +79,16 @@ public BlobReader Skip()
// sizes
int numSizes = reader.ReadCompressedInteger();
for (int i = 0; i < numSizes; i++)
+ {
reader.ReadCompressedInteger();
+ }
// bounds
int numBounds = reader.ReadCompressedInteger();
for (int i = 0; i < numBounds; i++)
+ {
reader.ReadCompressedSignedInteger();
+ }
return reader;
}
diff --git a/CompatibilityChecker.Library/AzurePipelinesMessageLogger.cs b/CompatibilityChecker.Library/AzurePipelinesMessageLogger.cs
new file mode 100644
index 0000000..dc00989
--- /dev/null
+++ b/CompatibilityChecker.Library/AzurePipelinesMessageLogger.cs
@@ -0,0 +1,45 @@
+namespace CompatibilityChecker.Library
+{
+ using System;
+
+ public class AzurePipelinesMessageLogger : IMessageLogger
+ {
+ private Severity? maxSeverity;
+
+ public AzurePipelinesMessageLogger(Severity? maxSeverity)
+ {
+ this.maxSeverity = maxSeverity;
+ }
+
+ public AzurePipelinesMessageLogger()
+ {
+ maxSeverity = null;
+ }
+
+ public virtual void Report(Message message)
+ {
+ Severity sev;
+ if (maxSeverity.HasValue)
+ {
+ sev = message.Severity > maxSeverity.Value ? maxSeverity.Value : message.Severity;
+ }
+ else
+ {
+ sev = message.Severity;
+ }
+
+ switch (sev)
+ {
+ case Severity.Error:
+ Console.Error.WriteLine("##vso[task.logissue type=error]{0}", message);
+ break;
+ case Severity.Warning:
+ Console.Error.WriteLine("##vso[task.logissue type=warning]{0}", message);
+ break;
+ default:
+ Console.WriteLine(message);
+ break;
+ }
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/BasicListingReporter.cs b/CompatibilityChecker.Library/BasicListingReporter.cs
new file mode 100644
index 0000000..c5707ef
--- /dev/null
+++ b/CompatibilityChecker.Library/BasicListingReporter.cs
@@ -0,0 +1,52 @@
+namespace CompatibilityChecker.Library
+{
+ using System;
+ using System.Collections.Generic;
+
+ internal class BasicListingReporter : IMessageReporter
+ {
+ private IMessageLogger logger;
+
+ private List reportedMessages;
+
+ private int severityError = 0;
+ private int severityWarning = 0;
+ private int severityInformation = 0;
+ private int severityDisabled = 0;
+
+ IEnumerable IMessageReporter.ReportedMessages => reportedMessages;
+
+ IReportStatistics IMessageReporter.Statistics => new BasicListingStatistics(severityError, severityWarning, severityInformation, severityDisabled);
+
+ public BasicListingReporter(IMessageLogger logger)
+ {
+ this.logger = logger;
+
+ reportedMessages = new List();
+ }
+
+ void IMessageReporter.Report(Message message)
+ {
+ switch (message.Severity)
+ {
+ case Severity.Error:
+ severityError++;
+ break;
+ case Severity.Warning:
+ severityWarning++;
+ break;
+ case Severity.Information:
+ severityInformation++;
+ break;
+ case Severity.Disabled:
+ severityDisabled++;
+ break;
+ default:
+ throw new ArgumentException(string.Format("Severity {0} is not supported by this Message Reporter.", message.Severity));
+ }
+
+ reportedMessages.Add(message);
+ logger.Report(message);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/BasicListingStatistics.cs b/CompatibilityChecker.Library/BasicListingStatistics.cs
new file mode 100644
index 0000000..5c06d73
--- /dev/null
+++ b/CompatibilityChecker.Library/BasicListingStatistics.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CompatibilityChecker.Library
+{
+ internal class BasicListingStatistics : IReportStatistics
+ {
+ private (int error, int warning, int information, int disabled) severityCounts;
+
+ (int error, int warning, int information, int disabled) IReportStatistics.SeverityCounts => severityCounts;
+
+ public BasicListingStatistics(int severityError, int severityWarning, int severityInformation, int severityDisabled)
+ {
+ severityCounts = (error: severityError, warning: severityWarning, information: severityInformation, disabled: severityDisabled);
+ }
+ }
+}
diff --git a/CompatibilityChecker/BlobReaderExtensions.cs b/CompatibilityChecker.Library/BlobReaderExtensions.cs
similarity index 63%
rename from CompatibilityChecker/BlobReaderExtensions.cs
rename to CompatibilityChecker.Library/BlobReaderExtensions.cs
index 7c0ba21..b7b1f61 100644
--- a/CompatibilityChecker/BlobReaderExtensions.cs
+++ b/CompatibilityChecker.Library/BlobReaderExtensions.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Reflection.Metadata;
@@ -8,12 +8,12 @@ public static bool IsCustomModifier(this BlobReader blobReader)
{
switch (blobReader.ReadSignatureTypeCode())
{
- case SignatureTypeCode.OptionalModifier:
- case SignatureTypeCode.RequiredModifier:
- return true;
+ case SignatureTypeCode.OptionalModifier:
+ case SignatureTypeCode.RequiredModifier:
+ return true;
- default:
- return false;
+ default:
+ return false;
}
}
diff --git a/CompatibilityChecker.Library/CompatibilityChecker.Library.csproj b/CompatibilityChecker.Library/CompatibilityChecker.Library.csproj
new file mode 100644
index 0000000..c29ca3d
--- /dev/null
+++ b/CompatibilityChecker.Library/CompatibilityChecker.Library.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net7.0
+ latest
+ 0.5.0
+ This project implements a binary compatibility checker for .NET assemblies. The goal of this project is to automate the process of identifying binary- and source-breaking changes between releases of a .NET library. Libraries with string compatibility policies will eventually be able to incorporate this check in the unit tests for the library. The checker will download a declared previous release of the library from NuGet (or potentially from another source), and verify that the latest build of the library is compatible with the binary interfaces defined by the earlier release.
+
+ This library may also feature support for higher levels of compatibility, such as warning users if new overloads of a method could result in an AmbiguousMatchException for users who didn't specify a complete signature when using reflection.
+
+ Diagnostics produced by this checker will be categorized by their likely impact on consumers, and by whether the change constitutes a binary- or source-level breaking change. At this time, there are no plans to implement detection or reporting for changes in runtime semantics.
+
+ Apache-2.0
+ https://github.com/EraYaN/dotnet-compatibility
+ tunnelvisionlabs; EraYaN
+ true
+ AllEnabledByDefault
+ true
+ true
+ true
+ snupkg
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
diff --git a/CompatibilityChecker/ConsoleMessageLogger.cs b/CompatibilityChecker.Library/ConsoleMessageLogger.cs
similarity index 61%
rename from CompatibilityChecker/ConsoleMessageLogger.cs
rename to CompatibilityChecker.Library/ConsoleMessageLogger.cs
index 14dfa21..044ce98 100644
--- a/CompatibilityChecker/ConsoleMessageLogger.cs
+++ b/CompatibilityChecker.Library/ConsoleMessageLogger.cs
@@ -1,8 +1,8 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System;
- internal class ConsoleMessageLogger : IMessageLogger
+ public class ConsoleMessageLogger : IMessageLogger
{
public virtual void Report(Message message)
{
diff --git a/CompatibilityChecker/CustomModifierSignature.cs b/CompatibilityChecker.Library/CustomModifierSignature.cs
similarity index 68%
rename from CompatibilityChecker/CustomModifierSignature.cs
rename to CompatibilityChecker.Library/CustomModifierSignature.cs
index 656bdeb..0f283d2 100644
--- a/CompatibilityChecker/CustomModifierSignature.cs
+++ b/CompatibilityChecker.Library/CustomModifierSignature.cs
@@ -1,21 +1,21 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Reflection.Metadata;
public struct CustomModifierSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public CustomModifierSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public bool IsRequired
{
get
{
- return _reader.ReadSignatureTypeCode() == SignatureTypeCode.RequiredModifier;
+ return reader.ReadSignatureTypeCode() == SignatureTypeCode.RequiredModifier;
}
}
@@ -23,7 +23,7 @@ public Handle TypeHandle
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
reader.ReadSignatureTypeCode();
return reader.ReadTypeHandle();
}
@@ -31,7 +31,7 @@ public Handle TypeHandle
public BlobReader Skip()
{
- var reader = _reader;
+ var reader = this.reader;
reader.ReadSignatureTypeCode();
reader.ReadTypeHandle();
return reader;
diff --git a/CompatibilityChecker.Library/Descriptors/AbstractMustNotBeAddedToType.cs b/CompatibilityChecker.Library/Descriptors/AbstractMustNotBeAddedToType.cs
new file mode 100644
index 0000000..7579fa0
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/AbstractMustNotBeAddedToType.cs
@@ -0,0 +1,28 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ ///
+ /// The sealed modifier must not be added to a publicly-accessible type, unless that type does not have any
+ /// publicly-accessible constructors.
+ ///
+ internal class AbstractMustNotBeAddedToType : CompatibilityDescriptor
+ {
+ private const string Id = nameof(AbstractMustNotBeAddedToType);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "The 'abstract' modifier cannot be added to type '{0}'.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly AbstractMustNotBeAddedToType Instance = new ();
+
+ private AbstractMustNotBeAddedToType()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/AssemblyNameMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/AssemblyNameMustNotBeChanged.cs
new file mode 100644
index 0000000..88c2a4f
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/AssemblyNameMustNotBeChanged.cs
@@ -0,0 +1,33 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection;
+
+ ///
+ /// The simple name of an assembly cannot be changed.
+ ///
+ ///
+ /// The simple name of an assembly corresponds to the value of the
+ /// property.
+ ///
+ internal class AssemblyNameMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(AssemblyNameMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "The simple name of an assembly cannot change for '{0}'.";
+ private static new readonly string Category = Categories.Assembly;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly AssemblyNameMustNotBeChanged Instance = new ();
+
+ private AssemblyNameMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string assemblyName)
+ {
+ return new Message(Instance, assemblyName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/BaseTypeMustNotChange.cs b/CompatibilityChecker.Library/Descriptors/BaseTypeMustNotChange.cs
new file mode 100644
index 0000000..115488c
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/BaseTypeMustNotChange.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Base types cannot be changed. This includes renaming a type or changing the namespace of a type.
+ ///
+ internal class BaseTypeMustNotChange : CompatibilityDescriptor
+ {
+ private const string Id = nameof(BaseTypeMustNotChange);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Base type of '{0}' must not be changed.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly BaseTypeMustNotChange Instance = new ();
+
+ private BaseTypeMustNotChange()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/BaseTypeMustStayInAssembly.cs b/CompatibilityChecker.Library/Descriptors/BaseTypeMustStayInAssembly.cs
new file mode 100644
index 0000000..74d8665
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/BaseTypeMustStayInAssembly.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Base types cannot be moved out of the assembly.
+ ///
+ internal class BaseTypeMustStayInAssembly : CompatibilityDescriptor
+ {
+ private const string Id = nameof(BaseTypeMustStayInAssembly);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Base type of '{0}' must not be moved outside the assembly.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly BaseTypeMustStayInAssembly Instance = new ();
+
+ private BaseTypeMustStayInAssembly()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/Categories.cs b/CompatibilityChecker.Library/Descriptors/Categories.cs
new file mode 100644
index 0000000..77e7411
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/Categories.cs
@@ -0,0 +1,23 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ internal static class Categories
+ {
+ internal const string Assembly = nameof(Assembly);
+
+ internal const string Type = nameof(Type);
+
+ internal const string Method = nameof(Method);
+
+ internal const string Interface = nameof(Interface);
+
+ internal const string Field = nameof(Field);
+
+ internal const string Attribute = nameof(Attribute);
+
+ internal const string Event = nameof(Event);
+
+ internal const string Other = nameof(Other);
+
+ internal const string Property = nameof(Property);
+ }
+}
diff --git a/CompatibilityChecker/Descriptors/CompatibilityDescriptor.cs b/CompatibilityChecker.Library/Descriptors/CompatibilityDescriptor.cs
similarity index 70%
rename from CompatibilityChecker/Descriptors/CompatibilityDescriptor.cs
rename to CompatibilityChecker.Library/Descriptors/CompatibilityDescriptor.cs
index 9bcdbaf..5816857 100644
--- a/CompatibilityChecker/Descriptors/CompatibilityDescriptor.cs
+++ b/CompatibilityChecker.Library/Descriptors/CompatibilityDescriptor.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker.Descriptors
+namespace CompatibilityChecker.Library.Descriptors
{
using System;
@@ -7,13 +7,24 @@ internal abstract class CompatibilityDescriptor
protected CompatibilityDescriptor(string ruleId, string title, string messageFormat, string category, Severity defaultSeverity, string description = null)
{
if (ruleId == null)
- throw new ArgumentNullException("ruleId");
+ {
+ throw new ArgumentNullException(nameof(ruleId));
+ }
+
if (title == null)
- throw new ArgumentNullException("title");
+ {
+ throw new ArgumentNullException(nameof(title));
+ }
+
if (messageFormat == null)
- throw new ArgumentNullException("messageFormat");
+ {
+ throw new ArgumentNullException(nameof(messageFormat));
+ }
+
if (category == null)
- throw new ArgumentNullException("category");
+ {
+ throw new ArgumentNullException(nameof(category));
+ }
RuleId = ruleId;
Title = title;
diff --git a/CompatibilityChecker.Library/Descriptors/EventAdderMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/EventAdderMustNotBeRemoved.cs
new file mode 100644
index 0000000..2dd655e
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventAdderMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible events cannot have their adder removed.
+ ///
+ internal class EventAdderMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventAdderMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event '{0}' cannot have its adder removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventAdderMustNotBeRemoved Instance = new ();
+
+ private EventAdderMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/EventAttributesMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/EventAttributesMustNotBeChanged.cs
new file mode 100644
index 0000000..e72d54f
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventAttributesMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible event attributes cannot be changed or removed.
+ ///
+ internal class EventAttributesMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event attributes of '{0}' were changed or removed.";
+ private static new readonly string Category = Categories.Attribute;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventAttributesMustNotBeChanged Instance = new ();
+
+ private EventAttributesMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/EventMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/EventMustNotBeRemoved.cs
new file mode 100644
index 0000000..f39e0f3
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible events cannot be removed.
+ ///
+ internal class EventMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event '{0}' cannot be removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventMustNotBeRemoved Instance = new ();
+
+ private EventMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/EventRaiserMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/EventRaiserMustNotBeRemoved.cs
new file mode 100644
index 0000000..136aba8
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventRaiserMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible events cannot have their raiser removed.
+ ///
+ internal class EventRaiserMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventRaiserMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event '{0}' cannot have its raiser removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventRaiserMustNotBeRemoved Instance = new ();
+
+ private EventRaiserMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/EventRemoverMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/EventRemoverMustNotBeRemoved.cs
new file mode 100644
index 0000000..f40ac7e
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventRemoverMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible events cannot have their remover removed.
+ ///
+ internal class EventRemoverMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventRemoverMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event '{0}' cannot have its remover removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventRemoverMustNotBeRemoved Instance = new ();
+
+ private EventRemoverMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/EventSignatureMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/EventSignatureMustNotBeChanged.cs
new file mode 100644
index 0000000..ad568c1
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/EventSignatureMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible event signature cannot be changed or removed.
+ ///
+ internal class EventSignatureMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(EventAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible event signature of '{0}' was changed or removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly EventSignatureMustNotBeChanged Instance = new ();
+
+ private EventSignatureMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string eventName)
+ {
+ return new Message(Instance, eventName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/FieldAttributesMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/FieldAttributesMustNotBeChanged.cs
new file mode 100644
index 0000000..cb8bda6
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/FieldAttributesMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible field attributes cannot be changed or removed.
+ ///
+ internal class FieldAttributesMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(FieldAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible field attributes of '{0}' were changed or removed.";
+ private static new readonly string Category = Categories.Attribute;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly FieldAttributesMustNotBeChanged Instance = new ();
+
+ private FieldAttributesMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string fieldName)
+ {
+ return new Message(Instance, fieldName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/FieldMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/FieldMustNotBeChanged.cs
new file mode 100644
index 0000000..6cc7004
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/FieldMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible field cannot be changed or removed.
+ ///
+ internal class FieldMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(FieldMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible field '{0}' was renamed or removed.";
+ private static new readonly string Category = Categories.Field;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly FieldMustNotBeChanged Instance = new ();
+
+ private FieldMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string fieldName)
+ {
+ return new Message(Instance, fieldName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/ImplementedInterfaceMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/ImplementedInterfaceMustNotBeRemoved.cs
new file mode 100644
index 0000000..76bca83
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/ImplementedInterfaceMustNotBeRemoved.cs
@@ -0,0 +1,31 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Implemented interfaces cannot be removed. This includes renaming an interface.
+ ///
+ internal class ImplementedInterfaceMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(ImplementedInterfaceMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Implemented interface '{1}' cannot be removed from '{0}'.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly ImplementedInterfaceMustNotBeRemoved Instance = new ();
+
+ private ImplementedInterfaceMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName, string interfaceName)
+ {
+
+ return new Message(Instance, typeName, interfaceName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/MethodAttributesMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/MethodAttributesMustNotBeChanged.cs
new file mode 100644
index 0000000..1d0346d
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/MethodAttributesMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible method attributes cannot be changed or removed.
+ ///
+ internal class MethodAttributesMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(MethodAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible method attributes '{0}' were renamed or removed.";
+ private static new readonly string Category = Categories.Attribute;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly MethodAttributesMustNotBeChanged Instance = new ();
+
+ private MethodAttributesMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string methodName)
+ {
+ return new Message(Instance, methodName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/MethodMustNotBeAddedToInterface.cs b/CompatibilityChecker.Library/Descriptors/MethodMustNotBeAddedToInterface.cs
new file mode 100644
index 0000000..cc077e3
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/MethodMustNotBeAddedToInterface.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Methods should not be added to interfaces.
+ ///
+ internal class MethodMustNotBeAddedToInterface : CompatibilityDescriptor
+ {
+ private const string Id = nameof(MethodMustNotBeAddedToInterface);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Method '{1}' was added to interface '{0}'.";
+ private static new readonly string Category = Categories.Interface;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly MethodMustNotBeAddedToInterface Instance = new ();
+
+ private MethodMustNotBeAddedToInterface()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string interfaceName, string methodName)
+ {
+ return new Message(Instance, interfaceName, methodName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/MethodMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/MethodMustNotBeChanged.cs
new file mode 100644
index 0000000..8638f9b
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/MethodMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible method cannot be changed or removed.
+ ///
+ internal class MethodMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(MethodMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible method '{0}' was changed or removed.";
+ private static new readonly string Category = Categories.Method;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly MethodMustNotBeChanged Instance = new ();
+
+ private MethodMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string methodName)
+ {
+ return new Message(Instance, methodName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/OtherError.cs b/CompatibilityChecker.Library/Descriptors/OtherError.cs
new file mode 100644
index 0000000..45747c5
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/OtherError.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// OtherError catch-all class
+ ///
+ internal class OtherError : CompatibilityDescriptor
+ {
+ private const string Id = nameof(OtherError);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+
+ private static new readonly string MessageFormat = "Other error occured. {0}";
+ private static new readonly string Category = Categories.Other;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly OtherError Instance = new ();
+
+ private OtherError()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string error)
+ {
+ return new Message(Instance, error);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PropertyAttributesMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/PropertyAttributesMustNotBeChanged.cs
new file mode 100644
index 0000000..adf7959
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PropertyAttributesMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible property attributes cannot be changed or removed.
+ ///
+ internal class PropertyAttributesMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PropertyAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible property attributes of '{0}' were changed or removed.";
+ private static new readonly string Category = Categories.Attribute;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PropertyAttributesMustNotBeChanged Instance = new ();
+
+ private PropertyAttributesMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string propertyName)
+ {
+ return new Message(Instance, propertyName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PropertyGetterMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/PropertyGetterMustNotBeRemoved.cs
new file mode 100644
index 0000000..21d693b
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PropertyGetterMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible property getter cannot be removed.
+ ///
+ internal class PropertyGetterMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PropertyGetterMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible property getter '{0}' cannot be removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PropertyGetterMustNotBeRemoved Instance = new ();
+
+ private PropertyGetterMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string name)
+ {
+ return new Message(Instance, name);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PropertyMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/PropertyMustNotBeChanged.cs
new file mode 100644
index 0000000..468664e
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PropertyMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible property cannot be changed or removed.
+ ///
+ internal class PropertyMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PropertyMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible property '{0}' was renamed or removed.";
+ private static new readonly string Category = Categories.Property;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PropertyMustNotBeChanged Instance = new ();
+
+ private PropertyMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string propertyName)
+ {
+ return new Message(Instance, propertyName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PropertySetterMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/PropertySetterMustNotBeRemoved.cs
new file mode 100644
index 0000000..1305d24
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PropertySetterMustNotBeRemoved.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible property setter cannot be removed.
+ ///
+ internal class PropertySetterMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PropertySetterMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible property setter '{0}' cannot be removed.";
+ private static new readonly string Category = Categories.Event;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PropertySetterMustNotBeRemoved Instance = new ();
+
+ private PropertySetterMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string name)
+ {
+ return new Message(Instance, name);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PropertySignatureMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/PropertySignatureMustNotBeChanged.cs
new file mode 100644
index 0000000..303ed56
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PropertySignatureMustNotBeChanged.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Signature of publicly-accessible property cannot be changed or removed.
+ ///
+ internal class PropertySignatureMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PropertySignatureMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Signature of publicly-accessible property '{0}' was renamed or removed.";
+ private static new readonly string Category = Categories.Property;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PropertySignatureMustNotBeChanged Instance = new ();
+
+ private PropertySignatureMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string propertyName)
+ {
+ return new Message(Instance, propertyName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/PublicAttributesMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/PublicAttributesMustNotBeChanged.cs
new file mode 100644
index 0000000..c502cfa
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/PublicAttributesMustNotBeChanged.cs
@@ -0,0 +1,27 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ ///
+ /// Attributes of publicly-accessible types must not be changed.
+ ///
+ internal class PublicAttributesMustNotBeChanged : CompatibilityDescriptor
+ {
+ private const string Id = nameof(PublicAttributesMustNotBeChanged);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Attributes of publicly visible type '{0}' changed.";
+ private static new readonly string Category = Categories.Attribute;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly PublicAttributesMustNotBeChanged Instance = new ();
+
+ private PublicAttributesMustNotBeChanged()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker/Descriptors/PublicKeyMustNotBeChanged.cs b/CompatibilityChecker.Library/Descriptors/PublicKeyMustNotBeChanged.cs
similarity index 52%
rename from CompatibilityChecker/Descriptors/PublicKeyMustNotBeChanged.cs
rename to CompatibilityChecker.Library/Descriptors/PublicKeyMustNotBeChanged.cs
index b5759d0..66b5bee 100644
--- a/CompatibilityChecker/Descriptors/PublicKeyMustNotBeChanged.cs
+++ b/CompatibilityChecker.Library/Descriptors/PublicKeyMustNotBeChanged.cs
@@ -1,6 +1,5 @@
-namespace CompatibilityChecker.Descriptors
+namespace CompatibilityChecker.Library.Descriptors
{
- using System;
using System.Reflection;
///
@@ -15,22 +14,22 @@
internal class PublicKeyMustNotBeChanged : CompatibilityDescriptor
{
private const string Id = nameof(PublicKeyMustNotBeChanged);
- private static readonly string _title = TitleHelper.GenerateTitle(Id);
- private static readonly string _messageFormat = "The public key of a strong-named assembly cannot change.";
- private static readonly string _category = Categories.Assembly;
- private static readonly Severity _defaultSeverity = Severity.Error;
- private static readonly string _description = null;
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "The public key of a strong-named assembly '{0}' cannot change.";
+ private static new readonly string Category = Categories.Assembly;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
- private static readonly PublicKeyMustNotBeChanged Instance = new PublicKeyMustNotBeChanged();
+ private static readonly PublicKeyMustNotBeChanged Instance = new ();
private PublicKeyMustNotBeChanged()
- : base(Id, _title, _messageFormat, _category, _defaultSeverity, _description)
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
{
}
- internal static Message CreateMessage()
+ internal static Message CreateMessage(string assemblyName)
{
- return new Message(Instance);
+ return new Message(Instance, assemblyName);
}
}
}
diff --git a/CompatibilityChecker.Library/Descriptors/ResolutionScopeAssemblyReferenceMustNotChange.cs b/CompatibilityChecker.Library/Descriptors/ResolutionScopeAssemblyReferenceMustNotChange.cs
new file mode 100644
index 0000000..f9f201f
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/ResolutionScopeAssemblyReferenceMustNotChange.cs
@@ -0,0 +1,30 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Resolution scope assembly references cannot be changed.
+ ///
+ internal class ResolutionScopeAssemblyReferenceMustNotChange : CompatibilityDescriptor
+ {
+ private const string Id = nameof(ResolutionScopeAssemblyReferenceMustNotChange);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Resolution scope assembly reference for '{0}' must not be changed.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly ResolutionScopeAssemblyReferenceMustNotChange Instance = new ();
+
+ private ResolutionScopeAssemblyReferenceMustNotChange()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string assemblyName)
+ {
+ return new Message(Instance, assemblyName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/SealedMustNotBeAddedToType.cs b/CompatibilityChecker.Library/Descriptors/SealedMustNotBeAddedToType.cs
new file mode 100644
index 0000000..e951aa5
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/SealedMustNotBeAddedToType.cs
@@ -0,0 +1,28 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ ///
+ /// The sealed modifier must not be added to a publicly-accessible type, unless that type does not have any
+ /// publicly-accessible constructors.
+ ///
+ internal class SealedMustNotBeAddedToType : CompatibilityDescriptor
+ {
+ private const string Id = nameof(SealedMustNotBeAddedToType);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "The 'sealed' modifier cannot be added to type '{0}'.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly SealedMustNotBeAddedToType Instance = new ();
+
+ private SealedMustNotBeAddedToType()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker/Descriptors/TitleHelper.cs b/CompatibilityChecker.Library/Descriptors/TitleHelper.cs
similarity index 84%
rename from CompatibilityChecker/Descriptors/TitleHelper.cs
rename to CompatibilityChecker.Library/Descriptors/TitleHelper.cs
index 29ffe72..24a42d5 100644
--- a/CompatibilityChecker/Descriptors/TitleHelper.cs
+++ b/CompatibilityChecker.Library/Descriptors/TitleHelper.cs
@@ -1,13 +1,12 @@
-namespace CompatibilityChecker.Descriptors
+namespace CompatibilityChecker.Library.Descriptors
{
- using System;
using System.Text;
internal static class TitleHelper
{
internal static string GenerateTitle(string ruleId)
{
- StringBuilder builder = new StringBuilder();
+ StringBuilder builder = new ();
foreach (char c in ruleId)
{
if (builder.Length == 0)
diff --git a/CompatibilityChecker.Library/Descriptors/TypeMustNotBeMadePreliminaryFromStable.cs b/CompatibilityChecker.Library/Descriptors/TypeMustNotBeMadePreliminaryFromStable.cs
new file mode 100644
index 0000000..abb0806
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/TypeMustNotBeMadePreliminaryFromStable.cs
@@ -0,0 +1,27 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ ///
+ /// Publicly-accessible types cannot be changed from stable to preliminary.
+ ///
+ internal class TypeMustNotBeMadePreliminaryFromStable : CompatibilityDescriptor
+ {
+ private const string Id = nameof(TypeMustNotBeMadePreliminaryFromStable);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly visible type '{0}' changed from stable to preliminary.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly TypeMustNotBeMadePreliminaryFromStable Instance = new ();
+
+ private TypeMustNotBeMadePreliminaryFromStable()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/Descriptors/TypeMustNotBeRemoved.cs b/CompatibilityChecker.Library/Descriptors/TypeMustNotBeRemoved.cs
new file mode 100644
index 0000000..1f11273
--- /dev/null
+++ b/CompatibilityChecker.Library/Descriptors/TypeMustNotBeRemoved.cs
@@ -0,0 +1,32 @@
+namespace CompatibilityChecker.Library.Descriptors
+{
+ using System.Reflection.Metadata;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Publicly-accessible types cannot be removed. This includes renaming a type or changing the namespace of a type.
+ /// An exception to this rule applies for moving a type to another assembly, provided a
+ /// attribute is applied to the original assembly.
+ ///
+ internal class TypeMustNotBeRemoved : CompatibilityDescriptor
+ {
+ private const string Id = nameof(TypeMustNotBeRemoved);
+ private static new readonly string Title = TitleHelper.GenerateTitle(Id);
+ private static new readonly string MessageFormat = "Publicly-accessible type '{0}' cannot be removed.";
+ private static new readonly string Category = Categories.Type;
+ private static new readonly Severity DefaultSeverity = Severity.Error;
+ private static new readonly string Description = null;
+
+ private static readonly TypeMustNotBeRemoved Instance = new ();
+
+ private TypeMustNotBeRemoved()
+ : base(Id, Title, MessageFormat, Category, DefaultSeverity, Description)
+ {
+ }
+
+ internal static Message CreateMessage(string typeName)
+ {
+ return new Message(Instance, typeName);
+ }
+ }
+}
diff --git a/CompatibilityChecker/FieldSignature.cs b/CompatibilityChecker.Library/FieldSignature.cs
similarity index 82%
rename from CompatibilityChecker/FieldSignature.cs
rename to CompatibilityChecker.Library/FieldSignature.cs
index 9ee2bc4..f45a180 100644
--- a/CompatibilityChecker/FieldSignature.cs
+++ b/CompatibilityChecker.Library/FieldSignature.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System;
using System.Collections.Immutable;
@@ -6,21 +6,23 @@
public struct FieldSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public FieldSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public ImmutableArray CustomModifiers
{
get
{
- var reader = _reader;
+ var reader = this.reader;
var header = reader.ReadSignatureHeader();
if (header.Kind != SignatureKind.Field)
+ {
throw new InvalidOperationException("Expected a field signature.");
+ }
var builder = ImmutableArray.CreateBuilder();
while (reader.IsCustomModifier())
@@ -38,11 +40,13 @@ public TypeSignature Type
{
get
{
- var reader = _reader;
+ var reader = this.reader;
reader.ReadSignatureHeader();
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
return new TypeSignature(reader);
}
diff --git a/CompatibilityChecker/IMessageLogger.cs b/CompatibilityChecker.Library/IMessageLogger.cs
similarity index 68%
rename from CompatibilityChecker/IMessageLogger.cs
rename to CompatibilityChecker.Library/IMessageLogger.cs
index ebb5355..2ff0d6e 100644
--- a/CompatibilityChecker/IMessageLogger.cs
+++ b/CompatibilityChecker.Library/IMessageLogger.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
public interface IMessageLogger
{
diff --git a/CompatibilityChecker.Library/IMessageReporter.cs b/CompatibilityChecker.Library/IMessageReporter.cs
new file mode 100644
index 0000000..d57c034
--- /dev/null
+++ b/CompatibilityChecker.Library/IMessageReporter.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace CompatibilityChecker.Library
+{
+ public interface IMessageReporter
+ {
+ IEnumerable ReportedMessages { get; }
+
+ IReportStatistics Statistics { get; }
+
+ void Report(Message message);
+ }
+}
diff --git a/CompatibilityChecker.Library/IReportStatistics.cs b/CompatibilityChecker.Library/IReportStatistics.cs
new file mode 100644
index 0000000..5e6cb70
--- /dev/null
+++ b/CompatibilityChecker.Library/IReportStatistics.cs
@@ -0,0 +1,7 @@
+namespace CompatibilityChecker.Library
+{
+ public interface IReportStatistics
+ {
+ (int error, int warning, int information, int disabled) SeverityCounts { get; }
+ }
+}
\ No newline at end of file
diff --git a/CompatibilityChecker/Mapping`1.cs b/CompatibilityChecker.Library/Mapping.cs
similarity index 94%
rename from CompatibilityChecker/Mapping`1.cs
rename to CompatibilityChecker.Library/Mapping.cs
index 3a610de..89f1d55 100644
--- a/CompatibilityChecker/Mapping`1.cs
+++ b/CompatibilityChecker.Library/Mapping.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Collections.Immutable;
using System.Reflection.Metadata;
@@ -56,7 +56,9 @@ public static explicit operator Mapping(Mapping mapping)
{
var builder = ImmutableArray.CreateBuilder(mapping.CandidateTargets.Length);
foreach (var handle in mapping.CandidateTargets)
+ {
builder.Add(ConvertToHandle(handle));
+ }
}
}
@@ -79,7 +81,9 @@ public static explicit operator Mapping(Mapping mapping)
{
var builder = ImmutableArray.CreateBuilder(mapping.CandidateTargets.Length);
foreach (var handle in mapping.CandidateTargets)
+ {
builder.Add(ConvertToHandle(handle));
+ }
}
}
@@ -89,7 +93,9 @@ public static explicit operator Mapping(Mapping mapping)
private static Handle ConvertToHandle(dynamic handle)
{
if (handle.IsNil)
+ {
return default(Handle);
+ }
return (Handle)handle;
}
@@ -97,7 +103,9 @@ private static Handle ConvertToHandle(dynamic handle)
private static T ConvertToHandle(dynamic handle)
{
if (handle.IsNil)
+ {
return default(T);
+ }
return (T)handle;
}
diff --git a/CompatibilityChecker.Library/Message.cs b/CompatibilityChecker.Library/Message.cs
new file mode 100644
index 0000000..328a49e
--- /dev/null
+++ b/CompatibilityChecker.Library/Message.cs
@@ -0,0 +1,24 @@
+namespace CompatibilityChecker.Library
+{
+ using CompatibilityChecker.Library.Descriptors;
+
+ public class Message
+ {
+ private readonly CompatibilityDescriptor descriptor;
+ private readonly object[] arguments;
+
+ internal Message(CompatibilityDescriptor descriptor, params object[] arguments)
+ {
+ this.descriptor = descriptor;
+ this.arguments = arguments;
+ }
+
+ internal Severity Severity => descriptor.DefaultSeverity;
+
+ public override string ToString()
+ {
+ string message = string.Format(descriptor.MessageFormat, arguments);
+ return string.Format("{0} {1}: {2}", descriptor.DefaultSeverity, descriptor.RuleId, message);
+ }
+ }
+}
diff --git a/CompatibilityChecker.Library/MetadataMapping.cs b/CompatibilityChecker.Library/MetadataMapping.cs
new file mode 100644
index 0000000..8988f37
--- /dev/null
+++ b/CompatibilityChecker.Library/MetadataMapping.cs
@@ -0,0 +1,904 @@
+namespace CompatibilityChecker.Library
+{
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.Immutable;
+ using System.Linq;
+ using System.Reflection.Metadata;
+
+ internal class MetadataMapping
+ {
+ private readonly MetadataReader sourceMetadata;
+ private readonly MetadataReader targetMetadata;
+
+ private readonly ConcurrentDictionary> assemblyDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> assemblyFiles =
+ new ();
+
+ private readonly ConcurrentDictionary> assemblyReferences =
+ new ();
+
+ private readonly ConcurrentDictionary> constants =
+ new ();
+
+ private readonly ConcurrentDictionary> customAttributes =
+ new ();
+
+ private readonly ConcurrentDictionary> declarativeSecurityAttributes =
+ new ();
+
+ private readonly ConcurrentDictionary> eventDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> exportedTypes =
+ new ();
+
+ private readonly ConcurrentDictionary> fieldDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> genericParameters =
+ new ();
+
+ private readonly ConcurrentDictionary> genericParameterConstraints =
+ new ();
+
+ private readonly ConcurrentDictionary> interfaceImplementations =
+ new ();
+
+ private readonly ConcurrentDictionary> manifestResources =
+ new ();
+
+ private readonly ConcurrentDictionary> memberReferences =
+ new ();
+
+ private readonly ConcurrentDictionary> methodDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> methodImplementations =
+ new ();
+
+ private readonly ConcurrentDictionary> methodSpecifications =
+ new ();
+
+ private readonly ConcurrentDictionary> moduleDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> moduleReferences =
+ new ();
+
+ private readonly ConcurrentDictionary> namespaceDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> parameters =
+ new ();
+
+ private readonly ConcurrentDictionary> propertyDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> standaloneSignatures =
+ new ();
+
+ private readonly ConcurrentDictionary> typeDefinitions =
+ new ();
+
+ private readonly ConcurrentDictionary> typeReferences =
+ new ();
+
+ private readonly ConcurrentDictionary> typeSpecifications =
+ new ();
+
+ public MetadataMapping(MetadataReader sourceMetadata, MetadataReader targetMetadata)
+ {
+ if (sourceMetadata == null)
+ {
+ throw new ArgumentNullException(nameof(sourceMetadata));
+ }
+
+ if (targetMetadata == null)
+ {
+ throw new ArgumentNullException(nameof(targetMetadata));
+ }
+
+ this.sourceMetadata = sourceMetadata;
+ this.targetMetadata = targetMetadata;
+ }
+
+ public Mapping MapHandle(Handle handle)
+ {
+ if (handle.IsNil)
+ {
+ return new Mapping();
+ }
+
+ switch (handle.Kind)
+ {
+ case HandleKind.ModuleDefinition:
+ return (Mapping)MapModuleDefinition((ModuleDefinitionHandle)handle);
+
+ case HandleKind.TypeReference:
+ return (Mapping)MapTypeReference((TypeReferenceHandle)handle);
+
+ case HandleKind.TypeDefinition:
+ return (Mapping)MapTypeDefinition((TypeDefinitionHandle)handle);
+
+ case HandleKind.FieldDefinition:
+ return (Mapping)MapFieldDefinition((FieldDefinitionHandle)handle);
+
+ case HandleKind.MethodDefinition:
+ return (Mapping)MapMethodDefinition((MethodDefinitionHandle)handle);
+
+ case HandleKind.Parameter:
+ return (Mapping)MapParameter((ParameterHandle)handle);
+
+ case HandleKind.InterfaceImplementation:
+ return (Mapping)MapInterfaceImplementation((InterfaceImplementationHandle)handle);
+
+ case HandleKind.MemberReference:
+ return (Mapping)MapMemberReference((MemberReferenceHandle)handle);
+
+ case HandleKind.Constant:
+ return (Mapping)MapConstant((ConstantHandle)handle);
+
+ case HandleKind.CustomAttribute:
+ return (Mapping)MapCustomAttribute((CustomAttributeHandle)handle);
+
+ case HandleKind.DeclarativeSecurityAttribute:
+ return (Mapping)MapDeclarativeSecurityAttribute((DeclarativeSecurityAttributeHandle)handle);
+
+ case HandleKind.StandaloneSignature:
+ return (Mapping)MapStandaloneSignature((StandaloneSignatureHandle)handle);
+
+ case HandleKind.EventDefinition:
+ return (Mapping)MapEventDefinition((EventDefinitionHandle)handle);
+
+ case HandleKind.PropertyDefinition:
+ return (Mapping)MapPropertyDefinition((PropertyDefinitionHandle)handle);
+
+ case HandleKind.MethodImplementation:
+ return (Mapping)MapMethodImplementation((MethodImplementationHandle)handle);
+
+ case HandleKind.ModuleReference:
+ return (Mapping)MapModuleReference((ModuleReferenceHandle)handle);
+
+ case HandleKind.TypeSpecification:
+ return (Mapping)MapTypeSpecification((TypeSpecificationHandle)handle);
+
+ case HandleKind.AssemblyDefinition:
+ return (Mapping)MapAssemblyDefinition((AssemblyDefinitionHandle)handle);
+
+ case HandleKind.AssemblyFile:
+ return (Mapping)MapAssemblyFile((AssemblyFileHandle)handle);
+
+ case HandleKind.AssemblyReference:
+ return (Mapping)MapAssemblyReference((AssemblyReferenceHandle)handle);
+
+ case HandleKind.ExportedType:
+ return (Mapping)MapExportedType((ExportedTypeHandle)handle);
+
+ case HandleKind.GenericParameter:
+ return (Mapping)MapGenericParameter((GenericParameterHandle)handle);
+
+ case HandleKind.MethodSpecification:
+ return (Mapping)MapMethodSpecification((MethodSpecificationHandle)handle);
+
+ case HandleKind.GenericParameterConstraint:
+ return (Mapping)MapGenericParameterConstraint((GenericParameterConstraintHandle)handle);
+
+ case HandleKind.ManifestResource:
+ return (Mapping)MapManifestResource((ManifestResourceHandle)handle);
+
+ case HandleKind.NamespaceDefinition:
+ return (Mapping)MapNamespaceDefinition((NamespaceDefinitionHandle)handle);
+
+ default:
+ throw new NotSupportedException(string.Format("Mapping '{0}' handles between assemblies is not supported.", handle.Kind));
+ }
+ }
+
+ public Mapping MapAssemblyDefinition(AssemblyDefinitionHandle handle)
+ {
+ return assemblyDefinitions.GetOrAdd(handle, MapAssemblyDefinitionImpl);
+ }
+
+ public Mapping MapAssemblyFile(AssemblyFileHandle handle)
+ {
+ return assemblyFiles.GetOrAdd(handle, MapAssemblyFileImpl);
+ }
+
+ public Mapping MapAssemblyReference(AssemblyReferenceHandle handle)
+ {
+ return assemblyReferences.GetOrAdd(handle, MapAssemblyReferenceImpl);
+ }
+
+ public Mapping MapConstant(ConstantHandle handle)
+ {
+ return constants.GetOrAdd(handle, MapConstantImpl);
+ }
+
+ public Mapping MapCustomAttribute(CustomAttributeHandle handle)
+ {
+ return customAttributes.GetOrAdd(handle, MapCustomAttributeImpl);
+ }
+
+ public Mapping MapDeclarativeSecurityAttribute(DeclarativeSecurityAttributeHandle handle)
+ {
+ return declarativeSecurityAttributes.GetOrAdd(handle, MapDeclarativeSecurityAttributeImpl);
+ }
+
+ public Mapping MapEventDefinition(EventDefinitionHandle handle)
+ {
+ return eventDefinitions.GetOrAdd(handle, MapEventDefinitionImpl);
+ }
+
+ public Mapping MapExportedType(ExportedTypeHandle handle)
+ {
+ return exportedTypes.GetOrAdd(handle, MapExportedTypeImpl);
+ }
+
+ public Mapping MapFieldDefinition(FieldDefinitionHandle handle)
+ {
+ return fieldDefinitions.GetOrAdd(handle, MapFieldDefinitionImpl);
+ }
+
+ public Mapping MapGenericParameter(GenericParameterHandle handle)
+ {
+ return genericParameters.GetOrAdd(handle, MapGenericParameterImpl);
+ }
+
+ public Mapping MapGenericParameterConstraint(GenericParameterConstraintHandle handle)
+ {
+ return genericParameterConstraints.GetOrAdd(handle, MapGenericParameterConstraintImpl);
+ }
+
+ public Mapping MapInterfaceImplementation(InterfaceImplementationHandle handle)
+ {
+ return interfaceImplementations.GetOrAdd(handle, MapInterfaceImplementationImpl);
+ }
+
+ public Mapping MapManifestResource(ManifestResourceHandle handle)
+ {
+ return manifestResources.GetOrAdd(handle, MapManifestResourceImpl);
+ }
+
+ public Mapping MapMemberReference(MemberReferenceHandle handle)
+ {
+ return memberReferences.GetOrAdd(handle, MapMemberReferenceImpl);
+ }
+
+ public Mapping MapMethodDefinition(MethodDefinitionHandle handle)
+ {
+ return methodDefinitions.GetOrAdd(handle, MapMethodDefinitionImpl);
+ }
+
+ public Mapping MapMethodImplementation(MethodImplementationHandle handle)
+ {
+ return methodImplementations.GetOrAdd(handle, MapMethodImplementationImpl);
+ }
+
+ public Mapping MapMethodSpecification(MethodSpecificationHandle handle)
+ {
+ return methodSpecifications.GetOrAdd(handle, MapMethodSpecificationImpl);
+ }
+
+ public Mapping MapModuleDefinition(ModuleDefinitionHandle handle)
+ {
+ return moduleDefinitions.GetOrAdd(handle, MapModuleDefinitionImpl);
+ }
+
+ public Mapping MapModuleReference(ModuleReferenceHandle handle)
+ {
+ return moduleReferences.GetOrAdd(handle, MapModuleReferenceImpl);
+ }
+
+ public Mapping MapNamespaceDefinition(NamespaceDefinitionHandle handle)
+ {
+ return namespaceDefinitions.GetOrAdd(handle, MapNamespaceDefinitionImpl);
+ }
+
+ public Mapping MapParameter(ParameterHandle handle)
+ {
+ return parameters.GetOrAdd(handle, MapParameterImpl);
+ }
+
+ public Mapping MapPropertyDefinition(PropertyDefinitionHandle handle)
+ {
+ return propertyDefinitions.GetOrAdd(handle, MapPropertyDefinitionImpl);
+ }
+
+ public Mapping MapStandaloneSignature(StandaloneSignatureHandle handle)
+ {
+ return standaloneSignatures.GetOrAdd(handle, MapStandaloneSignatureImpl);
+ }
+
+ public Mapping MapTypeDefinition(TypeDefinitionHandle handle)
+ {
+ return typeDefinitions.GetOrAdd(handle, MapTypeDefinitionImpl);
+ }
+
+ public Mapping MapTypeReference(TypeReferenceHandle handle)
+ {
+ return typeReferences.GetOrAdd(handle, MapTypeReferenceImpl);
+ }
+
+ public Mapping MapTypeSpecification(TypeSpecificationHandle handle)
+ {
+ return typeSpecifications.GetOrAdd(handle, MapTypeSpecificationImpl);
+ }
+
+ private Mapping MapAssemblyDefinitionImpl(AssemblyDefinitionHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapAssemblyFileImpl(AssemblyFileHandle handle)
+ {
+ AssemblyFile assemblyFile = sourceMetadata.GetAssemblyFile(handle);
+ string name = sourceMetadata.GetString(assemblyFile.Name);
+ foreach (var targetHandle in targetMetadata.AssemblyFiles)
+ {
+ AssemblyFile target = targetMetadata.GetAssemblyFile(targetHandle);
+ if (!targetMetadata.StringComparer.Equals(target.Name, name))
+ {
+ continue;
+ }
+
+ return new Mapping(targetHandle);
+ }
+
+ return new Mapping();
+ }
+
+ private Mapping MapAssemblyReferenceImpl(AssemblyReferenceHandle handle)
+ {
+ AssemblyReference assemblyReference = sourceMetadata.GetAssemblyReference(handle);
+ string name = sourceMetadata.GetString(assemblyReference.Name);
+ string culture = sourceMetadata.GetString(assemblyReference.Culture);
+ ImmutableArray publicKeyOrToken = sourceMetadata.GetBlobContent(assemblyReference.PublicKeyOrToken);
+ foreach (var targetHandle in targetMetadata.AssemblyReferences)
+ {
+ AssemblyReference target = targetMetadata.GetAssemblyReference(targetHandle);
+ if (!targetMetadata.StringComparer.Equals(target.Name, name))
+ {
+ continue;
+ }
+
+ if (!targetMetadata.StringComparer.Equals(target.Culture, culture))
+ {
+ continue;
+ }
+
+ if (!publicKeyOrToken.IsDefaultOrEmpty)
+ {
+ if (target.Version != assemblyReference.Version)
+ {
+ continue;
+ }
+
+ ImmutableArray targetPublicKeyOrToken = targetMetadata.GetBlobContent(target.PublicKeyOrToken);
+ if (!targetPublicKeyOrToken.SequenceEqual(targetPublicKeyOrToken))
+ {
+ continue;
+ }
+ }
+
+ return new Mapping(targetHandle);
+ }
+
+ return new Mapping();
+ }
+
+ private Mapping MapConstantImpl(ConstantHandle handle)
+ {
+ Constant constant = sourceMetadata.GetConstant(handle);
+ Mapping parent = MapHandle(constant.Parent);
+ if (parent.Target.IsNil)
+ {
+ return new Mapping();
+ }
+
+ ConstantHandle targetHandle;
+ switch (parent.Target.Kind)
+ {
+ case HandleKind.Parameter:
+ Parameter targetParameter = targetMetadata.GetParameter((ParameterHandle)parent.Target);
+ targetHandle = targetParameter.GetDefaultValue();
+ break;
+
+ case HandleKind.FieldDefinition:
+ FieldDefinition targetFieldDefinition = targetMetadata.GetFieldDefinition((FieldDefinitionHandle)parent.Target);
+ targetHandle = targetFieldDefinition.GetDefaultValue();
+ break;
+
+ case HandleKind.PropertyDefinition:
+ PropertyDefinition targetPropertyDefinition = targetMetadata.GetPropertyDefinition((PropertyDefinitionHandle)parent.Target);
+ targetHandle = targetPropertyDefinition.GetDefaultValue();
+ break;
+
+ default:
+ throw new InvalidOperationException();
+ }
+
+ if (targetHandle.IsNil)
+ {
+ return new Mapping();
+ }
+
+ Constant targetConstant = targetMetadata.GetConstant(targetHandle);
+ if (constant.TypeCode != targetConstant.TypeCode)
+ {
+ var candidateTargets = ImmutableArray.Create(targetHandle);
+ var candidateReasons = ImmutableArray.Create("Mapped constant has a different type.");
+ return new Mapping(candidateTargets, candidateReasons);
+ }
+
+ ImmutableArray sourceContent = sourceMetadata.GetBlobContent(constant.Value);
+ ImmutableArray targetContent = targetMetadata.GetBlobContent(targetConstant.Value);
+ if (!sourceContent.SequenceEqual(targetContent))
+ {
+ var candidateTargets = ImmutableArray.Create(targetHandle);
+ var candidateReasons = ImmutableArray.Create("Mapped constant has a different value.");
+ return new Mapping(candidateTargets, candidateReasons);
+ }
+
+ return new Mapping(targetHandle);
+ }
+
+ private Mapping MapCustomAttributeImpl(CustomAttributeHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapDeclarativeSecurityAttributeImpl(DeclarativeSecurityAttributeHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapEventDefinitionImpl(EventDefinitionHandle handle)
+ {
+ EventDefinition eventDefinition = sourceMetadata.GetEventDefinition(handle);
+ EventAccessors accessors = eventDefinition.GetAccessors();
+
+ // events always have an adder method, so use that to find the declaring type
+ MethodDefinition adderMethodDefinition = sourceMetadata.GetMethodDefinition(accessors.Adder);
+ Mapping declaringTypeMapping = MapTypeDefinition(adderMethodDefinition.GetDeclaringType());
+ if (declaringTypeMapping.Target.IsNil)
+ {
+ return new Mapping();
+ }
+
+ // Make sure each of the accessors maps successfully. Only the raiser is optional.
+ Mapping adderMethodDefinitionMapping = MapMethodDefinition(accessors.Adder);
+ if (adderMethodDefinitionMapping.Target.IsNil)
+ {
+ return new Mapping();
+ }
+
+ Mapping removerMethodDefinitionMapping = MapMethodDefinition(accessors.Remover);
+ if (removerMethodDefinitionMapping.Target.IsNil)
+ {
+ return new Mapping();
+ }
+
+ Mapping raiserMethodDefinitionMapping = default(Mapping);
+ if (!accessors.Raiser.IsNil)
+ {
+ raiserMethodDefinitionMapping = MapMethodDefinition(accessors.Raiser);
+ if (raiserMethodDefinitionMapping.Target.IsNil)
+ {
+ return new Mapping();
+ }
+ }
+
+ // locate the target event by name
+ string eventName = sourceMetadata.GetString(eventDefinition.Name);
+ EventDefinitionHandle targetEventDefinitionHandle = default(EventDefinitionHandle);
+ EventDefinition targetEventDefinition = default(EventDefinition);
+ foreach (var targetHandle in targetMetadata.EventDefinitions)
+ {
+ targetEventDefinition = targetMetadata.GetEventDefinition(targetHandle);
+ MethodDefinition targetAdderMethodDefinition = targetMetadata.GetMethodDefinition(targetEventDefinition.GetAccessors().Adder);
+ if (targetAdderMethodDefinition.GetDeclaringType() != declaringTypeMapping.Target)
+ {
+ continue;
+ }
+
+ if (!targetMetadata.StringComparer.Equals(targetEventDefinition.Name, eventName))
+ {
+ continue;
+ }
+
+ targetEventDefinitionHandle = targetHandle;
+ break;
+ }
+
+ if (targetEventDefinitionHandle.IsNil)
+ {
+ return new Mapping();
+ }
+
+ EventAccessors targetAccessors = targetEventDefinition.GetAccessors();
+ if (targetAccessors.Adder != adderMethodDefinitionMapping.Target)
+ {
+ return new Mapping();
+ }
+
+ if (targetAccessors.Remover != removerMethodDefinitionMapping.Target)
+ {
+ return new Mapping();
+ }
+
+ if (!accessors.Raiser.IsNil)
+ {
+ if (targetAccessors.Raiser != raiserMethodDefinitionMapping.Target)
+ {
+ return new Mapping();
+ }
+ }
+
+ return new Mapping(targetEventDefinitionHandle);
+ }
+
+ private Mapping MapExportedTypeImpl(ExportedTypeHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapFieldDefinitionImpl(FieldDefinitionHandle handle)
+ {
+ FieldDefinition fieldDefinition = sourceMetadata.GetFieldDefinition(handle);
+
+ // Map the parent
+ Mapping declaringTypeMapping = MapTypeDefinition(fieldDefinition.GetDeclaringType());
+ if (declaringTypeMapping.Target.IsNil)
+ {
+ return new Mapping();
+ }
+
+ string fieldName = sourceMetadata.GetString(fieldDefinition.Name);
+
+ TypeDefinition targetDeclaringType = targetMetadata.GetTypeDefinition(declaringTypeMapping.Target);
+ foreach (var targetHandle in targetDeclaringType.GetFields())
+ {
+ var targetField = targetMetadata.GetFieldDefinition(targetHandle);
+ if (!targetMetadata.StringComparer.Equals(targetField.Name, fieldName))
+ {
+ continue;
+ }
+
+ // The name matches. If the signature matches, return in Target; otherwise, return in CandidateTargets.
+ FieldSignature sourceSignature = sourceMetadata.GetSignature(fieldDefinition);
+ FieldSignature targetSignature = targetMetadata.GetSignature(targetField);
+ string candidateReason = CompareFieldSignatures(sourceSignature, targetSignature);
+ if (candidateReason == null)
+ {
+ return new Mapping(targetHandle);
+ }
+
+ var candidateTargets = ImmutableArray.Create(targetHandle);
+ var candidateReasons = ImmutableArray.Create(candidateReason);
+ return new Mapping(candidateTargets, candidateReasons);
+ }
+
+ // No field with this name was located.
+ return new Mapping();
+ }
+
+ private string CompareFieldSignatures(FieldSignature sourceSignature, FieldSignature targetSignature)
+ {
+ if (!sourceSignature.CustomModifiers.IsEmpty || !targetSignature.CustomModifiers.IsEmpty)
+ {
+ throw new NotImplementedException();
+ }
+
+ return CompareTypeSignatures(sourceSignature.Type, targetSignature.Type);
+ }
+
+ private string CompareTypeSignatures(TypeSignature sourceSignature, TypeSignature targetSignature)
+ {
+ if (sourceSignature.TypeCode != targetSignature.TypeCode)
+ {
+ return "Type mismatch";
+ }
+
+ switch (sourceSignature.TypeCode)
+ {
+ case SignatureTypeCode.Boolean:
+ case SignatureTypeCode.Char:
+ case SignatureTypeCode.SByte:
+ case SignatureTypeCode.Byte:
+ case SignatureTypeCode.Int16:
+ case SignatureTypeCode.UInt16:
+ case SignatureTypeCode.Int32:
+ case SignatureTypeCode.UInt32:
+ case SignatureTypeCode.Int64:
+ case SignatureTypeCode.UInt64:
+ case SignatureTypeCode.IntPtr:
+ case SignatureTypeCode.UIntPtr:
+ case SignatureTypeCode.Single:
+ case SignatureTypeCode.Double:
+ return null;
+
+ case SignatureTypeCode.Object:
+ case SignatureTypeCode.String:
+ return null;
+
+ case SignatureTypeCode.Array:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
+
+ case SignatureTypeCode.FunctionPointer:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
+
+ case SignatureTypeCode.GenericTypeInstance:
+ if (!IsSameHandle(sourceSignature.TypeHandle, targetSignature.TypeHandle))
+ {
+ return "Unbound generic type does not match.";
+ }
+
+ ImmutableArray sourceGenericArguments = sourceSignature.GenericTypeArguments;
+ ImmutableArray targetGenericArguments = targetSignature.GenericTypeArguments;
+ if (sourceGenericArguments.Length != targetGenericArguments.Length)
+ {
+ return "Generic arity does not match.";
+ }
+
+ for (int i = 0; i < sourceGenericArguments.Length; i++)
+ {
+ string genericParameterResult = CompareTypeSignatures(sourceGenericArguments[i], targetGenericArguments[i]);
+ if (genericParameterResult != null)
+ {
+ return string.Format("Generic parameter {0} does not match: {1}", i, genericParameterResult);
+ }
+ }
+
+ return null;
+
+ case SignatureTypeCode.GenericMethodParameter:
+ case SignatureTypeCode.GenericTypeParameter:
+ if (sourceSignature.GenericParameterIndex != targetSignature.GenericParameterIndex)
+ {
+ return "Generic parameter index differs.";
+ }
+
+ return null;
+
+ case SignatureTypeCode.TypeHandle:
+ //throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
+ Handle referenceTypeHandle = sourceSignature.TypeHandle;
+ Handle newTypeHandle = targetSignature.TypeHandle;
+ return IsSameHandle(referenceTypeHandle, newTypeHandle) ? null : "Type handle mismatch";
+
+ case SignatureTypeCode.Pointer:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
+
+ case SignatureTypeCode.SZArray:
+ if (!sourceSignature.CustomModifiers.IsEmpty || !targetSignature.CustomModifiers.IsEmpty)
+ {
+ throw new NotImplementedException();
+ }
+
+ string szArrayResult = CompareTypeSignatures(sourceSignature.ElementType, targetSignature.ElementType);
+ if (szArrayResult != null)
+ {
+ szArrayResult = string.Format("SZArray element type mismatch: {0}", szArrayResult);
+ }
+
+ return szArrayResult;
+
+ default:
+ throw new InvalidOperationException("Invalid signature type code.");
+ }
+ }
+
+ private bool IsSameHandle(Handle sourceHandle, Handle targetHandle)
+ {
+ if (sourceHandle.IsNil != targetHandle.IsNil)
+ {
+ return false;
+ }
+
+ if (sourceHandle.IsNil)
+ {
+ return true;
+ }
+
+ Mapping mappedTarget = MapHandle(sourceHandle);
+ if (mappedTarget.Target.IsNil)
+ {
+ return false;
+ }
+
+ return mappedTarget.Target == targetHandle;
+ }
+
+ private Mapping MapGenericParameterImpl(GenericParameterHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapGenericParameterConstraintImpl(GenericParameterConstraintHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapInterfaceImplementationImpl(InterfaceImplementationHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapManifestResourceImpl(ManifestResourceHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapMemberReferenceImpl(MemberReferenceHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapMethodDefinitionImpl(MethodDefinitionHandle handle)
+ {
+ MetadataReader referenceMetadata = sourceMetadata;
+ MetadataReader newMetadata = targetMetadata;
+ MethodDefinition referenceMethodDefinition = referenceMetadata.GetMethodDefinition(handle);
+
+ string referenceName = referenceMetadata.GetString(referenceMethodDefinition.Name);
+
+ foreach (var MethodDefinitionHandle in newMetadata.MethodDefinitions)
+ {
+ var MethodDefinition = newMetadata.GetMethodDefinition(MethodDefinitionHandle);
+
+ if (!newMetadata.StringComparer.Equals(MethodDefinition.Name, referenceName))
+ {
+ continue;
+ }
+
+ if (!MethodDefinition.GetDeclaringType().IsNil)
+ {
+ if (referenceMethodDefinition.GetDeclaringType().IsNil)
+ {
+ continue;
+ }
+
+ Mapping newDeclaringTypeDefinitionHandle = MapTypeDefinition(referenceMethodDefinition.GetDeclaringType());
+ if (newDeclaringTypeDefinitionHandle.Target.IsNil)
+ {
+ continue;
+ }
+
+ if (newDeclaringTypeDefinitionHandle.Target != MethodDefinition.GetDeclaringType())
+ {
+ continue;
+ }
+ }
+
+ return new Mapping(MethodDefinitionHandle);
+ }
+
+ return new Mapping();
+ }
+
+ private Mapping MapMethodImplementationImpl(MethodImplementationHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapMethodSpecificationImpl(MethodSpecificationHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapModuleDefinitionImpl(ModuleDefinitionHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapModuleReferenceImpl(ModuleReferenceHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapNamespaceDefinitionImpl(NamespaceDefinitionHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapParameterImpl(ParameterHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapPropertyDefinitionImpl(PropertyDefinitionHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapStandaloneSignatureImpl(StandaloneSignatureHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+
+ private Mapping MapTypeDefinitionImpl(TypeDefinitionHandle handle)
+ {
+ MetadataReader referenceMetadata = sourceMetadata;
+ MetadataReader newMetadata = targetMetadata;
+ TypeDefinition referenceTypeDefinition = referenceMetadata.GetTypeDefinition(handle);
+
+ string referenceName = referenceMetadata.GetString(referenceTypeDefinition.Name);
+ string referenceNamespace = referenceMetadata.GetString(referenceTypeDefinition.Namespace);
+
+ foreach (var typeDefinitionHandle in newMetadata.TypeDefinitions)
+ {
+ var typeDefinition = newMetadata.GetTypeDefinition(typeDefinitionHandle);
+
+ if (!newMetadata.StringComparer.Equals(typeDefinition.Name, referenceName))
+ {
+ continue;
+ }
+
+ if (!newMetadata.StringComparer.Equals(typeDefinition.Namespace, referenceNamespace))
+ {
+ continue;
+ }
+
+ if (!typeDefinition.GetDeclaringType().IsNil)
+ {
+ if (referenceTypeDefinition.GetDeclaringType().IsNil)
+ {
+ continue;
+ }
+
+ Mapping newDeclaringTypeDefinitionHandle = MapTypeDefinition(referenceTypeDefinition.GetDeclaringType());
+ if (newDeclaringTypeDefinitionHandle.Target.IsNil)
+ {
+ continue;
+ }
+
+ if (newDeclaringTypeDefinitionHandle.Target != typeDefinition.GetDeclaringType())
+ {
+ continue;
+ }
+ }
+
+ return new Mapping(typeDefinitionHandle);
+ }
+
+ return new Mapping();
+ }
+
+ private Mapping MapTypeReferenceImpl(TypeReferenceHandle handle)
+ {
+ MetadataReader referenceMetadata = sourceMetadata;
+ MetadataReader newMetadata = targetMetadata;
+ TypeReference referenceTypeReference = referenceMetadata.GetTypeReference(handle);
+
+ string referenceName = referenceMetadata.GetString(referenceTypeReference.Name);
+ string referenceNamespace = referenceMetadata.GetString(referenceTypeReference.Namespace);
+
+ foreach (var typeReferenceHandle in newMetadata.TypeReferences)
+ {
+ var typeReference = newMetadata.GetTypeReference(typeReferenceHandle);
+
+ if (!newMetadata.StringComparer.Equals(typeReference.Name, referenceName))
+ {
+ continue;
+ }
+
+ if (!newMetadata.StringComparer.Equals(typeReference.Namespace, referenceNamespace))
+ {
+ continue;
+ }
+
+ return new Mapping(typeReferenceHandle);
+ }
+
+ return new Mapping();
+ }
+
+ private Mapping MapTypeSpecificationImpl(TypeSpecificationHandle handle)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/CompatibilityChecker/MetadataReaderExtensions.cs b/CompatibilityChecker.Library/MetadataReaderExtensions.cs
similarity index 96%
rename from CompatibilityChecker/MetadataReaderExtensions.cs
rename to CompatibilityChecker.Library/MetadataReaderExtensions.cs
index 75e76e0..316b9ca 100644
--- a/CompatibilityChecker/MetadataReaderExtensions.cs
+++ b/CompatibilityChecker.Library/MetadataReaderExtensions.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Reflection.Metadata;
diff --git a/CompatibilityChecker/MethodSignature.cs b/CompatibilityChecker.Library/MethodSignature.cs
similarity index 85%
rename from CompatibilityChecker/MethodSignature.cs
rename to CompatibilityChecker.Library/MethodSignature.cs
index fe23897..1c19814 100644
--- a/CompatibilityChecker/MethodSignature.cs
+++ b/CompatibilityChecker.Library/MethodSignature.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System;
using System.Collections.Immutable;
@@ -10,18 +10,18 @@
///
public struct MethodSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public MethodSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public SignatureHeader Header
{
get
{
- return _reader.ReadSignatureHeader();
+ return reader.ReadSignatureHeader();
}
}
@@ -29,11 +29,13 @@ public int GenericParameterCount
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
var header = reader.ReadSignatureHeader();
if (header.IsGeneric)
+ {
return reader.ReadCompressedInteger();
+ }
throw new InvalidOperationException("Only generic method signatures include a generic parameter count.");
}
@@ -43,12 +45,14 @@ public ReturnTypeSignature ReturnType
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
var header = reader.ReadSignatureHeader();
// skip the GenParamCount if present
if (header.IsGeneric)
+ {
reader.ReadCompressedInteger();
+ }
// skip the ParamCount
reader.ReadCompressedInteger();
@@ -61,12 +65,14 @@ public ImmutableArray Parameters
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
var header = reader.ReadSignatureHeader();
// skip the GenParamCount if present
if (header.IsGeneric)
+ {
reader.ReadCompressedInteger();
+ }
// read the ParamCount
int parameterCount = reader.ReadCompressedInteger();
@@ -77,7 +83,7 @@ public ImmutableArray Parameters
var builder = ImmutableArray.CreateBuilder(parameterCount);
for (int i = 0; i < parameterCount; i++)
{
- ParameterSignature parameterSignature = new ParameterSignature(reader);
+ ParameterSignature parameterSignature = new (reader);
builder.Add(parameterSignature);
reader = parameterSignature.Skip();
}
@@ -88,12 +94,14 @@ public ImmutableArray Parameters
public BlobReader Skip()
{
- BlobReader reader = _reader;
+ var reader = this.reader;
var header = reader.ReadSignatureHeader();
// skip the GenParamCount if present
if (header.IsGeneric)
+ {
reader.ReadCompressedInteger();
+ }
// read the ParamCount
int parameterCount = reader.ReadCompressedInteger();
@@ -102,7 +110,9 @@ public BlobReader Skip()
reader = new ReturnTypeSignature(reader).Skip();
for (int i = 0; i < parameterCount; i++)
+ {
reader = new ParameterSignature(reader).Skip();
+ }
return reader;
}
diff --git a/CompatibilityChecker/ParameterSignature.cs b/CompatibilityChecker.Library/ParameterSignature.cs
similarity index 69%
rename from CompatibilityChecker/ParameterSignature.cs
rename to CompatibilityChecker.Library/ParameterSignature.cs
index f96ccf3..8f591f4 100644
--- a/CompatibilityChecker/ParameterSignature.cs
+++ b/CompatibilityChecker.Library/ParameterSignature.cs
@@ -1,15 +1,15 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Collections.Immutable;
using System.Reflection.Metadata;
public struct ParameterSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public ParameterSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public ImmutableArray CustomModifiers
@@ -17,7 +17,7 @@ public ImmutableArray CustomModifiers
get
{
// this is always a restriction of RetType
- return new ReturnTypeSignature(_reader).CustomModifiers;
+ return new ReturnTypeSignature(reader).CustomModifiers;
}
}
@@ -26,7 +26,7 @@ public bool IsByRef
get
{
// this is always a restriction of RetType
- return new ReturnTypeSignature(_reader).IsByRef;
+ return new ReturnTypeSignature(reader).IsByRef;
}
}
@@ -35,7 +35,7 @@ public SignatureTypeCode TypeCode
get
{
// this is always a restriction of RetType
- return new ReturnTypeSignature(_reader).TypeCode;
+ return new ReturnTypeSignature(reader).TypeCode;
}
}
@@ -44,14 +44,14 @@ public TypeSignature Type
get
{
// this is always a restriction of RetType
- return new ReturnTypeSignature(_reader).Type;
+ return new ReturnTypeSignature(reader).Type;
}
}
public BlobReader Skip()
{
// this is always a restriction of RetType
- return new ReturnTypeSignature(_reader).Skip();
+ return new ReturnTypeSignature(reader).Skip();
}
}
}
diff --git a/CompatibilityChecker.Library/Properties/AssemblyInfo.cs b/CompatibilityChecker.Library/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..27c5a20
--- /dev/null
+++ b/CompatibilityChecker.Library/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("CompatibilityChecker.Library.Tests")]
diff --git a/CompatibilityChecker/PropertySignature.cs b/CompatibilityChecker.Library/PropertySignature.cs
similarity index 85%
rename from CompatibilityChecker/PropertySignature.cs
rename to CompatibilityChecker.Library/PropertySignature.cs
index eba18b7..4da67ae 100644
--- a/CompatibilityChecker/PropertySignature.cs
+++ b/CompatibilityChecker.Library/PropertySignature.cs
@@ -1,22 +1,22 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Collections.Immutable;
using System.Reflection.Metadata;
public struct PropertySignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public PropertySignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public SignatureHeader Header
{
get
{
- return _reader.ReadSignatureHeader();
+ return reader.ReadSignatureHeader();
}
}
@@ -24,7 +24,7 @@ public ImmutableArray CustomModifiers
{
get
{
- var reader = _reader;
+ var reader = this.reader;
// signature header
reader.ReadSignatureHeader();
@@ -48,7 +48,7 @@ public TypeSignature PropertyType
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
// header
reader.ReadSignatureHeader();
@@ -57,7 +57,9 @@ public TypeSignature PropertyType
reader.ReadCompressedInteger();
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
return new TypeSignature(reader);
}
@@ -67,13 +69,15 @@ public ImmutableArray Parameters
{
get
{
- BlobReader reader = _reader;
+ var reader = this.reader;
reader.ReadSignatureHeader();
int parameterCount = reader.ReadCompressedInteger();
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
reader = new TypeSignature(reader).Skip();
@@ -91,18 +95,22 @@ public ImmutableArray Parameters
public BlobReader Skip()
{
- BlobReader reader = _reader;
+ var reader = this.reader;
reader.ReadSignatureHeader();
int parameterCount = reader.ReadCompressedInteger();
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
reader = new TypeSignature(reader).Skip();
for (int i = 0; i < parameterCount; i++)
+ {
reader = new ParameterSignature(reader).Skip();
+ }
return reader;
}
diff --git a/CompatibilityChecker/ReturnTypeSignature.cs b/CompatibilityChecker.Library/ReturnTypeSignature.cs
similarity index 63%
rename from CompatibilityChecker/ReturnTypeSignature.cs
rename to CompatibilityChecker.Library/ReturnTypeSignature.cs
index 6936fa7..4aa0b58 100644
--- a/CompatibilityChecker/ReturnTypeSignature.cs
+++ b/CompatibilityChecker.Library/ReturnTypeSignature.cs
@@ -1,4 +1,4 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System;
using System.Collections.Immutable;
@@ -6,18 +6,18 @@
public struct ReturnTypeSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public ReturnTypeSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public ImmutableArray CustomModifiers
{
get
{
- var reader = _reader;
+ var reader = this.reader;
var builder = ImmutableArray.CreateBuilder();
while (reader.IsCustomModifier())
{
@@ -34,9 +34,11 @@ public bool IsByRef
{
get
{
- var reader = _reader;
+ var reader = this.reader;
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
return reader.ReadSignatureTypeCode() == SignatureTypeCode.ByReference;
}
@@ -46,22 +48,24 @@ public SignatureTypeCode TypeCode
{
get
{
- var reader = _reader;
+ var reader = this.reader;
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
switch (reader.PeekSignatureTypeCode())
{
- case SignatureTypeCode.TypedReference:
- case SignatureTypeCode.Void:
- return reader.PeekSignatureTypeCode();
+ case SignatureTypeCode.TypedReference:
+ case SignatureTypeCode.Void:
+ return reader.PeekSignatureTypeCode();
- case SignatureTypeCode.ByReference:
- reader.ReadSignatureTypeCode();
- goto default;
+ case SignatureTypeCode.ByReference:
+ reader.ReadSignatureTypeCode();
+ goto default;
- default:
- return new TypeSignature(reader).TypeCode;
+ default:
+ return new TypeSignature(reader).TypeCode;
}
}
}
@@ -86,46 +90,50 @@ public TypeSignature Type
{
get
{
- var reader = _reader;
+ var reader = this.reader;
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
switch (reader.PeekSignatureTypeCode())
{
- case SignatureTypeCode.ByReference:
- reader.ReadSignatureTypeCode();
- return new TypeSignature(reader);
+ case SignatureTypeCode.ByReference:
+ reader.ReadSignatureTypeCode();
+ return new TypeSignature(reader);
- case SignatureTypeCode.TypedReference:
- case SignatureTypeCode.Void:
- throw new InvalidOperationException(string.Format("RetType signatures with type code {0} do not have a Type signature.", reader.PeekSignatureTypeCode()));
+ case SignatureTypeCode.TypedReference:
+ case SignatureTypeCode.Void:
+ throw new InvalidOperationException(string.Format("RetType signatures with type code {0} do not have a Type signature.", reader.PeekSignatureTypeCode()));
- default:
- return new TypeSignature(reader);
+ default:
+ return new TypeSignature(reader);
}
}
}
public BlobReader Skip()
{
- var reader = _reader;
+ var reader = this.reader;
while (reader.IsCustomModifier())
+ {
reader = new CustomModifierSignature(reader).Skip();
+ }
switch (reader.PeekSignatureTypeCode())
{
- case SignatureTypeCode.ByReference:
- reader.ReadSignatureTypeCode();
- goto default;
-
- case SignatureTypeCode.TypedReference:
- case SignatureTypeCode.Void:
- reader.ReadSignatureTypeCode();
- break;
-
- default:
- reader = new TypeSignature(reader).Skip();
- break;
+ case SignatureTypeCode.ByReference:
+ reader.ReadSignatureTypeCode();
+ goto default;
+
+ case SignatureTypeCode.TypedReference:
+ case SignatureTypeCode.Void:
+ reader.ReadSignatureTypeCode();
+ break;
+
+ default:
+ reader = new TypeSignature(reader).Skip();
+ break;
}
return reader;
diff --git a/CompatibilityChecker.Library/Severity.cs b/CompatibilityChecker.Library/Severity.cs
new file mode 100644
index 0000000..15ee7c4
--- /dev/null
+++ b/CompatibilityChecker.Library/Severity.cs
@@ -0,0 +1,10 @@
+namespace CompatibilityChecker.Library
+{
+ public enum Severity
+ {
+ Disabled = 0,
+ Information = 1,
+ Warning = 2,
+ Error = 3,
+ }
+}
diff --git a/CompatibilityChecker.Library/TypeSignature.cs b/CompatibilityChecker.Library/TypeSignature.cs
new file mode 100644
index 0000000..63071c1
--- /dev/null
+++ b/CompatibilityChecker.Library/TypeSignature.cs
@@ -0,0 +1,305 @@
+namespace CompatibilityChecker.Library
+{
+ using System;
+ using System.Collections.Immutable;
+ using System.Reflection.Metadata;
+
+ ///
+ /// This structure represents a metadata Type signature, as described in ECMA-335 §II.23.2.12.
+ ///
+ public struct TypeSignature
+ {
+ private readonly BlobReader reader;
+
+ public TypeSignature(BlobReader blobReader)
+ {
+ reader = blobReader;
+ }
+
+ public SignatureTypeCode TypeCode
+ {
+ get
+ {
+ return reader.ReadSignatureTypeCode();
+ }
+ }
+
+ ///
+ /// Gets the index of a generic type or method parameter.
+ ///
+ ///
+ /// If is not or
+ /// .
+ ///
+ public int GenericParameterIndex
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.GenericMethodParameter:
+ case SignatureTypeCode.GenericTypeParameter:
+ return reader.ReadCompressedInteger();
+
+ default:
+ throw new InvalidOperationException("Only generic parameters have a generic parameter index.");
+ }
+ }
+ }
+
+ ///
+ /// Gets the type handle encoded in the signature.
+ ///
+ ///
+ /// If is not or
+ /// .
+ ///
+ public Handle TypeHandle
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.TypeHandle:
+ return reader.ReadTypeHandle();
+
+ case SignatureTypeCode.GenericTypeInstance:
+ reader.ReadSignatureTypeCode();
+ return reader.ReadTypeHandle();
+
+ default:
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have a type handle.", typeCode));
+ }
+ }
+ }
+
+ public ImmutableArray GenericTypeArguments
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+ if (typeCode != SignatureTypeCode.GenericTypeInstance)
+ {
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have generic arguments.", typeCode));
+ }
+
+ reader.ReadSignatureTypeCode();
+ reader.ReadTypeHandle();
+
+ int genericArgumentCount = reader.ReadCompressedInteger();
+ var builder = ImmutableArray.CreateBuilder(genericArgumentCount);
+ for (int i = 0; i < genericArgumentCount; i++)
+ {
+ TypeSignature argument = new (reader);
+ builder.Add(argument);
+ reader = argument.Skip();
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+
+ public ImmutableArray CustomModifiers
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.Pointer:
+ case SignatureTypeCode.SZArray:
+ break;
+
+ default:
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have custom modifiers.", typeCode));
+ }
+
+ var builder = ImmutableArray.CreateBuilder();
+ while (reader.IsCustomModifier())
+ {
+ var customModifierSignature = new CustomModifierSignature(reader);
+ builder.Add(customModifierSignature);
+ reader = customModifierSignature.Skip();
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+
+ public TypeSignature ElementType
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.Array:
+ return new TypeSignature(reader);
+
+ case SignatureTypeCode.Pointer:
+ while (reader.IsCustomModifier())
+ {
+ reader = new CustomModifierSignature(reader).Skip();
+ }
+
+ if (reader.PeekSignatureTypeCode() == SignatureTypeCode.Void)
+ {
+ goto default;
+ }
+
+ return new TypeSignature(reader);
+
+ case SignatureTypeCode.SZArray:
+ while (reader.IsCustomModifier())
+ {
+ reader = new CustomModifierSignature(reader).Skip();
+ }
+
+ return new TypeSignature(reader);
+
+ default:
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have an element type.", typeCode));
+ }
+ }
+ }
+
+ public ArrayShapeSignature ArrayShape
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.Array:
+ // skip past the type and return the array shape
+ reader = new TypeSignature(reader).Skip();
+ return new ArrayShapeSignature(reader);
+
+ default:
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have an array shape signature.", typeCode));
+ }
+ }
+ }
+
+ public MethodSignature MethodSignature
+ {
+ get
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.FunctionPointer:
+ return new MethodSignature(reader);
+
+ default:
+ throw new InvalidOperationException(string.Format("Type code '{0}' does not have a method signature.", typeCode));
+ }
+ }
+ }
+
+ public BlobReader Skip()
+ {
+ var reader = this.reader;
+ SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
+
+ switch (typeCode)
+ {
+ case SignatureTypeCode.Boolean:
+ case SignatureTypeCode.Char:
+ case SignatureTypeCode.SByte:
+ case SignatureTypeCode.Byte:
+ case SignatureTypeCode.Int16:
+ case SignatureTypeCode.UInt16:
+ case SignatureTypeCode.Int32:
+ case SignatureTypeCode.UInt32:
+ case SignatureTypeCode.Int64:
+ case SignatureTypeCode.UInt64:
+ case SignatureTypeCode.IntPtr:
+ case SignatureTypeCode.UIntPtr:
+ case SignatureTypeCode.Single:
+ case SignatureTypeCode.Double:
+ break;
+
+ case SignatureTypeCode.Object:
+ case SignatureTypeCode.String:
+ break;
+
+ case SignatureTypeCode.Array:
+ reader = new TypeSignature(reader).Skip();
+ reader = new ArrayShapeSignature(reader).Skip();
+ break;
+
+ case SignatureTypeCode.FunctionPointer:
+ throw new NotImplementedException(string.Format("{0} is not yet implemented.", typeCode));
+
+ case SignatureTypeCode.GenericTypeInstance:
+ reader.ReadSignatureTypeCode();
+ reader.ReadTypeHandle();
+
+ int argumentCount = reader.ReadCompressedInteger();
+ for (int i = 0; i < argumentCount; i++)
+ {
+ reader = new TypeSignature(reader).Skip();
+ }
+
+ break;
+
+ case SignatureTypeCode.GenericMethodParameter:
+ case SignatureTypeCode.GenericTypeParameter:
+ // skip the generic parameter index
+ reader.ReadCompressedInteger();
+ break;
+
+ case SignatureTypeCode.TypeHandle:
+ reader.ReadTypeHandle();
+ break;
+
+ case SignatureTypeCode.Pointer:
+ while (reader.IsCustomModifier())
+ {
+ reader = new CustomModifierSignature(reader).Skip();
+ }
+
+ if (reader.PeekSignatureTypeCode() == SignatureTypeCode.Void)
+ {
+ reader.ReadSignatureTypeCode();
+ }
+ else
+ {
+ reader = new TypeSignature(reader).Skip();
+ }
+
+ break;
+
+ case SignatureTypeCode.SZArray:
+ while (reader.IsCustomModifier())
+ {
+ reader = new CustomModifierSignature(reader).Skip();
+ }
+
+ reader = new TypeSignature(reader).Skip();
+ break;
+
+ default:
+ throw new InvalidOperationException("Invalid signature type code.");
+ }
+
+ return reader;
+ }
+ }
+}
diff --git a/CompatibilityChecker/TypeSpecificationSignature.cs b/CompatibilityChecker.Library/TypeSpecificationSignature.cs
similarity index 71%
rename from CompatibilityChecker/TypeSpecificationSignature.cs
rename to CompatibilityChecker.Library/TypeSpecificationSignature.cs
index 12a9d02..e259d95 100644
--- a/CompatibilityChecker/TypeSpecificationSignature.cs
+++ b/CompatibilityChecker.Library/TypeSpecificationSignature.cs
@@ -1,22 +1,22 @@
-namespace CompatibilityChecker
+namespace CompatibilityChecker.Library
{
using System.Collections.Immutable;
using System.Reflection.Metadata;
public struct TypeSpecificationSignature
{
- private readonly BlobReader _reader;
+ private readonly BlobReader reader;
public TypeSpecificationSignature(BlobReader blobReader)
{
- _reader = blobReader;
+ reader = blobReader;
}
public SignatureTypeCode TypeCode
{
get
{
- return _reader.ReadSignatureTypeCode();
+ return reader.ReadSignatureTypeCode();
}
}
@@ -25,7 +25,7 @@ public Handle TypeHandle
get
{
// this particular case is identical to Type signature for valid TypeSpec signatures
- return new TypeSignature(_reader).TypeHandle;
+ return new TypeSignature(reader).TypeHandle;
}
}
@@ -34,14 +34,14 @@ public ImmutableArray GenericTypeArguments
get
{
// this particular case is identical to Type signature for valid TypeSpec signatures
- return new TypeSignature(_reader).GenericTypeArguments;
+ return new TypeSignature(reader).GenericTypeArguments;
}
}
public BlobReader Skip()
{
// this particular case is identical to Type signature for valid TypeSpec signatures
- return new TypeSignature(_reader).Skip();
+ return new TypeSignature(reader).Skip();
}
}
}
diff --git a/CompatibilityChecker.sln b/CompatibilityChecker.sln
index 1b3f704..1248174 100644
--- a/CompatibilityChecker.sln
+++ b/CompatibilityChecker.sln
@@ -1,20 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.22310.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29519.181
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompatibilityChecker", "CompatibilityChecker\CompatibilityChecker.csproj", "{C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompatibilityCheckExample", "CompatibilityCheckExample\CompatibilityCheckExample.csproj", "{69E70F61-27CA-46A2-8017-A2F66B1D4AAA}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C355D891-5C1D-4794-9981-9077586D4D39}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
LICENSE = LICENSE
+ NOTICE = NOTICE
README.md = README.md
- TestSettings.testsettings = TestSettings.testsettings
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompatibilityCheckerTests", "CompatibilityCheckerTests\CompatibilityCheckerTests.csproj", "{44681692-0479-4C99-BF40-F310B78D87F0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompatibilityChecker.Library", "CompatibilityChecker.Library\CompatibilityChecker.Library.csproj", "{9A4BE2CE-277F-41C5-AB31-E5C6ECFD0EEB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompatibilityChecker", "CompatibilityChecker\CompatibilityChecker.csproj", "{F12B242C-9EC3-4ABC-BFC5-50156E4B5CB4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompatibilityChecker.Library.Tests", "tests\CompatibilityChecker.Library.Tests\CompatibilityChecker.Library.Tests.csproj", "{F46154D5-0FC7-4C2A-AB50-B5D81F73E178}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{76B2C3E5-B595-4539-A783-27313766B8F1}"
+ ProjectSection(SolutionItems) = preProject
+ tests\coverletArgs.runsettings = tests\coverletArgs.runsettings
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -22,20 +28,26 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}.Release|Any CPU.Build.0 = Release|Any CPU
- {69E70F61-27CA-46A2-8017-A2F66B1D4AAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {69E70F61-27CA-46A2-8017-A2F66B1D4AAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {69E70F61-27CA-46A2-8017-A2F66B1D4AAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {69E70F61-27CA-46A2-8017-A2F66B1D4AAA}.Release|Any CPU.Build.0 = Release|Any CPU
- {44681692-0479-4C99-BF40-F310B78D87F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {44681692-0479-4C99-BF40-F310B78D87F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {44681692-0479-4C99-BF40-F310B78D87F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {44681692-0479-4C99-BF40-F310B78D87F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9A4BE2CE-277F-41C5-AB31-E5C6ECFD0EEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9A4BE2CE-277F-41C5-AB31-E5C6ECFD0EEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9A4BE2CE-277F-41C5-AB31-E5C6ECFD0EEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9A4BE2CE-277F-41C5-AB31-E5C6ECFD0EEB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F12B242C-9EC3-4ABC-BFC5-50156E4B5CB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F12B242C-9EC3-4ABC-BFC5-50156E4B5CB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F12B242C-9EC3-4ABC-BFC5-50156E4B5CB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F12B242C-9EC3-4ABC-BFC5-50156E4B5CB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F46154D5-0FC7-4C2A-AB50-B5D81F73E178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F46154D5-0FC7-4C2A-AB50-B5D81F73E178}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F46154D5-0FC7-4C2A-AB50-B5D81F73E178}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F46154D5-0FC7-4C2A-AB50-B5D81F73E178}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F46154D5-0FC7-4C2A-AB50-B5D81F73E178} = {76B2C3E5-B595-4539-A783-27313766B8F1}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6892FBD2-1339-4781-A210-834B945609AC}
+ EndGlobalSection
EndGlobal
diff --git a/CompatibilityChecker/CompatibilityChecker.csproj b/CompatibilityChecker/CompatibilityChecker.csproj
index 2c7e75b..269c48c 100644
--- a/CompatibilityChecker/CompatibilityChecker.csproj
+++ b/CompatibilityChecker/CompatibilityChecker.csproj
@@ -1,90 +1,51 @@
-
-
-
+
+
- Debug
- AnyCPU
- {C3D7FCE7-0FED-462F-A4A6-BAFC6AA91EF2}
- Library
- Properties
- CompatibilityChecker
- CompatibilityChecker
- v4.5
- 512
+ Exe
+ net7.0
+ latest
+ 0.5.0
+ CompatibilityChecker
+ This project implements a binary compatibility checker for .NET assemblies. The goal of this project is to automate the process of identifying binary- and source-breaking changes between releases of a .NET library. Libraries with string compatibility policies will eventually be able to incorporate this check in the unit tests for the library. The checker will download a declared previous release of the library from NuGet (or potentially from another source), and verify that the latest build of the library is compatible with the binary interfaces defined by the earlier release.
+
+This library may also feature support for higher levels of compatibility, such as warning users if new overloads of a method could result in an AmbiguousMatchException for users who didn't specify a complete signature when using reflection.
+
+Diagnostics produced by this checker will be categorized by their likely impact on consumers, and by whether the change constitutes a binary- or source-level breaking change. At this time, there are no plans to implement detection or reporting for changes in runtime semantics.
+
+ Usage: dotnet compat Reference.dll New.dll
+ Apache-2.0
+ true
+ true
+ dotnet-compat
+ https://github.com/EraYaN/dotnet-compatibility
+ CompatibilityChecker
+ Rack Space Inc.,tunnelvisionlabs,EraYaN
+
+ true
+ AllEnabledByDefault
+ true
+ true
+ true
+ snupkg
-
+
+
+ portable
true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- bin\Debug\CompatibilityChecker.xml
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- bin\Release\CompatibilityChecker.xml
-
-
-
-
- False
- ..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
-
-
-
- ..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
-
+
-
-
-
\ No newline at end of file
+
+
diff --git a/CompatibilityChecker/Descriptors/AbstractMustNotBeAddedToType.cs b/CompatibilityChecker/Descriptors/AbstractMustNotBeAddedToType.cs
deleted file mode 100644
index 6ced582..0000000
--- a/CompatibilityChecker/Descriptors/AbstractMustNotBeAddedToType.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace CompatibilityChecker.Descriptors
-{
- ///
- /// The sealed modifier must not be added to a publicly-accessible type, unless that type does not have any
- /// publicly-accessible constructors.
- ///
- internal class AbstractMustNotBeAddedToType : CompatibilityDescriptor
- {
- private const string Id = nameof(AbstractMustNotBeAddedToType);
- private static readonly string _title = TitleHelper.GenerateTitle(Id);
- private static readonly string _messageFormat = "The 'abstract' modifier cannot be added to a type.";
- private static readonly string _category = Categories.Type;
- private static readonly Severity _defaultSeverity = Severity.Error;
- private static readonly string _description = null;
-
- private static readonly AbstractMustNotBeAddedToType Instance = new AbstractMustNotBeAddedToType();
-
- private AbstractMustNotBeAddedToType()
- : base(Id, _title, _messageFormat, _category, _defaultSeverity, _description)
- {
- }
-
- internal static Message CreateMessage()
- {
- return new Message(Instance);
- }
- }
-}
diff --git a/CompatibilityChecker/Descriptors/AssemblyNameMustNotBeChanged.cs b/CompatibilityChecker/Descriptors/AssemblyNameMustNotBeChanged.cs
deleted file mode 100644
index 611f7bd..0000000
--- a/CompatibilityChecker/Descriptors/AssemblyNameMustNotBeChanged.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-namespace CompatibilityChecker.Descriptors
-{
- using System;
- using System.Reflection;
-
- ///
- /// The simple name of an assembly cannot be changed.
- ///
- ///
- /// The simple name of an assembly corresponds to the value of the
- /// property.
- ///
- internal class AssemblyNameMustNotBeChanged : CompatibilityDescriptor
- {
- private const string Id = nameof(AssemblyNameMustNotBeChanged);
- private static readonly string _title = TitleHelper.GenerateTitle(Id);
- private static readonly string _messageFormat = "The simple name of an assembly cannot change.";
- private static readonly string _category = Categories.Assembly;
- private static readonly Severity _defaultSeverity = Severity.Error;
- private static readonly string _description = null;
-
- private static readonly AssemblyNameMustNotBeChanged Instance = new AssemblyNameMustNotBeChanged();
-
- private AssemblyNameMustNotBeChanged()
- : base(Id, _title, _messageFormat, _category, _defaultSeverity, _description)
- {
- }
-
- internal static Message CreateMessage()
- {
- return new Message(Instance);
- }
- }
-}
diff --git a/CompatibilityChecker/Descriptors/Categories.cs b/CompatibilityChecker/Descriptors/Categories.cs
deleted file mode 100644
index d7550b3..0000000
--- a/CompatibilityChecker/Descriptors/Categories.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace CompatibilityChecker.Descriptors
-{
- internal static class Categories
- {
- internal const string Assembly = nameof(Assembly);
-
- internal const string Type = nameof(Type);
- }
-}
diff --git a/CompatibilityChecker/Descriptors/SealedMustNotBeAddedToType.cs b/CompatibilityChecker/Descriptors/SealedMustNotBeAddedToType.cs
deleted file mode 100644
index 3430fa3..0000000
--- a/CompatibilityChecker/Descriptors/SealedMustNotBeAddedToType.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace CompatibilityChecker.Descriptors
-{
- ///
- /// The sealed modifier must not be added to a publicly-accessible type, unless that type does not have any
- /// publicly-accessible constructors.
- ///
- internal class SealedMustNotBeAddedToType : CompatibilityDescriptor
- {
- private const string Id = nameof(SealedMustNotBeAddedToType);
- private static readonly string _title = TitleHelper.GenerateTitle(Id);
- private static readonly string _messageFormat = "The 'sealed' modifier cannot be added to a type.";
- private static readonly string _category = Categories.Type;
- private static readonly Severity _defaultSeverity = Severity.Error;
- private static readonly string _description = null;
-
- private static readonly SealedMustNotBeAddedToType Instance = new SealedMustNotBeAddedToType();
-
- private SealedMustNotBeAddedToType()
- : base(Id, _title, _messageFormat, _category, _defaultSeverity, _description)
- {
- }
-
- internal static Message CreateMessage()
- {
- return new Message(Instance);
- }
- }
-}
diff --git a/CompatibilityChecker/Descriptors/TypeMustNotBeRemoved.cs b/CompatibilityChecker/Descriptors/TypeMustNotBeRemoved.cs
deleted file mode 100644
index 7d37e46..0000000
--- a/CompatibilityChecker/Descriptors/TypeMustNotBeRemoved.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-namespace CompatibilityChecker.Descriptors
-{
- using System.Runtime.CompilerServices;
-
- ///
- /// Publicly-accessible types cannot be removed. This includes renaming a type or changing the namespace of a type.
- /// An exception to this rule applies for moving a type to another assembly, provided a
- /// attribute is applied to the original assembly.
- ///
- internal class TypeMustNotBeRemoved : CompatibilityDescriptor
- {
- private const string Id = nameof(TypeMustNotBeRemoved);
- private static readonly string _title = TitleHelper.GenerateTitle(Id);
- private static readonly string _messageFormat = "A publicly-accessible type cannot be removed.";
- private static readonly string _category = Categories.Type;
- private static readonly Severity _defaultSeverity = Severity.Error;
- private static readonly string _description = null;
-
- private static readonly TypeMustNotBeRemoved Instance = new TypeMustNotBeRemoved();
-
- private TypeMustNotBeRemoved()
- : base(Id, _title, _messageFormat, _category, _defaultSeverity, _description)
- {
- }
-
- internal static Message CreateMessage()
- {
- return new Message(Instance);
- }
- }
-}
diff --git a/CompatibilityChecker/Message.cs b/CompatibilityChecker/Message.cs
deleted file mode 100644
index 5552005..0000000
--- a/CompatibilityChecker/Message.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace CompatibilityChecker
-{
- using CompatibilityChecker.Descriptors;
-
- public class Message
- {
- private readonly CompatibilityDescriptor _descriptor;
- private readonly object[] _arguments;
-
- internal Message(CompatibilityDescriptor descriptor, params object[] arguments)
- {
- _descriptor = descriptor;
- _arguments = arguments;
- }
-
- public override string ToString()
- {
- string message = string.Format(_descriptor.MessageFormat, _arguments);
- return string.Format("{0} {1}: {2}", _descriptor.DefaultSeverity, _descriptor.RuleId, message);
- }
- }
-}
diff --git a/CompatibilityChecker/MetadataMapping.cs b/CompatibilityChecker/MetadataMapping.cs
deleted file mode 100644
index 7c633d3..0000000
--- a/CompatibilityChecker/MetadataMapping.cs
+++ /dev/null
@@ -1,764 +0,0 @@
-namespace CompatibilityChecker
-{
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Immutable;
- using System.Linq;
- using System.Reflection.Metadata;
-
- internal class MetadataMapping
- {
- private readonly MetadataReader _sourceMetadata;
- private readonly MetadataReader _targetMetadata;
-
- private readonly ConcurrentDictionary> _assemblyDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _assemblyFiles =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _assemblyReferences =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _constants =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _customAttributes =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _declarativeSecurityAttributes =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _eventDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _exportedTypes =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _fieldDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _genericParameters =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _genericParameterConstraints =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _interfaceImplementations =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _manifestResources =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _memberReferences =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _methodDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _methodImplementations =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _methodSpecifications =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _moduleDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _moduleReferences =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _namespaceDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _parameters =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _propertyDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _standaloneSignatures =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _typeDefinitions =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _typeReferences =
- new ConcurrentDictionary>();
-
- private readonly ConcurrentDictionary> _typeSpecifications =
- new ConcurrentDictionary>();
-
- public MetadataMapping(MetadataReader sourceMetadata, MetadataReader targetMetadata)
- {
- if (sourceMetadata == null)
- throw new ArgumentNullException("sourceMetadata");
- if (targetMetadata == null)
- throw new ArgumentNullException("targetMetadata");
-
- _sourceMetadata = sourceMetadata;
- _targetMetadata = targetMetadata;
- }
-
- public Mapping MapHandle(Handle handle)
- {
- if (handle.IsNil)
- return new Mapping();
-
- switch (handle.Kind)
- {
- case HandleKind.ModuleDefinition:
- return (Mapping)MapModuleDefinition((ModuleDefinitionHandle)handle);
-
- case HandleKind.TypeReference:
- return (Mapping)MapTypeReference((TypeReferenceHandle)handle);
-
- case HandleKind.TypeDefinition:
- return (Mapping)MapTypeDefinition((TypeDefinitionHandle)handle);
-
- case HandleKind.FieldDefinition:
- return (Mapping)MapFieldDefinition((FieldDefinitionHandle)handle);
-
- case HandleKind.MethodDefinition:
- return (Mapping)MapMethodDefinition((MethodDefinitionHandle)handle);
-
- case HandleKind.Parameter:
- return (Mapping)MapParameter((ParameterHandle)handle);
-
- case HandleKind.InterfaceImplementation:
- return (Mapping)MapInterfaceImplementation((InterfaceImplementationHandle)handle);
-
- case HandleKind.MemberReference:
- return (Mapping)MapMemberReference((MemberReferenceHandle)handle);
-
- case HandleKind.Constant:
- return (Mapping)MapConstant((ConstantHandle)handle);
-
- case HandleKind.CustomAttribute:
- return (Mapping)MapCustomAttribute((CustomAttributeHandle)handle);
-
- case HandleKind.DeclarativeSecurityAttribute:
- return (Mapping)MapDeclarativeSecurityAttribute((DeclarativeSecurityAttributeHandle)handle);
-
- case HandleKind.StandaloneSignature:
- return (Mapping)MapStandaloneSignature((StandaloneSignatureHandle)handle);
-
- case HandleKind.EventDefinition:
- return (Mapping)MapEventDefinition((EventDefinitionHandle)handle);
-
- case HandleKind.PropertyDefinition:
- return (Mapping)MapPropertyDefinition((PropertyDefinitionHandle)handle);
-
- case HandleKind.MethodImplementation:
- return (Mapping)MapMethodImplementation((MethodImplementationHandle)handle);
-
- case HandleKind.ModuleReference:
- return (Mapping)MapModuleReference((ModuleReferenceHandle)handle);
-
- case HandleKind.TypeSpecification:
- return (Mapping)MapTypeSpecification((TypeSpecificationHandle)handle);
-
- case HandleKind.AssemblyDefinition:
- return (Mapping)MapAssemblyDefinition((AssemblyDefinitionHandle)handle);
-
- case HandleKind.AssemblyFile:
- return (Mapping)MapAssemblyFile((AssemblyFileHandle)handle);
-
- case HandleKind.AssemblyReference:
- return (Mapping)MapAssemblyReference((AssemblyReferenceHandle)handle);
-
- case HandleKind.ExportedType:
- return (Mapping)MapExportedType((ExportedTypeHandle)handle);
-
- case HandleKind.GenericParameter:
- return (Mapping)MapGenericParameter((GenericParameterHandle)handle);
-
- case HandleKind.MethodSpecification:
- return (Mapping)MapMethodSpecification((MethodSpecificationHandle)handle);
-
- case HandleKind.GenericParameterConstraint:
- return (Mapping)MapGenericParameterConstraint((GenericParameterConstraintHandle)handle);
-
- case HandleKind.ManifestResource:
- return (Mapping)MapManifestResource((ManifestResourceHandle)handle);
-
- case HandleKind.NamespaceDefinition:
- return (Mapping)MapNamespaceDefinition((NamespaceDefinitionHandle)handle);
-
- default:
- throw new NotSupportedException(string.Format("Mapping '{0}' handles between assemblies is not supported.", handle.Kind));
- }
- }
-
- public Mapping MapAssemblyDefinition(AssemblyDefinitionHandle handle)
- {
- return _assemblyDefinitions.GetOrAdd(handle, MapAssemblyDefinitionImpl);
- }
-
- public Mapping MapAssemblyFile(AssemblyFileHandle handle)
- {
- return _assemblyFiles.GetOrAdd(handle, MapAssemblyFileImpl);
- }
-
- public Mapping MapAssemblyReference(AssemblyReferenceHandle handle)
- {
- return _assemblyReferences.GetOrAdd(handle, MapAssemblyReferenceImpl);
- }
-
- public Mapping MapConstant(ConstantHandle handle)
- {
- return _constants.GetOrAdd(handle, MapConstantImpl);
- }
-
- public Mapping MapCustomAttribute(CustomAttributeHandle handle)
- {
- return _customAttributes.GetOrAdd(handle, MapCustomAttributeImpl);
- }
-
- public Mapping MapDeclarativeSecurityAttribute(DeclarativeSecurityAttributeHandle handle)
- {
- return _declarativeSecurityAttributes.GetOrAdd(handle, MapDeclarativeSecurityAttributeImpl);
- }
-
- public Mapping MapEventDefinition(EventDefinitionHandle handle)
- {
- return _eventDefinitions.GetOrAdd(handle, MapEventDefinitionImpl);
- }
-
- public Mapping MapExportedType(ExportedTypeHandle handle)
- {
- return _exportedTypes.GetOrAdd(handle, MapExportedTypeImpl);
- }
-
- public Mapping MapFieldDefinition(FieldDefinitionHandle handle)
- {
- return _fieldDefinitions.GetOrAdd(handle, MapFieldDefinitionImpl);
- }
-
- public Mapping MapGenericParameter(GenericParameterHandle handle)
- {
- return _genericParameters.GetOrAdd(handle, MapGenericParameterImpl);
- }
-
- public Mapping MapGenericParameterConstraint(GenericParameterConstraintHandle handle)
- {
- return _genericParameterConstraints.GetOrAdd(handle, MapGenericParameterConstraintImpl);
- }
-
- public Mapping MapInterfaceImplementation(InterfaceImplementationHandle handle)
- {
- return _interfaceImplementations.GetOrAdd(handle, MapInterfaceImplementationImpl);
- }
-
- public Mapping MapManifestResource(ManifestResourceHandle handle)
- {
- return _manifestResources.GetOrAdd(handle, MapManifestResourceImpl);
- }
-
- public Mapping MapMemberReference(MemberReferenceHandle handle)
- {
- return _memberReferences.GetOrAdd(handle, MapMemberReferenceImpl);
- }
-
- public Mapping MapMethodDefinition(MethodDefinitionHandle handle)
- {
- return _methodDefinitions.GetOrAdd(handle, MapMethodDefinitionImpl);
- }
-
- public Mapping MapMethodImplementation(MethodImplementationHandle handle)
- {
- return _methodImplementations.GetOrAdd(handle, MapMethodImplementationImpl);
- }
-
- public Mapping MapMethodSpecification(MethodSpecificationHandle handle)
- {
- return _methodSpecifications.GetOrAdd(handle, MapMethodSpecificationImpl);
- }
-
- public Mapping MapModuleDefinition(ModuleDefinitionHandle handle)
- {
- return _moduleDefinitions.GetOrAdd(handle, MapModuleDefinitionImpl);
- }
-
- public Mapping MapModuleReference(ModuleReferenceHandle handle)
- {
- return _moduleReferences.GetOrAdd(handle, MapModuleReferenceImpl);
- }
-
- public Mapping MapNamespaceDefinition(NamespaceDefinitionHandle handle)
- {
- return _namespaceDefinitions.GetOrAdd(handle, MapNamespaceDefinitionImpl);
- }
-
- public Mapping MapParameter(ParameterHandle handle)
- {
- return _parameters.GetOrAdd(handle, MapParameterImpl);
- }
-
- public Mapping MapPropertyDefinition(PropertyDefinitionHandle handle)
- {
- return _propertyDefinitions.GetOrAdd(handle, MapPropertyDefinitionImpl);
- }
-
- public Mapping MapStandaloneSignature(StandaloneSignatureHandle handle)
- {
- return _standaloneSignatures.GetOrAdd(handle, MapStandaloneSignatureImpl);
- }
-
- public Mapping MapTypeDefinition(TypeDefinitionHandle handle)
- {
- return _typeDefinitions.GetOrAdd(handle, MapTypeDefinitionImpl);
- }
-
- public Mapping MapTypeReference(TypeReferenceHandle handle)
- {
- return _typeReferences.GetOrAdd(handle, MapTypeReferenceImpl);
- }
-
- public Mapping MapTypeSpecification(TypeSpecificationHandle handle)
- {
- return _typeSpecifications.GetOrAdd(handle, MapTypeSpecificationImpl);
- }
-
- private Mapping MapAssemblyDefinitionImpl(AssemblyDefinitionHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapAssemblyFileImpl(AssemblyFileHandle handle)
- {
- AssemblyFile assemblyFile = _sourceMetadata.GetAssemblyFile(handle);
- string name = _sourceMetadata.GetString(assemblyFile.Name);
- foreach (var targetHandle in _targetMetadata.AssemblyFiles)
- {
- AssemblyFile target = _targetMetadata.GetAssemblyFile(targetHandle);
- if (!_targetMetadata.StringComparer.Equals(target.Name, name))
- continue;
-
- return new Mapping(targetHandle);
- }
-
- return new Mapping();
- }
-
- private Mapping MapAssemblyReferenceImpl(AssemblyReferenceHandle handle)
- {
- AssemblyReference assemblyReference = _sourceMetadata.GetAssemblyReference(handle);
- string name = _sourceMetadata.GetString(assemblyReference.Name);
- string culture = _sourceMetadata.GetString(assemblyReference.Culture);
- ImmutableArray publicKeyOrToken = _sourceMetadata.GetBlobContent(assemblyReference.PublicKeyOrToken);
- foreach (var targetHandle in _targetMetadata.AssemblyReferences)
- {
- AssemblyReference target = _targetMetadata.GetAssemblyReference(targetHandle);
- if (!_targetMetadata.StringComparer.Equals(target.Name, name))
- continue;
-
- if (!_targetMetadata.StringComparer.Equals(target.Culture, culture))
- continue;
-
- if (!publicKeyOrToken.IsDefaultOrEmpty)
- {
- if (target.Version != assemblyReference.Version)
- continue;
-
- ImmutableArray targetPublicKeyOrToken = _targetMetadata.GetBlobContent(target.PublicKeyOrToken);
- if (!targetPublicKeyOrToken.SequenceEqual(targetPublicKeyOrToken))
- continue;
- }
-
- return new Mapping(targetHandle);
- }
-
- return new Mapping();
- }
-
- private Mapping MapConstantImpl(ConstantHandle handle)
- {
- Constant constant = _sourceMetadata.GetConstant(handle);
- Mapping parent = MapHandle(constant.Parent);
- if (parent.Target.IsNil)
- return new Mapping();
-
- ConstantHandle targetHandle;
- switch (parent.Target.Kind)
- {
- case HandleKind.Parameter:
- Parameter targetParameter = _targetMetadata.GetParameter((ParameterHandle)parent.Target);
- targetHandle = targetParameter.GetDefaultValue();
- break;
-
- case HandleKind.FieldDefinition:
- FieldDefinition targetFieldDefinition = _targetMetadata.GetFieldDefinition((FieldDefinitionHandle)parent.Target);
- targetHandle = targetFieldDefinition.GetDefaultValue();
- break;
-
- case HandleKind.PropertyDefinition:
- PropertyDefinition targetPropertyDefinition = _targetMetadata.GetPropertyDefinition((PropertyDefinitionHandle)parent.Target);
- targetHandle = targetPropertyDefinition.GetDefaultValue();
- break;
-
- default:
- throw new InvalidOperationException();
- }
-
- if (targetHandle.IsNil)
- return new Mapping();
-
- Constant targetConstant = _targetMetadata.GetConstant(targetHandle);
- if (constant.TypeCode != targetConstant.TypeCode)
- {
- var candidateTargets = ImmutableArray.Create(targetHandle);
- var candidateReasons = ImmutableArray.Create("Mapped constant has a different type.");
- return new Mapping(candidateTargets, candidateReasons);
- }
-
- ImmutableArray sourceContent = _sourceMetadata.GetBlobContent(constant.Value);
- ImmutableArray targetContent = _targetMetadata.GetBlobContent(targetConstant.Value);
- if (!sourceContent.SequenceEqual(targetContent))
- {
- var candidateTargets = ImmutableArray.Create(targetHandle);
- var candidateReasons = ImmutableArray.Create("Mapped constant has a different value.");
- return new Mapping(candidateTargets, candidateReasons);
- }
-
- return new Mapping(targetHandle);
- }
-
- private Mapping MapCustomAttributeImpl(CustomAttributeHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapDeclarativeSecurityAttributeImpl(DeclarativeSecurityAttributeHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapEventDefinitionImpl(EventDefinitionHandle handle)
- {
- EventDefinition eventDefinition = _sourceMetadata.GetEventDefinition(handle);
- EventAccessors accessors = eventDefinition.GetAccessors();
-
- // events always have an adder method, so use that to find the declaring type
- MethodDefinition adderMethodDefinition = _sourceMetadata.GetMethodDefinition(accessors.Adder);
- Mapping declaringTypeMapping = MapTypeDefinition(adderMethodDefinition.GetDeclaringType());
- if (declaringTypeMapping.Target.IsNil)
- return new Mapping();
-
- // Make sure each of the accessors maps successfully. Only the raiser is optional.
- Mapping adderMethodDefinitionMapping = MapMethodDefinition(accessors.Adder);
- if (adderMethodDefinitionMapping.Target.IsNil)
- return new Mapping();
-
- Mapping removerMethodDefinitionMapping = MapMethodDefinition(accessors.Remover);
- if (removerMethodDefinitionMapping.Target.IsNil)
- return new Mapping();
-
- Mapping raiserMethodDefinitionMapping = default(Mapping);
- if (!accessors.Raiser.IsNil)
- {
- raiserMethodDefinitionMapping = MapMethodDefinition(accessors.Raiser);
- if (raiserMethodDefinitionMapping.Target.IsNil)
- return new Mapping();
- }
-
- // locate the target event by name
- string eventName = _sourceMetadata.GetString(eventDefinition.Name);
- EventDefinitionHandle targetEventDefinitionHandle = default(EventDefinitionHandle);
- EventDefinition targetEventDefinition = default(EventDefinition);
- foreach (var targetHandle in _targetMetadata.EventDefinitions)
- {
- targetEventDefinition = _targetMetadata.GetEventDefinition(targetHandle);
- MethodDefinition targetAdderMethodDefinition = _targetMetadata.GetMethodDefinition(targetEventDefinition.GetAccessors().Adder);
- if (targetAdderMethodDefinition.GetDeclaringType() != declaringTypeMapping.Target)
- continue;
-
- if (!_targetMetadata.StringComparer.Equals(targetEventDefinition.Name, eventName))
- continue;
-
- targetEventDefinitionHandle = targetHandle;
- break;
- }
-
- if (targetEventDefinitionHandle.IsNil)
- return new Mapping();
-
- EventAccessors targetAccessors = targetEventDefinition.GetAccessors();
- if (targetAccessors.Adder != adderMethodDefinitionMapping.Target)
- return new Mapping();
-
- if (targetAccessors.Remover != removerMethodDefinitionMapping.Target)
- return new Mapping();
-
- if (!accessors.Raiser.IsNil)
- {
- if (targetAccessors.Raiser != raiserMethodDefinitionMapping.Target)
- return new Mapping();
- }
-
- return new Mapping(targetEventDefinitionHandle);
- }
-
- private Mapping MapExportedTypeImpl(ExportedTypeHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapFieldDefinitionImpl(FieldDefinitionHandle handle)
- {
- FieldDefinition fieldDefinition = _sourceMetadata.GetFieldDefinition(handle);
-
- // Map the parent
- Mapping declaringTypeMapping = MapTypeDefinition(fieldDefinition.GetDeclaringType());
- if (declaringTypeMapping.Target.IsNil)
- return new Mapping();
-
- string fieldName = _sourceMetadata.GetString(fieldDefinition.Name);
-
- TypeDefinition targetDeclaringType = _targetMetadata.GetTypeDefinition(declaringTypeMapping.Target);
- foreach (var targetHandle in targetDeclaringType.GetFields())
- {
- var targetField = _targetMetadata.GetFieldDefinition(targetHandle);
- if (!_targetMetadata.StringComparer.Equals(targetField.Name, fieldName))
- continue;
-
- // The name matches. If the signature matches, return in Target; otherwise, return in CandidateTargets.
- FieldSignature sourceSignature = _sourceMetadata.GetSignature(fieldDefinition);
- FieldSignature targetSignature = _targetMetadata.GetSignature(targetField);
- string candidateReason = CompareFieldSignatures(sourceSignature, targetSignature);
- if (candidateReason == null)
- return new Mapping(targetHandle);
-
- var candidateTargets = ImmutableArray.Create(targetHandle);
- var candidateReasons = ImmutableArray.Create(candidateReason);
- return new Mapping(candidateTargets, candidateReasons);
- }
-
- // No field with this name was located.
- return new Mapping();
- }
-
- private string CompareFieldSignatures(FieldSignature sourceSignature, FieldSignature targetSignature)
- {
- if (!sourceSignature.CustomModifiers.IsEmpty || !targetSignature.CustomModifiers.IsEmpty)
- throw new NotImplementedException();
-
- return CompareTypeSignatures(sourceSignature.Type, targetSignature.Type);
- }
-
- private string CompareTypeSignatures(TypeSignature sourceSignature, TypeSignature targetSignature)
- {
- if (sourceSignature.TypeCode != targetSignature.TypeCode)
- return "Type mismatch";
-
- switch (sourceSignature.TypeCode)
- {
- case SignatureTypeCode.Boolean:
- case SignatureTypeCode.Char:
- case SignatureTypeCode.SByte:
- case SignatureTypeCode.Byte:
- case SignatureTypeCode.Int16:
- case SignatureTypeCode.UInt16:
- case SignatureTypeCode.Int32:
- case SignatureTypeCode.UInt32:
- case SignatureTypeCode.Int64:
- case SignatureTypeCode.UInt64:
- case SignatureTypeCode.IntPtr:
- case SignatureTypeCode.UIntPtr:
- case SignatureTypeCode.Single:
- case SignatureTypeCode.Double:
- return null;
-
- case SignatureTypeCode.Object:
- case SignatureTypeCode.String:
- return null;
-
- case SignatureTypeCode.Array:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
-
- case SignatureTypeCode.FunctionPointer:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
-
- case SignatureTypeCode.GenericTypeInstance:
- if (!IsSameHandle(sourceSignature.TypeHandle, targetSignature.TypeHandle))
- return "Unbound generic type does not match.";
-
- ImmutableArray sourceGenericArguments = sourceSignature.GenericTypeArguments;
- ImmutableArray targetGenericArguments = targetSignature.GenericTypeArguments;
- if (sourceGenericArguments.Length != targetGenericArguments.Length)
- return "Generic arity does not match.";
-
- for (int i = 0; i < sourceGenericArguments.Length; i++)
- {
- string genericParameterResult = CompareTypeSignatures(sourceGenericArguments[i], targetGenericArguments[i]);
- if (genericParameterResult != null)
- return string.Format("Generic parameter {0} does not match: {1}", i, genericParameterResult);
- }
-
- return null;
-
- case SignatureTypeCode.GenericMethodParameter:
- case SignatureTypeCode.GenericTypeParameter:
- if (sourceSignature.GenericParameterIndex != targetSignature.GenericParameterIndex)
- return "Generic parameter index differs.";
-
- return null;
-
- case SignatureTypeCode.TypeHandle:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
- //Handle referenceTypeHandle = sourceSignature.TypeHandle;
- //Handle newTypeHandle = targetSignature.TypeHandle;
- //return IsSameType(referenceMetadata, newMetadata, referenceTypeHandle, newTypeHandle);
-
- case SignatureTypeCode.Pointer:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", sourceSignature.TypeCode));
-
- case SignatureTypeCode.SZArray:
- if (!sourceSignature.CustomModifiers.IsEmpty || !targetSignature.CustomModifiers.IsEmpty)
- throw new NotImplementedException();
-
- string szArrayResult = CompareTypeSignatures(sourceSignature.ElementType, targetSignature.ElementType);
- if (szArrayResult != null)
- szArrayResult = string.Format("SZArray element type mismatch: {0}", szArrayResult);
-
- return szArrayResult;
-
- default:
- throw new InvalidOperationException("Invalid signature type code.");
- }
- }
-
- private bool IsSameHandle(Handle sourceHandle, Handle targetHandle)
- {
- if (sourceHandle.IsNil != targetHandle.IsNil)
- return false;
-
- if (sourceHandle.IsNil)
- return true;
-
- Mapping mappedTarget = MapHandle(sourceHandle);
- if (mappedTarget.Target.IsNil)
- return false;
-
- return mappedTarget.Target == targetHandle;
- }
-
- private Mapping MapGenericParameterImpl(GenericParameterHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapGenericParameterConstraintImpl(GenericParameterConstraintHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapInterfaceImplementationImpl(InterfaceImplementationHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapManifestResourceImpl(ManifestResourceHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapMemberReferenceImpl(MemberReferenceHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapMethodDefinitionImpl(MethodDefinitionHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapMethodImplementationImpl(MethodImplementationHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapMethodSpecificationImpl(MethodSpecificationHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapModuleDefinitionImpl(ModuleDefinitionHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapModuleReferenceImpl(ModuleReferenceHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapNamespaceDefinitionImpl(NamespaceDefinitionHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapParameterImpl(ParameterHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapPropertyDefinitionImpl(PropertyDefinitionHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapStandaloneSignatureImpl(StandaloneSignatureHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapTypeDefinitionImpl(TypeDefinitionHandle handle)
- {
- MetadataReader referenceMetadata = _sourceMetadata;
- MetadataReader newMetadata = _targetMetadata;
- TypeDefinition referenceTypeDefinition = referenceMetadata.GetTypeDefinition(handle);
-
- string referenceName = referenceMetadata.GetString(referenceTypeDefinition.Name);
- string referenceNamespace = referenceMetadata.GetString(referenceTypeDefinition.Namespace);
-
- foreach (var typeDefinitionHandle in newMetadata.TypeDefinitions)
- {
- var typeDefinition = newMetadata.GetTypeDefinition(typeDefinitionHandle);
-
- if (!newMetadata.StringComparer.Equals(typeDefinition.Name, referenceName))
- continue;
-
- if (!newMetadata.StringComparer.Equals(typeDefinition.Namespace, referenceNamespace))
- continue;
-
- if (!typeDefinition.GetDeclaringType().IsNil)
- {
- if (referenceTypeDefinition.GetDeclaringType().IsNil)
- continue;
-
- Mapping newDeclaringTypeDefinitionHandle = MapTypeDefinition(referenceTypeDefinition.GetDeclaringType());
- if (newDeclaringTypeDefinitionHandle.Target.IsNil)
- continue;
-
- if (newDeclaringTypeDefinitionHandle.Target != typeDefinition.GetDeclaringType())
- continue;
- }
-
- return new Mapping(typeDefinitionHandle);
- }
-
- return new Mapping();
- }
-
- private Mapping MapTypeReferenceImpl(TypeReferenceHandle handle)
- {
- throw new NotImplementedException();
- }
-
- private Mapping MapTypeSpecificationImpl(TypeSpecificationHandle handle)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/CompatibilityChecker/Program.cs b/CompatibilityChecker/Program.cs
new file mode 100644
index 0000000..e23892c
--- /dev/null
+++ b/CompatibilityChecker/Program.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.PortableExecutable;
+using CommandLine;
+using CommandLine.Text;
+using CompatibilityChecker.Library;
+
+namespace CompatibilityCheckerCoreCLI
+{
+ using File = System.IO.File;
+ using FileInfo = System.IO.FileInfo;
+
+ internal class Program
+ {
+ public class Options
+ {
+ [Value(0, MetaName = "reference assembly", Required = true, HelpText = "The reference assembly.")]
+ public string ReferenceAssembly { get; set; }
+
+ [Value(1, MetaName = "new assembly", Required = true, HelpText = "The new assembly.")]
+ public string NewAssembly { get; set; }
+
+ [Option('a', "azure-pipelines", Required = false, Default = false, HelpText = "Include the logging prefixes for Azure Pipelines.")]
+ public bool AzurePipelines { get; set; }
+
+ [Option('w', "warnings-only", Required = false, Default = false, HelpText = "Do not raise errors for Azure Pipelines, it also swallows the return code.")]
+ public bool WarningsOnly { get; set; }
+
+ [Usage(ApplicationAlias = "dotnet compat")]
+ public static IEnumerable Examples
+ {
+ get
+ {
+ yield return new Example("Compare versions", new Options { ReferenceAssembly = "Assembly-1.0.0.dll", NewAssembly = "Assembly-1.0.1.dll" });
+ yield return new Example("Compare versions in Azure Pipelines as CI", new Options { ReferenceAssembly = "Assembly-1.0.0.dll", NewAssembly = "Assembly-1.0.1.dll", AzurePipelines = true });
+ yield return new Example("Compare versions in Azure Pipelines as CI without failing the CI job", new Options { ReferenceAssembly = "Assembly-1.0.0.dll", NewAssembly = "Assembly-1.0.1.dll", AzurePipelines = true, WarningsOnly = true });
+ }
+ }
+ }
+
+ private static void Main(string[] args)
+ {
+ Console.WriteLine("Running dotnet-compat v{0}...", Assembly.GetExecutingAssembly().GetName().Version);
+ var result = CommandLine.Parser.Default.ParseArguments(args)
+ .WithParsed(opts => RunWithOptions(opts));
+#if DEBUG
+ Console.WriteLine("Done. Press any key to exit.");
+ Console.ReadKey();
+#endif
+ if (result.Tag == ParserResultType.NotParsed)
+ {
+ Environment.ExitCode = 1;
+ }
+ }
+
+ private static void RunWithOptions(Options opts)
+ {
+ //Guid timeline_guid = Guid.NewGuid();
+ FileInfo referenceFile = new(opts.ReferenceAssembly);
+ FileInfo newFile = new(opts.NewAssembly);
+ if (referenceFile.Exists && newFile.Exists)
+ {
+ //if (opts.AzurePipelines)
+ //Console.WriteLine("##vso[task.logdetail id={0};name=BinaryCompatibilityCheck;type=build;order=1;state=Initialized]Starting...", timeline_guid);
+ var refName = AssemblyName.GetAssemblyName(referenceFile.FullName);
+ var newName = AssemblyName.GetAssemblyName(newFile.FullName);
+ Console.WriteLine("Using '{0}' as the reference assembly.", refName.FullName);
+ Console.WriteLine("Using '{0}' as the new assembly.", refName.FullName);
+ using (PEReader referenceAssembly = new(File.OpenRead(referenceFile.FullName)))
+ {
+ using (PEReader newAssembly = new(File.OpenRead(newFile.FullName)))
+ {
+ IMessageLogger logger;
+ if (opts.AzurePipelines)
+ {
+ if (opts.WarningsOnly)
+ {
+ logger = new AzurePipelinesMessageLogger(Severity.Warning);
+ }
+ else
+ {
+ logger = new AzurePipelinesMessageLogger();
+ }
+ }
+ else
+ {
+ logger = new ConsoleMessageLogger();
+ }
+
+ Analyzer analyzer = new(referenceAssembly, newAssembly, null, logger);
+ analyzer.Run();
+ if (analyzer.HasRun)
+ {
+ Console.WriteLine(string.Format("Analyzer done. {0} errors, {1} warnings, {2} informational items.", analyzer.ResultStatistics.SeverityCounts.error, analyzer.ResultStatistics.SeverityCounts.warning, analyzer.ResultStatistics.SeverityCounts.information));
+
+ if (analyzer.ResultStatistics.SeverityCounts.error > 0)
+ {
+ if (opts.AzurePipelines)
+ {
+ Console.WriteLine("##vso[task.complete result=SucceededWithIssues]");
+ }
+
+ Environment.ExitCode = opts.WarningsOnly ? 0 : -2;
+ return;
+ }
+ else
+ {
+ if (opts.AzurePipelines)
+ {
+ Console.WriteLine("##vso[task.complete result=Succeeded]");
+ }
+
+ return;
+ }
+ }
+ else
+ {
+ if (opts.AzurePipelines)
+ {
+ Console.WriteLine("##vso[task.complete result=Failed]");
+ }
+
+ Environment.ExitCode = opts.WarningsOnly ? 0 : -1;
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!referenceFile.Exists)
+ {
+ Console.Error.WriteLine("{1}Reference file '{0}' not found or inaccessible.", referenceFile.FullName, opts.AzurePipelines ? "##vso[task.logissue type=error]" : string.Empty);
+ }
+
+ if (!newFile.Exists)
+ {
+ Console.Error.WriteLine("{1}New file '{0}' not found or inaccessible.", newFile.FullName, opts.AzurePipelines ? "##vso[task.logissue type=error]" : string.Empty);
+ }
+
+ Environment.ExitCode = 2;
+ return;
+ }
+ }
+ }
+}
diff --git a/CompatibilityChecker/Properties/AssemblyInfo.cs b/CompatibilityChecker/Properties/AssemblyInfo.cs
deleted file mode 100644
index 0e90bfe..0000000
--- a/CompatibilityChecker/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("CompatibilityChecker")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Rackspace, Inc.")]
-[assembly: AssemblyProduct("CompatibilityChecker")]
-[assembly: AssemblyCopyright("Copyright © Sam Harwell 2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: CLSCompliant(false)]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("c3d7fce7-0fed-462f-a4a6-bafc6aa91ef2")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-[assembly: AssemblyInformationalVersion("1.0.0.0-dev")]
diff --git a/CompatibilityChecker/Properties/PublishProfiles/FolderProfile.pubxml b/CompatibilityChecker/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..b2304cb
--- /dev/null
+++ b/CompatibilityChecker/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,16 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp2.2
+ bin\Release\netcoreapp2.2\publish\
+ linux-x64
+ false
+ <_IsPortable>true
+
+
\ No newline at end of file
diff --git a/CompatibilityChecker/Properties/launchSettings.json b/CompatibilityChecker/Properties/launchSettings.json
new file mode 100644
index 0000000..8a3af5c
--- /dev/null
+++ b/CompatibilityChecker/Properties/launchSettings.json
@@ -0,0 +1,7 @@
+{
+ "profiles": {
+ "CompatibilityCheckerCoreExample": {
+ "commandName": "Project"
+ }
+ }
+}
\ No newline at end of file
diff --git a/CompatibilityChecker/Severity.cs b/CompatibilityChecker/Severity.cs
deleted file mode 100644
index 23d3c09..0000000
--- a/CompatibilityChecker/Severity.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace CompatibilityChecker
-{
- internal enum Severity
- {
- Disabled,
- Information,
- Warning,
- Error,
- }
-}
diff --git a/CompatibilityChecker/TypeSignature.cs b/CompatibilityChecker/TypeSignature.cs
deleted file mode 100644
index 8368899..0000000
--- a/CompatibilityChecker/TypeSignature.cs
+++ /dev/null
@@ -1,287 +0,0 @@
-namespace CompatibilityChecker
-{
- using System;
- using System.Collections.Immutable;
- using System.Reflection.Metadata;
-
- ///
- /// This structure represents a metadata Type signature, as described in ECMA-335 §II.23.2.12.
- ///
- public struct TypeSignature
- {
- private readonly BlobReader _reader;
-
- public TypeSignature(BlobReader blobReader)
- {
- _reader = blobReader;
- }
-
- public SignatureTypeCode TypeCode
- {
- get
- {
- return _reader.ReadSignatureTypeCode();
- }
- }
-
- ///
- /// Gets the index of a generic type or method parameter.
- ///
- ///
- /// If is not or
- /// .
- ///
- public int GenericParameterIndex
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.GenericMethodParameter:
- case SignatureTypeCode.GenericTypeParameter:
- return reader.ReadCompressedInteger();
-
- default:
- throw new InvalidOperationException("Only generic parameters have a generic parameter index.");
- }
- }
- }
-
- ///
- /// Gets the type handle encoded in the signature.
- ///
- ///
- /// If is not or
- /// .
- ///
- public Handle TypeHandle
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.TypeHandle:
- return reader.ReadTypeHandle();
-
- case SignatureTypeCode.GenericTypeInstance:
- reader.ReadSignatureTypeCode();
- return reader.ReadTypeHandle();
-
- default:
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have a type handle.", typeCode));
- }
- }
- }
-
- public ImmutableArray GenericTypeArguments
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
- if (typeCode != SignatureTypeCode.GenericTypeInstance)
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have generic arguments.", typeCode));
-
- reader.ReadSignatureTypeCode();
- reader.ReadTypeHandle();
-
- int genericArgumentCount = reader.ReadCompressedInteger();
- var builder = ImmutableArray.CreateBuilder(genericArgumentCount);
- for (int i = 0; i < genericArgumentCount; i++)
- {
- TypeSignature argument = new TypeSignature(reader);
- builder.Add(argument);
- reader = argument.Skip();
- }
-
- return builder.ToImmutable();
- }
- }
-
- public ImmutableArray CustomModifiers
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.Pointer:
- case SignatureTypeCode.SZArray:
- break;
-
- default:
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have custom modifiers.", typeCode));
- }
-
- var builder = ImmutableArray.CreateBuilder();
- while (reader.IsCustomModifier())
- {
- var customModifierSignature = new CustomModifierSignature(reader);
- builder.Add(customModifierSignature);
- reader = customModifierSignature.Skip();
- }
-
- return builder.ToImmutable();
- }
- }
-
- public TypeSignature ElementType
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.Array:
- return new TypeSignature(reader);
-
- case SignatureTypeCode.Pointer:
- while (reader.IsCustomModifier())
- reader = new CustomModifierSignature(reader).Skip();
-
- if (reader.PeekSignatureTypeCode() == SignatureTypeCode.Void)
- goto default;
-
- return new TypeSignature(reader);
-
- case SignatureTypeCode.SZArray:
- while (reader.IsCustomModifier())
- reader = new CustomModifierSignature(reader).Skip();
-
- return new TypeSignature(reader);
-
- default:
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have an element type.", typeCode));
- }
- }
- }
-
- public ArrayShapeSignature ArrayShape
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.Array:
- // skip past the type and return the array shape
- reader = new TypeSignature(reader).Skip();
- return new ArrayShapeSignature(reader);
-
- default:
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have an array shape signature.", typeCode));
- }
- }
- }
-
- public MethodSignature MethodSignature
- {
- get
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.FunctionPointer:
- return new MethodSignature(reader);
-
- default:
- throw new InvalidOperationException(string.Format("Type code '{0}' does not have a method signature.", typeCode));
- }
- }
- }
-
- public BlobReader Skip()
- {
- BlobReader reader = _reader;
- SignatureTypeCode typeCode = reader.ReadSignatureTypeCode();
-
- switch (typeCode)
- {
- case SignatureTypeCode.Boolean:
- case SignatureTypeCode.Char:
- case SignatureTypeCode.SByte:
- case SignatureTypeCode.Byte:
- case SignatureTypeCode.Int16:
- case SignatureTypeCode.UInt16:
- case SignatureTypeCode.Int32:
- case SignatureTypeCode.UInt32:
- case SignatureTypeCode.Int64:
- case SignatureTypeCode.UInt64:
- case SignatureTypeCode.IntPtr:
- case SignatureTypeCode.UIntPtr:
- case SignatureTypeCode.Single:
- case SignatureTypeCode.Double:
- break;
-
- case SignatureTypeCode.Object:
- case SignatureTypeCode.String:
- break;
-
- case SignatureTypeCode.Array:
- reader = new TypeSignature(reader).Skip();
- reader = new ArrayShapeSignature(reader).Skip();
- break;
-
- case SignatureTypeCode.FunctionPointer:
- throw new NotImplementedException(string.Format("{0} is not yet implemented.", typeCode));
-
- case SignatureTypeCode.GenericTypeInstance:
- reader.ReadSignatureTypeCode();
- reader.ReadTypeHandle();
-
- int argumentCount = reader.ReadCompressedInteger();
- for (int i = 0; i < argumentCount; i++)
- reader = new TypeSignature(reader).Skip();
-
- break;
-
- case SignatureTypeCode.GenericMethodParameter:
- case SignatureTypeCode.GenericTypeParameter:
- // skip the generic parameter index
- reader.ReadCompressedInteger();
- break;
-
- case SignatureTypeCode.TypeHandle:
- reader.ReadTypeHandle();
- break;
-
- case SignatureTypeCode.Pointer:
- while (reader.IsCustomModifier())
- reader = new CustomModifierSignature(reader).Skip();
-
- if (reader.PeekSignatureTypeCode() == SignatureTypeCode.Void)
- reader.ReadSignatureTypeCode();
- else
- reader = new TypeSignature(reader).Skip();
-
- break;
-
- case SignatureTypeCode.SZArray:
- while (reader.IsCustomModifier())
- reader = new CustomModifierSignature(reader).Skip();
-
- reader = new TypeSignature(reader).Skip();
- break;
-
- default:
- throw new InvalidOperationException("Invalid signature type code.");
- }
-
- return reader;
- }
- }
-}
diff --git a/CompatibilityChecker/packages.config b/CompatibilityChecker/packages.config
deleted file mode 100644
index 52eda50..0000000
--- a/CompatibilityChecker/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/CompatibilityCheckerTests/CompatibilityCheckerTests.csproj b/CompatibilityCheckerTests/CompatibilityCheckerTests.csproj
deleted file mode 100644
index c360fcd..0000000
--- a/CompatibilityCheckerTests/CompatibilityCheckerTests.csproj
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
- Debug
- AnyCPU
- {44681692-0479-4C99-BF40-F310B78D87F0}
- Library
- Properties
- CompatibilityCheckerTests
- CompatibilityCheckerTests
- v4.5
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 10.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- UnitTest
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
- False
- ..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
-
-
- False
- ..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {c3d7fce7-0fed-462f-a4a6-bafc6aa91ef2}
- CompatibilityChecker
-
-
-
-
-
-
-
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CompatibilityCheckerTests/Properties/AssemblyInfo.cs b/CompatibilityCheckerTests/Properties/AssemblyInfo.cs
deleted file mode 100644
index 521ca41..0000000
--- a/CompatibilityCheckerTests/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("CompatibilityCheckerTests")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Rackspace, Inc.")]
-[assembly: AssemblyProduct("CompatibilityCheckerTests")]
-[assembly: AssemblyCopyright("Copyright © Sam Harwell 2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: CLSCompliant(false)]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("44681692-0479-4c99-bf40-f310b78d87f0")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-[assembly: AssemblyInformationalVersion("1.0.0.0-dev")]
diff --git a/CompatibilityCheckerTests/TestAssemblyAnalysis.cs b/CompatibilityCheckerTests/TestAssemblyAnalysis.cs
deleted file mode 100644
index 1283b7c..0000000
--- a/CompatibilityCheckerTests/TestAssemblyAnalysis.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-namespace CompatibilityCheckerTests
-{
- using System.Collections.ObjectModel;
- using System.Reflection;
- using System.Reflection.Emit;
- using CompatibilityChecker;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- [TestClass]
- public class TestAssemblyAnalysis
- {
- [TestMethod]
- public void TestAssemblyNameMustNotBeChanged_Pass()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
- }
-
- [TestMethod]
- public void TestAssemblyNameMustNotBeChanged_Fail()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly.V2");
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(1, messages.Count);
- Assert.AreEqual("Error AssemblyNameMustNotBeChanged: The simple name of an assembly cannot change.", messages[0].ToString());
- }
-
- [TestMethod]
- public void TestPublicKeyMustNotBeChanged_PassMissing()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
- }
-
- [TestMethod]
- public void TestPublicKeyMustNotBeChanged_PassUnchanged()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- referenceName.KeyPair = TestUtility.GenerateStrongNameKeyPair();
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly");
- newAssemblyName.KeyPair = referenceName.KeyPair;
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
- }
-
- [TestMethod]
- public void TestPublicKeyMustNotBeChanged_PassAdded()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly");
- newAssemblyName.KeyPair = TestUtility.GenerateStrongNameKeyPair();
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
- }
-
- [TestMethod]
- public void TestPublicKeyMustNotBeChanged_Fail()
- {
- AssemblyName referenceName = new AssemblyName("Test.Assembly");
- referenceName.KeyPair = TestUtility.GenerateStrongNameKeyPair();
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.ReflectionOnly);
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- AssemblyName newAssemblyName = new AssemblyName("Test.Assembly");
- newAssemblyName.KeyPair = TestUtility.GenerateStrongNameKeyPair();
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.ReflectionOnly);
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
-
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(1, messages.Count);
- Assert.AreEqual("Error PublicKeyMustNotBeChanged: The public key of a strong-named assembly cannot change.", messages[0].ToString());
- }
- }
-}
diff --git a/CompatibilityCheckerTests/TestUtility.cs b/CompatibilityCheckerTests/TestUtility.cs
deleted file mode 100644
index bcff1c9..0000000
--- a/CompatibilityCheckerTests/TestUtility.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-namespace CompatibilityCheckerTests
-{
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Reflection;
- using System.Reflection.PortableExecutable;
- using System.Security.Cryptography;
- using CompatibilityChecker;
- using File = System.IO.File;
-
- internal static class TestUtility
- {
- public static ReadOnlyCollection AnalyzeAssemblies(string referenceAssemblyFile, string newAssemblyFile)
- {
- using (PEReader referenceAssembly = new PEReader(File.OpenRead(referenceAssemblyFile)))
- {
- using (PEReader newAssembly = new PEReader(File.OpenRead(newAssemblyFile)))
- {
- TestMessageLogger logger = new TestMessageLogger();
- Analyzer analyzer = new Analyzer(referenceAssembly, newAssembly, logger);
- analyzer.Run();
-
- return logger.RawMessages;
- }
- }
- }
-
- public static StrongNameKeyPair GenerateStrongNameKeyPair()
- {
- using (var provider = new RSACryptoServiceProvider(1024, new CspParameters { KeyNumber = 2 }))
- {
- byte[] keyPairArray = provider.ExportCspBlob(true);
- return new StrongNameKeyPair(keyPairArray);
- }
- }
-
- internal class TestMessageLogger : IMessageLogger
- {
- private readonly List _rawMessages = new List();
- private readonly List _messages = new List();
-
- public ReadOnlyCollection RawMessages
- {
- get
- {
- return _rawMessages.AsReadOnly();
- }
- }
-
- public ReadOnlyCollection Messages
- {
- get
- {
- return _messages.AsReadOnly();
- }
- }
-
- public void Report(Message message)
- {
- _rawMessages.Add(message);
- _messages.Add(message.ToString());
- }
- }
- }
-}
diff --git a/CompatibilityCheckerTests/packages.config b/CompatibilityCheckerTests/packages.config
deleted file mode 100644
index 52eda50..0000000
--- a/CompatibilityCheckerTests/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 3a3c723..6b0b127 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,12 +1,203 @@
-Copyright (c) Rackspace, US Inc. All rights reserved.
-Licensed under the Apache License, Version 2.0 (the "License"); you may not use
-these files except in compliance with the License. You may obtain a copy of the
-License at
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
-http://www.apache.org/licenses/LICENSE-2.0
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-Unless required by applicable law or agreed to in writing, software distributed
-under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-CONDITIONS OF ANY KIND, either express or implied. See the License for the
-specific language governing permissions and limitations under the License.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..4a6ecf2
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,5 @@
+dotnet-compatibility (CompatibilityChecker)
+
+Copyright (c) Rackspace, US Inc.
+Copyright (c) tunnelvisionlabs
+Copyright (c) 2020 Erwin de Haan
diff --git a/README.md b/README.md
index 4f36b58..e35cdb3 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# Binary Compatibility Checker
+CompatibilityChecker: [](https://www.nuget.org/packages/CompatibilityChecker)
+CompatibilityChecker.Library: [](https://www.nuget.org/packages/CompatibilityChecker.Library)
+
This project implements a binary compatibility checker for .NET assemblies. The goal of this project is to automate the
process of identifying binary- and source-breaking changes between releases of a .NET library. Libraries with string
compatibility policies will eventually be able to incorporate this check in the unit tests for the library. The checker
@@ -14,6 +17,27 @@ Diagnostics produced by this checker will be categorized by their likely impact
constitutes a binary- or source-level breaking change. At this time, there are no plans to implement detection or
reporting for changes in runtime semantics.
+## Usage
+
+Compare versions:
+ `dotnet compat Assembly-1.0.0.dll Assembly-1.0.1.dll`
+Compare versions in Azure Pipelines as CI:
+ `dotnet compat --azure-pipelines Assembly-1.0.0.dll Assembly-1.0.1.dll`
+Compare versions in Azure Pipelines as CI without failing the CI job:
+ `dotnet compat --azure-pipelines --warnings-only Assembly-1.0.0.dll Assembly-1.0.1.dll`
+
+ -a, --azure-pipelines (Default: false) Include the logging prefixes for Azure Pipelines.
+
+ -w, --warnings-only (Default: false) Do not raise errors for Azure Pipelines, it also swallows the return code.
+
+ --help Display this help screen.
+
+ --version Display version information.
+
+ reference assembly (pos. 0) Required. The reference assembly.
+
+ new assembly (pos. 1) Required. The new assembly.
+
## Definitions
* **Reference assembly**: The "old" version of the assembly used for compatibility analysis.
diff --git a/TestSettings.testsettings b/TestSettings.testsettings
deleted file mode 100644
index 3d5d5d0..0000000
--- a/TestSettings.testsettings
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
- These are default test settings for a local test run.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pack.bat b/pack.bat
new file mode 100644
index 0000000..335d609
--- /dev/null
+++ b/pack.bat
@@ -0,0 +1,5 @@
+@ECHO OFF
+
+dotnet pack -c Release -o ./packed CompatibilityChecker.Library/CompatibilityChecker.Library.csproj
+
+dotnet pack -c Release -o ./packed CompatibilityChecker/CompatibilityChecker.csproj
\ No newline at end of file
diff --git a/tests/CompatibilityChecker.Library.Tests/CompatibilityChecker.Library.Tests.csproj b/tests/CompatibilityChecker.Library.Tests/CompatibilityChecker.Library.Tests.csproj
new file mode 100644
index 0000000..48f238e
--- /dev/null
+++ b/tests/CompatibilityChecker.Library.Tests/CompatibilityChecker.Library.Tests.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net7.0
+
+ false
+ true
+ AllEnabledByDefault
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/tests/CompatibilityChecker.Library.Tests/TestAssemblyAnalysis.cs b/tests/CompatibilityChecker.Library.Tests/TestAssemblyAnalysis.cs
new file mode 100644
index 0000000..fd61000
--- /dev/null
+++ b/tests/CompatibilityChecker.Library.Tests/TestAssemblyAnalysis.cs
@@ -0,0 +1,47 @@
+using System.Collections.Immutable;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using System.Reflection.Emit;
+using Lokad.ILPack;
+using Xunit;
+
+namespace CompatibilityChecker.Library.Tests
+{
+ public class TestAssemblyAnalysis
+ {
+ private readonly AssemblyGenerator generator = new ();
+
+ [Fact]
+ public void TestAssemblyNameMustNotBeChanged_Pass()
+ {
+ AssemblyName referenceName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.RunAndCollect);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
+
+ AssemblyName newAssemblyName = new ("Test.Assembly");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.RunAndCollect);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
+
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
+ }
+
+ [Fact]
+ public void TestAssemblyNameMustNotBeChanged_Fail()
+ {
+ AssemblyName referenceName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(referenceName, AssemblyBuilderAccess.Run);
+ referenceAssemblyBuilder.DefineDynamicModule("TestAssembly");
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
+
+ AssemblyName newAssemblyName = new ("Test.Assembly.V2");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(newAssemblyName, AssemblyBuilderAccess.Run);
+ newAssemblyBuilder.DefineDynamicModule("TestAssemblyV2");
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
+
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Single(messages);
+ Assert.Equal("Error AssemblyNameMustNotBeChanged: The simple name of an assembly cannot change for 'Test.Assembly'.", messages[0].ToString());
+ }
+ }
+}
diff --git a/CompatibilityCheckerTests/TestTypeAnalysis.cs b/tests/CompatibilityChecker.Library.Tests/TestTypeAnalysis.cs
similarity index 59%
rename from CompatibilityCheckerTests/TestTypeAnalysis.cs
rename to tests/CompatibilityChecker.Library.Tests/TestTypeAnalysis.cs
index c54af9b..b0d91a8 100644
--- a/CompatibilityCheckerTests/TestTypeAnalysis.cs
+++ b/tests/CompatibilityChecker.Library.Tests/TestTypeAnalysis.cs
@@ -1,190 +1,192 @@
-namespace CompatibilityCheckerTests
+using System.Collections.Immutable;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using System.Reflection.Emit;
+using Lokad.ILPack;
+using Xunit;
+
+namespace CompatibilityChecker.Library.Tests
{
- using System.Collections.ObjectModel;
- using System.Reflection;
- using System.Reflection.Emit;
- using CompatibilityChecker;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- [TestClass]
public class TestTypeAnalysis
{
- [TestMethod]
+ private readonly AssemblyGenerator generator = new ();
+
+ [Fact]
public void TestAbstractMustNotBeAddedToType_PassUnchanged()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestAbstractMustNotBeAddedToType_PassRemoved()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestAbstractMustNotBeAddedToType_PassNotPublic()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.NotPublic, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.Abstract, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestAbstractMustNotBeAddedToType_Fail()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(1, messages.Count);
- Assert.AreEqual("Error AbstractMustNotBeAddedToType: The 'abstract' modifier cannot be added to a type.", messages[0].ToString());
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Single(messages);
+ Assert.Equal("Error AbstractMustNotBeAddedToType: The 'abstract' modifier cannot be added to type '.MyType'.", messages[0].ToString());
}
- [TestMethod]
+ [Fact]
public void TestSealedMustNotBeAddedToType_PassUnchanged()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestSealedMustNotBeAddedToType_PassRemoved()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestSealedMustNotBeAddedToType_PassNotPublic()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.NotPublic, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.Sealed, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies("Test.Assembly.dll", "Test.Assembly.V2.dll");
- Assert.AreEqual(0, messages.Count);
+ ReadOnlyCollection messages = TestUtility.AnalyzeAssemblies(v1Bytes, v2Bytes);
+ Assert.Empty(messages);
}
- [TestMethod]
+ [Fact]
public void TestSealedMustNotBeAddedToType_Fail()
{
- AssemblyName assemblyName = new AssemblyName("Test.Assembly");
- AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.dll");
+ AssemblyName assemblyName = new ("Test.Assembly");
+ AssemblyBuilder referenceAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder referenceModuleBuilder = referenceAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder referenceTypeBuilder = referenceModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public, typeof(object));
referenceTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
referenceTypeBuilder.CreateType();
- referenceAssemblyBuilder.Save("Test.Assembly.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v1Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(referenceAssemblyBuilder));
- AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
- ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name, "Test.Assembly.V2.dll");
+ AssemblyBuilder newAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+ ModuleBuilder newModuleBuilder = newAssemblyBuilder.DefineDynamicModule(assemblyName.Name!);
TypeBuilder newTypeBuilder = newModuleBuilder.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, typeof(object));
newTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
newTypeBuilder.CreateType();
- newAssemblyBuilder.Save("Test.Assembly.V2.dll", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64);
+ var v2Bytes = ImmutableArray.Create(generator.GenerateAssemblyBytes(newAssemblyBuilder));
- ReadOnlyCollection