diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/BasePropertyGridAdapter.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/BasePropertyGridAdapter.cs new file mode 100644 index 0000000000..f2299d455c --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/BasePropertyGridAdapter.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.ComponentModel; + +namespace Roslyn.SyntaxVisualizer.Control.SymbolDisplay +{ + internal abstract class BasePropertyGridAdapter : ICustomTypeDescriptor + { + public virtual AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); + public virtual string GetClassName() => TypeDescriptor.GetClassName(this, true); + public virtual string GetComponentName() => TypeDescriptor.GetClassName(this, true); + public virtual TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true); + public virtual EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true); + public virtual PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true); + public virtual object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true); + public virtual EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true); + public virtual EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true); + public virtual PropertyDescriptorCollection GetProperties() => TypeDescriptor.GetProperties(this, true); + public virtual PropertyDescriptorCollection GetProperties(Attribute[] attributes) => TypeDescriptor.GetProperties(this, attributes, true); + public virtual object GetPropertyOwner(PropertyDescriptor pd) => null; + } +} diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/SymbolPropertyGridAdapter.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/SymbolPropertyGridAdapter.cs new file mode 100644 index 0000000000..0ac61df02e --- /dev/null +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SymbolDisplay/SymbolPropertyGridAdapter.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +#nullable enable + +namespace Roslyn.SyntaxVisualizer.Control.SymbolDisplay +{ + internal class SymbolPropertyGridAdapter : BasePropertyGridAdapter + { + private readonly Dictionary _dictionary; + + public SymbolPropertyGridAdapter(object symbol) => _dictionary = CreateDictionary(symbol); + + private static string GetStringValueOf(object obj) + { + var stringResult = obj switch + { + bool b => b.ToString(), + int i => i.ToString(), + string s => s.Length > 0 ? s : "None", + IEnumerable e => string.Join(", ", e.Select(x => GetStringValueOf(x))), + null => "", + object o => o.ToString(), + }; + return stringResult; + } + + private Dictionary CreateDictionary(object symbol) + { + var dictionry = new Dictionary(); + var type = symbol.GetType(); + + foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + + try + { + var value = property.GetValue(symbol, null); + var strVal = GetStringValueOf(value); + dictionry[property.Name] = strVal; + } + catch + { + + } + } + + var objectMethods = typeof(object).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + if (method.GetParameters().Length == 0 && IsNotInObjectType(method, objectMethods)) + { + try + { + var name = method.Name.Split('_').Last(); + var result = method.Invoke(symbol, null); + var stringResult = GetStringValueOf(result); + dictionry[name] = stringResult == string.Empty ? "None" : stringResult; + } + catch + { + } + } + } + return dictionry; + } + + private bool IsNotInObjectType(MethodInfo method, MethodInfo[] objectMethods) + { + return !objectMethods.Any(o => o.Name == method.Name); + } + + public override object GetPropertyOwner(PropertyDescriptor pd) + { + return _dictionary; + } + + public override PropertyDescriptor? GetDefaultProperty() + { + return null; + } + + public override PropertyDescriptorCollection GetProperties() + { + return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]); + } + + public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { + var properties = new List(); + foreach (var e in _dictionary) + { + properties.Add(new DictionaryPropertyDescriptor(_dictionary, e.Key)); + } + + return new PropertyDescriptorCollection(properties.ToArray()); + } + + class DictionaryPropertyDescriptor : PropertyDescriptor + { + Dictionary _dictionary; + string _key; + + internal DictionaryPropertyDescriptor(Dictionary d, string key) + : base(key.ToString(), null) + { + _dictionary = d; + _key = key; + } + + public override Type PropertyType => (_dictionary[_key])?.GetType() ?? typeof(object); + + public override void SetValue(object component, object value) + { + throw new InvalidOperationException("SetValue is not allowed!"); + } + + public override object GetValue(object component) => _dictionary[_key]; + + public override bool IsReadOnly => true; + + public override Type? ComponentType => null; + + public override bool CanResetValue(object component) => false; + + public override void ResetValue(object component) + { + } + + public override bool ShouldSerializeValue(object component) => false; + } + } +} diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs index 99abb17ffd..507834971e 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs @@ -23,6 +23,7 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Classification; +using Roslyn.SyntaxVisualizer.Control.SymbolDisplay; using SystemInformation = System.Windows.Forms.SystemInformation; namespace Roslyn.SyntaxVisualizer.Control @@ -995,6 +996,8 @@ private void DisplaySymbolInPropertyGrid(ISymbol symbol) kindTextLabel.Visibility = Visibility.Hidden; typeValueLabel.Content = string.Empty; kindValueLabel.Content = string.Empty; + + _propertyGrid.SelectedObject = null; } else { @@ -1002,9 +1005,9 @@ private void DisplaySymbolInPropertyGrid(ISymbol symbol) kindTextLabel.Visibility = Visibility.Visible; typeValueLabel.Content = symbol.GetType().Name; kindValueLabel.Content = symbol.Kind.ToString(); - } - _propertyGrid.SelectedObject = symbol; + _propertyGrid.SelectedObject = new SymbolPropertyGridAdapter(symbol); + } } private static TreeViewItem FindTreeViewItem(DependencyObject source)