mirror of https://github.com/icsharpcode/ILSpy.git
4 changed files with 167 additions and 56 deletions
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using Mono.Cecil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public class NameVariables |
||||
{ |
||||
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> { |
||||
{ "System.Boolean", "flag" }, |
||||
{ "System.Byte", "b" }, |
||||
{ "System.SByte", "b" }, |
||||
{ "System.Int16", "num" }, |
||||
{ "System.Int32", "num" }, |
||||
{ "System.Int64", "num" }, |
||||
{ "System.UInt16", "num" }, |
||||
{ "System.UInt32", "num" }, |
||||
{ "System.UInt64", "num" }, |
||||
{ "System.Single", "num" }, |
||||
{ "System.Double", "num" }, |
||||
{ "System.Decimal", "num" }, |
||||
{ "System.String", "text" }, |
||||
{ "System.Object", "obj" }, |
||||
}; |
||||
|
||||
|
||||
public static void AssignNamesToVariables(IEnumerable<string> existingNames, IEnumerable<ILVariable> variables, ILBlock methodBody) |
||||
{ |
||||
NameVariables nv = new NameVariables(); |
||||
nv.AddExistingNames(existingNames); |
||||
foreach (ILVariable varDef in variables) { |
||||
nv.AssignNameToVariable(varDef, methodBody.GetSelfAndChildrenRecursive<ILExpression>()); |
||||
} |
||||
} |
||||
|
||||
Dictionary<string, int> typeNames = new Dictionary<string, int>(); |
||||
|
||||
void AddExistingNames(IEnumerable<string> existingNames) |
||||
{ |
||||
foreach (string name in existingNames) { |
||||
if (string.IsNullOrEmpty(name)) |
||||
continue; |
||||
// First, identify whether the name already ends with a number:
|
||||
int pos = name.Length; |
||||
while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9') |
||||
pos--; |
||||
if (pos < name.Length) { |
||||
int number; |
||||
if (int.TryParse(name.Substring(pos), out number)) { |
||||
string nameWithoutDigits = name.Substring(0, pos); |
||||
int existingNumber; |
||||
if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) { |
||||
typeNames[nameWithoutDigits] = Math.Max(number, existingNumber); |
||||
} else { |
||||
typeNames.Add(nameWithoutDigits, number); |
||||
} |
||||
continue; |
||||
} |
||||
} |
||||
if (!typeNames.ContainsKey(name)) |
||||
typeNames.Add(name, 1); |
||||
} |
||||
} |
||||
|
||||
void AssignNameToVariable(ILVariable varDef, IEnumerable<ILExpression> allExpressions) |
||||
{ |
||||
string proposedName = null; |
||||
foreach (ILExpression expr in allExpressions) { |
||||
if (expr.Operand != varDef) |
||||
continue; |
||||
if (expr.Code == ILCode.Stloc) { |
||||
proposedName = GetNameFromExpression(expr.Arguments.Single()); |
||||
} |
||||
if (proposedName != null) |
||||
break; |
||||
} |
||||
if (proposedName == null) |
||||
proposedName = GetNameByType(varDef.Type); |
||||
|
||||
if (!typeNames.ContainsKey(proposedName)) { |
||||
typeNames.Add(proposedName, 0); |
||||
} |
||||
int count = ++typeNames[proposedName]; |
||||
if (count > 1) { |
||||
varDef.Name = proposedName + count.ToString(); |
||||
} else { |
||||
varDef.Name = proposedName; |
||||
} |
||||
} |
||||
|
||||
static string GetNameFromExpression(ILExpression expr) |
||||
{ |
||||
switch (expr.Code) { |
||||
case ILCode.Ldfld: |
||||
// Use the field name only if it's not a field on this (avoid confusion between local variables and fields)
|
||||
if (!(expr.Arguments[0].Code == ILCode.Ldloc && ((ParameterDefinition)expr.Arguments[0].Operand).Index < 0)) |
||||
return ((FieldReference)expr.Operand).Name; |
||||
break; |
||||
case ILCode.Ldsfld: |
||||
return ((FieldReference)expr.Operand).Name; |
||||
case ILCode.Call: |
||||
case ILCode.Callvirt: |
||||
MethodReference mr = (MethodReference)expr.Operand; |
||||
if (mr.Name.StartsWith("get_", StringComparison.Ordinal)) |
||||
return CleanUpVariableName(mr.Name.Substring(4)); |
||||
else if (mr.Name.StartsWith("Get", StringComparison.Ordinal) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) |
||||
return CleanUpVariableName(mr.Name.Substring(3)); |
||||
break; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
string GetNameByType(TypeReference type) |
||||
{ |
||||
GenericInstanceType git = type as GenericInstanceType; |
||||
if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) { |
||||
type = ((GenericInstanceType)type).GenericArguments[0]; |
||||
} |
||||
|
||||
if (type.FullName == "System.Int32") { |
||||
// try i,j,k, etc.
|
||||
for (char c = 'i'; c <= 'n'; c++) { |
||||
if (!typeNames.ContainsKey(c.ToString())) |
||||
return c.ToString(); |
||||
} |
||||
} |
||||
string name; |
||||
if (type.IsArray) { |
||||
name = "array"; |
||||
} else if (type.IsPointer) { |
||||
name = "ptr"; |
||||
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) { |
||||
name = type.Name; |
||||
// remove the 'I' for interfaces
|
||||
if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2])) |
||||
name = name.Substring(1); |
||||
name = CleanUpVariableName(name); |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
static string CleanUpVariableName(string name) |
||||
{ |
||||
// remove the backtick (generics)
|
||||
int pos = name.IndexOf('`'); |
||||
if (pos >= 0) |
||||
name = name.Substring(0, pos); |
||||
if (name.Length == 0) |
||||
return "obj"; |
||||
else |
||||
return char.ToLower(name[0]) + name.Substring(1); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue