diff --git a/Debuggee/Debuggee.csproj b/Debuggee/Debuggee.csproj
new file mode 100644
index 0000000..887c330
--- /dev/null
+++ b/Debuggee/Debuggee.csproj
@@ -0,0 +1,37 @@
+
+
+
+ netstandard2.0;net472;netcoreapp2.0
+ ExpressionTreeVisualizer.Serialization
+ ExpressionTreeVisualizer.Debuggee
+ 8.0
+ enable
+ true
+
+
+
+ false
+ false
+ bin/$(Configuration)/net2.0/
+
+
+
+ false
+ false
+ bin/$(Configuration)/netcoreapp/
+
+
+
+
+
+
+
+
+ ..\..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.DebuggerVisualizers.dll
+ false
+
+
+
+
+
+
diff --git a/Visualizer/VisualizerDataObjectSource.cs b/Debuggee/VisualizerDataObjectSource.cs
similarity index 91%
rename from Visualizer/VisualizerDataObjectSource.cs
rename to Debuggee/VisualizerDataObjectSource.cs
index dfdd224..ec63707 100644
--- a/Visualizer/VisualizerDataObjectSource.cs
+++ b/Debuggee/VisualizerDataObjectSource.cs
@@ -1,5 +1,6 @@
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.IO;
+using ExpressionTreeVisualizer.Serialization;
namespace ExpressionTreeVisualizer {
public class VisualizerDataObjectSource : VisualizerObjectSource {
diff --git a/ExpressionTreeVisualizer.sln b/ExpressionTreeVisualizer.sln
index 1ae6f97..bbfed8d 100644
--- a/ExpressionTreeVisualizer.sln
+++ b/ExpressionTreeVisualizer.sln
@@ -7,17 +7,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_visualizerTests", "_visual
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "_visualizerTests.VB", "_visualizerTests.VB\_visualizerTests.VB.vbproj", "{16EF3252-7F7C-4E3F-A3B0-275ACACFBA3A}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Visualizer", "Tests.Visualizer\Tests.Visualizer.csproj", "{A6DB4A34-28E2-4012-AF70-9E24DAB9BCD6}"
-EndProject
-Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Visualizer.Shared", "Visualizer.Shared\Visualizer.Shared.shproj", "{16CA0653-E03A-47DF-A5BF-292EEF9AA5F0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests.Visualizer\Tests.csproj", "{A6DB4A34-28E2-4012-AF70-9E24DAB9BCD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Visualizer", "Visualizer\Visualizer.csproj", "{83B4B968-2066-4463-8F62-A4DFA405A2DB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_visualizerTestNoRef", "_visualizerTestNoRef\_visualizerTestNoRef.csproj", "{5F11601F-1A4F-4C5B-99D5-5F5EC3F2EB1F}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Debuggee", "Debuggee\Debuggee.csproj", "{8D8CCC9D-618B-45A1-B6EE-02F675B4DB70}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Serialization", "Serialization\Serialization.shproj", "{9365B962-F17C-451C-92EB-F4FED9C6C84E}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "UI", "UI\UI.shproj", "{E1D67370-17AC-47FC-89BC-34B20B3BD6E7}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Visualizer.Xaml", "Visualizer.Xaml\Visualizer.Xaml.shproj", "{89DE9332-5AA0-4136-A785-ED712FDC39FC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Package", "Package\Package.csproj", "{0AA18EF4-75D3-42D8-A084-75F42F4E836A}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
- Visualizer.Shared\Visualizer.Shared.projitems*{16ca0653-e03a-47df-a5bf-292eef9aa5f0}*SharedItemsImports = 13
+ Visualizer.Xaml\Visualizer.Xaml.projitems*{89de9332-5aa0-4136-a785-ed712fdc39fc}*SharedItemsImports = 13
+ Serialization\Serialization.projitems*{9365b962-f17c-451c-92eb-f4fed9c6c84e}*SharedItemsImports = 13
+ UI\UI.projitems*{e1d67370-17ac-47fc-89bc-34b20b3bd6e7}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +51,14 @@ Global
{5F11601F-1A4F-4C5B-99D5-5F5EC3F2EB1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F11601F-1A4F-4C5B-99D5-5F5EC3F2EB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F11601F-1A4F-4C5B-99D5-5F5EC3F2EB1F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D8CCC9D-618B-45A1-B6EE-02F675B4DB70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D8CCC9D-618B-45A1-B6EE-02F675B4DB70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D8CCC9D-618B-45A1-B6EE-02F675B4DB70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D8CCC9D-618B-45A1-B6EE-02F675B4DB70}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0AA18EF4-75D3-42D8-A084-75F42F4E836A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0AA18EF4-75D3-42D8-A084-75F42F4E836A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0AA18EF4-75D3-42D8-A084-75F42F4E836A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0AA18EF4-75D3-42D8-A084-75F42F4E836A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Package/Package.csproj b/Package/Package.csproj
new file mode 100644
index 0000000..08c7c11
--- /dev/null
+++ b/Package/Package.csproj
@@ -0,0 +1,32 @@
+
+
+ net472
+ ExpressionTreeVisualizer
+ ExpressionTreeVisualizer.UI
+ 8.0
+ enable
+ true
+
+
+
+
+
+
+
+ ..\..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.DebuggerVisualizers.dll
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Serialization/EndNodeData.cs b/Serialization/EndNodeData.cs
new file mode 100644
index 0000000..0419819
--- /dev/null
+++ b/Serialization/EndNodeData.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace ExpressionTreeVisualizer.Serialization {
+ [Serializable]
+ [SuppressMessage("", "IDE0032", Justification = "https://github.com/dotnet/core/issues/2981")]
+ public struct EndNodeData {
+ private string? _closure;
+ private string? _name;
+ private string? _type;
+ private string? _value;
+
+ public string? Closure {
+ get => _closure;
+ set => _closure = value;
+ }
+ public string? Name {
+ get => _name;
+ set => _name = value;
+ }
+ public string? Type {
+ get => _type;
+ set => _type = value;
+ }
+ public string? Value {
+ get => _value;
+ set => _value = value;
+ }
+ }
+}
diff --git a/Serialization/EndNodeType.cs b/Serialization/EndNodeType.cs
new file mode 100644
index 0000000..9d5ab83
--- /dev/null
+++ b/Serialization/EndNodeType.cs
@@ -0,0 +1,8 @@
+namespace ExpressionTreeVisualizer.Serialization {
+ public enum EndNodeTypes {
+ Constant,
+ Parameter,
+ ClosedVar,
+ Default
+ }
+}
diff --git a/Visualizer/VisualizerData.cs b/Serialization/ExpressionNodeData.cs
similarity index 60%
rename from Visualizer/VisualizerData.cs
rename to Serialization/ExpressionNodeData.cs
index 87e75b8..659065a 100644
--- a/Visualizer/VisualizerData.cs
+++ b/Serialization/ExpressionNodeData.cs
@@ -1,113 +1,22 @@
-using ExpressionTreeToString;
-using ExpressionTreeToString.Util;
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Diagnostics;
using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static ExpressionTreeToString.Globals;
+using ExpressionTreeVisualizer.Serialization.Util;
using System.Linq.Expressions;
+using ExpressionTreeToString.Util;
+using System.Reflection;
+using static ExpressionTreeVisualizer.Serialization.EndNodeTypes;
using static ExpressionTreeToString.Util.Functions;
-using static ExpressionTreeVisualizer.EndNodeTypes;
-using static ExpressionTreeToString.FormatterNames;
using System.Collections;
+using static ExpressionTreeToString.FormatterNames;
using System.Runtime.CompilerServices;
-using static ExpressionTreeToString.Globals;
-using System.Reflection;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-
-namespace ExpressionTreeVisualizer {
- [Serializable]
- public class VisualizerDataOptions : INotifyPropertyChanged {
- private string _formatter = CSharp;
- public string Formatter {
- get => _formatter;
- set {
- Language = ResolveLanguage(value);
- this.NotifyChanged(ref _formatter, value, args => PropertyChanged?.Invoke(this, args));
- }
- }
-
- private string _language = CSharp;
- public string Language {
- get => _language;
- set => this.NotifyChanged(ref _language, value, args => PropertyChanged?.Invoke(this, args));
- }
-
- public string? Path { get; set; }
-
- [field: NonSerialized]
- public event PropertyChangedEventHandler? PropertyChanged;
-
- public VisualizerDataOptions(VisualizerDataOptions? options = null) {
- if (options is { }) {
- _formatter = options.Formatter;
- _language = options.Language;
- Path = options.Path;
- }
- }
- }
-
- [Serializable]
- public class VisualizerData {
- public string Source { get; set; }
- public VisualizerDataOptions Options { get; set; }
- public ExpressionNodeData NodeData { get; set; }
-
- [NonSerialized] // the items in this List are grouped and serialized into separate collections
- public List CollectedEndNodes;
- [NonSerialized]
- public Dictionary PathSpans;
-
- public Dictionary> Constants { get; }
- public Dictionary> Parameters { get; }
- public Dictionary> ClosedVars { get; }
- public Dictionary> Defaults { get; }
-
- public ExpressionNodeData FindNodeBySpan(int start, int length) {
- var end = start + length;
- //if (start < NodeData.Span.start || end > NodeData.SpanEnd) { throw new ArgumentOutOfRangeException(); }
- var current = NodeData;
- while (true) {
- var child = current.Children.SingleOrDefault(x => x.Span.start <= start && x.SpanEnd >= end);
- if (child == null) { break; }
- current = child;
- }
- return current;
- }
-
- public VisualizerData(object o, VisualizerDataOptions? options = null) {
- Options = options ?? new VisualizerDataOptions();
- if (!Options.Path.IsNullOrWhitespace()) {
- o = ((Expression)ResolvePath(o, Options.Path)).ExtractValue();
- }
- Source = WriterBase.Create(o, Options.Formatter, Options.Language, out var pathSpans).ToString();
- PathSpans = pathSpans;
- CollectedEndNodes = new List();
- NodeData = new ExpressionNodeData(o, ("", ""), this, false);
-
- // TODO it should be possible to write the following using LINQ
- Constants = new Dictionary>();
- Parameters = new Dictionary>();
- ClosedVars = new Dictionary>();
- Defaults = new Dictionary>();
-
- foreach (var x in CollectedEndNodes) {
- var dict = x.EndNodeType switch {
- Constant => Constants,
- Parameter => Parameters,
- ClosedVar => ClosedVars,
- Default => Defaults,
- _ => throw new InvalidOperationException(),
- };
- if (!dict.TryGetValue(x.EndNodeData, out var lst)) {
- lst = new List();
- dict[x.EndNodeData] = lst;
- }
- lst.Add(x);
- }
- }
- }
+namespace ExpressionTreeVisualizer.Serialization {
[Serializable]
[DebuggerDisplay("{FullPath}")]
public class ExpressionNodeData : INotifyPropertyChanged {
@@ -126,13 +35,13 @@ public class ExpressionNodeData : INotifyPropertyChanged {
public (string @namespace, string typename, string propertyname)? ParentProperty { get; set; }
public List<(string @namespace, string enumTypename, string membername)>? NodeTypesParts { get; set; }
- private readonly List<(string @namespace, string typename)> _baseTypes;
- public List<(string @namespace, string typename)> BaseTypes => _baseTypes;
+ private readonly List<(string @namespace, string typename)>? _baseTypes;
+ public List<(string @namespace, string typename)>? BaseTypes => _baseTypes;
public string? WatchExpressionFormatString { get; set; }
public bool EnableValueInNewWindow { get; set; }
private readonly string[] _factoryMethodNames;
- public string[] FactoryMethodNames => _factoryMethodNames;
+ public string[]? FactoryMethodNames => _factoryMethodNames;
public EndNodeData EndNodeData => new EndNodeData {
Closure = Closure,
@@ -157,11 +66,11 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
case Expression expr:
NodeType = expr.NodeType.ToString();
NodeTypesParts = new List<(string @namespace, string enumTypename, string membername)> {
- (typeof(ExpressionType).Namespace, nameof(ExpressionType), NodeType)
+ (typeof(ExpressionType).Namespace!, nameof(ExpressionType), NodeType)
};
if (expr is GotoExpression gexpr) {
NodeTypesParts.Add(
- typeof(GotoExpressionKind).Namespace, nameof(GotoExpressionKind), gexpr.Kind.ToString()
+ typeof(GotoExpressionKind).Namespace!, nameof(GotoExpressionKind), gexpr.Kind.ToString()
);
}
ReflectionTypeName = expr.Type.FriendlyName(language);
@@ -170,10 +79,10 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
// fill the Name and Closure properties, for expressions
Name = expr.Name(language);
- if (expr is MemberExpression mexpr &&
+ if (expr is MemberExpression mexpr &&
mexpr.Expression?.Type is Type expressionType &&
expressionType.IsClosureClass()) {
- Closure = expressionType.Name;
+ Closure = expressionType.Name;
}
object? value = null;
@@ -207,8 +116,8 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
case MemberBinding mbind:
NodeType = mbind.BindingType.ToString();
NodeTypesParts = new List<(string @namespace, string enumTypename, string membername)> {
- (typeof(MemberBindingType).Namespace, nameof(MemberBindingType), NodeType)
- };
+ (typeof(MemberBindingType).Namespace!, nameof(MemberBindingType), NodeType)
+ };
Name = mbind.Member.Name;
break;
case CallSiteBinder callSiteBinder:
@@ -225,7 +134,9 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
if (parentWatchExpression.IsNullOrWhitespace()) {
WatchExpressionFormatString = "{0}";
- } else if (pi != null) {
+ } else if (pi is { }) {
+ if (pi.DeclaringType is null) { throw new ArgumentNullException("pi.DeclaringType"); }
+
var watchPathFromParent = PathFromParent;
if (visualizerData.Options.Language == CSharp) {
WatchExpressionFormatString = $"(({pi.DeclaringType.FullName}){parentWatchExpression}).{watchPathFromParent}";
@@ -240,7 +151,7 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
var preferredOrder = PreferredPropertyOrders.FirstOrDefault(x => x.type.IsAssignableFrom(type)).Item2;
Children = type.GetProperties()
.Where(prp =>
- !(prp.DeclaringType.Name == "BlockExpression" && prp.Name == "Result") &&
+ !(prp.DeclaringType!.Name == "BlockExpression" && prp.Name == "Result") &&
propertyTypes.Any(x => x.IsAssignableFrom(prp.PropertyType))
)
.OrderBy(prp => {
@@ -252,7 +163,7 @@ internal ExpressionNodeData(object o, (string aggregatePath, string pathFromPare
if (prp.PropertyType.InheritsFromOrImplements()) {
return (prp.GetValue(o) as IEnumerable).Cast