mirror of https://github.com/icsharpcode/ILSpy.git
24 changed files with 3237 additions and 3189 deletions
@ -1,316 +1,316 @@
@@ -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<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); |
||||
|
||||
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 <Module> class
|
||||
if (typeDef.Name == "<Module>") 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<AttributeSection>()); |
||||
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<AttributeSection>()); |
||||
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<AttributeSection>(), |
||||
propDef.Name, |
||||
new List<ParameterDeclarationExpression>() |
||||
); |
||||
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); |
||||
|
||||
if (propDef.GetMethod != null) { |
||||
astProp.GetRegion = new PropertyGetRegion( |
||||
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), |
||||
new List<AttributeSection>() |
||||
); |
||||
} |
||||
if (propDef.SetMethod != null) { |
||||
astProp.SetRegion = new PropertySetRegion( |
||||
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), |
||||
new List<AttributeSection>() |
||||
); |
||||
} |
||||
|
||||
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<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)), |
||||
new List<AttributeSection>() |
||||
); |
||||
|
||||
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<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> 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<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); |
||||
|
||||
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 <Module> class
|
||||
if (typeDef.Name == "<Module>") 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<AttributeSection>()); |
||||
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<AttributeSection>()); |
||||
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<AttributeSection>(), |
||||
propDef.Name, |
||||
new List<ParameterDeclarationExpression>() |
||||
); |
||||
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); |
||||
|
||||
if (propDef.GetMethod != null) { |
||||
astProp.GetRegion = new PropertyGetRegion( |
||||
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), |
||||
new List<AttributeSection>() |
||||
); |
||||
} |
||||
if (propDef.SetMethod != null) { |
||||
astProp.SetRegion = new PropertySetRegion( |
||||
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), |
||||
new List<AttributeSection>() |
||||
); |
||||
} |
||||
|
||||
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<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)), |
||||
new List<AttributeSection>() |
||||
); |
||||
|
||||
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<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> 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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -1,76 +1,76 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -1,87 +1,87 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -1,50 +1,50 @@
@@ -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<string> usedLabels = new List<string>(); |
||||
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<string> usedLabels = new List<string>(); |
||||
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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,36 +1,36 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,186 +1,186 @@
@@ -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<StatementWithEmbeddedStatement> enteredLoops = new Stack<StatementWithEmbeddedStatement>(); |
||||
|
||||
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<StatementWithEmbeddedStatement> enteredLoops = new Stack<StatementWithEmbeddedStatement>(); |
||||
|
||||
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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,245 +1,245 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,75 +1,75 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,91 +1,91 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,192 +1,192 @@
@@ -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<Loop>(predecessor, child); |
||||
} else { |
||||
mergedNode = MergeChilds<AcyclicGraph>(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<SimpleBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<Loop>(predecessor, child); |
||||
} else { |
||||
mergedNode = MergeChilds<AcyclicGraph>(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<SimpleBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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<ShortCircuitBranch>(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(); |
||||
} |
||||
} |
||||
} |
||||
@ -1,233 +1,233 @@
@@ -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; |
||||
} |
||||
} |
||||
|
||||
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
|
||||
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<BasicBlock> 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<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||
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<BasicBlock> basicBlockSuccessors = new List<BasicBlock>(); |
||||
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; |
||||
} |
||||
} |
||||
|
||||
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
|
||||
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<BasicBlock> 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<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||
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<BasicBlock> basicBlockSuccessors = new List<BasicBlock>(); |
||||
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(); |
||||
} |
||||
} |
||||
} |
||||
@ -1,60 +1,60 @@
@@ -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<T>(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<T>(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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -1,130 +1,130 @@
@@ -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<Node> |
||||
{ |
||||
public static NodeCollection Empty = new NodeCollection(); |
||||
|
||||
public event EventHandler<NodeEventArgs> Added; |
||||
public event EventHandler<NodeEventArgs> 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<Node> items) |
||||
{ |
||||
foreach(Node item in items) { |
||||
this.Add(item); |
||||
} |
||||
} |
||||
|
||||
public void RemoveRange(IEnumerable<Node> 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<Node> 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<Node> |
||||
{ |
||||
public static NodeCollection Empty = new NodeCollection(); |
||||
|
||||
public event EventHandler<NodeEventArgs> Added; |
||||
public event EventHandler<NodeEventArgs> 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<Node> items) |
||||
{ |
||||
foreach(Node item in items) { |
||||
this.Add(item); |
||||
} |
||||
} |
||||
|
||||
public void RemoveRange(IEnumerable<Node> 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<Node> 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); |
||||
} |
||||
} |
||||
} |
||||
@ -1,255 +1,255 @@
@@ -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<ILNode> body = new List<ILNode>(); |
||||
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||
BasicBlock fallThroughBasicBlock; |
||||
BasicBlock branchBasicBlock; |
||||
|
||||
public List<ILNode> Body { |
||||
get { return body; } |
||||
} |
||||
|
||||
public List<BasicBlock> BasicBlockPredecessors { |
||||
get { return basicBlockPredecessors; } |
||||
} |
||||
|
||||
public BasicBlock FallThroughBasicBlock { |
||||
get { return fallThroughBasicBlock; } |
||||
set { fallThroughBasicBlock = value; } |
||||
} |
||||
|
||||
public BasicBlock BranchBasicBlock { |
||||
get { return branchBasicBlock; } |
||||
set { branchBasicBlock = value; } |
||||
} |
||||
|
||||
public IEnumerable<BasicBlock> 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<ILLabel, BasicBlock> labelToBasicBlock = new Dictionary<ILLabel, BasicBlock>(); |
||||
|
||||
public MethodBodyGraph(List<ILNode> 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<Node> SplitToBasicBlocks(List<ILNode> ast) |
||||
{ |
||||
if (ast.Count == 0) return new List<Node>(); |
||||
|
||||
List<Node> nodes = new List<Node>(); |
||||
|
||||
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<TypeReference> Types = new List<TypeReference>(); |
||||
} |
||||
|
||||
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<ILNode> body = new List<ILNode>(); |
||||
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||
BasicBlock fallThroughBasicBlock; |
||||
BasicBlock branchBasicBlock; |
||||
|
||||
public List<ILNode> Body { |
||||
get { return body; } |
||||
} |
||||
|
||||
public List<BasicBlock> BasicBlockPredecessors { |
||||
get { return basicBlockPredecessors; } |
||||
} |
||||
|
||||
public BasicBlock FallThroughBasicBlock { |
||||
get { return fallThroughBasicBlock; } |
||||
set { fallThroughBasicBlock = value; } |
||||
} |
||||
|
||||
public BasicBlock BranchBasicBlock { |
||||
get { return branchBasicBlock; } |
||||
set { branchBasicBlock = value; } |
||||
} |
||||
|
||||
public IEnumerable<BasicBlock> 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<ILLabel, BasicBlock> labelToBasicBlock = new Dictionary<ILLabel, BasicBlock>(); |
||||
|
||||
public MethodBodyGraph(List<ILNode> 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<Node> SplitToBasicBlocks(List<ILNode> ast) |
||||
{ |
||||
if (ast.Count == 0) return new List<Node>(); |
||||
|
||||
List<Node> nodes = new List<Node>(); |
||||
|
||||
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<TypeReference> Types = new List<TypeReference>(); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
} |
||||
} |
||||
@ -1,298 +1,298 @@
@@ -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<Slot> Items = new List<Slot>(); |
||||
|
||||
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<Instruction, ILStack> stackBefore = new Dictionary<Instruction, ILAstBuilder.ILStack>(); |
||||
Dictionary<Instruction, ILLabel> labels = new Dictionary<Instruction, ILLabel>(); |
||||
|
||||
public List<ILNode> Build(MethodDefinition methodDef) |
||||
{ |
||||
List<Instruction> body = new List<Instruction>(methodDef.Body.Instructions); |
||||
|
||||
if (body.Count == 0) return new List<ILNode>(); |
||||
|
||||
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<ILLabel> newOperand = new List<ILLabel>(); |
||||
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<ILNode> ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); |
||||
|
||||
return ast; |
||||
} |
||||
|
||||
public void StackAnalysis(List<Instruction> body, MethodDefinition methodDef) |
||||
{ |
||||
Queue<Instruction> agenda = new Queue<Instruction>(); |
||||
|
||||
// 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<TypeReference> typeArgs = new List<TypeReference>(); |
||||
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<Instruction> branchTargets = new List<Instruction>(); |
||||
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<ILNode> ConvertToAst(List<Instruction> body, IEnumerable<ExceptionHandler> ehs) |
||||
{ |
||||
List<ILNode> ast = new List<ILNode>(); |
||||
|
||||
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<ExceptionHandler> 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<ILTryCatchBlock.CatchBlock>(); |
||||
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<ExceptionHandler> nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); |
||||
List<ILNode> 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<ILNode> ConvertToAst(List<Instruction> body) |
||||
{ |
||||
List<ILNode> ast = new List<ILNode>(); |
||||
|
||||
// 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<Slot> Items = new List<Slot>(); |
||||
|
||||
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<Instruction, ILStack> stackBefore = new Dictionary<Instruction, ILAstBuilder.ILStack>(); |
||||
Dictionary<Instruction, ILLabel> labels = new Dictionary<Instruction, ILLabel>(); |
||||
|
||||
public List<ILNode> Build(MethodDefinition methodDef) |
||||
{ |
||||
List<Instruction> body = new List<Instruction>(methodDef.Body.Instructions); |
||||
|
||||
if (body.Count == 0) return new List<ILNode>(); |
||||
|
||||
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<ILLabel> newOperand = new List<ILLabel>(); |
||||
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<ILNode> ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); |
||||
|
||||
return ast; |
||||
} |
||||
|
||||
public void StackAnalysis(List<Instruction> body, MethodDefinition methodDef) |
||||
{ |
||||
Queue<Instruction> agenda = new Queue<Instruction>(); |
||||
|
||||
// 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<TypeReference> typeArgs = new List<TypeReference>(); |
||||
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<Instruction> branchTargets = new List<Instruction>(); |
||||
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<ILNode> ConvertToAst(List<Instruction> body, IEnumerable<ExceptionHandler> ehs) |
||||
{ |
||||
List<ILNode> ast = new List<ILNode>(); |
||||
|
||||
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<ExceptionHandler> 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<ILTryCatchBlock.CatchBlock>(); |
||||
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<ExceptionHandler> nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); |
||||
List<ILNode> 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<ILNode> ConvertToAst(List<Instruction> body) |
||||
{ |
||||
List<ILNode> ast = new List<ILNode>(); |
||||
|
||||
// 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; |
||||
} |
||||
} |
||||
} |
||||
@ -1,87 +1,87 @@
@@ -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<ILNode> Body; |
||||
} |
||||
|
||||
public List<ILNode> TryBlock; |
||||
public List<CatchBlock> CatchBlocks; |
||||
public List<ILNode> 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<ILExpression> Arguments { get; set; } |
||||
|
||||
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) |
||||
{ |
||||
this.OpCode = opCode; |
||||
this.Operand = operand; |
||||
this.Arguments = new List<ILExpression>(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<ILNode> Body; |
||||
} |
||||
|
||||
public List<ILNode> TryBlock; |
||||
public List<CatchBlock> CatchBlocks; |
||||
public List<ILNode> 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<ILExpression> Arguments { get; set; } |
||||
|
||||
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) |
||||
{ |
||||
this.OpCode = opCode; |
||||
this.Operand = operand; |
||||
this.Arguments = new List<ILExpression>(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(); |
||||
} |
||||
} |
||||
} |
||||
@ -1,22 +1,22 @@
@@ -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 |
||||
{ |
||||
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue