// 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; using System.Collections.Generic; using System.Reflection; using System.Text; using Debugger.MetaData; namespace Debugger { /// /// Description of IDStringProvider. /// public static class IDStringProvider { /// /// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity. /// public static string GetIDString(MemberInfo member) { StringBuilder b = new StringBuilder(); if (member is Type) { b.Append("T:"); AppendTypeName(b, (Type)member); } else { if (member is FieldInfo) b.Append("F:"); else if (member is PropertyInfo) b.Append("P:"); else if (member is EventInfo) b.Append("E:"); else if (member is MethodBase) b.Append("M:"); AppendTypeName(b, member.DeclaringType); b.Append('.'); b.Append(member.Name.Replace('.', '#')); IList parameters; Type explicitReturnType = null; if (member is PropertyInfo) { parameters = ((PropertyInfo)member).GetIndexParameters(); } else if (member is MethodInfo) { MethodInfo mr = (MethodInfo)member; if (mr.IsGenericMethod) { b.Append("``"); // DebugMethodInfo does not implement GetGenericArguments if (mr is DebugMethodInfo) b.Append(((DebugMethodInfo)mr).GenericParameterCount); else b.Append(mr.GetGenericArguments().Length); } parameters = mr.GetParameters(); if (mr.Name == "op_Implicit" || mr.Name == "op_Explicit") { explicitReturnType = mr.ReturnType; } } else { parameters = null; } if (parameters != null && parameters.Count > 0) { b.Append('('); for (int i = 0; i < parameters.Count; i++) { if (i > 0) b.Append(','); AppendTypeName(b, parameters[i].ParameterType); } b.Append(')'); } if (explicitReturnType != null) { b.Append('~'); AppendTypeName(b, explicitReturnType); } } return b.ToString(); } static void AppendTypeName(StringBuilder b, Type type) { if (type == null) { return; } if (type.IsGenericType) { AppendTypeNameWithArguments(b, type, type.GetGenericArguments()); } else if (type.HasElementType) { AppendTypeName(b, type.GetElementType()); if (type.IsArray) { b.Append('['); if (type.GetArrayRank() > 1) { for (int i = 0; i < type.GetArrayRank(); i++) { if (i > 0) b.Append(','); b.Append("0:"); } } b.Append(']'); } if (type.IsByRef) { b.Append('@'); } if (type.IsPointer) { b.Append('*'); } } else { if (type.IsGenericParameter) { b.Append('`'); if (type.DeclaringMethod != null) { b.Append('`'); } b.Append(type.GenericParameterPosition); } else if (type.DeclaringType != null) { AppendTypeName(b, type.DeclaringType); b.Append('.'); b.Append(type.Name); } else { b.Append(type.FullName); } } } static int AppendTypeNameWithArguments(StringBuilder b, Type type, IList genericArguments) { int outerTypeParameterCount = 0; if (type.DeclaringType != null) { Type declType = type.DeclaringType; outerTypeParameterCount = AppendTypeNameWithArguments(b, declType, genericArguments); b.Append('.'); } else if (!string.IsNullOrEmpty(type.Namespace)) { b.Append(type.Namespace); b.Append('.'); } int localTypeParameterCount = 0; b.Append(SplitTypeParameterCountFromReflectionName(type.Name, out localTypeParameterCount)); if (localTypeParameterCount > 0) { int totalTypeParameterCount = outerTypeParameterCount + localTypeParameterCount; b.Append('{'); for (int i = outerTypeParameterCount; i < totalTypeParameterCount && i < genericArguments.Count; i++) { if (i > outerTypeParameterCount) b.Append(','); AppendTypeName(b, genericArguments[i]); } b.Append('}'); } return outerTypeParameterCount + localTypeParameterCount; } static string SplitTypeParameterCountFromReflectionName(string reflectionName, out int typeParameterCount) { int pos = reflectionName.LastIndexOf('`'); if (pos < 0) { typeParameterCount = 0; return reflectionName; } else { string typeCount = reflectionName.Substring(pos + 1); if (int.TryParse(typeCount, out typeParameterCount)) return reflectionName.Substring(0, pos); else return reflectionName; } } } }