Browse Source

Move decompiler code into ICSharpCode.Decompiler; add very simple integration with ILSpy.

pull/1/head^2
Daniel Grunwald 15 years ago
parent
commit
949e7c2378
  1. 632
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 1496
      ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs
  3. 152
      ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs
  4. 174
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  5. 100
      ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs
  6. 72
      ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs
  7. 372
      ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs
  8. 490
      ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs
  9. 150
      ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs
  10. 182
      ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs
  11. 30
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  12. 384
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs
  13. 466
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs
  14. 120
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs
  15. 260
      ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs
  16. 510
      ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs
  17. 596
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  18. 174
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  19. 0
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs
  20. 0
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs
  21. 2
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs
  22. 44
      ICSharpCode.Decompiler/Options.cs
  23. 10
      ILSpy.sln
  24. 10
      ILSpy/CSharpLanguage.cs

632
Decompiler/src/Ast/AstBuilder.cs → ICSharpCode.Decompiler/Ast/AstBuilder.cs

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

1496
Decompiler/src/Ast/AstMetodBodyBuilder.cs → ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs

File diff suppressed because it is too large Load Diff

152
Decompiler/src/Ast/Transforms/Idioms.cs → ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs

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

174
Decompiler/src/Ast/Transforms/PushNegation.cs → ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

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

100
Decompiler/src/Ast/Transforms/RemoveDeadLabels.cs → ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs

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

72
Decompiler/src/Ast/Transforms/RemoveEmptyElseBody.cs → ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs

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

372
Decompiler/src/Ast/Transforms/RemoveGotos.cs → ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs

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

490
Decompiler/src/Ast/Transforms/RemoveParenthesis.cs → ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs

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

150
Decompiler/src/Ast/Transforms/RestoreLoop.cs → ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs

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

182
Decompiler/src/Ast/Transforms/SimplifyTypeReferences.cs → ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs

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

30
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -49,6 +49,16 @@ @@ -49,6 +49,16 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMetodBodyBuilder.cs" />
<Compile Include="Ast\Transforms\Idioms.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RemoveParenthesis.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />
@ -69,19 +79,39 @@ @@ -69,19 +79,39 @@
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ControlFlow\Node-Optimize.cs" />
<Compile Include="ILAst\ControlFlow\Node-Structure.cs" />
<Compile Include="ILAst\ControlFlow\Node-Transforms.cs" />
<Compile Include="ILAst\ControlFlow\NodeCollection.cs" />
<Compile Include="ILAst\ControlFlow\Nodes.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Decompiler\lib\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Ast" />
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
<Folder Include="ILAst\ControlFlow" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">

384
Decompiler/src/ILAst/ControlFlow/Node-Optimize.cs → ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs

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

466
Decompiler/src/ILAst/ControlFlow/Node-Structure.cs → ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs

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

120
Decompiler/src/ILAst/ControlFlow/Node-Transforms.cs → ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs

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

260
Decompiler/src/ILAst/ControlFlow/NodeCollection.cs → ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs

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

510
Decompiler/src/ILAst/ControlFlow/Nodes.cs → ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs

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

596
Decompiler/src/ILAst/ILAstBuilder.cs → ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

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

174
Decompiler/src/ILAst/ILAstTypes.cs → ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

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

0
Decompiler/src/Mono.Cecil.Rocks/Constants.cs → ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs

0
Decompiler/src/Mono.Cecil.Rocks/MethodBodyRocks.cs → ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs

2
Decompiler/src/Mono.Cecil.Rocks/MyRocks.cs → ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs

@ -126,7 +126,7 @@ namespace Decompiler.Mono.Cecil.Rocks @@ -126,7 +126,7 @@ namespace Decompiler.Mono.Cecil.Rocks
static public TypeReference GetCecilType(Type type)
{
return new TypeReference(type.Name, type.Namespace, null, type.IsValueType);
return new TypeReference(type.Name, type.Namespace, null, null, type.IsValueType);
}
static public TypeReference GetTypeInternal(this Instruction inst, MethodDefinition methodDef, List<TypeReference> args)

44
Decompiler/src/Options.cs → ICSharpCode.Decompiler/Options.cs

@ -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
{
}
}

10
ILSpy.sln

@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "A @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "Decompiler\lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@ -60,5 +62,13 @@ Global @@ -60,5 +62,13 @@ Global
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|x86.Build.0 = Debug|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|x86.ActiveCfg = Debug|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|x86.Build.0 = Release|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|x86.ActiveCfg = Release|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.Build.0 = Release|Any CPU
{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
EndGlobal

10
ILSpy/CSharpLanguage.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using Decompiler;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -37,7 +38,14 @@ namespace ICSharpCode.ILSpy @@ -37,7 +38,14 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
throw new NotImplementedException();
throw new NotImplementedException("Currently we can decompile only whole types.");
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddType(type);
output.Write(codeDomBuilder.GenerateCode());
}
}
}

Loading…
Cancel
Save