mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
5.5 KiB
155 lines
5.5 KiB
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) |
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System.Reflection; |
|
|
|
using Debugger; |
|
using Debugger.MetaData; |
|
using ICSharpCode.NRefactory.Ast; |
|
using ICSharpCode.NRefactory.CSharp; |
|
using ILSpy.Debugger.Services; |
|
using ILSpy.Debugger.Services.Debugger; |
|
using Module = Debugger.Module; |
|
|
|
namespace ILSpy.Debugger.Models.TreeModel |
|
{ |
|
public partial class Utils |
|
{ |
|
public static IEnumerable<TreeNode> LazyGetChildNodesOfObject(Expression targetObject, DebugType shownType) |
|
{ |
|
MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); |
|
MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); |
|
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly); |
|
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); |
|
|
|
DebugType baseType = (DebugType)shownType.BaseType; |
|
if (baseType != null) { |
|
yield return new TreeNode( |
|
ImageService.GetImage("Icons.16x16.Class"), |
|
"BaseClass", |
|
baseType.Name, |
|
baseType.FullName, |
|
baseType.FullName == "System.Object" ? null : Utils.LazyGetChildNodesOfObject(targetObject, baseType) |
|
); |
|
} |
|
|
|
if (nonPublicInstance.Length > 0) { |
|
yield return new TreeNode( |
|
null, |
|
"NonPublicMembers", |
|
string.Empty, |
|
string.Empty, |
|
Utils.LazyGetMembersOfObject(targetObject, nonPublicInstance) |
|
); |
|
} |
|
|
|
if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) { |
|
IEnumerable<TreeNode> childs = Utils.LazyGetMembersOfObject(targetObject, publicStatic); |
|
if (nonPublicStatic.Length > 0) { |
|
TreeNode nonPublicStaticNode = new TreeNode( |
|
null, |
|
"NonPublicStaticMembers", |
|
string.Empty, |
|
string.Empty, |
|
Utils.LazyGetMembersOfObject(targetObject, nonPublicStatic) |
|
); |
|
childs = Utils.PrependNode(nonPublicStaticNode, childs); |
|
} |
|
yield return new TreeNode( |
|
null, |
|
"StaticMembers", |
|
string.Empty, |
|
string.Empty, |
|
childs |
|
); |
|
} |
|
|
|
DebugType iListType = (DebugType)shownType.GetInterface(typeof(IList).FullName); |
|
if (iListType != null) { |
|
yield return new IListNode(targetObject); |
|
} else { |
|
DebugType iEnumerableType, itemType; |
|
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) { |
|
yield return new IEnumerableNode(targetObject, itemType); |
|
} |
|
} |
|
|
|
foreach(TreeNode node in LazyGetMembersOfObject(targetObject, publicInstance)) { |
|
yield return node; |
|
} |
|
} |
|
|
|
public static IEnumerable<TreeNode> LazyGetMembersOfObject(Expression expression, MemberInfo[] members) |
|
{ |
|
List<TreeNode> nodes = new List<TreeNode>(); |
|
foreach(MemberInfo memberInfo in members) { |
|
string imageName; |
|
var image = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo, out imageName); |
|
var exp = new ExpressionNode(image, memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo)); |
|
exp.ImageName = imageName; |
|
nodes.Add(exp); |
|
} |
|
|
|
return nodes; |
|
} |
|
|
|
|
|
public static IEnumerable<TreeNode> LazyGetItemsOfIList(Expression targetObject) |
|
{ |
|
// This is needed for expanding IEnumerable<T> |
|
|
|
var type = new SimpleType() { Identifier = typeof(IList).FullName }; |
|
type.AddAnnotation(typeof(IList)); |
|
|
|
targetObject = new CastExpression() { Expression = targetObject.Clone(), Type = type }; |
|
|
|
int count = 0; |
|
GetValueException error = null; |
|
try { |
|
count = GetIListCount(targetObject); |
|
} catch (GetValueException e) { |
|
// Cannot yield a value in the body of a catch clause (CS1631) |
|
error = e; |
|
} |
|
if (error != null) { |
|
yield return new TreeNode(null, "(error)", error.Message, null, null); |
|
} else if (count == 0) { |
|
yield return new TreeNode(null, "(empty)", null, null, null); |
|
} else { |
|
for(int i = 0; i < count; i++) { |
|
string imageName; |
|
var image = ExpressionNode.GetImageForArrayIndexer(out imageName); |
|
var expression = new ExpressionNode(image, "[" + i + "]", targetObject.AppendIndexer(i)); |
|
expression.ImageName = imageName; |
|
yield return expression; |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Evaluates System.Collections.ICollection.Count property on given object. |
|
/// </summary> |
|
/// <exception cref="GetValueException">Evaluating System.Collections.ICollection.Count on targetObject failed.</exception> |
|
public static int GetIListCount(Expression targetObject) |
|
{ |
|
Value list = targetObject.Evaluate(WindowsDebugger.CurrentProcess); |
|
var iCollectionInterface = list.Type.GetInterface(typeof(ICollection).FullName); |
|
if (iCollectionInterface == null) |
|
throw new GetValueException(targetObject, targetObject.PrettyPrint() + " does not implement System.Collections.ICollection"); |
|
PropertyInfo countProperty = iCollectionInterface.GetProperty("Count"); |
|
// Do not get string representation since it can be printed in hex |
|
return (int)list.GetPropertyValue(countProperty).PrimitiveValue; |
|
} |
|
|
|
public static IEnumerable<TreeNode> PrependNode(TreeNode node, IEnumerable<TreeNode> rest) |
|
{ |
|
yield return node; |
|
if (rest != null) { |
|
foreach(TreeNode absNode in rest) { |
|
yield return absNode; |
|
} |
|
} |
|
} |
|
} |
|
}
|
|
|