|
|
|
|
@ -9,330 +9,12 @@ using System;
@@ -9,330 +9,12 @@ using System;
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using Debugger.Wrappers.CorDebug; |
|
|
|
|
using Debugger.Wrappers.MetaData; |
|
|
|
|
using System.Reflection; |
|
|
|
|
|
|
|
|
|
namespace Debugger.MetaData |
|
|
|
|
{ |
|
|
|
|
public partial class DebugType |
|
|
|
|
{ |
|
|
|
|
class Query { |
|
|
|
|
public Type MemberType; |
|
|
|
|
public BindingFlags BindingFlags; |
|
|
|
|
public string Name; |
|
|
|
|
public uint? Token; |
|
|
|
|
|
|
|
|
|
public Query(Type memberType, BindingFlags bindingFlags, string name, Nullable<uint> token) |
|
|
|
|
{ |
|
|
|
|
this.MemberType = memberType; |
|
|
|
|
this.BindingFlags = bindingFlags; |
|
|
|
|
this.Name = name; |
|
|
|
|
this.Token = token; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override int GetHashCode() |
|
|
|
|
{ |
|
|
|
|
int hashCode = 0; |
|
|
|
|
unchecked { |
|
|
|
|
if (MemberType != null) hashCode += 1000000007 * MemberType.GetHashCode(); |
|
|
|
|
hashCode += 1000000009 * BindingFlags.GetHashCode(); |
|
|
|
|
if (Name != null) hashCode += 1000000021 * Name.GetHashCode(); |
|
|
|
|
hashCode += 1000000033 * Token.GetHashCode(); |
|
|
|
|
} |
|
|
|
|
return hashCode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj) |
|
|
|
|
{ |
|
|
|
|
Query other = obj as Query; |
|
|
|
|
if (other == null) return false; |
|
|
|
|
return object.Equals(this.MemberType, other.MemberType) && this.BindingFlags == other.BindingFlags && this.Name == other.Name && this.Token == other.Token; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Dictionary<Query, object> queries = new Dictionary<Query, object>(); |
|
|
|
|
|
|
|
|
|
List<T> QueryMembers<T>(BindingFlags bindingFlags) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<T>(bindingFlags, null, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<T> QueryMembers<T>(string name) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<T>(BindingFlags.All, name, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T QueryMember<T>(string name) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
List<T> result = QueryMembers<T>(BindingFlags.All, name, null); |
|
|
|
|
if (result.Count > 0) { |
|
|
|
|
return result[0]; |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T QueryMember<T>(string name, BindingFlags bindingFlags) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
List<T> result = QueryMembers<T>(bindingFlags, name, null); |
|
|
|
|
if (result.Count > 0) { |
|
|
|
|
return result[0]; |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T QueryMember<T>(uint token) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
List<T> result = QueryMembers<T>(BindingFlags.All, null, token); |
|
|
|
|
if (result.Count > 0) { |
|
|
|
|
return result[0]; |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<T> QueryMembers<T>(BindingFlags bindingFlags, string name, Nullable<uint> token) where T:MemberInfo |
|
|
|
|
{ |
|
|
|
|
Query query = new Query(typeof(T), bindingFlags, name, token); |
|
|
|
|
|
|
|
|
|
if (queries.ContainsKey(query)) { |
|
|
|
|
return (List<T>)queries[query]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
List<T> results = new List<T>(); |
|
|
|
|
foreach(MemberInfo memberInfo in members) { |
|
|
|
|
// Filter by type
|
|
|
|
|
if (!(memberInfo is T)) continue; // Reject item
|
|
|
|
|
|
|
|
|
|
// Filter by access
|
|
|
|
|
if ((bindingFlags & BindingFlags.AccessMask) != 0) { |
|
|
|
|
bool accept = false; |
|
|
|
|
if ((bindingFlags & BindingFlags.Public) != 0 && memberInfo.IsPublic) accept = true; |
|
|
|
|
if ((bindingFlags & BindingFlags.NonPublic) != 0 && !memberInfo.IsPublic) accept = true; |
|
|
|
|
if (!accept) continue; // Reject item
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Filter by static / instance
|
|
|
|
|
if ((bindingFlags & BindingFlags.InstanceStaticMask) != 0) { |
|
|
|
|
bool accept = false; |
|
|
|
|
if ((bindingFlags & BindingFlags.Static) != 0 && memberInfo.IsStatic) accept = true; |
|
|
|
|
if ((bindingFlags & BindingFlags.Instance) != 0 && !memberInfo.IsStatic) accept = true; |
|
|
|
|
if (!accept) continue; // Reject item
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Filter by type
|
|
|
|
|
if ((bindingFlags & BindingFlags.TypeMask) != 0) { |
|
|
|
|
bool accept = false; |
|
|
|
|
if ((bindingFlags & BindingFlags.Field) != 0 && memberInfo is DebugFieldInfo) accept = true; |
|
|
|
|
if ((bindingFlags & BindingFlags.Property) != 0 && memberInfo is PropertyInfo) accept = true; |
|
|
|
|
if ((bindingFlags & BindingFlags.Method) != 0 && memberInfo is MethodInfo) accept = true; |
|
|
|
|
if ((bindingFlags & BindingFlags.GetProperty) != 0 && |
|
|
|
|
memberInfo is PropertyInfo && |
|
|
|
|
((PropertyInfo)memberInfo).GetMethod != null && |
|
|
|
|
((PropertyInfo)memberInfo).GetMethod.ParameterCount == 0) |
|
|
|
|
{ |
|
|
|
|
accept = true; |
|
|
|
|
} |
|
|
|
|
if (!accept) continue; // Reject item
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Filter by name
|
|
|
|
|
if (name != null) { |
|
|
|
|
if (memberInfo.Name != name) continue; // Reject item
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Filter by token
|
|
|
|
|
if (token.HasValue) { |
|
|
|
|
if (memberInfo.MetadataToken != token.Value) continue; // Reject item
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
results.Add((T)memberInfo); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Query supertype
|
|
|
|
|
if ((bindingFlags & BindingFlags.IncludeSuperType) != 0 && this.BaseType != null) { |
|
|
|
|
List<T> superResults = this.BaseType.QueryMembers<T>(bindingFlags, name, token); |
|
|
|
|
results.AddRange(superResults); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
queries[query] = results; |
|
|
|
|
return results; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#region Queries
|
|
|
|
|
|
|
|
|
|
/// <summary> Return all public members.</summary>
|
|
|
|
|
public IList<MemberInfo> GetMembers() |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MemberInfo>(BindingFlags.Public); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all members with the given name.</summary>
|
|
|
|
|
public IList<MemberInfo> GetMembers(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MemberInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all members satisfing binding flags.</summary>
|
|
|
|
|
public IList<MemberInfo> GetMembers(string name, BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MemberInfo>(bindingFlags, name, null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all members satisfing binding flags.</summary>
|
|
|
|
|
public IList<MemberInfo> GetMembers(BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MemberInfo>(bindingFlags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first member with the given name</summary>
|
|
|
|
|
public MemberInfo GetMember(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<MemberInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first member with the given name</summary>
|
|
|
|
|
public MemberInfo GetMember(string name, BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<MemberInfo>(name, bindingFlags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first member with the given token</summary>
|
|
|
|
|
public MemberInfo GetMember(uint token) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<MemberInfo>(token); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> Return all public fields.</summary>
|
|
|
|
|
public IList<DebugFieldInfo> GetFields() |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<DebugFieldInfo>(BindingFlags.Public); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all fields satisfing binding flags.</summary>
|
|
|
|
|
public IList<DebugFieldInfo> GetFields(BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<DebugFieldInfo>(bindingFlags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first field with the given name</summary>
|
|
|
|
|
public DebugFieldInfo GetField(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<DebugFieldInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return fields with the given name</summary>
|
|
|
|
|
public IList<DebugFieldInfo> GetFields(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<DebugFieldInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first field with the given token</summary>
|
|
|
|
|
public DebugFieldInfo GetField(uint token) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<DebugFieldInfo>(token); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> Return all public methods.</summary>
|
|
|
|
|
public IList<MethodInfo> GetMethods() |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MethodInfo>(BindingFlags.Public); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all methods satisfing binding flags.</summary>
|
|
|
|
|
public IList<MethodInfo> GetMethods(BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MethodInfo>(bindingFlags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first method with the given name</summary>
|
|
|
|
|
public MethodInfo GetMethod(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<MethodInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return methods with the given name</summary>
|
|
|
|
|
public IList<MethodInfo> GetMethods(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<MethodInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return method overload with given type parameters </summary>
|
|
|
|
|
/// <returns> Null if not found </returns>
|
|
|
|
|
public MethodInfo GetMethod(string name, params DebugType[] paramTypes) |
|
|
|
|
{ |
|
|
|
|
foreach(MethodInfo candidate in GetMethods(name)) { |
|
|
|
|
if (candidate.ParameterCount == paramTypes.Length) { |
|
|
|
|
bool match = true; |
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++) { |
|
|
|
|
if (paramTypes[i] != candidate.ParameterTypes[i]) |
|
|
|
|
match = false; |
|
|
|
|
} |
|
|
|
|
if (match) |
|
|
|
|
return candidate; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return method overload with given parameter names </summary>
|
|
|
|
|
/// <returns> Null if not found </returns>
|
|
|
|
|
public MethodInfo GetMethod(string name, params string[] paramNames) |
|
|
|
|
{ |
|
|
|
|
foreach(MethodInfo candidate in GetMethods(name)) { |
|
|
|
|
if (candidate.ParameterCount == paramNames.Length) { |
|
|
|
|
bool match = true; |
|
|
|
|
for(int i = 0; i < paramNames.Length; i++) { |
|
|
|
|
if (paramNames[i] != candidate.ParameterNames[i]) |
|
|
|
|
match = false; |
|
|
|
|
} |
|
|
|
|
if (match) |
|
|
|
|
return candidate; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first method with the given token</summary>
|
|
|
|
|
public MethodInfo GetMethod(uint token) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<MethodInfo>(token); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> Return all public properties.</summary>
|
|
|
|
|
public IList<PropertyInfo> GetProperties() |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<PropertyInfo>(BindingFlags.Public); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return all properties satisfing binding flags.</summary>
|
|
|
|
|
public IList<PropertyInfo> GetProperties(BindingFlags bindingFlags) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<PropertyInfo>(bindingFlags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first property with the given name</summary>
|
|
|
|
|
public PropertyInfo GetProperty(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<PropertyInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return propertyies with the given name</summary>
|
|
|
|
|
public IList<PropertyInfo> GetProperties(string name) |
|
|
|
|
{ |
|
|
|
|
return QueryMembers<PropertyInfo>(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> Return first property with the given token</summary>
|
|
|
|
|
public PropertyInfo GetProperty(uint token) |
|
|
|
|
{ |
|
|
|
|
return QueryMember<PropertyInfo>(token); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private bool primitiveTypeCached; |
|
|
|
|
private System.Type primitiveType; |
|
|
|
|
|
|
|
|
|
|