mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
change: simplified approach based on string parsing rather than recursive structure analysis. Not fully tested but pretty sure it will work.
This commit is contained in:
@@ -146,30 +146,36 @@ namespace ICSharpCode.ILSpy.AddIn
|
||||
return allGenericParameters.ToArray();
|
||||
}
|
||||
|
||||
static void AppendParameterTypeName(StringBuilder b, EnvDTE80.CodeParameter2 parameter, string[] genericTypeParameters, string[] genericMethodParameters)
|
||||
private static void AppendParameterTypeName(StringBuilder b, EnvDTE80.CodeParameter2 parameter, string[] genericTypeParameters, string[] genericMethodParameters)
|
||||
{
|
||||
EnvDTE80.CodeTypeRef2 typeRef = (EnvDTE80.CodeTypeRef2)parameter.Type;
|
||||
|
||||
int indexOfGenericTypeParameter = Array.IndexOf(genericTypeParameters, typeRef.AsFullName);
|
||||
int indexOfGenericMethodParameter = Array.IndexOf(genericMethodParameters, typeRef.AsFullName);
|
||||
if (indexOfGenericTypeParameter >= 0) {
|
||||
b.Append("`");
|
||||
b.Append(indexOfGenericTypeParameter);
|
||||
}
|
||||
else if (indexOfGenericMethodParameter >= 0) {
|
||||
b.Append("``");
|
||||
b.Append(indexOfGenericMethodParameter);
|
||||
}
|
||||
else if (typeRef.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefPointer) {
|
||||
AppendTypeNameWithArguments(b, (EnvDTE.CodeElement)typeRef.ElementType, genericTypeParameters, genericMethodParameters);
|
||||
}
|
||||
else {
|
||||
AppendTypeNameWithArguments(b, (EnvDTE.CodeElement)typeRef.CodeType, genericTypeParameters, genericMethodParameters);
|
||||
EnvDTE80.CodeTypeRef2 parameterTypeRef = (EnvDTE80.CodeTypeRef2)parameter.Type;
|
||||
string parameterTypeString = parameterTypeRef.AsFullName;
|
||||
int substringStart = 0;
|
||||
for (int i = 0; i < parameterTypeString.Length; ++i) {
|
||||
switch (parameterTypeString[i]) {
|
||||
case '<':
|
||||
AppendParameterTypeSubstring(b, parameterTypeString, substringStart, i, genericTypeParameters, genericMethodParameters);
|
||||
substringStart = i + 1;
|
||||
b.Append('{');
|
||||
break;
|
||||
case '>':
|
||||
AppendParameterTypeSubstring(b, parameterTypeString, substringStart, i, genericTypeParameters, genericMethodParameters);
|
||||
substringStart = i + 1;
|
||||
b.Append('}');
|
||||
break;
|
||||
case ',':
|
||||
AppendParameterTypeSubstring(b, parameterTypeString, substringStart, i, genericTypeParameters, genericMethodParameters);
|
||||
substringStart = i + 1;
|
||||
b.Append(',');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeRef.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefArray) {
|
||||
AppendParameterTypeSubstring(b, parameterTypeString, substringStart, parameterTypeString.Length, genericTypeParameters, genericMethodParameters);
|
||||
|
||||
if (parameterTypeRef.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefArray) {
|
||||
b.Append('[');
|
||||
for (int i = 0; i < typeRef.Rank; i++) {
|
||||
for (int i = 0; i < parameterTypeRef.Rank; i++) {
|
||||
if (i > 0)
|
||||
b.Append(',');
|
||||
// TODO: how to get array bounds from EnvDTE code model?
|
||||
@@ -190,200 +196,30 @@ namespace ICSharpCode.ILSpy.AddIn
|
||||
}
|
||||
|
||||
// TODO: test pointer parameters
|
||||
if (typeRef.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefPointer) {
|
||||
if (parameterTypeRef.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefPointer) {
|
||||
b.Append('*');
|
||||
}
|
||||
}
|
||||
|
||||
private static void AppendTypeNameWithArguments(StringBuilder b, EnvDTE.CodeElement type, string[] genericTypeParameters, string[] genericMethodParameters)
|
||||
private static void AppendParameterTypeSubstring(StringBuilder b, string parameterTypeString, int substringStart, int substringStop, string[] genericTypeParameters, string[] genericMethodParameters)
|
||||
{
|
||||
int nameIndex = type.FullName.LastIndexOf(type.Name);
|
||||
string containerName = type.FullName.Substring(0, nameIndex - 1);
|
||||
string typeName = type.FullName.Substring(nameIndex);
|
||||
|
||||
EnvDTE.CodeElement declaringElement = null;
|
||||
try {
|
||||
declaringElement = (EnvDTE.CodeElement)type.Collection.Parent;
|
||||
}
|
||||
catch (Exception) {
|
||||
}
|
||||
|
||||
if (declaringElement == null) {
|
||||
if (!string.IsNullOrEmpty(containerName)) {
|
||||
b.Append(containerName);
|
||||
b.Append('.');
|
||||
if (substringStart < substringStop) {
|
||||
string substring = parameterTypeString.Substring(substringStart, substringStop - substringStart);
|
||||
int indexOfGenericTypeParameter = Array.IndexOf(genericTypeParameters, substring);
|
||||
int indexOfGenericMethodParameter = Array.IndexOf(genericMethodParameters, substring);
|
||||
if (indexOfGenericTypeParameter >= 0) {
|
||||
b.Append("`");
|
||||
b.Append(indexOfGenericTypeParameter);
|
||||
}
|
||||
}
|
||||
else if (declaringElement.Kind == EnvDTE.vsCMElement.vsCMElementNamespace) {
|
||||
b.Append(declaringElement.FullName);
|
||||
b.Append('.');
|
||||
}
|
||||
else {
|
||||
AppendTypeNameWithArguments(b, declaringElement, genericTypeParameters, genericMethodParameters);
|
||||
b.Append('.');
|
||||
}
|
||||
|
||||
string[] localTypeParameters = AppendTypeName(b, typeName, false, false);
|
||||
|
||||
if (localTypeParameters.Length > 0) {
|
||||
b.Append('{');
|
||||
for (int i = 0; i < localTypeParameters.Length; i++) {
|
||||
if (i > 0) b.Append(',');
|
||||
string localTypeParameter = localTypeParameters[i];
|
||||
int indexOfGenericTypeParameter = Array.IndexOf(genericTypeParameters, localTypeParameter);
|
||||
int indexOfGenericMethodParameter = Array.IndexOf(genericMethodParameters, localTypeParameter);
|
||||
if (indexOfGenericTypeParameter >= 0) {
|
||||
b.Append("`");
|
||||
b.Append(indexOfGenericTypeParameter);
|
||||
}
|
||||
else if (indexOfGenericMethodParameter >= 0) {
|
||||
b.Append("``");
|
||||
b.Append(indexOfGenericMethodParameter);
|
||||
}
|
||||
else {
|
||||
b.Append(localTypeParameter);
|
||||
}
|
||||
else if (indexOfGenericMethodParameter >= 0) {
|
||||
b.Append("``");
|
||||
b.Append(indexOfGenericMethodParameter);
|
||||
}
|
||||
else {
|
||||
b.Append(substring.Trim());
|
||||
}
|
||||
b.Append('}');
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static string XXXGetKey(EnvDTE.CodeElement codeElement)
|
||||
{
|
||||
switch (codeElement.Kind) {
|
||||
case EnvDTE.vsCMElement.vsCMElementEvent:
|
||||
return string.Concat("E:",
|
||||
GetCodeElementContainerString((EnvDTE.CodeElement)codeElement.Collection.Parent),
|
||||
".", codeElement.Name);
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementVariable:
|
||||
return string.Concat("F:",
|
||||
GetCodeElementContainerString((EnvDTE.CodeElement)codeElement.Collection.Parent),
|
||||
".", codeElement.Name);
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementFunction: {
|
||||
var codeFunction = (EnvDTE80.CodeFunction2)codeElement;
|
||||
|
||||
var idBuilder = new System.Text.StringBuilder();
|
||||
idBuilder.Append("M:");
|
||||
|
||||
// Constructors need to be called "#ctor" for navigation purposes.
|
||||
string[] genericClassTypeParameters;
|
||||
string classFullName = GetCodeElementContainerString((EnvDTE.CodeElement)codeFunction.Parent, out genericClassTypeParameters);
|
||||
string functionName = (codeFunction.FunctionKind == EnvDTE.vsCMFunction.vsCMFunctionConstructor ? "#ctor" : codeFunction.Name);
|
||||
idBuilder.Append(classFullName);
|
||||
idBuilder.Append('.');
|
||||
idBuilder.Append(functionName);
|
||||
|
||||
// Get type parameters to generic method, if present.
|
||||
string[] genericMethodTypeParameters = new string[0];
|
||||
int iGenericParams = codeFunction.FullName.LastIndexOf('<');
|
||||
if ((codeFunction.IsGeneric) && (iGenericParams >= 0)) {
|
||||
genericMethodTypeParameters = codeFunction.FullName.Substring(iGenericParams).Split(new char[] {'<', ',', ' ', '>'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
idBuilder.Append("``");
|
||||
idBuilder.Append(genericMethodTypeParameters.Length);
|
||||
}
|
||||
|
||||
// Append parameter types, to disambiguate overloaded methods.
|
||||
if (codeFunction.Parameters.Count > 0) {
|
||||
idBuilder.Append("(");
|
||||
bool first = true;
|
||||
foreach (EnvDTE.CodeParameter parameter in codeFunction.Parameters) {
|
||||
if (!first) {
|
||||
idBuilder.Append(",");
|
||||
}
|
||||
first = false;
|
||||
int genericClassTypeParameterIndex = Array.IndexOf(genericClassTypeParameters, parameter.Type.AsFullName);
|
||||
if (genericClassTypeParameterIndex >= 0) {
|
||||
idBuilder.Append('`');
|
||||
idBuilder.Append(genericClassTypeParameterIndex);
|
||||
}
|
||||
else {
|
||||
int genericMethodTypeParameterIndex = Array.IndexOf(genericMethodTypeParameters, parameter.Type.AsFullName);
|
||||
if (genericMethodTypeParameterIndex >= 0) {
|
||||
idBuilder.Append("``");
|
||||
idBuilder.Append(genericMethodTypeParameterIndex);
|
||||
}
|
||||
else {
|
||||
// Special handling for arrays, because AsFullName for an array is empty.
|
||||
if (parameter.Type.TypeKind == EnvDTE.vsCMTypeRef.vsCMTypeRefArray) {
|
||||
idBuilder.Append(parameter.Type.ElementType.AsFullName);
|
||||
idBuilder.Append("[]");
|
||||
}
|
||||
else {
|
||||
idBuilder.Append(parameter.Type.AsFullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idBuilder.Append(")");
|
||||
}
|
||||
return idBuilder.ToString();
|
||||
}
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementNamespace:
|
||||
return string.Concat("N:",
|
||||
codeElement.FullName);
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementProperty:
|
||||
return string.Concat("P:",
|
||||
GetCodeElementContainerString((EnvDTE.CodeElement)codeElement.Collection.Parent),
|
||||
".", codeElement.Name);
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementDelegate:
|
||||
case EnvDTE.vsCMElement.vsCMElementEnum:
|
||||
case EnvDTE.vsCMElement.vsCMElementInterface:
|
||||
case EnvDTE.vsCMElement.vsCMElementStruct:
|
||||
case EnvDTE.vsCMElement.vsCMElementClass:
|
||||
return string.Concat("T:",
|
||||
GetCodeElementContainerString(codeElement));
|
||||
|
||||
default:
|
||||
return string.Format("!:Code element {0} is of unsupported type {1}", codeElement.FullName, codeElement.Kind.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCodeElementContainerString(EnvDTE.CodeElement containerElement)
|
||||
{
|
||||
string[] genericTypeParametersIgnored;
|
||||
return GetCodeElementContainerString(containerElement, out genericTypeParametersIgnored);
|
||||
}
|
||||
|
||||
private static string GetCodeElementContainerString(EnvDTE.CodeElement containerElement, out string[] genericTypeParameters)
|
||||
{
|
||||
genericTypeParameters = new string[0];
|
||||
|
||||
switch (containerElement.Kind) {
|
||||
case EnvDTE.vsCMElement.vsCMElementNamespace:
|
||||
return containerElement.FullName;
|
||||
|
||||
case EnvDTE.vsCMElement.vsCMElementInterface:
|
||||
case EnvDTE.vsCMElement.vsCMElementStruct:
|
||||
case EnvDTE.vsCMElement.vsCMElementClass: {
|
||||
var idBuilder = new System.Text.StringBuilder();
|
||||
idBuilder.Append(GetCodeElementContainerString((EnvDTE.CodeElement)containerElement.Collection.Parent));
|
||||
idBuilder.Append('.');
|
||||
idBuilder.Append(containerElement.Name);
|
||||
|
||||
// For "Generic<T1,T2>" we need "Generic`2".
|
||||
bool isGeneric =
|
||||
((containerElement.Kind == EnvDTE.vsCMElement.vsCMElementClass) && ((EnvDTE80.CodeClass2)containerElement).IsGeneric) ||
|
||||
((containerElement.Kind == EnvDTE.vsCMElement.vsCMElementStruct) && ((EnvDTE80.CodeStruct2)containerElement).IsGeneric) ||
|
||||
((containerElement.Kind == EnvDTE.vsCMElement.vsCMElementInterface) && ((EnvDTE80.CodeInterface2)containerElement).IsGeneric);
|
||||
int iGenericParams = containerElement.FullName.LastIndexOf('<');
|
||||
if (isGeneric && (iGenericParams >= 0)) {
|
||||
genericTypeParameters = containerElement.FullName.Substring(iGenericParams).Split(new char[] {'<', ',', ' ', '>'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
idBuilder.Append('`');
|
||||
idBuilder.Append(genericTypeParameters.Length);
|
||||
}
|
||||
|
||||
return idBuilder.ToString();
|
||||
}
|
||||
|
||||
default:
|
||||
return string.Format("!:Code element {0} is of unsupported container type {1}", containerElement.FullName, containerElement.Kind.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user