diff options
Diffstat (limited to 'ICSharpCode.Decompiler/Ast/NameVariables.cs')
-rw-r--r-- | ICSharpCode.Decompiler/Ast/NameVariables.cs | 347 |
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); - } - } -} |