diff --git a/Decompiler/src/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs similarity index 97% rename from Decompiler/src/Ast/AstBuilder.cs rename to ICSharpCode.Decompiler/Ast/AstBuilder.cs index b716d403a..e94cfb4c3 100644 --- a/Decompiler/src/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1,316 +1,316 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.PrettyPrinter; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace Decompiler -{ - public class AstBuilder - { - CompilationUnit astCompileUnit = new CompilationUnit(); - Dictionary astNamespaces = new Dictionary(); - - public string GenerateCode() - { - CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); - - for (int i = 0; i < 4; i++) { - if (Options.ReduceAstJumps) { - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); - } - if (Options.ReduceAstLoops) { - astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); - } - if (Options.ReduceAstOther) { - astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); - } - } - if (Options.ReduceAstOther) { - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); - astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); - } - if (Options.ReduceAstLoops) { - astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); - } - - astCompileUnit.AcceptVisitor(csOutVisitor, null); - - string code = csOutVisitor.Text; - for(int i = 10; i >= 0; i--) { - code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {"); - } - code = code.Replace("\t", " "); - code = code.Replace("\"/***", ""); - code = code.Replace("***/\";", ""); - - // Post processing commands - while(true) { - int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length; - if (endIndex != -1) { - int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); - if (startIndex != -1) { - code = code.Remove(startIndex, endIndex - startIndex); - continue; - } - } - break; - } - while(true) { - int endIndex = code.IndexOf("[Tab]"); - if (endIndex != -1) { - int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); - if (startIndex != -1) { - code = code.Remove(endIndex, "[Tab]".Length); - code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex))); - continue; - } - } - break; - } - - return code; - } - - public void AddAssembly(AssemblyDefinition assemblyDefinition) - { - Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); - astCompileUnit.Children.Add(astUsing); - - foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { - // Skip nested types - they will be added by the parent type - if (typeDef.DeclaringType != null) continue; - // Skip the class - if (typeDef.Name == "") continue; - - AddType(typeDef); - } - } - - NamespaceDeclaration GetCodeNamespace(string name) - { - if (string.IsNullOrEmpty(name)) { - return null; - } - if (astNamespaces.ContainsKey(name)) { - return astNamespaces[name]; - } else { - // Create the namespace - NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); - astCompileUnit.Children.Add(astNamespace); - astNamespaces[name] = astNamespace; - return astNamespace; - } - } - - public void AddType(TypeDefinition typeDef) - { - if (!string.IsNullOrEmpty(Options.TypeFilter) && typeDef.Name != Options.TypeFilter) return; - - TypeDeclaration astType = CreateType(typeDef); - NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); - if (astNS != null) { - astNS.Children.Add(astType); - } else { - astCompileUnit.Children.Add(astType); - } - } - - public TypeDeclaration CreateType(TypeDefinition typeDef) - { - TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List()); - astType.Name = typeDef.Name; - - if (typeDef.IsEnum) { // NB: Enum is value type - astType.Type = ClassType.Enum; - } else if (typeDef.IsValueType) { - astType.Type = ClassType.Struct; - } else if (typeDef.IsInterface) { - astType.Type = ClassType.Interface; - } else { - astType.Type = ClassType.Class; - } - - // Nested types - foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { - astType.Children.Add(CreateType(nestedTypeDef)); - } - - // Base type - if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { - astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); - } - - AddTypeMembers(astType, typeDef); - - return astType; - } - - Modifiers ConvertModifiers(TypeDefinition typeDef) - { - return - (typeDef.IsNestedPrivate ? Modifiers.Private : Modifiers.None) | - (typeDef.IsNestedFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access - (typeDef.IsNestedAssembly ? Modifiers.Internal : Modifiers.None) | - (typeDef.IsNestedFamily ? Modifiers.Protected : Modifiers.None) | - (typeDef.IsNestedFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | - (typeDef.IsPublic ? Modifiers.Public : Modifiers.None) | - (typeDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); - } - - Modifiers ConvertModifiers(FieldDefinition fieldDef) - { - return - (fieldDef.IsPrivate ? Modifiers.Private : Modifiers.None) | - (fieldDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access - (fieldDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | - (fieldDef.IsFamily ? Modifiers.Protected : Modifiers.None) | - (fieldDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | - (fieldDef.IsPublic ? Modifiers.Public : Modifiers.None) | - (fieldDef.IsLiteral ? Modifiers.Const : Modifiers.None) | - (fieldDef.IsStatic ? Modifiers.Static : Modifiers.None); - } - - Modifiers ConvertModifiers(MethodDefinition methodDef) - { - return - (methodDef.IsCompilerControlled ? Modifiers.None : Modifiers.None) | - (methodDef.IsPrivate ? Modifiers.Private : Modifiers.None) | - (methodDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access - (methodDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | - (methodDef.IsFamily ? Modifiers.Protected : Modifiers.None) | - (methodDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | - (methodDef.IsPublic ? Modifiers.Public : Modifiers.None) | - (methodDef.IsStatic ? Modifiers.Static : Modifiers.None) | - (methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | - (methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); - } - - void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) - { - // Add fields - foreach(FieldDefinition fieldDef in typeDef.Fields) { - Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List()); - astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name)); - astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName); - astField.Modifier = ConvertModifiers(fieldDef); - - astType.Children.Add(astField); - } - - if (typeDef.Fields.Count > 0) { - astType.Children.Add(new IdentifierExpression("\r\n")); - } - - // Add events - foreach(EventDefinition eventDef in typeDef.Events) { - Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); - astEvent.Name = eventDef.Name; - astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName); - astEvent.Modifier = ConvertModifiers(eventDef.AddMethod); - - astType.Children.Add(astEvent); - } - - if (typeDef.Events.Count > 0) { - astType.Children.Add(new IdentifierExpression("\r\n")); - } - - // Add properties - foreach(PropertyDefinition propDef in typeDef.Properties) { - Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( - ConvertModifiers(propDef.GetMethod), - new List(), - propDef.Name, - new List() - ); - astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); - - if (propDef.GetMethod != null) { - astProp.GetRegion = new PropertyGetRegion( - AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), - new List() - ); - } - if (propDef.SetMethod != null) { - astProp.SetRegion = new PropertySetRegion( - AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), - new List() - ); - } - - astType.Children.Add(astProp); - } - - if (typeDef.Properties.Count > 0) { - astType.Children.Add(new IdentifierExpression("\r\n")); - } - - // Add constructors - foreach(MethodDefinition methodDef in typeDef.Methods) { - if (!methodDef.IsConstructor) continue; - - Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( - methodDef.Name, - ConvertModifiers(methodDef), - new List(MakeParameters(methodDef.Parameters)), - new List() - ); - - astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); - - astType.Children.Add(astMethod); - astType.Children.Add(new IdentifierExpression("\r\n")); - } - - // Add methods - foreach(MethodDefinition methodDef in typeDef.Methods) { - if (methodDef.IsSpecialName) continue; - - Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); - astMethod.Name = methodDef.Name; - astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName); - astMethod.Modifier = ConvertModifiers(methodDef); - - astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); - - astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); - - astType.Children.Add(astMethod); - - astType.Children.Add(new IdentifierExpression("\r\n")); - } - - if (astType.Children.LastOrDefault() is IdentifierExpression) { - astType.Children.Last.Remove(); - } - } - - IEnumerable MakeParameters(IEnumerable paramCol) - { - foreach(ParameterDefinition paramDef in paramCol) { - Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( - new Ast.TypeReference(paramDef.ParameterType.FullName), - paramDef.Name - ); - - if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; - if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; - if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; - - yield return astParam; - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.PrettyPrinter; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Decompiler +{ + public class AstBuilder + { + CompilationUnit astCompileUnit = new CompilationUnit(); + Dictionary astNamespaces = new Dictionary(); + + public string GenerateCode() + { + CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); + + for (int i = 0; i < 4; i++) { + if (Options.ReduceAstJumps) { + astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); + } + if (Options.ReduceAstLoops) { + astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); + } + if (Options.ReduceAstOther) { + astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); + } + } + if (Options.ReduceAstOther) { + astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); + astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); + } + if (Options.ReduceAstLoops) { + astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); + } + + astCompileUnit.AcceptVisitor(csOutVisitor, null); + + string code = csOutVisitor.Text; + for(int i = 10; i >= 0; i--) { + code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {"); + } + code = code.Replace("\t", " "); + code = code.Replace("\"/***", ""); + code = code.Replace("***/\";", ""); + + // Post processing commands + while(true) { + int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length; + if (endIndex != -1) { + int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); + if (startIndex != -1) { + code = code.Remove(startIndex, endIndex - startIndex); + continue; + } + } + break; + } + while(true) { + int endIndex = code.IndexOf("[Tab]"); + if (endIndex != -1) { + int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); + if (startIndex != -1) { + code = code.Remove(endIndex, "[Tab]".Length); + code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex))); + continue; + } + } + break; + } + + return code; + } + + public void AddAssembly(AssemblyDefinition assemblyDefinition) + { + Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); + astCompileUnit.Children.Add(astUsing); + + foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { + // Skip nested types - they will be added by the parent type + if (typeDef.DeclaringType != null) continue; + // Skip the class + if (typeDef.Name == "") continue; + + AddType(typeDef); + } + } + + NamespaceDeclaration GetCodeNamespace(string name) + { + if (string.IsNullOrEmpty(name)) { + return null; + } + if (astNamespaces.ContainsKey(name)) { + return astNamespaces[name]; + } else { + // Create the namespace + NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); + astCompileUnit.Children.Add(astNamespace); + astNamespaces[name] = astNamespace; + return astNamespace; + } + } + + public void AddType(TypeDefinition typeDef) + { + if (!string.IsNullOrEmpty(Options.TypeFilter) && typeDef.Name != Options.TypeFilter) return; + + TypeDeclaration astType = CreateType(typeDef); + NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); + if (astNS != null) { + astNS.Children.Add(astType); + } else { + astCompileUnit.Children.Add(astType); + } + } + + public TypeDeclaration CreateType(TypeDefinition typeDef) + { + TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List()); + astType.Name = typeDef.Name; + + if (typeDef.IsEnum) { // NB: Enum is value type + astType.Type = ClassType.Enum; + } else if (typeDef.IsValueType) { + astType.Type = ClassType.Struct; + } else if (typeDef.IsInterface) { + astType.Type = ClassType.Interface; + } else { + astType.Type = ClassType.Class; + } + + // Nested types + foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { + astType.Children.Add(CreateType(nestedTypeDef)); + } + + // Base type + if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { + astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); + } + + AddTypeMembers(astType, typeDef); + + return astType; + } + + Modifiers ConvertModifiers(TypeDefinition typeDef) + { + return + (typeDef.IsNestedPrivate ? Modifiers.Private : Modifiers.None) | + (typeDef.IsNestedFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access + (typeDef.IsNestedAssembly ? Modifiers.Internal : Modifiers.None) | + (typeDef.IsNestedFamily ? Modifiers.Protected : Modifiers.None) | + (typeDef.IsNestedFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | + (typeDef.IsPublic ? Modifiers.Public : Modifiers.None) | + (typeDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); + } + + Modifiers ConvertModifiers(FieldDefinition fieldDef) + { + return + (fieldDef.IsPrivate ? Modifiers.Private : Modifiers.None) | + (fieldDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access + (fieldDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | + (fieldDef.IsFamily ? Modifiers.Protected : Modifiers.None) | + (fieldDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | + (fieldDef.IsPublic ? Modifiers.Public : Modifiers.None) | + (fieldDef.IsLiteral ? Modifiers.Const : Modifiers.None) | + (fieldDef.IsStatic ? Modifiers.Static : Modifiers.None); + } + + Modifiers ConvertModifiers(MethodDefinition methodDef) + { + return + (methodDef.IsCompilerControlled ? Modifiers.None : Modifiers.None) | + (methodDef.IsPrivate ? Modifiers.Private : Modifiers.None) | + (methodDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access + (methodDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | + (methodDef.IsFamily ? Modifiers.Protected : Modifiers.None) | + (methodDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | + (methodDef.IsPublic ? Modifiers.Public : Modifiers.None) | + (methodDef.IsStatic ? Modifiers.Static : Modifiers.None) | + (methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | + (methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); + } + + void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) + { + // Add fields + foreach(FieldDefinition fieldDef in typeDef.Fields) { + Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List()); + astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name)); + astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName); + astField.Modifier = ConvertModifiers(fieldDef); + + astType.Children.Add(astField); + } + + if (typeDef.Fields.Count > 0) { + astType.Children.Add(new IdentifierExpression("\r\n")); + } + + // Add events + foreach(EventDefinition eventDef in typeDef.Events) { + Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); + astEvent.Name = eventDef.Name; + astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName); + astEvent.Modifier = ConvertModifiers(eventDef.AddMethod); + + astType.Children.Add(astEvent); + } + + if (typeDef.Events.Count > 0) { + astType.Children.Add(new IdentifierExpression("\r\n")); + } + + // Add properties + foreach(PropertyDefinition propDef in typeDef.Properties) { + Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( + ConvertModifiers(propDef.GetMethod), + new List(), + propDef.Name, + new List() + ); + astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); + + if (propDef.GetMethod != null) { + astProp.GetRegion = new PropertyGetRegion( + AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), + new List() + ); + } + if (propDef.SetMethod != null) { + astProp.SetRegion = new PropertySetRegion( + AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), + new List() + ); + } + + astType.Children.Add(astProp); + } + + if (typeDef.Properties.Count > 0) { + astType.Children.Add(new IdentifierExpression("\r\n")); + } + + // Add constructors + foreach(MethodDefinition methodDef in typeDef.Methods) { + if (!methodDef.IsConstructor) continue; + + Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( + methodDef.Name, + ConvertModifiers(methodDef), + new List(MakeParameters(methodDef.Parameters)), + new List() + ); + + astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); + + astType.Children.Add(astMethod); + astType.Children.Add(new IdentifierExpression("\r\n")); + } + + // Add methods + foreach(MethodDefinition methodDef in typeDef.Methods) { + if (methodDef.IsSpecialName) continue; + + Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); + astMethod.Name = methodDef.Name; + astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName); + astMethod.Modifier = ConvertModifiers(methodDef); + + astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); + + astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); + + astType.Children.Add(astMethod); + + astType.Children.Add(new IdentifierExpression("\r\n")); + } + + if (astType.Children.LastOrDefault() is IdentifierExpression) { + astType.Children.Last.Remove(); + } + } + + IEnumerable MakeParameters(IEnumerable paramCol) + { + foreach(ParameterDefinition paramDef in paramCol) { + Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( + new Ast.TypeReference(paramDef.ParameterType.FullName), + paramDef.Name + ); + + if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; + if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; + if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; + + yield return astParam; + } + } + } +} diff --git a/Decompiler/src/Ast/AstMetodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs similarity index 97% rename from Decompiler/src/Ast/AstMetodBodyBuilder.cs rename to ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs index 224b12395..fbfa918f0 100644 --- a/Decompiler/src/Ast/AstMetodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs @@ -1,748 +1,748 @@ -using System; -using System.Collections.Generic; - -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using Cecil = Mono.Cecil; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; -using Decompiler.ControlFlow; - -namespace Decompiler -{ - public class AstMetodBodyBuilder - { - MethodDefinition methodDef; - static Dictionary localVarTypes = new Dictionary(); - static Dictionary localVarDefined = new Dictionary(); - - public static BlockStatement CreateMetodBody(MethodDefinition methodDef) - { - AstMetodBodyBuilder builder = new AstMetodBodyBuilder(); - builder.methodDef = methodDef; - try { - return builder.CreateMetodBody(); - } catch { - BlockStatement block = new BlockStatement(); - block.Children.Add(MakeComment("Exception during decompilation")); - return block; - } - } - - public BlockStatement CreateMetodBody() - { - Ast.BlockStatement astBlock = new Ast.BlockStatement(); - - if (methodDef.Body == null) return astBlock; - - methodDef.Body.SimplifyMacros(); - - List body = new ILAstBuilder().Build(methodDef); - - MethodBodyGraph bodyGraph = new MethodBodyGraph(body); - bodyGraph.Optimize(); - - List intNames = new List(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); - Dictionary typeNames = new Dictionary(); - int boolFlagId = 1; - foreach(VariableDefinition varDef in methodDef.Body.Variables) { - if (string.IsNullOrEmpty(varDef.Name)) { - if (varDef.VariableType.FullName == Constants.Int32 && intNames.Count > 0) { - varDef.Name = intNames[0]; - intNames.RemoveAt(0); - } else if (varDef.VariableType.FullName == Constants.Boolean) { - if (boolFlagId == 1) { - varDef.Name = "flag"; - } else { - varDef.Name = "flag" + boolFlagId; - } - boolFlagId++; - } else { - string name; - if (varDef.VariableType.IsArray) { - name = "array"; - } else { - name = varDef.VariableType.Name; - name = char.ToLower(name[0]) + name.Substring(1); - } - if (!typeNames.ContainsKey(name)) { - typeNames.Add(name, 0); - } - int count = typeNames[name]; - if (count > 0) { - name += count.ToString(); - } - varDef.Name = name; - } - } - localVarTypes[varDef.Name] = varDef.VariableType; - localVarDefined[varDef.Name] = false; - -// 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); - } - - astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); - - return astBlock; - } - - IEnumerable TransformNodes(IEnumerable nodes) - { - foreach(Node node in nodes) { - foreach(Ast.Statement stmt in TransformNode(node)) { - yield return stmt; - } - } - } - - IEnumerable TransformNode(Node node) - { - if (Options.NodeComments) { - yield return MakeComment("// " + node.Description); - } - - yield return new Ast.LabelStatement(node.Label); - - if (node is BasicBlock) { - foreach(ILNode expr in ((BasicBlock)node).Body) { - if (expr is ILLabel) { - yield return new Ast.LabelStatement(((ILLabel)expr).Name); - } else { - Statement stmt = TransformExpressionToStatement((ILExpression)expr); - if (stmt != null) { - yield return stmt; - } - } - } - Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; - // If there is default branch and it is not the following node - if (fallThroughNode != null) { - yield return new Ast.GotoStatement(fallThroughNode.Label); - } - } else if (node is AcyclicGraph) { - Ast.BlockStatement blockStatement = new Ast.BlockStatement(); - blockStatement.Children.AddRange(TransformNodes(node.Childs)); - yield return blockStatement; - } else if (node is Loop) { - Ast.BlockStatement blockStatement = new Ast.BlockStatement(); - blockStatement.Children.AddRange(TransformNodes(node.Childs)); - yield return new Ast.ForStatement( - null, - null, - null, - blockStatement - ); - } else if (node is Block) { - foreach(Ast.INode inode in TransformNodes(node.Childs)) { - yield return inode; - } - } else if (node is Branch) { - yield return new Ast.LabelStatement(((Branch)node).FirstBasicBlock.Label); - - Ast.BlockStatement trueBlock = new Ast.BlockStatement(); - trueBlock.Children.Add(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label)); - - Ast.BlockStatement falseBlock = new Ast.BlockStatement(); - falseBlock.Children.Add(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label)); - - Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( - MakeBranchCondition((Branch)node), - trueBlock, - falseBlock - ); - trueBlock.Parent = ifElseStmt; - falseBlock.Parent = ifElseStmt; - - yield return ifElseStmt; - } else if (node is ConditionalNode) { - ConditionalNode conditionalNode = (ConditionalNode)node; - yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.Label); - - Ast.BlockStatement trueBlock = new Ast.BlockStatement(); - // The block entry code - trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label)); - // Sugested content - trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); - - Ast.BlockStatement falseBlock = new Ast.BlockStatement(); - // The block entry code - falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label)); - // Sugested content - falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); - - Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( - // Method bodies are swapped - new Ast.UnaryOperatorExpression( - new Ast.ParenthesizedExpression( - MakeBranchCondition(conditionalNode.Condition) - ), - UnaryOperatorType.Not - ), - falseBlock, - trueBlock - ); - trueBlock.Parent = ifElseStmt; - falseBlock.Parent = ifElseStmt; - - yield return ifElseStmt; - } else if (node is TryCatchNode) { - TryCatchNode tryCachNode = ((TryCatchNode)node); - Ast.BlockStatement tryBlock = new Ast.BlockStatement(); - tryBlock.Children.AddRange(TransformNode(tryCachNode.Childs[0])); - Ast.BlockStatement finallyBlock = null; - if (tryCachNode.Childs[1].Childs.Count > 0) { - finallyBlock = new Ast.BlockStatement(); - finallyBlock.Children.AddRange(TransformNode(tryCachNode.Childs[1])); - } - List ccs = new List(); - for (int i = 0; i < tryCachNode.Types.Count; i++) { - Ast.BlockStatement catchBlock = new Ast.BlockStatement(); - catchBlock.Children.AddRange(TransformNode(tryCachNode.Childs[i + 2])); - Ast.CatchClause cc = new Ast.CatchClause( - new Ast.TypeReference(tryCachNode.Types[i].FullName), - "exception", - catchBlock - ); - ccs.Add(cc); - } - Ast.TryCatchStatement tryCachStmt = new Ast.TryCatchStatement(tryBlock, ccs, finallyBlock); - yield return tryCachStmt; - } else { - throw new Exception("Bad node type"); - } - - if (Options.NodeComments) { - yield return MakeComment(""); - } - } - - List TransformExpressionArguments(ILExpression expr) - { - List args = new List(); - // Args generated by nested expressions (which must be closed) - foreach(ILExpression arg in expr.Arguments) { - args.Add((Ast.Expression)TransformExpression(arg)); - } - return args; - } - - object TransformExpression(ILExpression expr) - { - List args = TransformExpressionArguments(expr); - return TransformByteCode(methodDef, expr, args); - } - - Ast.Statement TransformExpressionToStatement(ILExpression expr) - { - object codeExpr = TransformExpression(expr); - if (codeExpr == null) { - return null; - } else if (codeExpr is Ast.Expression) { - return new Ast.ExpressionStatement((Ast.Expression)codeExpr); - } else if (codeExpr is Ast.Statement) { - return (Ast.Statement)codeExpr; - } else { - throw new Exception(); - } - } - - static Ast.ExpressionStatement MakeComment(string text) - { - text = "/***" + text + "***/"; - return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); - } - - Ast.Expression MakeBranchCondition(Branch branch) - { - return new ParenthesizedExpression(MakeBranchCondition_Internal(branch)); - } - - Ast.Expression MakeBranchCondition_Internal(Branch branch) - { - if (branch is SimpleBranch) { - List args = TransformExpressionArguments((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]); - Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; - Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; - switch(((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]).OpCode.Code) { - case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not); - case Code.Brtrue: return arg1; - case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); - case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); - case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); - case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); - case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); - case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); - case Code.Leave: return new Ast.PrimitiveExpression(true, true.ToString()); - default: throw new Exception("Bad opcode"); - } - } else if (branch is ShortCircuitBranch) { - ShortCircuitBranch scBranch = (ShortCircuitBranch)branch; - switch(scBranch.Operator) { - case ShortCircuitOperator.LeftAndRight: - return new BinaryOperatorExpression( - MakeBranchCondition(scBranch.Left), - BinaryOperatorType.LogicalAnd, - MakeBranchCondition(scBranch.Right) - ); - case ShortCircuitOperator.LeftOrRight: - return new BinaryOperatorExpression( - MakeBranchCondition(scBranch.Left), - BinaryOperatorType.LogicalOr, - MakeBranchCondition(scBranch.Right) - ); - case ShortCircuitOperator.NotLeftAndRight: - return new BinaryOperatorExpression( - new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), - BinaryOperatorType.LogicalAnd, - MakeBranchCondition(scBranch.Right) - ); - case ShortCircuitOperator.NotLeftOrRight: - return new BinaryOperatorExpression( - new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), - BinaryOperatorType.LogicalOr, - MakeBranchCondition(scBranch.Right) - ); - default: - throw new Exception("Bad operator"); - } - } else { - throw new Exception("Bad type"); - } - } - - static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List args) - { - try { - Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args); - if (ret is Ast.Expression) { - ret = new ParenthesizedExpression((Ast.Expression)ret); - } - // ret.UserData["Type"] = byteCode.Type; - return ret; - } catch (NotImplementedException) { - // Output the operand of the unknown IL code as well - if (byteCode.Operand != null) { - args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); - } - return new Ast.InvocationExpression(new IdentifierExpression("__" + byteCode.OpCode.Name), args); - } - } - - static string FormatByteCodeOperand(object operand) - { - if (operand == null) { - return string.Empty; - //} else if (operand is ILExpression) { - // return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset); - } else if (operand is MethodReference) { - return ((MethodReference)operand).Name + "()"; - } else if (operand is Cecil.TypeReference) { - return ((Cecil.TypeReference)operand).FullName; - } else if (operand is VariableDefinition) { - return ((VariableDefinition)operand).Name; - } else if (operand is ParameterDefinition) { - return ((ParameterDefinition)operand).Name; - } else if (operand is FieldReference) { - return ((FieldReference)operand).Name; - } else if (operand is string) { - return "\"" + operand + "\""; - } else if (operand is int) { - return operand.ToString(); - } else { - return operand.ToString(); - } - } - - static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List args) - { - // throw new NotImplementedException(); - - OpCode opCode = byteCode.OpCode; - object operand = byteCode.Operand; - Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; - ILExpression operandAsByteCode = operand as ILExpression; - Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; - Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; - Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; - - Ast.Statement branchCommand = null; - if (byteCode.Operand is ILExpression) { - branchCommand = new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); - } - - switch(opCode.Code) { - #region Arithmetic - case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - case Code.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); - case Code.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); - case Code.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); - case Code.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); - case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); - case Code.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); - case Code.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); - case Code.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); - case Code.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); - case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); - case Code.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); - case Code.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); - case Code.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); - case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); - case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); - - case Code.Neg: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Minus); - case Code.Not: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.BitNot); - #endregion - #region Arrays - case Code.Newarr: - operandAsTypeRef.RankSpecifier = new int[] {0}; - return new Ast.ArrayCreateExpression(operandAsTypeRef, new List(new Expression[] {arg1})); - - case Code.Ldlen: return new Ast.MemberReferenceExpression(arg1, "Length"); - - case Code.Ldelem_I: - case Code.Ldelem_I1: - case Code.Ldelem_I2: - case Code.Ldelem_I4: - case Code.Ldelem_I8: - case Code.Ldelem_U1: - case Code.Ldelem_U2: - case Code.Ldelem_U4: - case Code.Ldelem_R4: - case Code.Ldelem_R8: - case Code.Ldelem_Ref: return new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})); - case Code.Ldelem_Any: throw new NotImplementedException(); - case Code.Ldelema: return new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})); - - case Code.Stelem_I: - case Code.Stelem_I1: - case Code.Stelem_I2: - case Code.Stelem_I4: - case Code.Stelem_I8: - case Code.Stelem_R4: - case Code.Stelem_R8: - case Code.Stelem_Ref: return new Ast.AssignmentExpression(new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})), AssignmentOperatorType.Assign, arg3); - case Code.Stelem_Any: throw new NotImplementedException(); - #endregion - #region Branching - case Code.Br: return branchCommand; - case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand); - case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand); - case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand); - case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); - case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); - case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); - case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); - case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); - case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); - case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); - case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); - case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand); - #endregion - #region Comparison - case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2)); - case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - #endregion - #region Conversions - case Code.Conv_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); - case Code.Conv_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); - case Code.Conv_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); - case Code.Conv_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); - case Code.Conv_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); - case Code.Conv_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); - case Code.Conv_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); - case Code.Conv_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); - case Code.Conv_R4: return new Ast.CastExpression(new Ast.TypeReference(typeof(float).FullName), arg1, CastType.Cast); - case Code.Conv_R8: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); - case Code.Conv_R_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); // TODO - - case Code.Conv_Ovf_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_Ovf_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_Ovf_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); - - case Code.Conv_Ovf_I_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_Ovf_I1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_I8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO - case Code.Conv_Ovf_U1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); - case Code.Conv_Ovf_U8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); - #endregion - #region Indirect - case Code.Ldind_I: throw new NotImplementedException(); - case Code.Ldind_I1: throw new NotImplementedException(); - case Code.Ldind_I2: throw new NotImplementedException(); - case Code.Ldind_I4: throw new NotImplementedException(); - case Code.Ldind_I8: throw new NotImplementedException(); - case Code.Ldind_U1: throw new NotImplementedException(); - case Code.Ldind_U2: throw new NotImplementedException(); - case Code.Ldind_U4: throw new NotImplementedException(); - case Code.Ldind_R4: throw new NotImplementedException(); - case Code.Ldind_R8: throw new NotImplementedException(); - case Code.Ldind_Ref: throw new NotImplementedException(); - - case Code.Stind_I: throw new NotImplementedException(); - case Code.Stind_I1: throw new NotImplementedException(); - case Code.Stind_I2: throw new NotImplementedException(); - case Code.Stind_I4: throw new NotImplementedException(); - case Code.Stind_I8: throw new NotImplementedException(); - case Code.Stind_R4: throw new NotImplementedException(); - case Code.Stind_R8: throw new NotImplementedException(); - case Code.Stind_Ref: throw new NotImplementedException(); - #endregion - case Code.Arglist: throw new NotImplementedException(); - case Code.Box: throw new NotImplementedException(); - case Code.Break: throw new NotImplementedException(); - case Code.Call: - case Code.Callvirt: - // TODO: Diferentiate vitual and non-vitual dispach - Cecil.MethodReference cecilMethod = ((MethodReference)operand); - Ast.Expression target; - List methodArgs = new List(args); - if (cecilMethod.HasThis) { - target = methodArgs[0]; - methodArgs.RemoveAt(0); - } else { - target = new Ast.IdentifierExpression(cecilMethod.DeclaringType.FullName); - } - - // TODO: Constructors are ignored - if (cecilMethod.Name == ".ctor") { - return MakeComment("// Constructor"); - } - - // TODO: Hack, detect properties properly - if (cecilMethod.Name.StartsWith("get_")) { - return new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)); - } else if (cecilMethod.Name.StartsWith("set_")) { - return new Ast.AssignmentExpression( - new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)), - AssignmentOperatorType.Assign, - methodArgs[0] - ); - } - - // Multi-dimensional array acces // TODO: do properly - if (cecilMethod.Name == "Get") { - return new Ast.IndexerExpression(target, methodArgs); - } else if (cecilMethod.Name == "Set") { - Expression val = methodArgs[methodArgs.Count - 1]; - methodArgs.RemoveAt(methodArgs.Count - 1); - return new Ast.AssignmentExpression( - new Ast.IndexerExpression(target, methodArgs), - AssignmentOperatorType.Assign, - Convert(val, ((Cecil.ArrayType)target.UserData["Type"]).ElementType) - ); - } - - // Default invocation - return new Ast.InvocationExpression( - new Ast.MemberReferenceExpression(target, cecilMethod.Name), - methodArgs - ); - case Code.Calli: throw new NotImplementedException(); - case Code.Castclass: return new Ast.CastExpression(operandAsTypeRef, arg1, CastType.Cast); - case Code.Ckfinite: throw new NotImplementedException(); - case Code.Constrained: throw new NotImplementedException(); - case Code.Cpblk: throw new NotImplementedException(); - case Code.Cpobj: throw new NotImplementedException(); - case Code.Dup: return arg1; - case Code.Endfilter: throw new NotImplementedException(); - case Code.Endfinally: return null; - case Code.Initblk: throw new NotImplementedException(); - case Code.Initobj: throw new NotImplementedException(); - case Code.Isinst: return new Ast.TypeOfIsExpression(arg1, new Ast.TypeReference(((Cecil.TypeReference)operand).FullName)); - case Code.Jmp: throw new NotImplementedException(); - case Code.Ldarg: - if (methodDef.HasThis && ((ParameterDefinition)operand).Index == 0) { - return new Ast.ThisReferenceExpression(); - } else { - return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); - } - case Code.Ldarga: throw new NotImplementedException(); - case Code.Ldc_I4: - case Code.Ldc_I8: - case Code.Ldc_R4: - case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand, null); - case Code.Ldfld: - case Code.Ldsfld: { - if (operand is FieldDefinition) { - FieldDefinition field = (FieldDefinition) operand; - if (field.IsStatic) { - return new Ast.MemberReferenceExpression( - new Ast.IdentifierExpression(field.DeclaringType.FullName), - field.Name - ); - } else { - return new Ast.MemberReferenceExpression(arg1, field.Name); - } - } else { - // TODO: Static accesses - return new Ast.MemberReferenceExpression(arg1, ((FieldReference)operand).Name); - } - } - case Code.Stfld: - case Code.Stsfld: { - FieldDefinition field = (FieldDefinition) operand; - if (field.IsStatic) { - return new AssignmentExpression( - new Ast.MemberReferenceExpression( - new Ast.IdentifierExpression(field.DeclaringType.FullName), - field.Name - ), - AssignmentOperatorType.Assign, - arg1 - ); - } else { - return new AssignmentExpression( - new Ast.MemberReferenceExpression(arg1, field.Name), - AssignmentOperatorType.Assign, - arg2 - ); - } - } - case Code.Ldflda: - case Code.Ldsflda: throw new NotImplementedException(); - case Code.Ldftn: throw new NotImplementedException(); - case Code.Ldloc: - if (operand is ILStackVariable) { - return new Ast.IdentifierExpression(((ILStackVariable)operand).Name); - } else { - return new Ast.IdentifierExpression(((VariableDefinition)operand).Name); - } - case Code.Ldloca: throw new NotImplementedException(); - case Code.Ldnull: return new Ast.PrimitiveExpression(null, null); - case Code.Ldobj: throw new NotImplementedException(); - case Code.Ldstr: return new Ast.PrimitiveExpression(operand, null); - case Code.Ldtoken: - if (operand is Cecil.TypeReference) { - return new Ast.MemberReferenceExpression( - new Ast.TypeOfExpression(operandAsTypeRef), - "TypeHandle" - ); - } else { - throw new NotImplementedException(); - } - case Code.Ldvirtftn: throw new NotImplementedException(); - case Code.Leave: return null; - case Code.Localloc: throw new NotImplementedException(); - case Code.Mkrefany: throw new NotImplementedException(); - case Code.Newobj: - Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; - // TODO: Ensure that the corrent overloaded constructor is called - if (declaringType is ArrayType) { - return new Ast.ArrayCreateExpression( - new Ast.TypeReference(((ArrayType)declaringType).ElementType.FullName, new int[] {}), - new List(args) - ); - } - return new Ast.ObjectCreateExpression( - new Ast.TypeReference(declaringType.FullName), - new List(args) - ); - case Code.No: throw new NotImplementedException(); - case Code.Nop: return null; - case Code.Or: throw new NotImplementedException(); - case Code.Pop: return arg1; - case Code.Readonly: throw new NotImplementedException(); - case Code.Refanytype: throw new NotImplementedException(); - case Code.Refanyval: throw new NotImplementedException(); - case Code.Ret: { - if (methodDef.ReturnType.FullName != Constants.Void) { - arg1 = Convert(arg1, methodDef.ReturnType); - return new Ast.ReturnStatement(arg1); - } else { - return new Ast.ReturnStatement(null); - } - } - case Code.Rethrow: return new Ast.ThrowStatement(new IdentifierExpression("exception")); - case Code.Sizeof: throw new NotImplementedException(); - case Code.Starg: throw new NotImplementedException(); - case Code.Stloc: { - if (operand is ILStackVariable) { - return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ILStackVariable)operand).Name), AssignmentOperatorType.Assign, arg1); - } - VariableDefinition locVar = (VariableDefinition)operand; - string name = locVar.Name; - arg1 = Convert(arg1, locVar.VariableType); - if (localVarDefined.ContainsKey(name)) { - if (localVarDefined[name]) { - return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); - } else { - Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1)); - astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName); - localVarDefined[name] = true; - return astLocalVar; - } - } else { - return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); - } - } - case Code.Stobj: throw new NotImplementedException(); - case Code.Switch: throw new NotImplementedException(); - case Code.Tail: throw new NotImplementedException(); - case Code.Throw: return new Ast.ThrowStatement(arg1); - case Code.Unaligned: throw new NotImplementedException(); - case Code.Unbox: throw new NotImplementedException(); - case Code.Unbox_Any: throw new NotImplementedException(); - case Code.Volatile: throw new NotImplementedException(); - default: throw new Exception("Unknown OpCode: " + opCode); - } - } - - static Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference reqType) - { - if (reqType == null) { - return expr; - } else { - return Convert(expr, reqType.FullName); - } - } - - static Ast.Expression Convert(Ast.Expression expr, string reqType) - { -// if (expr.UserData.ContainsKey("Type")) { -// Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"]; -// if (exprType == ByteCode.TypeZero && -// reqType == ByteCode.TypeBool.FullName) { -// return new PrimitiveExpression(false, "false"); -// } -// if (exprType == ByteCode.TypeOne && -// reqType == ByteCode.TypeBool.FullName) { -// return new PrimitiveExpression(true, "true"); -// } -// } - return expr; - } - - static Ast.Expression ConvertIntToBool(Ast.Expression astInt) - { - return astInt; - // return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0"))); - } - } -} +using System; +using System.Collections.Generic; + +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using Cecil = Mono.Cecil; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Decompiler.ControlFlow; + +namespace Decompiler +{ + public class AstMetodBodyBuilder + { + MethodDefinition methodDef; + static Dictionary localVarTypes = new Dictionary(); + static Dictionary localVarDefined = new Dictionary(); + + public static BlockStatement CreateMetodBody(MethodDefinition methodDef) + { + AstMetodBodyBuilder builder = new AstMetodBodyBuilder(); + builder.methodDef = methodDef; + try { + return builder.CreateMetodBody(); + } catch { + BlockStatement block = new BlockStatement(); + block.Children.Add(MakeComment("Exception during decompilation")); + return block; + } + } + + public BlockStatement CreateMetodBody() + { + Ast.BlockStatement astBlock = new Ast.BlockStatement(); + + if (methodDef.Body == null) return astBlock; + + methodDef.Body.SimplifyMacros(); + + List body = new ILAstBuilder().Build(methodDef); + + MethodBodyGraph bodyGraph = new MethodBodyGraph(body); + bodyGraph.Optimize(); + + List intNames = new List(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); + Dictionary typeNames = new Dictionary(); + int boolFlagId = 1; + foreach(VariableDefinition varDef in methodDef.Body.Variables) { + if (string.IsNullOrEmpty(varDef.Name)) { + if (varDef.VariableType.FullName == Constants.Int32 && intNames.Count > 0) { + varDef.Name = intNames[0]; + intNames.RemoveAt(0); + } else if (varDef.VariableType.FullName == Constants.Boolean) { + if (boolFlagId == 1) { + varDef.Name = "flag"; + } else { + varDef.Name = "flag" + boolFlagId; + } + boolFlagId++; + } else { + string name; + if (varDef.VariableType.IsArray) { + name = "array"; + } else { + name = varDef.VariableType.Name; + name = char.ToLower(name[0]) + name.Substring(1); + } + if (!typeNames.ContainsKey(name)) { + typeNames.Add(name, 0); + } + int count = typeNames[name]; + if (count > 0) { + name += count.ToString(); + } + varDef.Name = name; + } + } + localVarTypes[varDef.Name] = varDef.VariableType; + localVarDefined[varDef.Name] = false; + +// 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); + } + + astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); + + return astBlock; + } + + IEnumerable TransformNodes(IEnumerable nodes) + { + foreach(Node node in nodes) { + foreach(Ast.Statement stmt in TransformNode(node)) { + yield return stmt; + } + } + } + + IEnumerable TransformNode(Node node) + { + if (Options.NodeComments) { + yield return MakeComment("// " + node.Description); + } + + yield return new Ast.LabelStatement(node.Label); + + if (node is BasicBlock) { + foreach(ILNode expr in ((BasicBlock)node).Body) { + if (expr is ILLabel) { + yield return new Ast.LabelStatement(((ILLabel)expr).Name); + } else { + Statement stmt = TransformExpressionToStatement((ILExpression)expr); + if (stmt != null) { + yield return stmt; + } + } + } + Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; + // If there is default branch and it is not the following node + if (fallThroughNode != null) { + yield return new Ast.GotoStatement(fallThroughNode.Label); + } + } else if (node is AcyclicGraph) { + Ast.BlockStatement blockStatement = new Ast.BlockStatement(); + blockStatement.Children.AddRange(TransformNodes(node.Childs)); + yield return blockStatement; + } else if (node is Loop) { + Ast.BlockStatement blockStatement = new Ast.BlockStatement(); + blockStatement.Children.AddRange(TransformNodes(node.Childs)); + yield return new Ast.ForStatement( + null, + null, + null, + blockStatement + ); + } else if (node is Block) { + foreach(Ast.INode inode in TransformNodes(node.Childs)) { + yield return inode; + } + } else if (node is Branch) { + yield return new Ast.LabelStatement(((Branch)node).FirstBasicBlock.Label); + + Ast.BlockStatement trueBlock = new Ast.BlockStatement(); + trueBlock.Children.Add(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label)); + + Ast.BlockStatement falseBlock = new Ast.BlockStatement(); + falseBlock.Children.Add(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label)); + + Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( + MakeBranchCondition((Branch)node), + trueBlock, + falseBlock + ); + trueBlock.Parent = ifElseStmt; + falseBlock.Parent = ifElseStmt; + + yield return ifElseStmt; + } else if (node is ConditionalNode) { + ConditionalNode conditionalNode = (ConditionalNode)node; + yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.Label); + + Ast.BlockStatement trueBlock = new Ast.BlockStatement(); + // The block entry code + trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label)); + // Sugested content + trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); + + Ast.BlockStatement falseBlock = new Ast.BlockStatement(); + // The block entry code + falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label)); + // Sugested content + falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); + + Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( + // Method bodies are swapped + new Ast.UnaryOperatorExpression( + new Ast.ParenthesizedExpression( + MakeBranchCondition(conditionalNode.Condition) + ), + UnaryOperatorType.Not + ), + falseBlock, + trueBlock + ); + trueBlock.Parent = ifElseStmt; + falseBlock.Parent = ifElseStmt; + + yield return ifElseStmt; + } else if (node is TryCatchNode) { + TryCatchNode tryCachNode = ((TryCatchNode)node); + Ast.BlockStatement tryBlock = new Ast.BlockStatement(); + tryBlock.Children.AddRange(TransformNode(tryCachNode.Childs[0])); + Ast.BlockStatement finallyBlock = null; + if (tryCachNode.Childs[1].Childs.Count > 0) { + finallyBlock = new Ast.BlockStatement(); + finallyBlock.Children.AddRange(TransformNode(tryCachNode.Childs[1])); + } + List ccs = new List(); + for (int i = 0; i < tryCachNode.Types.Count; i++) { + Ast.BlockStatement catchBlock = new Ast.BlockStatement(); + catchBlock.Children.AddRange(TransformNode(tryCachNode.Childs[i + 2])); + Ast.CatchClause cc = new Ast.CatchClause( + new Ast.TypeReference(tryCachNode.Types[i].FullName), + "exception", + catchBlock + ); + ccs.Add(cc); + } + Ast.TryCatchStatement tryCachStmt = new Ast.TryCatchStatement(tryBlock, ccs, finallyBlock); + yield return tryCachStmt; + } else { + throw new Exception("Bad node type"); + } + + if (Options.NodeComments) { + yield return MakeComment(""); + } + } + + List TransformExpressionArguments(ILExpression expr) + { + List args = new List(); + // Args generated by nested expressions (which must be closed) + foreach(ILExpression arg in expr.Arguments) { + args.Add((Ast.Expression)TransformExpression(arg)); + } + return args; + } + + object TransformExpression(ILExpression expr) + { + List args = TransformExpressionArguments(expr); + return TransformByteCode(methodDef, expr, args); + } + + Ast.Statement TransformExpressionToStatement(ILExpression expr) + { + object codeExpr = TransformExpression(expr); + if (codeExpr == null) { + return null; + } else if (codeExpr is Ast.Expression) { + return new Ast.ExpressionStatement((Ast.Expression)codeExpr); + } else if (codeExpr is Ast.Statement) { + return (Ast.Statement)codeExpr; + } else { + throw new Exception(); + } + } + + static Ast.ExpressionStatement MakeComment(string text) + { + text = "/***" + text + "***/"; + return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); + } + + Ast.Expression MakeBranchCondition(Branch branch) + { + return new ParenthesizedExpression(MakeBranchCondition_Internal(branch)); + } + + Ast.Expression MakeBranchCondition_Internal(Branch branch) + { + if (branch is SimpleBranch) { + List args = TransformExpressionArguments((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]); + Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; + Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; + switch(((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]).OpCode.Code) { + case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not); + case Code.Brtrue: return arg1; + case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); + case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); + case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); + case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); + case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); + case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); + case Code.Leave: return new Ast.PrimitiveExpression(true, true.ToString()); + default: throw new Exception("Bad opcode"); + } + } else if (branch is ShortCircuitBranch) { + ShortCircuitBranch scBranch = (ShortCircuitBranch)branch; + switch(scBranch.Operator) { + case ShortCircuitOperator.LeftAndRight: + return new BinaryOperatorExpression( + MakeBranchCondition(scBranch.Left), + BinaryOperatorType.LogicalAnd, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.LeftOrRight: + return new BinaryOperatorExpression( + MakeBranchCondition(scBranch.Left), + BinaryOperatorType.LogicalOr, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.NotLeftAndRight: + return new BinaryOperatorExpression( + new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), + BinaryOperatorType.LogicalAnd, + MakeBranchCondition(scBranch.Right) + ); + case ShortCircuitOperator.NotLeftOrRight: + return new BinaryOperatorExpression( + new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), + BinaryOperatorType.LogicalOr, + MakeBranchCondition(scBranch.Right) + ); + default: + throw new Exception("Bad operator"); + } + } else { + throw new Exception("Bad type"); + } + } + + static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List args) + { + try { + Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args); + if (ret is Ast.Expression) { + ret = new ParenthesizedExpression((Ast.Expression)ret); + } + // ret.UserData["Type"] = byteCode.Type; + return ret; + } catch (NotImplementedException) { + // Output the operand of the unknown IL code as well + if (byteCode.Operand != null) { + args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); + } + return new Ast.InvocationExpression(new IdentifierExpression("__" + byteCode.OpCode.Name), args); + } + } + + static string FormatByteCodeOperand(object operand) + { + if (operand == null) { + return string.Empty; + //} else if (operand is ILExpression) { + // return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset); + } else if (operand is MethodReference) { + return ((MethodReference)operand).Name + "()"; + } else if (operand is Cecil.TypeReference) { + return ((Cecil.TypeReference)operand).FullName; + } else if (operand is VariableDefinition) { + return ((VariableDefinition)operand).Name; + } else if (operand is ParameterDefinition) { + return ((ParameterDefinition)operand).Name; + } else if (operand is FieldReference) { + return ((FieldReference)operand).Name; + } else if (operand is string) { + return "\"" + operand + "\""; + } else if (operand is int) { + return operand.ToString(); + } else { + return operand.ToString(); + } + } + + static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List args) + { + // throw new NotImplementedException(); + + OpCode opCode = byteCode.OpCode; + object operand = byteCode.Operand; + Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; + ILExpression operandAsByteCode = operand as ILExpression; + Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; + Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; + Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; + + Ast.Statement branchCommand = null; + if (byteCode.Operand is ILExpression) { + branchCommand = new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); + } + + switch(opCode.Code) { + #region Arithmetic + case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); + case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); + case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); + case Code.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); + case Code.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); + case Code.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); + case Code.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); + case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); + case Code.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); + case Code.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); + case Code.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); + case Code.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); + case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); + case Code.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); + case Code.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); + case Code.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); + case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); + case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); + + case Code.Neg: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Minus); + case Code.Not: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.BitNot); + #endregion + #region Arrays + case Code.Newarr: + operandAsTypeRef.RankSpecifier = new int[] {0}; + return new Ast.ArrayCreateExpression(operandAsTypeRef, new List(new Expression[] {arg1})); + + case Code.Ldlen: return new Ast.MemberReferenceExpression(arg1, "Length"); + + case Code.Ldelem_I: + case Code.Ldelem_I1: + case Code.Ldelem_I2: + case Code.Ldelem_I4: + case Code.Ldelem_I8: + case Code.Ldelem_U1: + case Code.Ldelem_U2: + case Code.Ldelem_U4: + case Code.Ldelem_R4: + case Code.Ldelem_R8: + case Code.Ldelem_Ref: return new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})); + case Code.Ldelem_Any: throw new NotImplementedException(); + case Code.Ldelema: return new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})); + + case Code.Stelem_I: + case Code.Stelem_I1: + case Code.Stelem_I2: + case Code.Stelem_I4: + case Code.Stelem_I8: + case Code.Stelem_R4: + case Code.Stelem_R8: + case Code.Stelem_Ref: return new Ast.AssignmentExpression(new Ast.IndexerExpression(arg1, new List(new Expression[] {arg2})), AssignmentOperatorType.Assign, arg3); + case Code.Stelem_Any: throw new NotImplementedException(); + #endregion + #region Branching + case Code.Br: return branchCommand; + case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand); + case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand); + case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand); + case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); + case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); + case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); + case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); + case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); + case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); + case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); + case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); + case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand); + #endregion + #region Comparison + case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2)); + case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); + case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); + #endregion + #region Conversions + case Code.Conv_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); + case Code.Conv_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); + case Code.Conv_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); + case Code.Conv_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); + case Code.Conv_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); + case Code.Conv_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); + case Code.Conv_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); + case Code.Conv_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); + case Code.Conv_R4: return new Ast.CastExpression(new Ast.TypeReference(typeof(float).FullName), arg1, CastType.Cast); + case Code.Conv_R8: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); + case Code.Conv_R_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); // TODO + + case Code.Conv_Ovf_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_Ovf_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_Ovf_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); + + case Code.Conv_Ovf_I_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_Ovf_I1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_I8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO + case Code.Conv_Ovf_U1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); + case Code.Conv_Ovf_U8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); + #endregion + #region Indirect + case Code.Ldind_I: throw new NotImplementedException(); + case Code.Ldind_I1: throw new NotImplementedException(); + case Code.Ldind_I2: throw new NotImplementedException(); + case Code.Ldind_I4: throw new NotImplementedException(); + case Code.Ldind_I8: throw new NotImplementedException(); + case Code.Ldind_U1: throw new NotImplementedException(); + case Code.Ldind_U2: throw new NotImplementedException(); + case Code.Ldind_U4: throw new NotImplementedException(); + case Code.Ldind_R4: throw new NotImplementedException(); + case Code.Ldind_R8: throw new NotImplementedException(); + case Code.Ldind_Ref: throw new NotImplementedException(); + + case Code.Stind_I: throw new NotImplementedException(); + case Code.Stind_I1: throw new NotImplementedException(); + case Code.Stind_I2: throw new NotImplementedException(); + case Code.Stind_I4: throw new NotImplementedException(); + case Code.Stind_I8: throw new NotImplementedException(); + case Code.Stind_R4: throw new NotImplementedException(); + case Code.Stind_R8: throw new NotImplementedException(); + case Code.Stind_Ref: throw new NotImplementedException(); + #endregion + case Code.Arglist: throw new NotImplementedException(); + case Code.Box: throw new NotImplementedException(); + case Code.Break: throw new NotImplementedException(); + case Code.Call: + case Code.Callvirt: + // TODO: Diferentiate vitual and non-vitual dispach + Cecil.MethodReference cecilMethod = ((MethodReference)operand); + Ast.Expression target; + List methodArgs = new List(args); + if (cecilMethod.HasThis) { + target = methodArgs[0]; + methodArgs.RemoveAt(0); + } else { + target = new Ast.IdentifierExpression(cecilMethod.DeclaringType.FullName); + } + + // TODO: Constructors are ignored + if (cecilMethod.Name == ".ctor") { + return MakeComment("// Constructor"); + } + + // TODO: Hack, detect properties properly + if (cecilMethod.Name.StartsWith("get_")) { + return new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)); + } else if (cecilMethod.Name.StartsWith("set_")) { + return new Ast.AssignmentExpression( + new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)), + AssignmentOperatorType.Assign, + methodArgs[0] + ); + } + + // Multi-dimensional array acces // TODO: do properly + if (cecilMethod.Name == "Get") { + return new Ast.IndexerExpression(target, methodArgs); + } else if (cecilMethod.Name == "Set") { + Expression val = methodArgs[methodArgs.Count - 1]; + methodArgs.RemoveAt(methodArgs.Count - 1); + return new Ast.AssignmentExpression( + new Ast.IndexerExpression(target, methodArgs), + AssignmentOperatorType.Assign, + Convert(val, ((Cecil.ArrayType)target.UserData["Type"]).ElementType) + ); + } + + // Default invocation + return new Ast.InvocationExpression( + new Ast.MemberReferenceExpression(target, cecilMethod.Name), + methodArgs + ); + case Code.Calli: throw new NotImplementedException(); + case Code.Castclass: return new Ast.CastExpression(operandAsTypeRef, arg1, CastType.Cast); + case Code.Ckfinite: throw new NotImplementedException(); + case Code.Constrained: throw new NotImplementedException(); + case Code.Cpblk: throw new NotImplementedException(); + case Code.Cpobj: throw new NotImplementedException(); + case Code.Dup: return arg1; + case Code.Endfilter: throw new NotImplementedException(); + case Code.Endfinally: return null; + case Code.Initblk: throw new NotImplementedException(); + case Code.Initobj: throw new NotImplementedException(); + case Code.Isinst: return new Ast.TypeOfIsExpression(arg1, new Ast.TypeReference(((Cecil.TypeReference)operand).FullName)); + case Code.Jmp: throw new NotImplementedException(); + case Code.Ldarg: + if (methodDef.HasThis && ((ParameterDefinition)operand).Index == 0) { + return new Ast.ThisReferenceExpression(); + } else { + return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); + } + case Code.Ldarga: throw new NotImplementedException(); + case Code.Ldc_I4: + case Code.Ldc_I8: + case Code.Ldc_R4: + case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand, null); + case Code.Ldfld: + case Code.Ldsfld: { + if (operand is FieldDefinition) { + FieldDefinition field = (FieldDefinition) operand; + if (field.IsStatic) { + return new Ast.MemberReferenceExpression( + new Ast.IdentifierExpression(field.DeclaringType.FullName), + field.Name + ); + } else { + return new Ast.MemberReferenceExpression(arg1, field.Name); + } + } else { + // TODO: Static accesses + return new Ast.MemberReferenceExpression(arg1, ((FieldReference)operand).Name); + } + } + case Code.Stfld: + case Code.Stsfld: { + FieldDefinition field = (FieldDefinition) operand; + if (field.IsStatic) { + return new AssignmentExpression( + new Ast.MemberReferenceExpression( + new Ast.IdentifierExpression(field.DeclaringType.FullName), + field.Name + ), + AssignmentOperatorType.Assign, + arg1 + ); + } else { + return new AssignmentExpression( + new Ast.MemberReferenceExpression(arg1, field.Name), + AssignmentOperatorType.Assign, + arg2 + ); + } + } + case Code.Ldflda: + case Code.Ldsflda: throw new NotImplementedException(); + case Code.Ldftn: throw new NotImplementedException(); + case Code.Ldloc: + if (operand is ILStackVariable) { + return new Ast.IdentifierExpression(((ILStackVariable)operand).Name); + } else { + return new Ast.IdentifierExpression(((VariableDefinition)operand).Name); + } + case Code.Ldloca: throw new NotImplementedException(); + case Code.Ldnull: return new Ast.PrimitiveExpression(null, null); + case Code.Ldobj: throw new NotImplementedException(); + case Code.Ldstr: return new Ast.PrimitiveExpression(operand, null); + case Code.Ldtoken: + if (operand is Cecil.TypeReference) { + return new Ast.MemberReferenceExpression( + new Ast.TypeOfExpression(operandAsTypeRef), + "TypeHandle" + ); + } else { + throw new NotImplementedException(); + } + case Code.Ldvirtftn: throw new NotImplementedException(); + case Code.Leave: return null; + case Code.Localloc: throw new NotImplementedException(); + case Code.Mkrefany: throw new NotImplementedException(); + case Code.Newobj: + Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; + // TODO: Ensure that the corrent overloaded constructor is called + if (declaringType is ArrayType) { + return new Ast.ArrayCreateExpression( + new Ast.TypeReference(((ArrayType)declaringType).ElementType.FullName, new int[] {}), + new List(args) + ); + } + return new Ast.ObjectCreateExpression( + new Ast.TypeReference(declaringType.FullName), + new List(args) + ); + case Code.No: throw new NotImplementedException(); + case Code.Nop: return null; + case Code.Or: throw new NotImplementedException(); + case Code.Pop: return arg1; + case Code.Readonly: throw new NotImplementedException(); + case Code.Refanytype: throw new NotImplementedException(); + case Code.Refanyval: throw new NotImplementedException(); + case Code.Ret: { + if (methodDef.ReturnType.FullName != Constants.Void) { + arg1 = Convert(arg1, methodDef.ReturnType); + return new Ast.ReturnStatement(arg1); + } else { + return new Ast.ReturnStatement(null); + } + } + case Code.Rethrow: return new Ast.ThrowStatement(new IdentifierExpression("exception")); + case Code.Sizeof: throw new NotImplementedException(); + case Code.Starg: throw new NotImplementedException(); + case Code.Stloc: { + if (operand is ILStackVariable) { + return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ILStackVariable)operand).Name), AssignmentOperatorType.Assign, arg1); + } + VariableDefinition locVar = (VariableDefinition)operand; + string name = locVar.Name; + arg1 = Convert(arg1, locVar.VariableType); + if (localVarDefined.ContainsKey(name)) { + if (localVarDefined[name]) { + return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); + } else { + Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1)); + astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName); + localVarDefined[name] = true; + return astLocalVar; + } + } else { + return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); + } + } + case Code.Stobj: throw new NotImplementedException(); + case Code.Switch: throw new NotImplementedException(); + case Code.Tail: throw new NotImplementedException(); + case Code.Throw: return new Ast.ThrowStatement(arg1); + case Code.Unaligned: throw new NotImplementedException(); + case Code.Unbox: throw new NotImplementedException(); + case Code.Unbox_Any: throw new NotImplementedException(); + case Code.Volatile: throw new NotImplementedException(); + default: throw new Exception("Unknown OpCode: " + opCode); + } + } + + static Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference reqType) + { + if (reqType == null) { + return expr; + } else { + return Convert(expr, reqType.FullName); + } + } + + static Ast.Expression Convert(Ast.Expression expr, string reqType) + { +// if (expr.UserData.ContainsKey("Type")) { +// Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"]; +// if (exprType == ByteCode.TypeZero && +// reqType == ByteCode.TypeBool.FullName) { +// return new PrimitiveExpression(false, "false"); +// } +// if (exprType == ByteCode.TypeOne && +// reqType == ByteCode.TypeBool.FullName) { +// return new PrimitiveExpression(true, "true"); +// } +// } + return expr; + } + + static Ast.Expression ConvertIntToBool(Ast.Expression astInt) + { + return astInt; + // return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0"))); + } + } +} diff --git a/Decompiler/src/Ast/Transforms/Idioms.cs b/ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs similarity index 97% rename from Decompiler/src/Ast/Transforms/Idioms.cs rename to ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs index 7e00a3c43..3f23b68a5 100644 --- a/Decompiler/src/Ast/Transforms/Idioms.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs @@ -1,76 +1,76 @@ -using System; -using System.Collections.Generic; -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class Idioms: AbstractAstTransformer - { - public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) - { - base.VisitInvocationExpression(invocationExpression, data); - - // Reduce "String.Concat(a, b)" to "a + b" - MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression; - if (target != null && - target.MemberName == "Concat" && - invocationExpression.Arguments.Count == 2 && - target.TargetObject is IdentifierExpression && - (target.TargetObject as IdentifierExpression).Identifier == "String") - { - ReplaceCurrentNode( - new BinaryOperatorExpression( - invocationExpression.Arguments[0], - BinaryOperatorType.Add, - invocationExpression.Arguments[1] - ) - ); - } - - return null; - } - - public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) - { - IdentifierExpression ident = assignment.Left as IdentifierExpression; - BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; - if (ident != null && binary != null) { - IdentifierExpression binaryLeft = binary.Left as IdentifierExpression; - if (binaryLeft != null && - binaryLeft.Identifier == ident.Identifier) { - if (binary.Right is PrimitiveExpression && - 1.Equals((binary.Right as PrimitiveExpression).Value)) { - if (binary.Op == BinaryOperatorType.Add) { - ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement)); - } - if (binary.Op == BinaryOperatorType.Subtract) { - ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement)); - } - } else { - if (binary.Op == BinaryOperatorType.Add) { - ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right)); - } - if (binary.Op == BinaryOperatorType.Subtract) { - ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right)); - } - } - return null; - } - } - return null; - } - - public override object VisitCastExpression(CastExpression castExpression, object data) - { - if (castExpression.CastTo.Type == "int" && - castExpression.Expression is MemberReferenceExpression && - (castExpression.Expression as MemberReferenceExpression).MemberName == "Length") { - ReplaceCurrentNode(castExpression.Expression); - return null; - } - return base.VisitCastExpression(castExpression, data); - } - } -} +using System; +using System.Collections.Generic; +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class Idioms: AbstractAstTransformer + { + public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) + { + base.VisitInvocationExpression(invocationExpression, data); + + // Reduce "String.Concat(a, b)" to "a + b" + MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression; + if (target != null && + target.MemberName == "Concat" && + invocationExpression.Arguments.Count == 2 && + target.TargetObject is IdentifierExpression && + (target.TargetObject as IdentifierExpression).Identifier == "String") + { + ReplaceCurrentNode( + new BinaryOperatorExpression( + invocationExpression.Arguments[0], + BinaryOperatorType.Add, + invocationExpression.Arguments[1] + ) + ); + } + + return null; + } + + public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) + { + IdentifierExpression ident = assignment.Left as IdentifierExpression; + BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; + if (ident != null && binary != null) { + IdentifierExpression binaryLeft = binary.Left as IdentifierExpression; + if (binaryLeft != null && + binaryLeft.Identifier == ident.Identifier) { + if (binary.Right is PrimitiveExpression && + 1.Equals((binary.Right as PrimitiveExpression).Value)) { + if (binary.Op == BinaryOperatorType.Add) { + ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement)); + } + if (binary.Op == BinaryOperatorType.Subtract) { + ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement)); + } + } else { + if (binary.Op == BinaryOperatorType.Add) { + ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right)); + } + if (binary.Op == BinaryOperatorType.Subtract) { + ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right)); + } + } + return null; + } + } + return null; + } + + public override object VisitCastExpression(CastExpression castExpression, object data) + { + if (castExpression.CastTo.Type == "int" && + castExpression.Expression is MemberReferenceExpression && + (castExpression.Expression as MemberReferenceExpression).MemberName == "Length") { + ReplaceCurrentNode(castExpression.Expression); + return null; + } + return base.VisitCastExpression(castExpression, data); + } + } +} diff --git a/Decompiler/src/Ast/Transforms/PushNegation.cs b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs similarity index 97% rename from Decompiler/src/Ast/Transforms/PushNegation.cs rename to ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs index 175864c83..7e6d26ade 100644 --- a/Decompiler/src/Ast/Transforms/PushNegation.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; - -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class PushNegation: AbstractAstTransformer - { - public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) - { - // Remove double negation - // !!a - if (unary.Op == UnaryOperatorType.Not && - unary.Expression is UnaryOperatorExpression && - (unary.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { - Expression newParenth = new ParenthesizedExpression((unary.Expression as UnaryOperatorExpression).Expression); - ReplaceCurrentNode(newParenth); - return newParenth.AcceptVisitor(this, data); - } - - // Basic assumtion is that we have something in form !(a) - if (unary.Op == UnaryOperatorType.Not && - unary.Expression is ParenthesizedExpression) { - ParenthesizedExpression parenth = ((ParenthesizedExpression)unary.Expression); - - // Push through two parenthesis - // !((a)) - if (parenth.Expression is ParenthesizedExpression) { - parenth.Expression = new UnaryOperatorExpression(parenth.Expression, UnaryOperatorType.Not); - ReplaceCurrentNode(parenth); - return parenth.AcceptVisitor(this, data); - } - - // Remove double negation - // !(!a) - if (parenth.Expression is UnaryOperatorExpression && - (parenth.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { - parenth.Expression = (parenth.Expression as UnaryOperatorExpression).Expression; - ReplaceCurrentNode(parenth); - return parenth.AcceptVisitor(this, data); - } - - // Push through binary operation - // !((a) op (b)) - BinaryOperatorExpression binaryOp = parenth.Expression as BinaryOperatorExpression; - if (binaryOp != null && - binaryOp.Left is ParenthesizedExpression && - binaryOp.Right is ParenthesizedExpression) { - - bool sucessful = true; - switch(binaryOp.Op) { - case BinaryOperatorType.Equality: binaryOp.Op = BinaryOperatorType.InEquality; break; - case BinaryOperatorType.InEquality: binaryOp.Op = BinaryOperatorType.Equality; break; - case BinaryOperatorType.GreaterThan: binaryOp.Op = BinaryOperatorType.LessThanOrEqual; break; - case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Op = BinaryOperatorType.LessThan; break; - case BinaryOperatorType.LessThanOrEqual: binaryOp.Op = BinaryOperatorType.GreaterThan; break; - case BinaryOperatorType.LessThan: binaryOp.Op = BinaryOperatorType.GreaterThanOrEqual; break; - default: sucessful = false; break; - } - if (sucessful) { - ReplaceCurrentNode(parenth); - return parenth.AcceptVisitor(this, data); - } - - sucessful = true; - switch(binaryOp.Op) { - case BinaryOperatorType.BitwiseAnd: binaryOp.Op = BinaryOperatorType.BitwiseOr; break; - case BinaryOperatorType.BitwiseOr: binaryOp.Op = BinaryOperatorType.BitwiseAnd; break; - case BinaryOperatorType.LogicalAnd: binaryOp.Op = BinaryOperatorType.LogicalOr; break; - case BinaryOperatorType.LogicalOr: binaryOp.Op = BinaryOperatorType.LogicalAnd; break; - default: sucessful = false; break; - } - if (sucessful) { - binaryOp.Left = new UnaryOperatorExpression(binaryOp.Left, UnaryOperatorType.Not); - binaryOp.Right = new UnaryOperatorExpression(binaryOp.Right, UnaryOperatorType.Not); - ReplaceCurrentNode(parenth); - return parenth.AcceptVisitor(this, data); - } - } - } - - return base.VisitUnaryOperatorExpression(unary, data); - } - } -} +using System; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class PushNegation: AbstractAstTransformer + { + public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) + { + // Remove double negation + // !!a + if (unary.Op == UnaryOperatorType.Not && + unary.Expression is UnaryOperatorExpression && + (unary.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { + Expression newParenth = new ParenthesizedExpression((unary.Expression as UnaryOperatorExpression).Expression); + ReplaceCurrentNode(newParenth); + return newParenth.AcceptVisitor(this, data); + } + + // Basic assumtion is that we have something in form !(a) + if (unary.Op == UnaryOperatorType.Not && + unary.Expression is ParenthesizedExpression) { + ParenthesizedExpression parenth = ((ParenthesizedExpression)unary.Expression); + + // Push through two parenthesis + // !((a)) + if (parenth.Expression is ParenthesizedExpression) { + parenth.Expression = new UnaryOperatorExpression(parenth.Expression, UnaryOperatorType.Not); + ReplaceCurrentNode(parenth); + return parenth.AcceptVisitor(this, data); + } + + // Remove double negation + // !(!a) + if (parenth.Expression is UnaryOperatorExpression && + (parenth.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { + parenth.Expression = (parenth.Expression as UnaryOperatorExpression).Expression; + ReplaceCurrentNode(parenth); + return parenth.AcceptVisitor(this, data); + } + + // Push through binary operation + // !((a) op (b)) + BinaryOperatorExpression binaryOp = parenth.Expression as BinaryOperatorExpression; + if (binaryOp != null && + binaryOp.Left is ParenthesizedExpression && + binaryOp.Right is ParenthesizedExpression) { + + bool sucessful = true; + switch(binaryOp.Op) { + case BinaryOperatorType.Equality: binaryOp.Op = BinaryOperatorType.InEquality; break; + case BinaryOperatorType.InEquality: binaryOp.Op = BinaryOperatorType.Equality; break; + case BinaryOperatorType.GreaterThan: binaryOp.Op = BinaryOperatorType.LessThanOrEqual; break; + case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Op = BinaryOperatorType.LessThan; break; + case BinaryOperatorType.LessThanOrEqual: binaryOp.Op = BinaryOperatorType.GreaterThan; break; + case BinaryOperatorType.LessThan: binaryOp.Op = BinaryOperatorType.GreaterThanOrEqual; break; + default: sucessful = false; break; + } + if (sucessful) { + ReplaceCurrentNode(parenth); + return parenth.AcceptVisitor(this, data); + } + + sucessful = true; + switch(binaryOp.Op) { + case BinaryOperatorType.BitwiseAnd: binaryOp.Op = BinaryOperatorType.BitwiseOr; break; + case BinaryOperatorType.BitwiseOr: binaryOp.Op = BinaryOperatorType.BitwiseAnd; break; + case BinaryOperatorType.LogicalAnd: binaryOp.Op = BinaryOperatorType.LogicalOr; break; + case BinaryOperatorType.LogicalOr: binaryOp.Op = BinaryOperatorType.LogicalAnd; break; + default: sucessful = false; break; + } + if (sucessful) { + binaryOp.Left = new UnaryOperatorExpression(binaryOp.Left, UnaryOperatorType.Not); + binaryOp.Right = new UnaryOperatorExpression(binaryOp.Right, UnaryOperatorType.Not); + ReplaceCurrentNode(parenth); + return parenth.AcceptVisitor(this, data); + } + } + } + + return base.VisitUnaryOperatorExpression(unary, data); + } + } +} diff --git a/Decompiler/src/Ast/Transforms/RemoveDeadLabels.cs b/ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs similarity index 96% rename from Decompiler/src/Ast/Transforms/RemoveDeadLabels.cs rename to ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs index 520e1fddd..66ef6710f 100644 --- a/Decompiler/src/Ast/Transforms/RemoveDeadLabels.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs @@ -1,50 +1,50 @@ -using System; -using System.Collections.Generic; -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class RemoveDeadLabels: AbstractAstTransformer - { - List usedLabels = new List(); - bool collectingUsedLabels; - - public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) - { - collectingUsedLabels = true; - base.VisitConstructorDeclaration(constructorDeclaration, data); - collectingUsedLabels = false; - base.VisitConstructorDeclaration(constructorDeclaration, data); - return null; - } - - public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) - { - collectingUsedLabels = true; - base.VisitMethodDeclaration(methodDeclaration, data); - collectingUsedLabels = false; - base.VisitMethodDeclaration(methodDeclaration, data); - return null; - } - - public override object VisitGotoStatement(GotoStatement gotoStatement, object data) - { - if (collectingUsedLabels) { - usedLabels.Add(gotoStatement.Label); - } - return null; - } - - public override object VisitLabelStatement(LabelStatement labelStatement, object data) - { - if (!collectingUsedLabels) { - if (!usedLabels.Contains(labelStatement.Label)) { - RemoveCurrentNode(); - } - } - return null; - } - } -} +using System; +using System.Collections.Generic; +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RemoveDeadLabels: AbstractAstTransformer + { + List usedLabels = new List(); + bool collectingUsedLabels; + + public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) + { + collectingUsedLabels = true; + base.VisitConstructorDeclaration(constructorDeclaration, data); + collectingUsedLabels = false; + base.VisitConstructorDeclaration(constructorDeclaration, data); + return null; + } + + public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) + { + collectingUsedLabels = true; + base.VisitMethodDeclaration(methodDeclaration, data); + collectingUsedLabels = false; + base.VisitMethodDeclaration(methodDeclaration, data); + return null; + } + + public override object VisitGotoStatement(GotoStatement gotoStatement, object data) + { + if (collectingUsedLabels) { + usedLabels.Add(gotoStatement.Label); + } + return null; + } + + public override object VisitLabelStatement(LabelStatement labelStatement, object data) + { + if (!collectingUsedLabels) { + if (!usedLabels.Contains(labelStatement.Label)) { + RemoveCurrentNode(); + } + } + return null; + } + } +} diff --git a/Decompiler/src/Ast/Transforms/RemoveEmptyElseBody.cs b/ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs similarity index 96% rename from Decompiler/src/Ast/Transforms/RemoveEmptyElseBody.cs rename to ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs index e7e8b22e7..67852d787 100644 --- a/Decompiler/src/Ast/Transforms/RemoveEmptyElseBody.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs @@ -1,36 +1,36 @@ -using System; - -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class RemoveEmptyElseBody: AbstractAstTransformer - { - public override object VisitBlockStatement(BlockStatement blockStatement, object data) - { - for(int i = 0; i < blockStatement.Children.Count; i++) { - if (blockStatement.Children[i] is Statement && - ((Statement)blockStatement.Children[i]).IsNull) - { - blockStatement.Children.RemoveAt(i); - i--; - } - } - return base.VisitBlockStatement(blockStatement, data); - } - - public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) - { - base.VisitIfElseStatement(ifElseStatement, data); - if (ifElseStatement.FalseStatement.Count == 1 && - ifElseStatement.FalseStatement[0] is BlockStatement && - ifElseStatement.FalseStatement[0].Children.Count == 0) - { - ifElseStatement.FalseStatement.Clear(); - } - return null; - } - } -} +using System; + +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RemoveEmptyElseBody: AbstractAstTransformer + { + public override object VisitBlockStatement(BlockStatement blockStatement, object data) + { + for(int i = 0; i < blockStatement.Children.Count; i++) { + if (blockStatement.Children[i] is Statement && + ((Statement)blockStatement.Children[i]).IsNull) + { + blockStatement.Children.RemoveAt(i); + i--; + } + } + return base.VisitBlockStatement(blockStatement, data); + } + + public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) + { + base.VisitIfElseStatement(ifElseStatement, data); + if (ifElseStatement.FalseStatement.Count == 1 && + ifElseStatement.FalseStatement[0] is BlockStatement && + ifElseStatement.FalseStatement[0].Children.Count == 0) + { + ifElseStatement.FalseStatement.Clear(); + } + return null; + } + } +} diff --git a/Decompiler/src/Ast/Transforms/RemoveGotos.cs b/ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs similarity index 96% rename from Decompiler/src/Ast/Transforms/RemoveGotos.cs rename to ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs index a28cb774d..a737b9c8b 100644 --- a/Decompiler/src/Ast/Transforms/RemoveGotos.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs @@ -1,186 +1,186 @@ -using System; -using System.Collections.Generic; - -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class RemoveGotos: AbstractAstTransformer - { - Stack enteredLoops = new Stack(); - - StatementWithEmbeddedStatement CurrentLoop { - get { - if (enteredLoops.Count > 0) { - return enteredLoops.Peek(); - } else { - return null; - } - } - } - - public override object VisitForStatement(ForStatement forStatement, object data) - { - enteredLoops.Push(forStatement); - base.VisitForStatement(forStatement, data); - enteredLoops.Pop(); - return null; - } - - public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) - { - enteredLoops.Push(doLoopStatement); - base.VisitDoLoopStatement(doLoopStatement, data); - enteredLoops.Pop(); - return null; - } - - public override object VisitBlockStatement(BlockStatement blockStatement, object data) - { - base.VisitBlockStatement(blockStatement, data); - - // Remove redundant jump at the end of block - INode lastStmt = blockStatement.Children.Last; - // End of while loop - if (lastStmt is ContinueStatement && - blockStatement.Parent is DoLoopStatement) - { - lastStmt.Remove(); - return null; - } - // End of for loop - if (lastStmt is ContinueStatement && - blockStatement.Parent is ForStatement) - { - lastStmt.Remove(); - return null; - } - // End of method - if (lastStmt is ReturnStatement && - (blockStatement.Parent is MethodDeclaration || blockStatement.Parent is ConstructorDeclaration) && - ((ReturnStatement)lastStmt).Expression.IsNull) - { - lastStmt.Remove(); - return null; - } - - return null; - } - - // Get the next statement that will be executed after this one - // May return null - public static INode GetNextStatement(Statement statement) - { - if (statement == null) throw new ArgumentNullException(); - - Statement next = (Statement)statement.Next(); - - if (next != null) { - return EnterBlockStatement(next); - } else { - if (statement.Parent is BlockStatement && - statement.Parent.Parent is Statement) { - return ExitBlockStatement((Statement)statement.Parent.Parent); - } else { - return null; - } - } - } - - // Get the statement that will be executed once the given block exits by the end brace - // May return null - public static INode ExitBlockStatement(Statement statement) - { - if (statement == null) throw new ArgumentNullException(); - - // When an 'if' body is finished the execution continues with the - // next statement after the 'if' statement - if (statement is IfElseStatement) { - return GetNextStatement((IfElseStatement)statement); - } - - // When a 'for' body is finished the execution continues by: - // Iterator; Condition; Body - if (statement is ForStatement) { - ForStatement forLoop = statement as ForStatement; - if (forLoop.Iterator.Count > 0) { - return forLoop.Iterator[0]; - } else if (!forLoop.Condition.IsNull) { - return forLoop.Condition; - } else { - return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); - } - } - - return null; - } - - // Get the first statement that will be executed in the given block - public static INode EnterBlockStatement(Statement statement) - { - if (statement == null) throw new ArgumentNullException(); - - // For loop starts as follows: Initializers; Condition; Body - if (statement is ForStatement) { - ForStatement forLoop = statement as ForStatement; - if (forLoop.Initializers.Count > 0) { - return forLoop.Initializers[0]; - } else if (!forLoop.Condition.IsNull) { - return forLoop.Condition; - } else if (forLoop.EmbeddedStatement is BlockStatement && - forLoop.EmbeddedStatement.Children.Count > 0) { - statement = (Statement)forLoop.EmbeddedStatement.Children.First; - return EnterBlockStatement(statement); // Simplify again - } - } - - return statement; // Can not simplify - } - - public override object VisitGotoStatement(GotoStatement gotoStatement, object data) - { - // Remove redundant goto which goes to a label that imideately follows - INode fallthoughTarget = GetNextStatement(gotoStatement); - if ((fallthoughTarget is LabelStatement) && - (fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { - RemoveCurrentNode(); - return null; - } - - // Replace goto with 'break' - // Break statement moves right outside the looop - if (CurrentLoop != null) { - INode breakTarget = GetNextStatement(CurrentLoop); - if ((breakTarget is LabelStatement) && - (breakTarget as LabelStatement).Label == gotoStatement.Label) { - ReplaceCurrentNode(new BreakStatement()); - return null; - } - } - - // Replace goto with 'continue' - // Continue statement which moves at the very end of loop - if (CurrentLoop != null && - (CurrentLoop.EmbeddedStatement is BlockStatement) && - ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement) != null && - ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement).Label == gotoStatement.Label) { - ReplaceCurrentNode(new ContinueStatement()); - return null; - } - - // Replace goto with 'continue' - // Continue statement which moves at the very start of for loop - if (CurrentLoop != null) { - INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop - if ((continueTarget is LabelStatement) && - (continueTarget as LabelStatement).Label == gotoStatement.Label) { - ReplaceCurrentNode(new ContinueStatement()); - return null; - } - } - - return null; - } - } -} +using System; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RemoveGotos: AbstractAstTransformer + { + Stack enteredLoops = new Stack(); + + StatementWithEmbeddedStatement CurrentLoop { + get { + if (enteredLoops.Count > 0) { + return enteredLoops.Peek(); + } else { + return null; + } + } + } + + public override object VisitForStatement(ForStatement forStatement, object data) + { + enteredLoops.Push(forStatement); + base.VisitForStatement(forStatement, data); + enteredLoops.Pop(); + return null; + } + + public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) + { + enteredLoops.Push(doLoopStatement); + base.VisitDoLoopStatement(doLoopStatement, data); + enteredLoops.Pop(); + return null; + } + + public override object VisitBlockStatement(BlockStatement blockStatement, object data) + { + base.VisitBlockStatement(blockStatement, data); + + // Remove redundant jump at the end of block + INode lastStmt = blockStatement.Children.Last; + // End of while loop + if (lastStmt is ContinueStatement && + blockStatement.Parent is DoLoopStatement) + { + lastStmt.Remove(); + return null; + } + // End of for loop + if (lastStmt is ContinueStatement && + blockStatement.Parent is ForStatement) + { + lastStmt.Remove(); + return null; + } + // End of method + if (lastStmt is ReturnStatement && + (blockStatement.Parent is MethodDeclaration || blockStatement.Parent is ConstructorDeclaration) && + ((ReturnStatement)lastStmt).Expression.IsNull) + { + lastStmt.Remove(); + return null; + } + + return null; + } + + // Get the next statement that will be executed after this one + // May return null + public static INode GetNextStatement(Statement statement) + { + if (statement == null) throw new ArgumentNullException(); + + Statement next = (Statement)statement.Next(); + + if (next != null) { + return EnterBlockStatement(next); + } else { + if (statement.Parent is BlockStatement && + statement.Parent.Parent is Statement) { + return ExitBlockStatement((Statement)statement.Parent.Parent); + } else { + return null; + } + } + } + + // Get the statement that will be executed once the given block exits by the end brace + // May return null + public static INode ExitBlockStatement(Statement statement) + { + if (statement == null) throw new ArgumentNullException(); + + // When an 'if' body is finished the execution continues with the + // next statement after the 'if' statement + if (statement is IfElseStatement) { + return GetNextStatement((IfElseStatement)statement); + } + + // When a 'for' body is finished the execution continues by: + // Iterator; Condition; Body + if (statement is ForStatement) { + ForStatement forLoop = statement as ForStatement; + if (forLoop.Iterator.Count > 0) { + return forLoop.Iterator[0]; + } else if (!forLoop.Condition.IsNull) { + return forLoop.Condition; + } else { + return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); + } + } + + return null; + } + + // Get the first statement that will be executed in the given block + public static INode EnterBlockStatement(Statement statement) + { + if (statement == null) throw new ArgumentNullException(); + + // For loop starts as follows: Initializers; Condition; Body + if (statement is ForStatement) { + ForStatement forLoop = statement as ForStatement; + if (forLoop.Initializers.Count > 0) { + return forLoop.Initializers[0]; + } else if (!forLoop.Condition.IsNull) { + return forLoop.Condition; + } else if (forLoop.EmbeddedStatement is BlockStatement && + forLoop.EmbeddedStatement.Children.Count > 0) { + statement = (Statement)forLoop.EmbeddedStatement.Children.First; + return EnterBlockStatement(statement); // Simplify again + } + } + + return statement; // Can not simplify + } + + public override object VisitGotoStatement(GotoStatement gotoStatement, object data) + { + // Remove redundant goto which goes to a label that imideately follows + INode fallthoughTarget = GetNextStatement(gotoStatement); + if ((fallthoughTarget is LabelStatement) && + (fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { + RemoveCurrentNode(); + return null; + } + + // Replace goto with 'break' + // Break statement moves right outside the looop + if (CurrentLoop != null) { + INode breakTarget = GetNextStatement(CurrentLoop); + if ((breakTarget is LabelStatement) && + (breakTarget as LabelStatement).Label == gotoStatement.Label) { + ReplaceCurrentNode(new BreakStatement()); + return null; + } + } + + // Replace goto with 'continue' + // Continue statement which moves at the very end of loop + if (CurrentLoop != null && + (CurrentLoop.EmbeddedStatement is BlockStatement) && + ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement) != null && + ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement).Label == gotoStatement.Label) { + ReplaceCurrentNode(new ContinueStatement()); + return null; + } + + // Replace goto with 'continue' + // Continue statement which moves at the very start of for loop + if (CurrentLoop != null) { + INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop + if ((continueTarget is LabelStatement) && + (continueTarget as LabelStatement).Label == gotoStatement.Label) { + ReplaceCurrentNode(new ContinueStatement()); + return null; + } + } + + return null; + } + } +} diff --git a/Decompiler/src/Ast/Transforms/RemoveParenthesis.cs b/ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs similarity index 97% rename from Decompiler/src/Ast/Transforms/RemoveParenthesis.cs rename to ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs index 26cc3fc0e..787782e7b 100644 --- a/Decompiler/src/Ast/Transforms/RemoveParenthesis.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs @@ -1,245 +1,245 @@ -using System; -using System.Collections.Generic; - -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class RemoveParenthesis: AbstractAstTransformer - { - public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) - { - // The following do not need to be parenthesized - if (parenthesizedExpression.Expression is IdentifierExpression || - parenthesizedExpression.Expression is PrimitiveExpression || - parenthesizedExpression.Expression is ThisReferenceExpression || - parenthesizedExpression.Expression is ParenthesizedExpression) { - ReplaceCurrentNode(parenthesizedExpression.Expression); - return null; - } - return base.VisitParenthesizedExpression(parenthesizedExpression, data); - } - - public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) - { - assignmentExpression.Left = Deparenthesize(assignmentExpression.Left); - assignmentExpression.Right = Deparenthesize(assignmentExpression.Right); - return base.VisitAssignmentExpression(assignmentExpression, data); - } - - public override object VisitArrayCreateExpression(ArrayCreateExpression array, object data) - { - for(int i = 0; i < array.Arguments.Count; i++) { - array.Arguments[i] = Deparenthesize(array.Arguments[i]); - } - return base.VisitArrayCreateExpression(array, data); - } - - public override object VisitReturnStatement(ReturnStatement returnStatement, object data) - { - returnStatement.Expression = Deparenthesize(returnStatement.Expression); - return base.VisitReturnStatement(returnStatement, data); - } - - public override object VisitCastExpression(CastExpression castExpression, object data) - { - if (GetPrecedence(castExpression.Expression) > GetPrecedence(castExpression)) { - castExpression.Expression = Deparenthesize(castExpression.Expression); - } - return base.VisitCastExpression(castExpression, data); - } - - public override object VisitIndexerExpression(IndexerExpression indexer, object data) - { - if (GetPrecedence(indexer.TargetObject) >= GetPrecedence(indexer)) { - indexer.TargetObject = Deparenthesize(indexer.TargetObject); - } - return base.VisitIndexerExpression(indexer, data); - } - - public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) - { - ifElseStatement.Condition = Deparenthesize(ifElseStatement.Condition); - return base.VisitIfElseStatement(ifElseStatement, data); - } - - public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data) - { - variableDeclaration.Initializer = Deparenthesize(variableDeclaration.Initializer); - return base.VisitVariableDeclaration(variableDeclaration, data); - } - - public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) - { - if (GetPrecedence(unary.Expression) > GetPrecedence(unary)) { - unary.Expression = Deparenthesize(unary.Expression); - } - return base.VisitUnaryOperatorExpression(unary, data); - } - - public override object VisitMemberReferenceExpression(MemberReferenceExpression memberRef, object data) - { - if (GetPrecedence(memberRef.TargetObject) >= GetPrecedence(memberRef)) { - memberRef.TargetObject = Deparenthesize(memberRef.TargetObject); - } - return base.VisitMemberReferenceExpression(memberRef, data); - } - - public override object VisitInvocationExpression(InvocationExpression invocation, object data) - { - if (GetPrecedence(invocation.TargetObject) >= GetPrecedence(invocation)) { - invocation.TargetObject = Deparenthesize(invocation.TargetObject); - } - for(int i = 0; i < invocation.Arguments.Count; i++) { - invocation.Arguments[i] = Deparenthesize(invocation.Arguments[i]); - } - return base.VisitInvocationExpression(invocation, data); - } - - public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binary, object data) - { - int? myPrecedence = GetPrecedence(binary); - if (GetPrecedence(binary.Left) > myPrecedence) { - binary.Left = Deparenthesize(binary.Left); - } - if (GetPrecedence(binary.Right) > myPrecedence) { - binary.Right = Deparenthesize(binary.Right); - } - // Associativity - if (GetPrecedence(binary.Left) == myPrecedence && myPrecedence.HasValue) { - binary.Left = Deparenthesize(binary.Left); - } - return base.VisitBinaryOperatorExpression(binary, data); - } - - public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) - { - expressionStatement.Expression = Deparenthesize(expressionStatement.Expression); - return base.VisitExpressionStatement(expressionStatement, data); - } - - public override object VisitForStatement(ForStatement forStatement, object data) - { - forStatement.Condition = Deparenthesize(forStatement.Condition); - return base.VisitForStatement(forStatement, data); - } - - Expression Deparenthesize(Expression expr) - { - if (expr is ParenthesizedExpression) { - return Deparenthesize(((ParenthesizedExpression)expr).Expression); - } else { - return expr; - } - } - - int? GetPrecedence(Expression expr) - { - if (expr is ParenthesizedExpression) { - return GetPrecedence(((ParenthesizedExpression)expr).Expression); - } - - UnaryOperatorExpression unary = expr as UnaryOperatorExpression; - BinaryOperatorExpression binary = expr as BinaryOperatorExpression; - - // see http://msdn2.microsoft.com/en-us/library/ms173145.aspx - - // Primary - // x.y - if (expr is MemberReferenceExpression) return 15; - // f(x) - if (expr is InvocationExpression) return 15; - // a[x] - if (expr is IndexerExpression) return 15; - // x++ - if (unary != null && unary.Op == UnaryOperatorType.PostIncrement) return 15; - // x-- - if (unary != null && unary.Op == UnaryOperatorType.PostDecrement) return 15; - // new T(...) - if (expr is ObjectCreateExpression) return 15; - // new T(...){...} - // new {...} - // new T[...] - if (expr is ArrayCreateExpression) return 15; - // typeof(T) - if (expr is TypeOfExpression) return 15; - // checked(x) - // unchecked(x) - // default (T) - // delegate {} - // Unary - // +x - if (unary != null && unary.Op == UnaryOperatorType.Plus) return 14; - // -x - if (unary != null && unary.Op == UnaryOperatorType.Minus) return 14; - // !x - if (unary != null && unary.Op == UnaryOperatorType.Not) return 14; - // ~x - if (unary != null && unary.Op == UnaryOperatorType.BitNot) return 14; - // ++x - if (unary != null && unary.Op == UnaryOperatorType.Increment) return 14; - // --x - if (unary != null && unary.Op == UnaryOperatorType.Decrement) return 14; - // (T)x - if (expr is CastExpression) return 14; - // Multiplicative - // *, , - if (binary != null && binary.Op == BinaryOperatorType.Multiply) return 13; - // / - if (binary != null && binary.Op == BinaryOperatorType.Divide) return 13; - // % - if (binary != null && binary.Op == BinaryOperatorType.Modulus) return 13; - // Additive - // x + y - if (binary != null && binary.Op == BinaryOperatorType.Add) return 12; - // x - y - if (binary != null && binary.Op == BinaryOperatorType.Subtract) return 12; - // Shift - // x << y - // x >> y - // Relational and Type Testing - // x < y - if (binary != null && binary.Op == BinaryOperatorType.LessThan) return 10; - // x > y - if (binary != null && binary.Op == BinaryOperatorType.GreaterThan) return 10; - // x <= y - if (binary != null && binary.Op == BinaryOperatorType.LessThanOrEqual) return 10; - // x >= y - if (binary != null && binary.Op == BinaryOperatorType.GreaterThanOrEqual) return 10; - // x is T - // x as T - // Equality - // x == y - if (binary != null && binary.Op == BinaryOperatorType.Equality) return 9; - // x != y - if (binary != null && binary.Op == BinaryOperatorType.InEquality) return 9; - // Logical AND - // x & y - if (binary != null && binary.Op == BinaryOperatorType.BitwiseAnd) return 8; - // Logical XOR - // x ^ y - if (binary != null && binary.Op == BinaryOperatorType.ExclusiveOr) return 7; - // Logical OR - // x | y - if (binary != null && binary.Op == BinaryOperatorType.BitwiseOr) return 6; - // Conditional AND - // x && y - if (binary != null && binary.Op == BinaryOperatorType.LogicalAnd) return 5; - // Conditional OR - // x || y - if (binary != null && binary.Op == BinaryOperatorType.LogicalOr) return 4; - // Null coalescing - // X ?? y - // Conditional - // x ?: y : z - // Assignment or anonymous function - // =, , => - if (expr is AssignmentExpression) return 1; - // x op= y - // (T x) => y - - return null; - } - } -} +using System; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RemoveParenthesis: AbstractAstTransformer + { + public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) + { + // The following do not need to be parenthesized + if (parenthesizedExpression.Expression is IdentifierExpression || + parenthesizedExpression.Expression is PrimitiveExpression || + parenthesizedExpression.Expression is ThisReferenceExpression || + parenthesizedExpression.Expression is ParenthesizedExpression) { + ReplaceCurrentNode(parenthesizedExpression.Expression); + return null; + } + return base.VisitParenthesizedExpression(parenthesizedExpression, data); + } + + public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) + { + assignmentExpression.Left = Deparenthesize(assignmentExpression.Left); + assignmentExpression.Right = Deparenthesize(assignmentExpression.Right); + return base.VisitAssignmentExpression(assignmentExpression, data); + } + + public override object VisitArrayCreateExpression(ArrayCreateExpression array, object data) + { + for(int i = 0; i < array.Arguments.Count; i++) { + array.Arguments[i] = Deparenthesize(array.Arguments[i]); + } + return base.VisitArrayCreateExpression(array, data); + } + + public override object VisitReturnStatement(ReturnStatement returnStatement, object data) + { + returnStatement.Expression = Deparenthesize(returnStatement.Expression); + return base.VisitReturnStatement(returnStatement, data); + } + + public override object VisitCastExpression(CastExpression castExpression, object data) + { + if (GetPrecedence(castExpression.Expression) > GetPrecedence(castExpression)) { + castExpression.Expression = Deparenthesize(castExpression.Expression); + } + return base.VisitCastExpression(castExpression, data); + } + + public override object VisitIndexerExpression(IndexerExpression indexer, object data) + { + if (GetPrecedence(indexer.TargetObject) >= GetPrecedence(indexer)) { + indexer.TargetObject = Deparenthesize(indexer.TargetObject); + } + return base.VisitIndexerExpression(indexer, data); + } + + public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) + { + ifElseStatement.Condition = Deparenthesize(ifElseStatement.Condition); + return base.VisitIfElseStatement(ifElseStatement, data); + } + + public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data) + { + variableDeclaration.Initializer = Deparenthesize(variableDeclaration.Initializer); + return base.VisitVariableDeclaration(variableDeclaration, data); + } + + public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) + { + if (GetPrecedence(unary.Expression) > GetPrecedence(unary)) { + unary.Expression = Deparenthesize(unary.Expression); + } + return base.VisitUnaryOperatorExpression(unary, data); + } + + public override object VisitMemberReferenceExpression(MemberReferenceExpression memberRef, object data) + { + if (GetPrecedence(memberRef.TargetObject) >= GetPrecedence(memberRef)) { + memberRef.TargetObject = Deparenthesize(memberRef.TargetObject); + } + return base.VisitMemberReferenceExpression(memberRef, data); + } + + public override object VisitInvocationExpression(InvocationExpression invocation, object data) + { + if (GetPrecedence(invocation.TargetObject) >= GetPrecedence(invocation)) { + invocation.TargetObject = Deparenthesize(invocation.TargetObject); + } + for(int i = 0; i < invocation.Arguments.Count; i++) { + invocation.Arguments[i] = Deparenthesize(invocation.Arguments[i]); + } + return base.VisitInvocationExpression(invocation, data); + } + + public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binary, object data) + { + int? myPrecedence = GetPrecedence(binary); + if (GetPrecedence(binary.Left) > myPrecedence) { + binary.Left = Deparenthesize(binary.Left); + } + if (GetPrecedence(binary.Right) > myPrecedence) { + binary.Right = Deparenthesize(binary.Right); + } + // Associativity + if (GetPrecedence(binary.Left) == myPrecedence && myPrecedence.HasValue) { + binary.Left = Deparenthesize(binary.Left); + } + return base.VisitBinaryOperatorExpression(binary, data); + } + + public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) + { + expressionStatement.Expression = Deparenthesize(expressionStatement.Expression); + return base.VisitExpressionStatement(expressionStatement, data); + } + + public override object VisitForStatement(ForStatement forStatement, object data) + { + forStatement.Condition = Deparenthesize(forStatement.Condition); + return base.VisitForStatement(forStatement, data); + } + + Expression Deparenthesize(Expression expr) + { + if (expr is ParenthesizedExpression) { + return Deparenthesize(((ParenthesizedExpression)expr).Expression); + } else { + return expr; + } + } + + int? GetPrecedence(Expression expr) + { + if (expr is ParenthesizedExpression) { + return GetPrecedence(((ParenthesizedExpression)expr).Expression); + } + + UnaryOperatorExpression unary = expr as UnaryOperatorExpression; + BinaryOperatorExpression binary = expr as BinaryOperatorExpression; + + // see http://msdn2.microsoft.com/en-us/library/ms173145.aspx + + // Primary + // x.y + if (expr is MemberReferenceExpression) return 15; + // f(x) + if (expr is InvocationExpression) return 15; + // a[x] + if (expr is IndexerExpression) return 15; + // x++ + if (unary != null && unary.Op == UnaryOperatorType.PostIncrement) return 15; + // x-- + if (unary != null && unary.Op == UnaryOperatorType.PostDecrement) return 15; + // new T(...) + if (expr is ObjectCreateExpression) return 15; + // new T(...){...} + // new {...} + // new T[...] + if (expr is ArrayCreateExpression) return 15; + // typeof(T) + if (expr is TypeOfExpression) return 15; + // checked(x) + // unchecked(x) + // default (T) + // delegate {} + // Unary + // +x + if (unary != null && unary.Op == UnaryOperatorType.Plus) return 14; + // -x + if (unary != null && unary.Op == UnaryOperatorType.Minus) return 14; + // !x + if (unary != null && unary.Op == UnaryOperatorType.Not) return 14; + // ~x + if (unary != null && unary.Op == UnaryOperatorType.BitNot) return 14; + // ++x + if (unary != null && unary.Op == UnaryOperatorType.Increment) return 14; + // --x + if (unary != null && unary.Op == UnaryOperatorType.Decrement) return 14; + // (T)x + if (expr is CastExpression) return 14; + // Multiplicative + // *, , + if (binary != null && binary.Op == BinaryOperatorType.Multiply) return 13; + // / + if (binary != null && binary.Op == BinaryOperatorType.Divide) return 13; + // % + if (binary != null && binary.Op == BinaryOperatorType.Modulus) return 13; + // Additive + // x + y + if (binary != null && binary.Op == BinaryOperatorType.Add) return 12; + // x - y + if (binary != null && binary.Op == BinaryOperatorType.Subtract) return 12; + // Shift + // x << y + // x >> y + // Relational and Type Testing + // x < y + if (binary != null && binary.Op == BinaryOperatorType.LessThan) return 10; + // x > y + if (binary != null && binary.Op == BinaryOperatorType.GreaterThan) return 10; + // x <= y + if (binary != null && binary.Op == BinaryOperatorType.LessThanOrEqual) return 10; + // x >= y + if (binary != null && binary.Op == BinaryOperatorType.GreaterThanOrEqual) return 10; + // x is T + // x as T + // Equality + // x == y + if (binary != null && binary.Op == BinaryOperatorType.Equality) return 9; + // x != y + if (binary != null && binary.Op == BinaryOperatorType.InEquality) return 9; + // Logical AND + // x & y + if (binary != null && binary.Op == BinaryOperatorType.BitwiseAnd) return 8; + // Logical XOR + // x ^ y + if (binary != null && binary.Op == BinaryOperatorType.ExclusiveOr) return 7; + // Logical OR + // x | y + if (binary != null && binary.Op == BinaryOperatorType.BitwiseOr) return 6; + // Conditional AND + // x && y + if (binary != null && binary.Op == BinaryOperatorType.LogicalAnd) return 5; + // Conditional OR + // x || y + if (binary != null && binary.Op == BinaryOperatorType.LogicalOr) return 4; + // Null coalescing + // X ?? y + // Conditional + // x ?: y : z + // Assignment or anonymous function + // =, , => + if (expr is AssignmentExpression) return 1; + // x op= y + // (T x) => y + + return null; + } + } +} diff --git a/Decompiler/src/Ast/Transforms/RestoreLoop.cs b/ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs similarity index 97% rename from Decompiler/src/Ast/Transforms/RestoreLoop.cs rename to ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs index 7c18fb216..1fd61a623 100644 --- a/Decompiler/src/Ast/Transforms/RestoreLoop.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs @@ -1,75 +1,75 @@ -using System; - -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class RestoreLoop: AbstractAstTransformer - { - public override object VisitForStatement(ForStatement forStatement, object data) - { - base.VisitForStatement(forStatement, data); - - // Restore loop initializer - if (forStatement.Initializers.Count == 0) { - LocalVariableDeclaration varDeclr = forStatement.Previous() as LocalVariableDeclaration; - if (varDeclr != null) { - varDeclr.ReplaceWith(Statement.Null); - forStatement.Initializers.Add(varDeclr); - } - } - - // Restore loop condition - if (forStatement.Condition.IsNull && - forStatement.EmbeddedStatement.Children.Count >= 3) - { - IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; - BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; - LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement; - if (condition != null && breakStmt != null && label != null && - condition.TrueStatement.Count == 1) - { - GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement; - if (gotoStmt != null && gotoStmt.Label == label.Label) { - condition.Remove(); - breakStmt.Remove(); - forStatement.Condition = condition.Condition; - } - } - } - - // Restore loop condition (version 2) - if (forStatement.Condition.IsNull) { - IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; - if (condition != null && - condition.TrueStatement.Count == 1 && - condition.TrueStatement[0] is BlockStatement && - condition.TrueStatement[0].Children.Count == 1 && - condition.TrueStatement[0].Children.First is BreakStatement && - condition.FalseStatement.Count == 1 && - condition.FalseStatement[0] is BlockStatement && - condition.FalseStatement[0].Children.Count == 0) - { - condition.Remove(); - forStatement.Condition = new UnaryOperatorExpression(condition.Condition, UnaryOperatorType.Not); - } - } - - // Restore loop iterator - if (forStatement.EmbeddedStatement.Children.Count > 0 && - forStatement.Iterator.Count == 0) - { - ExpressionStatement lastStmt = forStatement.EmbeddedStatement.Children.Last as ExpressionStatement; - if (lastStmt != null && - (lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { - lastStmt.Remove(); - forStatement.Iterator.Add(lastStmt); - } - } - - return null; - } - } -} +using System; + +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RestoreLoop: AbstractAstTransformer + { + public override object VisitForStatement(ForStatement forStatement, object data) + { + base.VisitForStatement(forStatement, data); + + // Restore loop initializer + if (forStatement.Initializers.Count == 0) { + LocalVariableDeclaration varDeclr = forStatement.Previous() as LocalVariableDeclaration; + if (varDeclr != null) { + varDeclr.ReplaceWith(Statement.Null); + forStatement.Initializers.Add(varDeclr); + } + } + + // Restore loop condition + if (forStatement.Condition.IsNull && + forStatement.EmbeddedStatement.Children.Count >= 3) + { + IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; + BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; + LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement; + if (condition != null && breakStmt != null && label != null && + condition.TrueStatement.Count == 1) + { + GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement; + if (gotoStmt != null && gotoStmt.Label == label.Label) { + condition.Remove(); + breakStmt.Remove(); + forStatement.Condition = condition.Condition; + } + } + } + + // Restore loop condition (version 2) + if (forStatement.Condition.IsNull) { + IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; + if (condition != null && + condition.TrueStatement.Count == 1 && + condition.TrueStatement[0] is BlockStatement && + condition.TrueStatement[0].Children.Count == 1 && + condition.TrueStatement[0].Children.First is BreakStatement && + condition.FalseStatement.Count == 1 && + condition.FalseStatement[0] is BlockStatement && + condition.FalseStatement[0].Children.Count == 0) + { + condition.Remove(); + forStatement.Condition = new UnaryOperatorExpression(condition.Condition, UnaryOperatorType.Not); + } + } + + // Restore loop iterator + if (forStatement.EmbeddedStatement.Children.Count > 0 && + forStatement.Iterator.Count == 0) + { + ExpressionStatement lastStmt = forStatement.EmbeddedStatement.Children.Last as ExpressionStatement; + if (lastStmt != null && + (lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { + lastStmt.Remove(); + forStatement.Iterator.Add(lastStmt); + } + } + + return null; + } + } +} diff --git a/Decompiler/src/Ast/Transforms/SimplifyTypeReferences.cs b/ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs similarity index 96% rename from Decompiler/src/Ast/Transforms/SimplifyTypeReferences.cs rename to ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs index 4c4a36861..958af3200 100644 --- a/Decompiler/src/Ast/Transforms/SimplifyTypeReferences.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs @@ -1,91 +1,91 @@ -using System; - -using Ast = ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; - -namespace Decompiler.Transforms.Ast -{ - public class SimplifyTypeReferences: AbstractAstTransformer - { - string currentNamepace = string.Empty; - string currentClass = null; - - public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) - { - currentNamepace = namespaceDeclaration.Name; - base.VisitNamespaceDeclaration(namespaceDeclaration, data); - currentNamepace = string.Empty; - return null; - } - - public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) - { - currentClass = currentNamepace + "." + typeDeclaration.Name; - base.VisitTypeDeclaration(typeDeclaration, data); - currentClass = null; - return null; - } - - public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) - { - IdentifierExpression id = memberReferenceExpression.TargetObject as IdentifierExpression; - if (id != null) { - if (id.Identifier == "System" || id.Identifier == currentClass) { - ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); - return null; - } - if (id.Identifier.StartsWith("System.")) { - id.Identifier = id.Identifier.Replace("System.", ""); - return null; - } - } - if (memberReferenceExpression.TargetObject is ThisReferenceExpression) { - ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); - return null; - } - return base.VisitMemberReferenceExpression(memberReferenceExpression, data); - } - - public override object VisitTypeReference(TypeReference typeReference, object data) - { - string fullName = typeReference.Type; - string shortName = GetShortName(fullName); - if (shortName != null) { - typeReference.Type = shortName; - return null; - } - if (fullName.EndsWith("[]")) { - shortName = GetShortName(fullName.Replace("[]","")); - if (shortName != null) { - typeReference.Type = shortName + "[]"; - return null; - } - } - return null; - } - - public string GetShortName(string fullName) - { - switch(fullName) { - case "System.Boolean": return "bool"; - case "System.Byte": return "byte"; - case "System.Char": return "char"; - case "System.Decimal": return "decimal"; - case "System.Double": return "double"; - case "System.Single": return "float"; - case "System.Int32": return "int"; - case "System.Int64": return "long"; - case "System.Object": return "object"; - case "System.SByte": return "sbyte"; - case "System.Int16": return "short"; - case "System.String": return "string"; - case "System.UInt32": return "uint"; - case "System.UInt64": return "ulong"; - case "System.UInt16": return "ushort"; - case "System.Void": return "void"; - } - return null; - } - } -} +using System; + +using Ast = ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class SimplifyTypeReferences: AbstractAstTransformer + { + string currentNamepace = string.Empty; + string currentClass = null; + + public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) + { + currentNamepace = namespaceDeclaration.Name; + base.VisitNamespaceDeclaration(namespaceDeclaration, data); + currentNamepace = string.Empty; + return null; + } + + public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) + { + currentClass = currentNamepace + "." + typeDeclaration.Name; + base.VisitTypeDeclaration(typeDeclaration, data); + currentClass = null; + return null; + } + + public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) + { + IdentifierExpression id = memberReferenceExpression.TargetObject as IdentifierExpression; + if (id != null) { + if (id.Identifier == "System" || id.Identifier == currentClass) { + ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); + return null; + } + if (id.Identifier.StartsWith("System.")) { + id.Identifier = id.Identifier.Replace("System.", ""); + return null; + } + } + if (memberReferenceExpression.TargetObject is ThisReferenceExpression) { + ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); + return null; + } + return base.VisitMemberReferenceExpression(memberReferenceExpression, data); + } + + public override object VisitTypeReference(TypeReference typeReference, object data) + { + string fullName = typeReference.Type; + string shortName = GetShortName(fullName); + if (shortName != null) { + typeReference.Type = shortName; + return null; + } + if (fullName.EndsWith("[]")) { + shortName = GetShortName(fullName.Replace("[]","")); + if (shortName != null) { + typeReference.Type = shortName + "[]"; + return null; + } + } + return null; + } + + public string GetShortName(string fullName) + { + switch(fullName) { + case "System.Boolean": return "bool"; + case "System.Byte": return "byte"; + case "System.Char": return "char"; + case "System.Decimal": return "decimal"; + case "System.Double": return "double"; + case "System.Single": return "float"; + case "System.Int32": return "int"; + case "System.Int64": return "long"; + case "System.Object": return "object"; + case "System.SByte": return "sbyte"; + case "System.Int16": return "short"; + case "System.String": return "string"; + case "System.UInt32": return "uint"; + case "System.UInt64": return "ulong"; + case "System.UInt16": return "ushort"; + case "System.Void": return "void"; + } + return null; + } + } +} diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 4dfda9609..af57a944b 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -49,6 +49,16 @@ + + + + + + + + + + @@ -69,19 +79,39 @@ + + + + + + + + + + + + + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} + NRefactory + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil + + + + + diff --git a/Decompiler/src/ILAst/ControlFlow/Node-Optimize.cs b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs similarity index 96% rename from Decompiler/src/ILAst/ControlFlow/Node-Optimize.cs rename to ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs index 3bb1debe9..134992804 100644 --- a/Decompiler/src/ILAst/ControlFlow/Node-Optimize.cs +++ b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs @@ -1,192 +1,192 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Decompiler.ControlFlow -{ - public abstract partial class Node - { - public void Optimize() - { - if (Options.ReduceLoops) { - OptimizeLoops(); - } - if (Options.ReduceConditonals) { - OptimizeShortCircuits(); - OptimizeConditions(); - } - } - - public void OptimizeLoops() - { - Reset: - foreach(Node child in this.Childs) { - if (child.Predecessors.Count == 1) { - Node predecessor = child.Predecessors[0]; - Node mergedNode; - if (child.Successors.Contains(predecessor)) { - mergedNode = MergeChilds(predecessor, child); - } else { - mergedNode = MergeChilds(predecessor, child); - } - mergedNode.FalttenAcyclicChilds(); - goto Reset; - } - } - // If the result is single acyclic node, eliminate it - if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) { - Node headChild = this.HeadChild; - this.Childs.Remove(this.HeadChild); - headChild.Childs.MoveTo(this); - } - } - - NodeCollection GetReachableNodes() - { - NodeCollection reachableNodes = new NodeCollection(); - reachableNodes.Add(this); - for(int i = 0; i < reachableNodes.Count; i++) { - foreach(Node alsoReachable in reachableNodes[i].Successors) { - // Do not go though the head child - if (alsoReachable != this.Parent.HeadChild) { - reachableNodes.Add(alsoReachable); - } - } - } - return reachableNodes; - } - - public void OptimizeShortCircuits() - { - foreach(Node child in this.Childs) { - if (child is Loop) { - child.OptimizeShortCircuits(); - } - } - - Reset: - foreach(Node child in this.Childs) { - if (TryOptimizeShortCircuit(child)) { - goto Reset; - } - } - } - - public static bool TryOptimizeShortCircuit(Node head) - { - if ((head is BasicBlock) && - (head as BasicBlock).BranchBasicBlock != null && - (head as BasicBlock).FallThroughBasicBlock != null) { - head.Parent.MergeChilds(head); - return true; - } - - Branch top = head as Branch; - if (top == null) return false; - - Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch; - Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch; - - // A & B - if (left != null && - left.Predecessors.Count == 1 && - left.FalseSuccessor == top.FalseSuccessor) { - ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); - scBranch.Operator = ShortCircuitOperator.LeftAndRight; - return true; - } - - // ~A | B - if (left != null && - left.Predecessors.Count == 1 && - left.TrueSuccessor == top.FalseSuccessor) { - ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); - scBranch.Operator = ShortCircuitOperator.NotLeftOrRight; - return true; - } - - // A | B - if (right != null && - right.Predecessors.Count == 1 && - right.TrueSuccessor == top.TrueSuccessor) { - ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); - scBranch.Operator = ShortCircuitOperator.LeftOrRight; - return true; - } - - // ~A & B - if (right != null && - right.Predecessors.Count == 1 && - right.FalseSuccessor == top.TrueSuccessor) { - ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); - scBranch.Operator = ShortCircuitOperator.NotLeftAndRight; - return true; - } - - return false; - } - - public void OptimizeConditions() - { - foreach(Node child in this.Childs) { - if (child is Loop) { - child.OptimizeConditions(); - } - } - - Node conditionNode = this.HeadChild; - while(conditionNode != null) { - // Keep looking for some conditional block - if (conditionNode is Branch) { - // Found start of conditional - OptimizeIf((Branch)conditionNode); - // Restart - conditionNode = this.HeadChild; - continue; - } else if (conditionNode.Successors.Count > 0) { - // Keep looking down - conditionNode = conditionNode.Successors[0]; - if (conditionNode == this.HeadChild) { - return; - } - continue; // Next - } else { - return; // End of block - } - } - } - - public static void OptimizeIf(Branch condition) - { - Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor); - Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor); - - NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; - NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; - NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); - - NodeCollection trueNodes = trueReachable.Clone(); - trueNodes.RemoveRange(commonReachable); - NodeCollection falseNodes = falseReachable.Clone(); - falseNodes.RemoveRange(commonReachable); - - // Replace the basic block with condition node - Node conditionParent = condition.Parent; - int conditionIndex = condition.Index; - ConditionalNode conditionalNode = new ConditionalNode(condition); - conditionalNode.MoveTo(conditionParent, conditionIndex); - - // If there are no common nodes, let the 'true' block be the default - if (commonReachable.Count > 0) { - trueNodes.MoveTo(conditionalNode.TrueBody); - } - - falseNodes.MoveTo(conditionalNode.FalseBody); - - // Optimize the created subtrees - conditionalNode.TrueBody.OptimizeConditions(); - conditionalNode.FalseBody.OptimizeConditions(); - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Decompiler.ControlFlow +{ + public abstract partial class Node + { + public void Optimize() + { + if (Options.ReduceLoops) { + OptimizeLoops(); + } + if (Options.ReduceConditonals) { + OptimizeShortCircuits(); + OptimizeConditions(); + } + } + + public void OptimizeLoops() + { + Reset: + foreach(Node child in this.Childs) { + if (child.Predecessors.Count == 1) { + Node predecessor = child.Predecessors[0]; + Node mergedNode; + if (child.Successors.Contains(predecessor)) { + mergedNode = MergeChilds(predecessor, child); + } else { + mergedNode = MergeChilds(predecessor, child); + } + mergedNode.FalttenAcyclicChilds(); + goto Reset; + } + } + // If the result is single acyclic node, eliminate it + if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) { + Node headChild = this.HeadChild; + this.Childs.Remove(this.HeadChild); + headChild.Childs.MoveTo(this); + } + } + + NodeCollection GetReachableNodes() + { + NodeCollection reachableNodes = new NodeCollection(); + reachableNodes.Add(this); + for(int i = 0; i < reachableNodes.Count; i++) { + foreach(Node alsoReachable in reachableNodes[i].Successors) { + // Do not go though the head child + if (alsoReachable != this.Parent.HeadChild) { + reachableNodes.Add(alsoReachable); + } + } + } + return reachableNodes; + } + + public void OptimizeShortCircuits() + { + foreach(Node child in this.Childs) { + if (child is Loop) { + child.OptimizeShortCircuits(); + } + } + + Reset: + foreach(Node child in this.Childs) { + if (TryOptimizeShortCircuit(child)) { + goto Reset; + } + } + } + + public static bool TryOptimizeShortCircuit(Node head) + { + if ((head is BasicBlock) && + (head as BasicBlock).BranchBasicBlock != null && + (head as BasicBlock).FallThroughBasicBlock != null) { + head.Parent.MergeChilds(head); + return true; + } + + Branch top = head as Branch; + if (top == null) return false; + + Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch; + Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch; + + // A & B + if (left != null && + left.Predecessors.Count == 1 && + left.FalseSuccessor == top.FalseSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); + scBranch.Operator = ShortCircuitOperator.LeftAndRight; + return true; + } + + // ~A | B + if (left != null && + left.Predecessors.Count == 1 && + left.TrueSuccessor == top.FalseSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, left); + scBranch.Operator = ShortCircuitOperator.NotLeftOrRight; + return true; + } + + // A | B + if (right != null && + right.Predecessors.Count == 1 && + right.TrueSuccessor == top.TrueSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); + scBranch.Operator = ShortCircuitOperator.LeftOrRight; + return true; + } + + // ~A & B + if (right != null && + right.Predecessors.Count == 1 && + right.FalseSuccessor == top.TrueSuccessor) { + ShortCircuitBranch scBranch = top.Parent.MergeChilds(top, right); + scBranch.Operator = ShortCircuitOperator.NotLeftAndRight; + return true; + } + + return false; + } + + public void OptimizeConditions() + { + foreach(Node child in this.Childs) { + if (child is Loop) { + child.OptimizeConditions(); + } + } + + Node conditionNode = this.HeadChild; + while(conditionNode != null) { + // Keep looking for some conditional block + if (conditionNode is Branch) { + // Found start of conditional + OptimizeIf((Branch)conditionNode); + // Restart + conditionNode = this.HeadChild; + continue; + } else if (conditionNode.Successors.Count > 0) { + // Keep looking down + conditionNode = conditionNode.Successors[0]; + if (conditionNode == this.HeadChild) { + return; + } + continue; // Next + } else { + return; // End of block + } + } + } + + public static void OptimizeIf(Branch condition) + { + Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor); + Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor); + + NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; + NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; + NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); + + NodeCollection trueNodes = trueReachable.Clone(); + trueNodes.RemoveRange(commonReachable); + NodeCollection falseNodes = falseReachable.Clone(); + falseNodes.RemoveRange(commonReachable); + + // Replace the basic block with condition node + Node conditionParent = condition.Parent; + int conditionIndex = condition.Index; + ConditionalNode conditionalNode = new ConditionalNode(condition); + conditionalNode.MoveTo(conditionParent, conditionIndex); + + // If there are no common nodes, let the 'true' block be the default + if (commonReachable.Count > 0) { + trueNodes.MoveTo(conditionalNode.TrueBody); + } + + falseNodes.MoveTo(conditionalNode.FalseBody); + + // Optimize the created subtrees + conditionalNode.TrueBody.OptimizeConditions(); + conditionalNode.FalseBody.OptimizeConditions(); + } + } +} diff --git a/Decompiler/src/ILAst/ControlFlow/Node-Structure.cs b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs similarity index 95% rename from Decompiler/src/ILAst/ControlFlow/Node-Structure.cs rename to ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs index e2ba6b73e..e76bf5333 100644 --- a/Decompiler/src/ILAst/ControlFlow/Node-Structure.cs +++ b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs @@ -1,233 +1,233 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Decompiler.ControlFlow -{ - public abstract partial class Node - { - public static int NextNodeID = 1; - - int id; - string label; - Node parent; - NodeCollection childs = new NodeCollection(); - - // Structural and linking cache - NodeCollection basicBlocks_cache = null; - NodeCollection predecessors_cache = null; - NodeCollection successors_cache = null; - - public int ID { - get { return id; } - } - - public string Label { - get { return label; } - } - - public Node Parent { - get { return parent; } - } - - public Node HeadChild { - get { - if (this.Childs.Count > 0) { - return this.Childs[0]; - } else { - return null; - } - } - } - - public NodeCollection Childs { - get { - return childs; - } - } - - /// All basic blocks within the scope of this node (inclusive) - public NodeCollection BasicBlocks { - get { - if (basicBlocks_cache == null) { - NodeCollection basicBlocks = new NodeCollection(); - - if (this is BasicBlock) { - basicBlocks.Add(this); - } - foreach(Node child in this.Childs) { - basicBlocks.AddRange(child.BasicBlocks); - } - - basicBlocks_cache = basicBlocks; - } - return basicBlocks_cache; - } - } - - NodeCollection FloatUpToNeighbours(IEnumerable basicBlocks) - { - NodeCollection neighbours = new NodeCollection(); - if (this.Parent != null) { - foreach(BasicBlock basicBlock in basicBlocks) { - Node targetNode = FloatUpToNeighbours(basicBlock); - // The target is outside the scope of the parent node - if (targetNode == null) continue; - // This child is a loop - if (targetNode == this) continue; - // We found a target in our scope - neighbours.Add(targetNode); - } - } - return neighbours; - } - - Node FloatUpToNeighbours(BasicBlock basicBlock) - { - // Find neighbour coresponding to the basickBlock - Node targetNode = basicBlock; - while(targetNode != null && targetNode.Parent != this.Parent) { - targetNode = targetNode.Parent; - } - return targetNode; - } - - public NodeCollection Predecessors { - get { - if (predecessors_cache == null) { - List basicBlockPredecessors = new List(); - foreach(BasicBlock basicBlock in this.BasicBlocks) { - foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) { - basicBlockPredecessors.Add(basicBlockPredecessor); - } - } - - predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors); - } - return predecessors_cache; - } - } - - public NodeCollection Successors { - get { - if (successors_cache == null) { - List basicBlockSuccessors = new List(); - foreach(BasicBlock basicBlock in this.BasicBlocks) { - foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) { - basicBlockSuccessors.Add(basicBlockSuccessor); - } - } - - successors_cache = FloatUpToNeighbours(basicBlockSuccessors); - } - return successors_cache; - } - } - - int Index { - get { - if (this.Parent == null) throw new Exception("Does not have a parent"); - return this.Parent.Childs.IndexOf(this); - } - } - - public Node NextNode { - get { - int index = this.Index + 1; - if (0 <= index && index < this.Parent.Childs.Count) { - return this.Parent.Childs[index]; - } else { - return null; - } - } - } - - public string Description { - get { - return ToString(); - } - } - - protected Node() - { - this.id = NextNodeID++; - this.label = this.GetType().Name + "_" + ID; - this.Childs.Added += delegate(object sender, NodeEventArgs e) { - if (e.Node.Parent != null) { - throw new Exception("Node is already assigned to other parent"); - } - e.Node.parent = this; - NotifyChildsChanged(); - }; - this.Childs.Removed += delegate(object sender, NodeEventArgs e) { - e.Node.parent = null; - NotifyChildsChanged(); - }; - } - - void NotifyChildsChanged() - { - this.basicBlocks_cache = null; - foreach(Node child in this.Childs) { - child.predecessors_cache = null; - child.successors_cache = null; - } - if (this.Parent != null) { - this.Parent.NotifyChildsChanged(); - } - } - - public override string ToString() - { - System.Text.StringBuilder sb = new System.Text.StringBuilder(); - sb.Append(this.GetType().Name); - sb.Append(" "); - sb.Append(ID); - sb.Append(" "); - - sb.Append("("); - - if (this.Predecessors.Count > 0) { - sb.Append("Predecessors:"); - bool isFirst = true; - foreach(Node predecessor in this.Predecessors) { - if (isFirst) { - isFirst = false; - } else { - sb.Append(","); - } - sb.Append(predecessor.ID); - } - sb.Append(" "); - } - - if (this.Successors.Count > 0) { - sb.Append("Successors:"); - bool isFirst = true; - foreach(Node successor in this.Successors) { - if (isFirst) { - isFirst = false; - } else { - sb.Append(","); - } - sb.Append(successor.ID); - } - sb.Append(" "); - } - - if (this.Parent != null) { - sb.Append("Parent:"); - sb.Append(this.Parent.ID); - sb.Append(" "); - } - - if (sb[sb.Length - 1] == '(') { - sb.Length -= 1; - } else if (sb[sb.Length - 1] == ' ') { - sb.Length -= 1; - sb.Append(")"); - } - return sb.ToString(); - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Decompiler.ControlFlow +{ + public abstract partial class Node + { + public static int NextNodeID = 1; + + int id; + string label; + Node parent; + NodeCollection childs = new NodeCollection(); + + // Structural and linking cache + NodeCollection basicBlocks_cache = null; + NodeCollection predecessors_cache = null; + NodeCollection successors_cache = null; + + public int ID { + get { return id; } + } + + public string Label { + get { return label; } + } + + public Node Parent { + get { return parent; } + } + + public Node HeadChild { + get { + if (this.Childs.Count > 0) { + return this.Childs[0]; + } else { + return null; + } + } + } + + public NodeCollection Childs { + get { + return childs; + } + } + + /// All basic blocks within the scope of this node (inclusive) + public NodeCollection BasicBlocks { + get { + if (basicBlocks_cache == null) { + NodeCollection basicBlocks = new NodeCollection(); + + if (this is BasicBlock) { + basicBlocks.Add(this); + } + foreach(Node child in this.Childs) { + basicBlocks.AddRange(child.BasicBlocks); + } + + basicBlocks_cache = basicBlocks; + } + return basicBlocks_cache; + } + } + + NodeCollection FloatUpToNeighbours(IEnumerable basicBlocks) + { + NodeCollection neighbours = new NodeCollection(); + if (this.Parent != null) { + foreach(BasicBlock basicBlock in basicBlocks) { + Node targetNode = FloatUpToNeighbours(basicBlock); + // The target is outside the scope of the parent node + if (targetNode == null) continue; + // This child is a loop + if (targetNode == this) continue; + // We found a target in our scope + neighbours.Add(targetNode); + } + } + return neighbours; + } + + Node FloatUpToNeighbours(BasicBlock basicBlock) + { + // Find neighbour coresponding to the basickBlock + Node targetNode = basicBlock; + while(targetNode != null && targetNode.Parent != this.Parent) { + targetNode = targetNode.Parent; + } + return targetNode; + } + + public NodeCollection Predecessors { + get { + if (predecessors_cache == null) { + List basicBlockPredecessors = new List(); + foreach(BasicBlock basicBlock in this.BasicBlocks) { + foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) { + basicBlockPredecessors.Add(basicBlockPredecessor); + } + } + + predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors); + } + return predecessors_cache; + } + } + + public NodeCollection Successors { + get { + if (successors_cache == null) { + List basicBlockSuccessors = new List(); + foreach(BasicBlock basicBlock in this.BasicBlocks) { + foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) { + basicBlockSuccessors.Add(basicBlockSuccessor); + } + } + + successors_cache = FloatUpToNeighbours(basicBlockSuccessors); + } + return successors_cache; + } + } + + int Index { + get { + if (this.Parent == null) throw new Exception("Does not have a parent"); + return this.Parent.Childs.IndexOf(this); + } + } + + public Node NextNode { + get { + int index = this.Index + 1; + if (0 <= index && index < this.Parent.Childs.Count) { + return this.Parent.Childs[index]; + } else { + return null; + } + } + } + + public string Description { + get { + return ToString(); + } + } + + protected Node() + { + this.id = NextNodeID++; + this.label = this.GetType().Name + "_" + ID; + this.Childs.Added += delegate(object sender, NodeEventArgs e) { + if (e.Node.Parent != null) { + throw new Exception("Node is already assigned to other parent"); + } + e.Node.parent = this; + NotifyChildsChanged(); + }; + this.Childs.Removed += delegate(object sender, NodeEventArgs e) { + e.Node.parent = null; + NotifyChildsChanged(); + }; + } + + void NotifyChildsChanged() + { + this.basicBlocks_cache = null; + foreach(Node child in this.Childs) { + child.predecessors_cache = null; + child.successors_cache = null; + } + if (this.Parent != null) { + this.Parent.NotifyChildsChanged(); + } + } + + public override string ToString() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.Append(this.GetType().Name); + sb.Append(" "); + sb.Append(ID); + sb.Append(" "); + + sb.Append("("); + + if (this.Predecessors.Count > 0) { + sb.Append("Predecessors:"); + bool isFirst = true; + foreach(Node predecessor in this.Predecessors) { + if (isFirst) { + isFirst = false; + } else { + sb.Append(","); + } + sb.Append(predecessor.ID); + } + sb.Append(" "); + } + + if (this.Successors.Count > 0) { + sb.Append("Successors:"); + bool isFirst = true; + foreach(Node successor in this.Successors) { + if (isFirst) { + isFirst = false; + } else { + sb.Append(","); + } + sb.Append(successor.ID); + } + sb.Append(" "); + } + + if (this.Parent != null) { + sb.Append("Parent:"); + sb.Append(this.Parent.ID); + sb.Append(" "); + } + + if (sb[sb.Length - 1] == '(') { + sb.Length -= 1; + } else if (sb[sb.Length - 1] == ' ') { + sb.Length -= 1; + sb.Append(")"); + } + return sb.ToString(); + } + } +} diff --git a/Decompiler/src/ILAst/ControlFlow/Node-Transforms.cs b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs similarity index 95% rename from Decompiler/src/ILAst/ControlFlow/Node-Transforms.cs rename to ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs index e46cea4c3..02b267935 100644 --- a/Decompiler/src/ILAst/ControlFlow/Node-Transforms.cs +++ b/ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs @@ -1,60 +1,60 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Decompiler.ControlFlow -{ - public abstract partial class Node - { - public void Remove() - { - if (this.Parent != null) { - this.Parent.Childs.Remove(this); - } - } - - public void MoveTo(Node newNode) - { - MoveTo(newNode, newNode.Childs.Count); - } - - public void MoveTo(Node newNode, int index) - { - this.Remove(); - newNode.Childs.Insert(index, this); - } - - T MergeChilds(params Node[] nodes) where T: Node, new() - { - foreach(Node node in nodes) { - if (node == null) throw new ArgumentNullException("nodes"); - if (node.Parent != this) throw new ArgumentException("The node is not my child"); - } - if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); - - T mergedNode = new T(); - - // Add the merged node - int headIndex = this.Childs.IndexOf(nodes[0]); - this.Childs.Insert(headIndex, mergedNode); - - foreach(Node node in nodes) { - node.MoveTo(mergedNode); - } - - return mergedNode; - } - - public void FalttenAcyclicChilds() - { - Reset: - foreach(Node child in this.Childs) { - if (child is AcyclicGraph) { - child.Childs.MoveTo(this, child.Index); - child.Remove(); - goto Reset; - } - } - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Decompiler.ControlFlow +{ + public abstract partial class Node + { + public void Remove() + { + if (this.Parent != null) { + this.Parent.Childs.Remove(this); + } + } + + public void MoveTo(Node newNode) + { + MoveTo(newNode, newNode.Childs.Count); + } + + public void MoveTo(Node newNode, int index) + { + this.Remove(); + newNode.Childs.Insert(index, this); + } + + T MergeChilds(params Node[] nodes) where T: Node, new() + { + foreach(Node node in nodes) { + if (node == null) throw new ArgumentNullException("nodes"); + if (node.Parent != this) throw new ArgumentException("The node is not my child"); + } + if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); + + T mergedNode = new T(); + + // Add the merged node + int headIndex = this.Childs.IndexOf(nodes[0]); + this.Childs.Insert(headIndex, mergedNode); + + foreach(Node node in nodes) { + node.MoveTo(mergedNode); + } + + return mergedNode; + } + + public void FalttenAcyclicChilds() + { + Reset: + foreach(Node child in this.Childs) { + if (child is AcyclicGraph) { + child.Childs.MoveTo(this, child.Index); + child.Remove(); + goto Reset; + } + } + } + } +} diff --git a/Decompiler/src/ILAst/ControlFlow/NodeCollection.cs b/ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs similarity index 94% rename from Decompiler/src/ILAst/ControlFlow/NodeCollection.cs rename to ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs index eae0ad78b..5ccc1592c 100644 --- a/Decompiler/src/ILAst/ControlFlow/NodeCollection.cs +++ b/ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs @@ -1,130 +1,130 @@ -using System; -using System.Collections.Generic; - -namespace Decompiler.ControlFlow -{ - public class NodeEventArgs: EventArgs - { - Node node; - - public Node Node { - get { return node; } - } - - public NodeEventArgs(Node node) - { - this.node = node; - } - } - - public class NodeCollection: System.Collections.ObjectModel.Collection - { - public static NodeCollection Empty = new NodeCollection(); - - public event EventHandler Added; - public event EventHandler Removed; - - protected virtual void OnAdded(Node node) - { - if (Added != null) { - Added(this, new NodeEventArgs(node)); - } - } - - protected virtual void OnRemoved(Node node) - { - if (Removed != null) { - Removed(this, new NodeEventArgs(node)); - } - } - - protected override void ClearItems() - { - while(this.Count > 0) { - this.RemoveAt(this.Count - 1); - } - } - - protected override void InsertItem(int index, Node item) - { - if (!this.Contains(item)) { - base.InsertItem(index, item); - } - OnAdded(item); - } - - protected override void RemoveItem(int index) - { - Node node = this[index]; - base.RemoveItem(index); - OnRemoved(node); - } - - protected override void SetItem(int index, Node item) - { - this.RemoveAt(index); - this.Insert(index, item); - } - - - public void AddRange(IEnumerable items) - { - foreach(Node item in items) { - this.Add(item); - } - } - - public void RemoveRange(IEnumerable items) - { - foreach(Node item in items) { - this.Remove(item); - } - } - - public void MoveTo(Node newNode) - { - foreach(Node child in this.Clone()) { - child.MoveTo(newNode); - } - } - - public void MoveTo(Node newNode, int index) - { - foreach(Node child in this.Clone()) { - child.MoveTo(newNode, index); - index++; - } - } - - public NodeCollection() - { - - } - - public NodeCollection(IEnumerable items) - { - this.AddRange(items); - } - - public NodeCollection Clone() - { - return new NodeCollection(this); - } - - public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB) - { - NodeCollection result = new NodeCollection(); - foreach(Node a in collectionA) { - if (collectionB.Contains(a)) { - result.Add(a); - } - } - return result; - } - - public override string ToString() - { - return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count); - } - } -} +using System; +using System.Collections.Generic; + +namespace Decompiler.ControlFlow +{ + public class NodeEventArgs: EventArgs + { + Node node; + + public Node Node { + get { return node; } + } + + public NodeEventArgs(Node node) + { + this.node = node; + } + } + + public class NodeCollection: System.Collections.ObjectModel.Collection + { + public static NodeCollection Empty = new NodeCollection(); + + public event EventHandler Added; + public event EventHandler Removed; + + protected virtual void OnAdded(Node node) + { + if (Added != null) { + Added(this, new NodeEventArgs(node)); + } + } + + protected virtual void OnRemoved(Node node) + { + if (Removed != null) { + Removed(this, new NodeEventArgs(node)); + } + } + + protected override void ClearItems() + { + while(this.Count > 0) { + this.RemoveAt(this.Count - 1); + } + } + + protected override void InsertItem(int index, Node item) + { + if (!this.Contains(item)) { + base.InsertItem(index, item); + } + OnAdded(item); + } + + protected override void RemoveItem(int index) + { + Node node = this[index]; + base.RemoveItem(index); + OnRemoved(node); + } + + protected override void SetItem(int index, Node item) + { + this.RemoveAt(index); + this.Insert(index, item); + } + + + public void AddRange(IEnumerable items) + { + foreach(Node item in items) { + this.Add(item); + } + } + + public void RemoveRange(IEnumerable items) + { + foreach(Node item in items) { + this.Remove(item); + } + } + + public void MoveTo(Node newNode) + { + foreach(Node child in this.Clone()) { + child.MoveTo(newNode); + } + } + + public void MoveTo(Node newNode, int index) + { + foreach(Node child in this.Clone()) { + child.MoveTo(newNode, index); + index++; + } + } + + public NodeCollection() + { + + } + + public NodeCollection(IEnumerable items) + { + this.AddRange(items); + } + + public NodeCollection Clone() + { + return new NodeCollection(this); + } + + public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB) + { + NodeCollection result = new NodeCollection(); + foreach(Node a in collectionA) { + if (collectionB.Contains(a)) { + result.Add(a); + } + } + return result; + } + + public override string ToString() + { + return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count); + } + } +} diff --git a/Decompiler/src/ILAst/ControlFlow/Nodes.cs b/ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs similarity index 95% rename from Decompiler/src/ILAst/ControlFlow/Nodes.cs rename to ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs index 3d781161a..38687a2f5 100644 --- a/Decompiler/src/ILAst/ControlFlow/Nodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs @@ -1,255 +1,255 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Decompiler.Mono.Cecil.Rocks; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace Decompiler.ControlFlow -{ - public class BasicBlock: Node - { - List body = new List(); - List basicBlockPredecessors = new List(); - BasicBlock fallThroughBasicBlock; - BasicBlock branchBasicBlock; - - public List Body { - get { return body; } - } - - public List BasicBlockPredecessors { - get { return basicBlockPredecessors; } - } - - public BasicBlock FallThroughBasicBlock { - get { return fallThroughBasicBlock; } - set { fallThroughBasicBlock = value; } - } - - public BasicBlock BranchBasicBlock { - get { return branchBasicBlock; } - set { branchBasicBlock = value; } - } - - public IEnumerable BasicBlockSuccessors { - get { - if (this.FallThroughBasicBlock != null) { - yield return this.FallThroughBasicBlock; - } - if (this.BranchBasicBlock != null) { - yield return this.BranchBasicBlock; - } - } - } - } - - public enum ShortCircuitOperator { - LeftAndRight, - LeftOrRight, - NotLeftAndRight, - NotLeftOrRight, - } - - public abstract class Branch: Node - { - public abstract BasicBlock FirstBasicBlock { get; } - public abstract BasicBlock TrueSuccessor { get; } - public abstract BasicBlock FalseSuccessor { get; } - } - - public class SimpleBranch: Branch - { - public override BasicBlock FirstBasicBlock { - get { - return this.BasicBlock; - } - } - - public BasicBlock BasicBlock { - get { return (BasicBlock)this.Childs[0]; } - } - - public override BasicBlock TrueSuccessor { - get { return this.BasicBlock.BranchBasicBlock; } - } - - public override BasicBlock FalseSuccessor { - get { return this.BasicBlock.FallThroughBasicBlock; } - } - } - - public class ShortCircuitBranch: Branch - { - ShortCircuitOperator @operator; - - public override BasicBlock FirstBasicBlock { - get { - return this.Left.FirstBasicBlock; - } - } - - public Branch Left { - get { return (Branch)this.Childs[0];; } - } - - public Branch Right { - get { return (Branch)this.Childs[1]; } - } - - public ShortCircuitOperator Operator { - get { return @operator; } - set { @operator = value; } - } - - public override BasicBlock TrueSuccessor { - get { return this.Right.TrueSuccessor; } - } - - public override BasicBlock FalseSuccessor { - get { return this.Right.FalseSuccessor; } - } - } - - public class MethodBodyGraph: Node - { - BasicBlock methodEntry; - - public BasicBlock MethodEntry { - get { return methodEntry; } - } - - Dictionary labelToBasicBlock = new Dictionary(); - - public MethodBodyGraph(List ast) - { - if (ast.Count == 0) throw new ArgumentException("Count == 0", "ast"); - this.methodEntry = new BasicBlock(); - this.Childs.Add(this.methodEntry); - this.Childs.AddRange(SplitToBasicBlocks(ast)); - - // Add branch links to BasicBlocks - foreach(BasicBlock basicBlock in this.BasicBlocks) { - foreach(ILNode node in basicBlock.Body) { - if (node is ILExpression) { - ILExpression expr = (ILExpression)node; - if (expr.Operand is ILLabel) { - BasicBlock target = labelToBasicBlock[(ILLabel)expr.Operand]; - basicBlock.BranchBasicBlock = target; - target.BasicBlockPredecessors.Add(basicBlock); - } - // TODO: Switch - } - } - } - } - - public List SplitToBasicBlocks(List ast) - { - if (ast.Count == 0) return new List(); - - List nodes = new List(); - - BasicBlock basicBlock = null; - - for(int i = 0; i < ast.Count; i++) { - if (i == 0 || - ast[i] is ILLabel || - ast[i - 1] is ILTryCatchBlock || - ast[i] is ILTryCatchBlock || - (ast[i - 1] is ILExpression) && ((ILExpression)ast[i - 1]).OpCode.IsBranch() || - (ast[i] is ILExpression) && ((ILExpression)ast[i]).OpCode.IsBranch()) - { - BasicBlock oldBB = basicBlock; - basicBlock = new BasicBlock(); - nodes.Add(basicBlock); - // Links - if (oldBB != null && ast[i - 1] is ILExpression && ((ILExpression)ast[i - 1]).OpCode.CanFallThough()) { - oldBB.FallThroughBasicBlock = basicBlock; - basicBlock.BasicBlockPredecessors.Add(oldBB); - } - } - if (ast[i] is ILTryCatchBlock) { - nodes.Add(ConvertTryCatch((ILTryCatchBlock)ast[i])); - } else { - basicBlock.Body.Add(ast[i]); - } - if (ast[i] is ILLabel) { - labelToBasicBlock[(ILLabel)ast[i]] = basicBlock; - } - } - - return nodes; - } - - public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch) - { - TryCatchNode tryCatch = new TryCatchNode(); - - Block tryBlock = new Block(); - tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock)); - tryBlock.MoveTo(tryCatch); - - Block finallyBlock = new Block(); - if (ilTryCatch.FinallyBlock != null) { - finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock)); - } - finallyBlock.MoveTo(tryCatch); - - foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) { - tryCatch.Types.Add(cb.ExceptionType); - Block catchBlock = new Block(); - catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body)); - catchBlock.MoveTo(tryCatch); - } - - return tryCatch; - } - - } - - public class TryCatchNode: Node - { - public List Types = new List(); - } - - public class AcyclicGraph: Node - { - } - - public class Loop: Node - { - } - - public class Block: Node - { - } - - public class ConditionalNode: Node - { - Branch condition; - Block trueBody = new Block(); - Block falseBody = new Block(); - - public Branch Condition { - get { return condition; } - } - - public Block TrueBody { - get { return trueBody; } - } - - public Block FalseBody { - get { return falseBody; } - } - - public ConditionalNode(Branch condition) - { - this.condition = condition; - - condition.MoveTo(this); - trueBody.MoveTo(this); - falseBody.MoveTo(this); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Decompiler.Mono.Cecil.Rocks; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Decompiler.ControlFlow +{ + public class BasicBlock: Node + { + List body = new List(); + List basicBlockPredecessors = new List(); + BasicBlock fallThroughBasicBlock; + BasicBlock branchBasicBlock; + + public List Body { + get { return body; } + } + + public List BasicBlockPredecessors { + get { return basicBlockPredecessors; } + } + + public BasicBlock FallThroughBasicBlock { + get { return fallThroughBasicBlock; } + set { fallThroughBasicBlock = value; } + } + + public BasicBlock BranchBasicBlock { + get { return branchBasicBlock; } + set { branchBasicBlock = value; } + } + + public IEnumerable BasicBlockSuccessors { + get { + if (this.FallThroughBasicBlock != null) { + yield return this.FallThroughBasicBlock; + } + if (this.BranchBasicBlock != null) { + yield return this.BranchBasicBlock; + } + } + } + } + + public enum ShortCircuitOperator { + LeftAndRight, + LeftOrRight, + NotLeftAndRight, + NotLeftOrRight, + } + + public abstract class Branch: Node + { + public abstract BasicBlock FirstBasicBlock { get; } + public abstract BasicBlock TrueSuccessor { get; } + public abstract BasicBlock FalseSuccessor { get; } + } + + public class SimpleBranch: Branch + { + public override BasicBlock FirstBasicBlock { + get { + return this.BasicBlock; + } + } + + public BasicBlock BasicBlock { + get { return (BasicBlock)this.Childs[0]; } + } + + public override BasicBlock TrueSuccessor { + get { return this.BasicBlock.BranchBasicBlock; } + } + + public override BasicBlock FalseSuccessor { + get { return this.BasicBlock.FallThroughBasicBlock; } + } + } + + public class ShortCircuitBranch: Branch + { + ShortCircuitOperator @operator; + + public override BasicBlock FirstBasicBlock { + get { + return this.Left.FirstBasicBlock; + } + } + + public Branch Left { + get { return (Branch)this.Childs[0];; } + } + + public Branch Right { + get { return (Branch)this.Childs[1]; } + } + + public ShortCircuitOperator Operator { + get { return @operator; } + set { @operator = value; } + } + + public override BasicBlock TrueSuccessor { + get { return this.Right.TrueSuccessor; } + } + + public override BasicBlock FalseSuccessor { + get { return this.Right.FalseSuccessor; } + } + } + + public class MethodBodyGraph: Node + { + BasicBlock methodEntry; + + public BasicBlock MethodEntry { + get { return methodEntry; } + } + + Dictionary labelToBasicBlock = new Dictionary(); + + public MethodBodyGraph(List ast) + { + if (ast.Count == 0) throw new ArgumentException("Count == 0", "ast"); + this.methodEntry = new BasicBlock(); + this.Childs.Add(this.methodEntry); + this.Childs.AddRange(SplitToBasicBlocks(ast)); + + // Add branch links to BasicBlocks + foreach(BasicBlock basicBlock in this.BasicBlocks) { + foreach(ILNode node in basicBlock.Body) { + if (node is ILExpression) { + ILExpression expr = (ILExpression)node; + if (expr.Operand is ILLabel) { + BasicBlock target = labelToBasicBlock[(ILLabel)expr.Operand]; + basicBlock.BranchBasicBlock = target; + target.BasicBlockPredecessors.Add(basicBlock); + } + // TODO: Switch + } + } + } + } + + public List SplitToBasicBlocks(List ast) + { + if (ast.Count == 0) return new List(); + + List nodes = new List(); + + BasicBlock basicBlock = null; + + for(int i = 0; i < ast.Count; i++) { + if (i == 0 || + ast[i] is ILLabel || + ast[i - 1] is ILTryCatchBlock || + ast[i] is ILTryCatchBlock || + (ast[i - 1] is ILExpression) && ((ILExpression)ast[i - 1]).OpCode.IsBranch() || + (ast[i] is ILExpression) && ((ILExpression)ast[i]).OpCode.IsBranch()) + { + BasicBlock oldBB = basicBlock; + basicBlock = new BasicBlock(); + nodes.Add(basicBlock); + // Links + if (oldBB != null && ast[i - 1] is ILExpression && ((ILExpression)ast[i - 1]).OpCode.CanFallThough()) { + oldBB.FallThroughBasicBlock = basicBlock; + basicBlock.BasicBlockPredecessors.Add(oldBB); + } + } + if (ast[i] is ILTryCatchBlock) { + nodes.Add(ConvertTryCatch((ILTryCatchBlock)ast[i])); + } else { + basicBlock.Body.Add(ast[i]); + } + if (ast[i] is ILLabel) { + labelToBasicBlock[(ILLabel)ast[i]] = basicBlock; + } + } + + return nodes; + } + + public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch) + { + TryCatchNode tryCatch = new TryCatchNode(); + + Block tryBlock = new Block(); + tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock)); + tryBlock.MoveTo(tryCatch); + + Block finallyBlock = new Block(); + if (ilTryCatch.FinallyBlock != null) { + finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock)); + } + finallyBlock.MoveTo(tryCatch); + + foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) { + tryCatch.Types.Add(cb.ExceptionType); + Block catchBlock = new Block(); + catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body)); + catchBlock.MoveTo(tryCatch); + } + + return tryCatch; + } + + } + + public class TryCatchNode: Node + { + public List Types = new List(); + } + + public class AcyclicGraph: Node + { + } + + public class Loop: Node + { + } + + public class Block: Node + { + } + + public class ConditionalNode: Node + { + Branch condition; + Block trueBody = new Block(); + Block falseBody = new Block(); + + public Branch Condition { + get { return condition; } + } + + public Block TrueBody { + get { return trueBody; } + } + + public Block FalseBody { + get { return falseBody; } + } + + public ConditionalNode(Branch condition) + { + this.condition = condition; + + condition.MoveTo(this); + trueBody.MoveTo(this); + falseBody.MoveTo(this); + } + } +} diff --git a/Decompiler/src/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs similarity index 97% rename from Decompiler/src/ILAst/ILAstBuilder.cs rename to ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 9b13ea396..b03abec23 100644 --- a/Decompiler/src/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -1,298 +1,298 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Decompiler.Mono.Cecil.Rocks; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Cecil = Mono.Cecil; - -namespace Decompiler -{ - public class ILAstBuilder - { - class ILStack - { - public class Slot - { - public Instruction PushedBy; - public TypeReference Type; - - public Slot(Instruction inst, TypeReference type) - { - this.PushedBy = inst; - this.Type = type; - } - } - - public List Items = new List(); - - public ILStack Clone() - { - ILStack clone = new ILStack(); - foreach(Slot s in this.Items) { - clone.Items.Add(new Slot(s.PushedBy, s.Type)); - } - return clone; - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - bool first = true; - foreach (Slot s in this.Items) { - if (!first) sb.Append(", "); - sb.Append(s.PushedBy.Offset.ToString("X")); - first = false; - } - return sb.ToString(); - } - } - - Dictionary stackBefore = new Dictionary(); - Dictionary labels = new Dictionary(); - - public List Build(MethodDefinition methodDef) - { - List body = new List(methodDef.Body.Instructions); - - if (body.Count == 0) return new List(); - - StackAnalysis(body, methodDef); - - // Create branch labels for instructins; use the labels as branch operands - foreach (Instruction inst in body) { - if (inst.Operand is Instruction[]) { - List newOperand = new List(); - foreach(Instruction target in (Instruction[])inst.Operand) { - if (!labels.ContainsKey(target)) { - labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; - } - newOperand.Add(labels[target]); - } - inst.Operand = newOperand.ToArray(); - } else if (inst.Operand is Instruction) { - Instruction target = (Instruction)inst.Operand; - if (!labels.ContainsKey(target)) { - labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; - } - inst.Operand = labels[target]; - } - } - - List ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); - - return ast; - } - - public void StackAnalysis(List body, MethodDefinition methodDef) - { - Queue agenda = new Queue(); - - // Add known states - stackBefore[body[0]] = new ILStack(); - agenda.Enqueue(body[0]); - - if(methodDef.Body.HasExceptionHandlers) { - foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { - stackBefore[ex.TryStart] = new ILStack(); - agenda.Enqueue(ex.TryStart); - - ILStack stack = new ILStack(); - stack.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); - stackBefore[ex.HandlerStart] = stack; - agenda.Enqueue(ex.HandlerStart); - } - } - - // Process agenda - while(agenda.Count > 0) { - Instruction inst = agenda.Dequeue(); - - // What is the effect of the instruction on the stack? - ILStack newStack = stackBefore[inst].Clone(); - int popCount = inst.GetPopCount(); - if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all - List typeArgs = new List(); - for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { - typeArgs.Add(newStack.Items[i].Type); - } - TypeReference type; - try { - type = inst.GetTypeInternal(methodDef, typeArgs); - } catch { - type = MyRocks.TypeObject; - } - if (popCount > 0) { - newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); - } - int pushCount = inst.GetPushCount(); - for (int i = 0; i < pushCount; i++) { - newStack.Items.Add(new ILStack.Slot(inst, type)); - } - - // Apply the state to any successors - List branchTargets = new List(); - if (inst.OpCode.CanFallThough()) { - branchTargets.Add(inst.Next); - } - if (inst.OpCode.IsBranch()) { - if (inst.Operand is Instruction[]) { - branchTargets.AddRange((Instruction[])inst.Operand); - } else { - branchTargets.Add((Instruction)inst.Operand); - } - } - foreach (Instruction branchTarget in branchTargets) { - ILStack nextStack; - if (stackBefore.TryGetValue(branchTarget, out nextStack)) { - // TODO: Compare stacks - } else { - stackBefore[branchTarget] = newStack; - agenda.Enqueue(branchTarget); - } - } - } - } - - public List ConvertToAst(List body, IEnumerable ehs) - { - List ast = new List(); - - while (ehs.Any()) { - ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); - - // Find the first and widest scope - int tryStart = ehs.Min(eh => eh.TryStart.Offset); - int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); - var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); - - // Cut all instructions up to the try block - { - int tryStartIdx; - for (tryStartIdx = 0; body[tryStartIdx].Offset != tryStart; tryStartIdx++); - ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); - } - - // Cut the try block - { - List nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList(); - int tryEndIdx; - for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); - tryCatchBlock.TryBlock = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs); - } - - // Cut all handlers - tryCatchBlock.CatchBlocks = new List(); - foreach(ExceptionHandler eh in handlers) { - int start; - for (start = 0; body[start] != eh.HandlerStart; start++); - int end; - for (end = 0; body[end] != eh.HandlerEnd; end++); - int count = end - start; - List nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); - List handlerAst = ConvertToAst(body.CutRange(start, count), nestedEHs); - if (eh.HandlerType == ExceptionHandlerType.Catch) { - tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { - ExceptionType = eh.CatchType, - Body = handlerAst - }); - } else if (eh.HandlerType == ExceptionHandlerType.Finally) { - tryCatchBlock.FinallyBlock = handlerAst; - } else { - // TODO - } - } - - ehs = ehs.Where(eh => eh.TryStart.Offset > tryEnd).ToList(); - - ast.Add(tryCatchBlock); - } - - // Add whatever is left - ast.AddRange(ConvertToAst(body)); - - return ast; - } - - public List ConvertToAst(List body) - { - List ast = new List(); - - // Convert stack-based IL code to ILAst tree - foreach(Instruction inst in body) { - ILExpression expr = new ILExpression(inst.OpCode, inst.Operand); - - // Label for this instruction - ILLabel label; - if (labels.TryGetValue(inst, out label)) { - ast.Add(label); - } - - // Reference arguments using temporary variables - ILStack stack = stackBefore[inst]; - int popCount = inst.GetPopCount(); - if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all - for (int i = stack.Items.Count - popCount; i < stack.Items.Count; i++) { - Instruction pushedBy = stack.Items[i].PushedBy; - if (pushedBy != null) { - ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "expr" + pushedBy.Offset.ToString("X2") }); - expr.Arguments.Add(ldExpr); - } else { - ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "exception" }); - expr.Arguments.Add(ldExpr); - } - } - - // If the bytecode pushes anything store the result in temporary variable - int pushCount = inst.GetPushCount(); - if (pushCount > 0) { - ILExpression stExpr = new ILExpression(OpCodes.Stloc, new ILStackVariable() { Name = "expr" + inst.Offset.ToString("X2"), RefCount = pushCount }); - stExpr.Arguments.Add(expr); - expr = stExpr; - } - - ast.Add(expr); - } - - // Try to in-line stloc / ldloc pairs - for(int i = 0; i < ast.Count - 1; i++) { - ILExpression expr = ast[i] as ILExpression; - ILExpression nextExpr = ast[i + 1] as ILExpression; - - if (expr != null && nextExpr != null && expr.OpCode.Code == Code.Stloc && expr.Operand is ILStackVariable) { - - // If the next expression is stloc, look inside - if (nextExpr.OpCode.Code == Code.Stloc && nextExpr.Operand is ILStackVariable) { - nextExpr = nextExpr.Arguments[0]; - } - - // Find the use of the 'expr' - for(int j = 0; j < nextExpr.Arguments.Count; j++) { - ILExpression arg = nextExpr.Arguments[j]; - - // TODO: Check if duplicating the dup opcode has side-effects - - if (arg.OpCode.Code == Code.Ldloc && arg.Operand is ILStackVariable) { - ILStackVariable stVar = (ILStackVariable)expr.Operand; - ILStackVariable ldVar = (ILStackVariable)arg.Operand; - if (stVar.Name == ldVar.Name) { - stVar.RefCount--; - if (stVar.RefCount <= 0) { - ast.RemoveAt(i); - } - nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body - i = Math.Max(0, i - 2); // Try the same index again - break; // Found - } - } else { - break; // This argument might have side effects so we can not move the 'expr' after it. - } - } - } - } - - return ast; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Decompiler.Mono.Cecil.Rocks; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Cecil = Mono.Cecil; + +namespace Decompiler +{ + public class ILAstBuilder + { + class ILStack + { + public class Slot + { + public Instruction PushedBy; + public TypeReference Type; + + public Slot(Instruction inst, TypeReference type) + { + this.PushedBy = inst; + this.Type = type; + } + } + + public List Items = new List(); + + public ILStack Clone() + { + ILStack clone = new ILStack(); + foreach(Slot s in this.Items) { + clone.Items.Add(new Slot(s.PushedBy, s.Type)); + } + return clone; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + bool first = true; + foreach (Slot s in this.Items) { + if (!first) sb.Append(", "); + sb.Append(s.PushedBy.Offset.ToString("X")); + first = false; + } + return sb.ToString(); + } + } + + Dictionary stackBefore = new Dictionary(); + Dictionary labels = new Dictionary(); + + public List Build(MethodDefinition methodDef) + { + List body = new List(methodDef.Body.Instructions); + + if (body.Count == 0) return new List(); + + StackAnalysis(body, methodDef); + + // Create branch labels for instructins; use the labels as branch operands + foreach (Instruction inst in body) { + if (inst.Operand is Instruction[]) { + List newOperand = new List(); + foreach(Instruction target in (Instruction[])inst.Operand) { + if (!labels.ContainsKey(target)) { + labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; + } + newOperand.Add(labels[target]); + } + inst.Operand = newOperand.ToArray(); + } else if (inst.Operand is Instruction) { + Instruction target = (Instruction)inst.Operand; + if (!labels.ContainsKey(target)) { + labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; + } + inst.Operand = labels[target]; + } + } + + List ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); + + return ast; + } + + public void StackAnalysis(List body, MethodDefinition methodDef) + { + Queue agenda = new Queue(); + + // Add known states + stackBefore[body[0]] = new ILStack(); + agenda.Enqueue(body[0]); + + if(methodDef.Body.HasExceptionHandlers) { + foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { + stackBefore[ex.TryStart] = new ILStack(); + agenda.Enqueue(ex.TryStart); + + ILStack stack = new ILStack(); + stack.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); + stackBefore[ex.HandlerStart] = stack; + agenda.Enqueue(ex.HandlerStart); + } + } + + // Process agenda + while(agenda.Count > 0) { + Instruction inst = agenda.Dequeue(); + + // What is the effect of the instruction on the stack? + ILStack newStack = stackBefore[inst].Clone(); + int popCount = inst.GetPopCount(); + if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all + List typeArgs = new List(); + for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { + typeArgs.Add(newStack.Items[i].Type); + } + TypeReference type; + try { + type = inst.GetTypeInternal(methodDef, typeArgs); + } catch { + type = MyRocks.TypeObject; + } + if (popCount > 0) { + newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); + } + int pushCount = inst.GetPushCount(); + for (int i = 0; i < pushCount; i++) { + newStack.Items.Add(new ILStack.Slot(inst, type)); + } + + // Apply the state to any successors + List branchTargets = new List(); + if (inst.OpCode.CanFallThough()) { + branchTargets.Add(inst.Next); + } + if (inst.OpCode.IsBranch()) { + if (inst.Operand is Instruction[]) { + branchTargets.AddRange((Instruction[])inst.Operand); + } else { + branchTargets.Add((Instruction)inst.Operand); + } + } + foreach (Instruction branchTarget in branchTargets) { + ILStack nextStack; + if (stackBefore.TryGetValue(branchTarget, out nextStack)) { + // TODO: Compare stacks + } else { + stackBefore[branchTarget] = newStack; + agenda.Enqueue(branchTarget); + } + } + } + } + + public List ConvertToAst(List body, IEnumerable ehs) + { + List ast = new List(); + + while (ehs.Any()) { + ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); + + // Find the first and widest scope + int tryStart = ehs.Min(eh => eh.TryStart.Offset); + int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); + var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); + + // Cut all instructions up to the try block + { + int tryStartIdx; + for (tryStartIdx = 0; body[tryStartIdx].Offset != tryStart; tryStartIdx++); + ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); + } + + // Cut the try block + { + List nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList(); + int tryEndIdx; + for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); + tryCatchBlock.TryBlock = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs); + } + + // Cut all handlers + tryCatchBlock.CatchBlocks = new List(); + foreach(ExceptionHandler eh in handlers) { + int start; + for (start = 0; body[start] != eh.HandlerStart; start++); + int end; + for (end = 0; body[end] != eh.HandlerEnd; end++); + int count = end - start; + List nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); + List handlerAst = ConvertToAst(body.CutRange(start, count), nestedEHs); + if (eh.HandlerType == ExceptionHandlerType.Catch) { + tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { + ExceptionType = eh.CatchType, + Body = handlerAst + }); + } else if (eh.HandlerType == ExceptionHandlerType.Finally) { + tryCatchBlock.FinallyBlock = handlerAst; + } else { + // TODO + } + } + + ehs = ehs.Where(eh => eh.TryStart.Offset > tryEnd).ToList(); + + ast.Add(tryCatchBlock); + } + + // Add whatever is left + ast.AddRange(ConvertToAst(body)); + + return ast; + } + + public List ConvertToAst(List body) + { + List ast = new List(); + + // Convert stack-based IL code to ILAst tree + foreach(Instruction inst in body) { + ILExpression expr = new ILExpression(inst.OpCode, inst.Operand); + + // Label for this instruction + ILLabel label; + if (labels.TryGetValue(inst, out label)) { + ast.Add(label); + } + + // Reference arguments using temporary variables + ILStack stack = stackBefore[inst]; + int popCount = inst.GetPopCount(); + if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all + for (int i = stack.Items.Count - popCount; i < stack.Items.Count; i++) { + Instruction pushedBy = stack.Items[i].PushedBy; + if (pushedBy != null) { + ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "expr" + pushedBy.Offset.ToString("X2") }); + expr.Arguments.Add(ldExpr); + } else { + ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "exception" }); + expr.Arguments.Add(ldExpr); + } + } + + // If the bytecode pushes anything store the result in temporary variable + int pushCount = inst.GetPushCount(); + if (pushCount > 0) { + ILExpression stExpr = new ILExpression(OpCodes.Stloc, new ILStackVariable() { Name = "expr" + inst.Offset.ToString("X2"), RefCount = pushCount }); + stExpr.Arguments.Add(expr); + expr = stExpr; + } + + ast.Add(expr); + } + + // Try to in-line stloc / ldloc pairs + for(int i = 0; i < ast.Count - 1; i++) { + ILExpression expr = ast[i] as ILExpression; + ILExpression nextExpr = ast[i + 1] as ILExpression; + + if (expr != null && nextExpr != null && expr.OpCode.Code == Code.Stloc && expr.Operand is ILStackVariable) { + + // If the next expression is stloc, look inside + if (nextExpr.OpCode.Code == Code.Stloc && nextExpr.Operand is ILStackVariable) { + nextExpr = nextExpr.Arguments[0]; + } + + // Find the use of the 'expr' + for(int j = 0; j < nextExpr.Arguments.Count; j++) { + ILExpression arg = nextExpr.Arguments[j]; + + // TODO: Check if duplicating the dup opcode has side-effects + + if (arg.OpCode.Code == Code.Ldloc && arg.Operand is ILStackVariable) { + ILStackVariable stVar = (ILStackVariable)expr.Operand; + ILStackVariable ldVar = (ILStackVariable)arg.Operand; + if (stVar.Name == ldVar.Name) { + stVar.RefCount--; + if (stVar.RefCount <= 0) { + ast.RemoveAt(i); + } + nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body + i = Math.Max(0, i - 2); // Try the same index again + break; // Found + } + } else { + break; // This argument might have side effects so we can not move the 'expr' after it. + } + } + } + } + + return ast; + } + } +} diff --git a/Decompiler/src/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs similarity index 94% rename from Decompiler/src/ILAst/ILAstTypes.cs rename to ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index 43a3c6042..77eb40bda 100644 --- a/Decompiler/src/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Text; - -using Decompiler.ControlFlow; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Cecil = Mono.Cecil; - -namespace Decompiler -{ - public class ILNode - { - } - - public class ILLabel: ILNode - { - public string Name; - - public override string ToString() - { - return Name + ":"; - } - } - - public class ILTryCatchBlock: ILNode - { - public class CatchBlock - { - public TypeReference ExceptionType; - public List Body; - } - - public List TryBlock; - public List CatchBlocks; - public List FinallyBlock; - - public override string ToString() - { - return "Try-Catch{}"; - } - } - - public class ILStackVariable - { - public string Name; - public int RefCount; - - public override string ToString() - { - return Name; - } - } - - public class ILExpression: ILNode - { - public OpCode OpCode { get; set; } - public object Operand { get; set; } - public List Arguments { get; set; } - - public ILExpression(OpCode opCode, object operand, params ILExpression[] args) - { - this.OpCode = opCode; - this.Operand = operand; - this.Arguments = new List(args); - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - sb.Append(OpCode.Name); - sb.Append('('); - bool first = true; - if (Operand != null) { - sb.Append(Operand.ToString()); - first = false; - } - foreach (ILExpression arg in this.Arguments) { - if (!first) sb.Append(","); - sb.Append(arg.ToString()); - first = false; - } - sb.Append(')'); - return sb.ToString(); - } - } -} +using System; +using System.Collections.Generic; +using System.Text; + +using Decompiler.ControlFlow; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Cecil = Mono.Cecil; + +namespace Decompiler +{ + public class ILNode + { + } + + public class ILLabel: ILNode + { + public string Name; + + public override string ToString() + { + return Name + ":"; + } + } + + public class ILTryCatchBlock: ILNode + { + public class CatchBlock + { + public TypeReference ExceptionType; + public List Body; + } + + public List TryBlock; + public List CatchBlocks; + public List FinallyBlock; + + public override string ToString() + { + return "Try-Catch{}"; + } + } + + public class ILStackVariable + { + public string Name; + public int RefCount; + + public override string ToString() + { + return Name; + } + } + + public class ILExpression: ILNode + { + public OpCode OpCode { get; set; } + public object Operand { get; set; } + public List Arguments { get; set; } + + public ILExpression(OpCode opCode, object operand, params ILExpression[] args) + { + this.OpCode = opCode; + this.Operand = operand; + this.Arguments = new List(args); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append(OpCode.Name); + sb.Append('('); + bool first = true; + if (Operand != null) { + sb.Append(Operand.ToString()); + first = false; + } + foreach (ILExpression arg in this.Arguments) { + if (!first) sb.Append(","); + sb.Append(arg.ToString()); + first = false; + } + sb.Append(')'); + return sb.ToString(); + } + } +} diff --git a/Decompiler/src/Mono.Cecil.Rocks/Constants.cs b/ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs similarity index 100% rename from Decompiler/src/Mono.Cecil.Rocks/Constants.cs rename to ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs diff --git a/Decompiler/src/Mono.Cecil.Rocks/MethodBodyRocks.cs b/ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs similarity index 100% rename from Decompiler/src/Mono.Cecil.Rocks/MethodBodyRocks.cs rename to ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs diff --git a/Decompiler/src/Mono.Cecil.Rocks/MyRocks.cs b/ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs similarity index 99% rename from Decompiler/src/Mono.Cecil.Rocks/MyRocks.cs rename to ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs index cc74565ca..1f976df93 100644 --- a/Decompiler/src/Mono.Cecil.Rocks/MyRocks.cs +++ b/ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs @@ -126,7 +126,7 @@ namespace Decompiler.Mono.Cecil.Rocks static public TypeReference GetCecilType(Type type) { - return new TypeReference(type.Name, type.Namespace, null, type.IsValueType); + return new TypeReference(type.Name, type.Namespace, null, null, type.IsValueType); } static public TypeReference GetTypeInternal(this Instruction inst, MethodDefinition methodDef, List args) diff --git a/Decompiler/src/Options.cs b/ICSharpCode.Decompiler/Options.cs similarity index 95% rename from Decompiler/src/Options.cs rename to ICSharpCode.Decompiler/Options.cs index a89dc0672..7c9091ab7 100644 --- a/Decompiler/src/Options.cs +++ b/ICSharpCode.Decompiler/Options.cs @@ -1,22 +1,22 @@ -using System; - -namespace Decompiler -{ - public static class Options - { - public static string TypeFilter = null; - public static int CollapseExpression = 1000; - public static int ReduceGraph = 1000; - public static bool NodeComments = false; - public static bool ReduceLoops = true; - public static bool ReduceConditonals = true; - public static bool ReduceAstJumps = true; - public static bool ReduceAstLoops = true; - public static bool ReduceAstOther = true; - } - - class StopOptimizations: Exception - { - - } -} +using System; + +namespace Decompiler +{ + public static class Options + { + public static string TypeFilter = null; + public static int CollapseExpression = 1000; + public static int ReduceGraph = 1000; + public static bool NodeComments = false; + public static bool ReduceLoops = true; + public static bool ReduceConditonals = true; + public static bool ReduceAstJumps = true; + public static bool ReduceAstLoops = true; + public static bool ReduceAstOther = true; + } + + class StopOptimizations: Exception + { + + } +} diff --git a/ILSpy.sln b/ILSpy.sln index 4592525fc..a42f89148 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "A EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "Decompiler\lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -60,5 +62,13 @@ Global {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|x86.Build.0 = Debug|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|x86.ActiveCfg = Debug|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|x86.Build.0 = Release|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|x86.ActiveCfg = Release|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.Build.0 = Release|Any CPU + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection EndGlobal diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 0c4c39f5f..bee12435b 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using Decompiler; using ICSharpCode.Decompiler; using Mono.Cecil; @@ -37,7 +38,14 @@ namespace ICSharpCode.ILSpy public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { - throw new NotImplementedException(); + throw new NotImplementedException("Currently we can decompile only whole types."); + } + + public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) + { + AstBuilder codeDomBuilder = new AstBuilder(); + codeDomBuilder.AddType(type); + output.Write(codeDomBuilder.GenerateCode()); } } }