Browse Source

Improve naming of local variables.

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
4be02c001f
  1. 7
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 57
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 158
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  4. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

7
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -198,6 +198,13 @@ namespace Decompiler
.MakeArrayType((type as Mono.Cecil.ArrayType).Rank); .MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type; GenericInstanceType gType = (GenericInstanceType)type;
if (gType.ElementType.Namespace == "System" && gType.ElementType.Name == "Nullable`1" && gType.GenericArguments.Count == 1) {
typeIndex++;
return new ComposedType {
BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex),
HasNullableSpecifier = true
};
}
AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex); AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex);
foreach (var typeArgument in gType.GenericArguments) { foreach (var typeArgument in gType.GenericArguments) {
typeIndex++; typeIndex++;

57
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -45,23 +45,6 @@ namespace Decompiler
} }
} }
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 BlockStatement CreateMethodBody() public BlockStatement CreateMethodBody()
{ {
if (methodDef.Body == null) return null; if (methodDef.Body == null) return null;
@ -76,45 +59,7 @@ namespace Decompiler
bodyGraph.Optimize(context, ilMethod); bodyGraph.Optimize(context, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); NameVariables.AssignNamesToVariables(methodDef.Parameters.Select(p => p.Name), astBuilder.Variables, ilMethod);
Dictionary<string, int> typeNames = new Dictionary<string, int>();
foreach(ILVariable varDef in astBuilder.Variables) {
if (varDef.Type.FullName == "System.Int32" && intNames.Count > 0) {
varDef.Name = intNames[0];
intNames.RemoveAt(0);
} else {
string name;
if (varDef.Type.IsArray) {
name = "array";
} else if (!typeNameToVariableNameDict.TryGetValue(varDef.Type.FullName, out name)) {
name = varDef.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);
// remove the backtick (generics)
int pos = name.IndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
if (name.Length == 0)
name = "obj";
else
name = char.ToLower(name[0]) + name.Substring(1);
}
if (!typeNames.ContainsKey(name)) {
typeNames.Add(name, 0);
}
int count = ++(typeNames[name]);
if (count > 1) {
name += count.ToString();
}
varDef.Name = name;
}
// Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name);
// Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(astVar);
// astLocalVar.TypeReference = new Ast.TypeReference(varDef.VariableType.FullName);
// astBlock.Children.Add(astLocalVar);
}
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod); Ast.BlockStatement astBlock = TransformBlock(ilMethod);

158
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -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);
}
}
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -53,6 +53,7 @@
<Compile Include="Ast\AstMethodBodyBuilder.cs" /> <Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" /> <Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DecompilerContext.cs" /> <Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" /> <Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" /> <Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />

Loading…
Cancel
Save