summaryrefslogtreecommitdiff
path: root/ICSharpCode.Decompiler/Ast/NameVariables.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ICSharpCode.Decompiler/Ast/NameVariables.cs')
-rw-r--r--ICSharpCode.Decompiler/Ast/NameVariables.cs347
1 files changed, 0 insertions, 347 deletions
diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs
deleted file mode 100644
index 3da808cb..00000000
--- a/ICSharpCode.Decompiler/Ast/NameVariables.cs
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this
-// software and associated documentation files (the "Software"), to deal in the Software
-// without restriction, including without limitation the rights to use, copy, modify, merge,
-// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
-// to whom the Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or
-// substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using ICSharpCode.Decompiler.ILAst;
-using Mono.Cecil;
-
-namespace ICSharpCode.Decompiler.Ast
-{
- 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" },
- { "System.Char", "c" }
- };
-
-
- public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> variables, ILBlock methodBody)
- {
- NameVariables nv = new NameVariables();
- nv.context = context;
- nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList();
- // First mark existing variable names as reserved.
- foreach (string name in context.ReservedVariableNames)
- nv.AddExistingName(name);
- foreach (var p in parameters)
- nv.AddExistingName(p.Name);
- foreach (var v in variables) {
- if (v.IsGenerated) {
- // don't introduce names for variables generated by ILSpy - keep "expr"/"arg"
- nv.AddExistingName(v.Name);
- } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
- string varName = v.OriginalVariable.Name;
- if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName))
- {
- // don't use the name from the debug symbols if it looks like a generated name
- v.Name = null;
- } else {
- // use the name from the debug symbols
- // (but ensure we don't use the same name for two variables)
- v.Name = nv.GetAlternativeName(varName);
- }
- } else {
- v.Name = null;
- }
- }
- // Now generate names:
- foreach (ILVariable p in parameters) {
- if (string.IsNullOrEmpty(p.Name))
- p.Name = nv.GenerateNameForVariable(p, methodBody);
- }
- foreach (ILVariable varDef in variables) {
- if (string.IsNullOrEmpty(varDef.Name))
- varDef.Name = nv.GenerateNameForVariable(varDef, methodBody);
- }
- }
-
- static bool IsValidName(string varName)
- {
- if (string.IsNullOrEmpty(varName))
- return false;
- if (!(char.IsLetter(varName[0]) || varName[0] == '_'))
- return false;
- for (int i = 1; i < varName.Length; i++) {
- if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_'))
- return false;
- }
- return true;
- }
-
- DecompilerContext context;
- List<string> fieldNamesInCurrentType;
- Dictionary<string, int> typeNames = new Dictionary<string, int>();
-
- public void AddExistingName(string name)
- {
- if (string.IsNullOrEmpty(name))
- return;
- int number;
- string nameWithoutDigits = SplitName(name, out number);
- int existingNumber;
- if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) {
- typeNames[nameWithoutDigits] = Math.Max(number, existingNumber);
- } else {
- typeNames.Add(nameWithoutDigits, number);
- }
- }
-
- string SplitName(string name, out int number)
- {
- // 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) {
- if (int.TryParse(name.Substring(pos), out number)) {
- return name.Substring(0, pos);
- }
- }
- number = 1;
- return name;
- }
-
- const char maxLoopVariableName = 'n';
-
- public string GetAlternativeName(string oldVariableName)
- {
- if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) {
- for (char c = 'i'; c <= maxLoopVariableName; c++) {
- if (!typeNames.ContainsKey(c.ToString())) {
- typeNames.Add(c.ToString(), 1);
- return c.ToString();
- }
- }
- }
-
- int number;
- string nameWithoutDigits = SplitName(oldVariableName, out number);
-
- if (!typeNames.ContainsKey(nameWithoutDigits)) {
- typeNames.Add(nameWithoutDigits, number - 1);
- }
- int count = ++typeNames[nameWithoutDigits];
- if (count != 1) {
- return nameWithoutDigits + count.ToString();
- } else {
- return nameWithoutDigits;
- }
- }
-
- string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
- {
- string proposedName = null;
- if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) {
- // test whether the variable might be a loop counter
- bool isLoopCounter = false;
- foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
- ILExpression expr = loop.Condition;
- while (expr != null && expr.Code == ILCode.LogicNot)
- expr = expr.Arguments[0];
- if (expr != null) {
- switch (expr.Code) {
- case ILCode.Clt:
- case ILCode.Clt_Un:
- case ILCode.Cgt:
- case ILCode.Cgt_Un:
- case ILCode.Cle:
- case ILCode.Cle_Un:
- case ILCode.Cge:
- case ILCode.Cge_Un:
- ILVariable loadVar;
- if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
- isLoopCounter = true;
- }
- break;
- }
- }
- }
- if (isLoopCounter) {
- // For loop variables, use i,j,k,l,m,n
- for (char c = 'i'; c <= maxLoopVariableName; c++) {
- if (!typeNames.ContainsKey(c.ToString())) {
- proposedName = c.ToString();
- break;
- }
- }
- }
- }
- if (string.IsNullOrEmpty(proposedName)) {
- var proposedNameForStores =
- (from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
- where expr.Code == ILCode.Stloc && expr.Operand == variable
- select GetNameFromExpression(expr.Arguments.Single())
- ).Except(fieldNamesInCurrentType).ToList();
- if (proposedNameForStores.Count == 1) {
- proposedName = proposedNameForStores[0];
- }
- }
- if (string.IsNullOrEmpty(proposedName)) {
- var proposedNameForLoads =
- (from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
- from i in Enumerable.Range(0, expr.Arguments.Count)
- let arg = expr.Arguments[i]
- where arg.Code == ILCode.Ldloc && arg.Operand == variable
- select GetNameForArgument(expr, i)
- ).Except(fieldNamesInCurrentType).ToList();
- if (proposedNameForLoads.Count == 1) {
- proposedName = proposedNameForLoads[0];
- }
- }
- if (string.IsNullOrEmpty(proposedName)) {
- proposedName = GetNameByType(variable.Type);
- }
-
- // remove any numbers from the proposed name
- int number;
- proposedName = SplitName(proposedName, out number);
-
- if (!typeNames.ContainsKey(proposedName)) {
- typeNames.Add(proposedName, 0);
- }
- int count = ++typeNames[proposedName];
- if (count > 1) {
- return proposedName + count.ToString();
- } else {
- return proposedName;
- }
- }
-
- static string GetNameFromExpression(ILExpression expr)
- {
- switch (expr.Code) {
- case ILCode.Ldfld:
- case ILCode.Ldsfld:
- return CleanUpVariableName(((FieldReference)expr.Operand).Name);
- case ILCode.Call:
- case ILCode.Callvirt:
- case ILCode.CallGetter:
- case ILCode.CallvirtGetter:
- MethodReference mr = (MethodReference)expr.Operand;
- if (mr.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase) && mr.Parameters.Count == 0) {
- // use name from properties, but not from indexers
- return CleanUpVariableName(mr.Name.Substring(4));
- } else if (mr.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) {
- // use name from Get-methods
- return CleanUpVariableName(mr.Name.Substring(3));
- }
- break;
- }
- return null;
- }
-
- static string GetNameForArgument(ILExpression parent, int i)
- {
- switch (parent.Code) {
- case ILCode.Stfld:
- case ILCode.Stsfld:
- if (i == parent.Arguments.Count - 1) // last argument is stored value
- return CleanUpVariableName(((FieldReference)parent.Operand).Name);
- else
- break;
- case ILCode.Call:
- case ILCode.Callvirt:
- case ILCode.Newobj:
- case ILCode.CallGetter:
- case ILCode.CallvirtGetter:
- case ILCode.CallSetter:
- case ILCode.CallvirtSetter:
- MethodReference methodRef = (MethodReference)parent.Operand;
- if (methodRef.Parameters.Count == 1 && i == parent.Arguments.Count - 1) {
- // argument might be value of a setter
- if (methodRef.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) {
- return CleanUpVariableName(methodRef.Name.Substring(4));
- } else if (methodRef.Name.StartsWith("Set", StringComparison.OrdinalIgnoreCase) && methodRef.Name.Length >= 4 && char.IsUpper(methodRef.Name[3])) {
- return CleanUpVariableName(methodRef.Name.Substring(3));
- }
- }
- MethodDefinition methodDef = methodRef.Resolve();
- if (methodDef != null) {
- var p = methodDef.Parameters.ElementAtOrDefault((parent.Code != ILCode.Newobj && methodDef.HasThis) ? i - 1 : i);
- if (p != null && !string.IsNullOrEmpty(p.Name))
- return CleanUpVariableName(p.Name);
- }
- break;
- case ILCode.Ret:
- return "result";
- }
- return null;
- }
-
- string GetNameByType(TypeReference type)
- {
- type = TypeAnalysis.UnpackModifiers(type);
-
- GenericInstanceType git = type as GenericInstanceType;
- if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) {
- type = ((GenericInstanceType)type).GenericArguments[0];
- }
-
- string name;
- if (type.IsArray) {
- name = "array";
- } else if (type.IsPointer || type.IsByReference) {
- name = "ptr";
- } else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) {
- name = "ex";
- } 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);
-
- // remove field prefix:
- if (name.Length > 2 && name.StartsWith("m_", StringComparison.Ordinal))
- name = name.Substring(2);
- else if (name.Length > 1 && name[0] == '_')
- name = name.Substring(1);
-
- if (name.Length == 0)
- return "obj";
- else
- return char.ToLower(name[0]) + name.Substring(1);
- }
- }
-}