diff --git a/ILSpy/Images/DictionaryContain.svg b/ILSpy/Images/DictionaryContain.svg
new file mode 100644
index 000000000..bb184464c
--- /dev/null
+++ b/ILSpy/Images/DictionaryContain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ILSpy/Images/DictionaryContain.xaml b/ILSpy/Images/DictionaryContain.xaml
new file mode 100644
index 000000000..f0dd255a2
--- /dev/null
+++ b/ILSpy/Images/DictionaryContain.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/Images/ExpandAll.svg b/ILSpy/Images/ExpandAll.svg
new file mode 100644
index 000000000..6279eada7
--- /dev/null
+++ b/ILSpy/Images/ExpandAll.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ILSpy/Images/ExpandAll.xaml b/ILSpy/Images/ExpandAll.xaml
new file mode 100644
index 000000000..e46b95c82
--- /dev/null
+++ b/ILSpy/Images/ExpandAll.xaml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/Images/README.md b/ILSpy/Images/README.md
index 05dcc6f09..6d78750cc 100644
--- a/ILSpy/Images/README.md
+++ b/ILSpy/Images/README.md
@@ -15,9 +15,11 @@ Icons used in ILSpy:
| Copy | x | x | VS 2017 Icon Pack (Copy) | |
| Delegate | x | x | VS 2017 Icon Pack (Delegate) | |
| Delete | x | x | VS 2017 Icon Pack (Remove_color) | |
+| DictionaryContain | x | x | VS 2017 Icon Pack (DictionaryContain) | |
| Enum | x | x | VS 2017 Icon Pack (Enumerator) | |
| EnumValue | x | x | VS 2017 Icon Pack (EnumItem) | |
| Event | x | x | VS 2017 Icon Pack (Event) | |
+| ExpandAll | x | x | VS 2017 Icon Pack (ExpandAll) | |
| ExportOverlay | x | x | slightly modified VS 2017 Icon Pack (Export) | |
| ExtensionMethod | x | x | VS 2017 Icon Pack (ExtensionMethod) | |
| Field | x | x | VS 2017 Icon Pack (Field) | |
@@ -62,6 +64,7 @@ Icons used in ILSpy:
| ResourceXml | x | x | VS 2017 Icon Pack (XMLFile) | |
| ResourceXsd | x | x | combined VS 2017 Icon Pack (XMLSchema) with the file symbol in ResourceXslt | |
| ResourceXsl | x | x | VS 2017 Icon Pack (XMLTransformation) | |
+| ResultToJSON | x | x | VS 2017 Icon Pack (ResultToJSON) | |
| ResourceXslt | x | x | VS 2017 Icon Pack (XSLTTemplate) | |
| Save | x | x | VS 2017 Icon Pack (Save) | |
| Search | x | x | VS 2017 Icon Pack (Search) | |
@@ -73,6 +76,7 @@ Icons used in ILSpy:
| Struct | x | x | VS 2017 Icon Pack (Structure) | |
| SubTypes | x | x | based on VS 2017 Icon Pack (BaseType) rotated +90° | |
| SuperTypes | x | x | based on VS 2017 Icon Pack (BaseType) rotated -90° | |
+| SwitchSourceOrTarget | x | x | VS 2017 Icon Pack (SwitchSourceOrTarget) | |
| ViewCode | x | x | VS 2017 Icon Pack (GoToSourceCode) | |
| VirtualMethod | x | x | combined VS 2017 Icon Pack (Method) two times | |
| Warning | x | x | VS 2017 Icon Pack (StatusWarning) | |
diff --git a/ILSpy/Images/ResultToJSON.svg b/ILSpy/Images/ResultToJSON.svg
new file mode 100644
index 000000000..9057dc768
--- /dev/null
+++ b/ILSpy/Images/ResultToJSON.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ILSpy/Images/ResultToJSON.xaml b/ILSpy/Images/ResultToJSON.xaml
new file mode 100644
index 000000000..1dfb33662
--- /dev/null
+++ b/ILSpy/Images/ResultToJSON.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/Images/SwitchSourceOrTarget.svg b/ILSpy/Images/SwitchSourceOrTarget.svg
new file mode 100644
index 000000000..b51f87a9e
--- /dev/null
+++ b/ILSpy/Images/SwitchSourceOrTarget.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ILSpy/Images/SwitchSourceOrTarget.xaml b/ILSpy/Images/SwitchSourceOrTarget.xaml
new file mode 100644
index 000000000..5a72dc2c1
--- /dev/null
+++ b/ILSpy/Images/SwitchSourceOrTarget.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/ViewModels/CompareViewModel.cs b/ILSpy/ViewModels/CompareViewModel.cs
index 7ae583564..529e04511 100644
--- a/ILSpy/ViewModels/CompareViewModel.cs
+++ b/ILSpy/ViewModels/CompareViewModel.cs
@@ -20,29 +20,30 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using System.Reflection.Metadata;
+using System.Text.Json;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
+using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.AssemblyTree;
+using ICSharpCode.ILSpy.TreeNodes;
+using ICSharpCode.ILSpy.Views;
using ICSharpCode.ILSpyX;
-
-using TomsToolbox.Wpf;
+using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
#nullable enable
namespace ICSharpCode.ILSpy.ViewModels
{
- using System.Linq;
- using System.Threading.Tasks;
- using System.Windows.Input;
- using System.Windows.Media;
-
- using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.TypeSystem;
- using ICSharpCode.ILSpy.Commands;
- using ICSharpCode.ILSpy.TreeNodes;
- using ICSharpCode.ILSpy.Views;
- using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
+
+ using TomsToolbox.Wpf;
class CompareViewModel : ObservableObject
{
@@ -70,6 +71,7 @@ namespace ICSharpCode.ILSpy.ViewModels
this.SwapAssembliesCommand = new DelegateCommand(OnSwapAssemblies);
this.ExpandAllCommand = new DelegateCommand(OnExpandAll);
+ this.CopyToClipboardAsJSONCommand = new DelegateCommand(OnCopyToClipboardAsJSON);
this.PropertyChanged += CompareViewModel_PropertyChanged;
}
@@ -153,6 +155,7 @@ namespace ICSharpCode.ILSpy.ViewModels
public ICommand SwapAssembliesCommand { get; set; }
public ICommand ExpandAllCommand { get; set; }
+ public ICommand CopyToClipboardAsJSONCommand { get; set; }
void OnSwapAssemblies()
{
@@ -163,7 +166,7 @@ namespace ICSharpCode.ILSpy.ViewModels
OnPropertyChanged(nameof(RightAssembly));
}
- public void OnExpandAll()
+ void OnExpandAll()
{
foreach (var node in RootEntry.DescendantsAndSelf())
{
@@ -171,6 +174,77 @@ namespace ICSharpCode.ILSpy.ViewModels
}
}
+ void OnCopyToClipboardAsJSON()
+ {
+ var options = new JsonSerializerOptions {
+ WriteIndented = true
+ };
+
+ var jsonEntry = ConvertToJson(this.root.Entry);
+ var json = JsonSerializer.Serialize(jsonEntry, options);
+ Clipboard.SetText(json);
+ }
+
+ private object ConvertToJson(Entry entry)
+ {
+ List changedTypes = new();
+ List addedTypes = new();
+ List removedTypes = new();
+
+ foreach (var item in TreeTraversal.PreOrder(entry, entry => entry.Children))
+ {
+ if (item.Entity is ITypeDefinition)
+ {
+ switch (item.RecursiveKind)
+ {
+ case DiffKind.Add:
+ addedTypes.Add(item);
+ break;
+ case DiffKind.Remove:
+ removedTypes.Add(item);
+ break;
+ case DiffKind.Update:
+ changedTypes.Add(item);
+ break;
+ }
+ }
+ }
+ var result = new {
+ left = LeftAssembly.FileName.Replace('\\', '/'),
+ right = RightAssembly.FileName.Replace('\\', '/'),
+ changedTypes = changedTypes.SelectArray(t => new { typeName = ((ITypeDefinition)t.Entity).FullName, changes = GetChanges(t.Children) }),
+ addedTypes = addedTypes.SelectArray(t => new { typeName = ((ITypeDefinition)t.Entity).FullName, changes = GetChanges(t.Children) }),
+ removedTypes = removedTypes.SelectArray(t => new { typeName = ((ITypeDefinition)t.Entity).FullName, changes = GetChanges(t.Children) })
+ };
+ return result;
+
+ string? GetEntityText(ISymbol? symbol) => symbol switch {
+ ITypeDefinition t => this.assemblyTreeModel.CurrentLanguage.TypeToString(t, includeNamespace: true),
+ IMethod m => this.assemblyTreeModel.CurrentLanguage.MethodToString(m, false, false, false),
+ IField f => this.assemblyTreeModel.CurrentLanguage.FieldToString(f, false, false, false),
+ IProperty p => this.assemblyTreeModel.CurrentLanguage.PropertyToString(p, false, false, false),
+ IEvent e => this.assemblyTreeModel.CurrentLanguage.EventToString(e, false, false, false),
+ INamespace n => n.FullName,
+ IModule m => m.FullAssemblyName,
+ _ => null,
+ };
+
+ IEnumerable