Browse Source

Initial port to new NRefactory.

pull/10/head
Daniel Grunwald 15 years ago
parent
commit
b48fabaf05
  1. 334
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 577
      ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs
  3. 38
      ICSharpCode.Decompiler/Ast/CommentStatement.cs
  4. 89
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  5. 102
      ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs
  6. 100
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  7. 28
      ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs
  8. 29
      ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs
  9. 24
      ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs
  10. 251
      ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs
  11. 9
      ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs
  12. 68
      ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs
  13. 11
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  14. 2
      ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs
  15. 2
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  16. 2
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs
  17. 12
      ILSpy.sln
  18. 2
      ILSpy/CSharpLanguage.cs
  19. 42
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs
  20. 55
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs
  21. 39
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
  22. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs
  23. 34
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs
  24. 24
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs
  25. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs
  26. 1
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/IAstVisitor.cs
  27. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs
  28. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs
  29. 11
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs
  30. 10
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs
  31. 7
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
  32. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs
  33. 2
      NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

334
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -2,11 +2,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Ast = ICSharpCode.NRefactory.Ast; using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PrettyPrinter;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
namespace Decompiler namespace Decompiler
{ {
@ -15,78 +15,44 @@ namespace Decompiler
CompilationUnit astCompileUnit = new CompilationUnit(); CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
public string GenerateCode() public void GenerateCode(ITextOutput output)
{ {
CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (Options.ReduceAstJumps) { if (Options.ReduceAstJumps) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); //astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
} }
if (Options.ReduceAstLoops) { if (Options.ReduceAstLoops) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); //astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
} }
if (Options.ReduceAstOther) { if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), 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);
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
} }
} }
if (Options.ReduceAstOther) { 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.SimplifyTypeReferences(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null);
} }
if (Options.ReduceAstLoops) { if (Options.ReduceAstLoops) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); //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; var outputFormatter = new TextOutputFormatter(output);
var formattingPolicy = new CSharpFormattingPolicy();
// disable whitespace in front of parentheses:
formattingPolicy.BeforeMethodCallParentheses = false;
formattingPolicy.BeforeMethodDeclarationParentheses = false;
astCompileUnit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null);
} }
public void AddAssembly(AssemblyDefinition assemblyDefinition) public void AddAssembly(AssemblyDefinition assemblyDefinition)
{ {
Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); astCompileUnit.AddChild(
astCompileUnit.Children.Add(astUsing); new UsingDeclaration {
Import = new SimpleType("System")
}, CompilationUnit.MemberRole);
foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
// Skip nested types - they will be added by the parent type // Skip nested types - they will be added by the parent type
@ -107,8 +73,8 @@ namespace Decompiler
return astNamespaces[name]; return astNamespaces[name];
} else { } else {
// Create the namespace // Create the namespace
NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); NamespaceDeclaration astNamespace = new NamespaceDeclaration { Name = name };
astCompileUnit.Children.Add(astNamespace); astCompileUnit.AddChild(astNamespace, CompilationUnit.MemberRole);
astNamespaces[name] = astNamespace; astNamespaces[name] = astNamespace;
return astNamespace; return astNamespace;
} }
@ -119,42 +85,137 @@ namespace Decompiler
TypeDeclaration astType = CreateType(typeDef); TypeDeclaration astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) { if (astNS != null) {
astNS.Children.Add(astType); astNS.AddChild(astType, NamespaceDeclaration.MemberRole);
} else { } else {
astCompileUnit.Children.Add(astType); astCompileUnit.AddChild(astType, CompilationUnit.MemberRole);
} }
} }
public TypeDeclaration CreateType(TypeDefinition typeDef) public TypeDeclaration CreateType(TypeDefinition typeDef)
{ {
TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List<AttributeSection>()); TypeDeclaration astType = new TypeDeclaration();
astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = typeDef.Name; astType.Name = typeDef.Name;
if (typeDef.IsEnum) { // NB: Enum is value type if (typeDef.IsEnum) { // NB: Enum is value type
astType.Type = ClassType.Enum; astType.ClassType = ClassType.Enum;
} else if (typeDef.IsValueType) { } else if (typeDef.IsValueType) {
astType.Type = ClassType.Struct; astType.ClassType = ClassType.Struct;
} else if (typeDef.IsInterface) { } else if (typeDef.IsInterface) {
astType.Type = ClassType.Interface; astType.ClassType = ClassType.Interface;
} else { } else {
astType.Type = ClassType.Class; astType.ClassType = ClassType.Class;
} }
// Nested types // Nested types
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
astType.Children.Add(CreateType(nestedTypeDef)); astType.AddChild(CreateType(nestedTypeDef), TypeDeclaration.MemberRole);
} }
// Base type // Base type
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) {
astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole);
} }
foreach (var i in typeDef.Interfaces)
astType.AddChild(ConvertType(i), TypeDeclaration.BaseTypeRole);
AddTypeMembers(astType, typeDef); AddTypeMembers(astType, typeDef);
return astType; return astType;
} }
#region Convert Type Reference
/// <summary>
/// Converts a type reference.
/// </summary>
/// <param name="type">The Cecil type reference that should be converted into
/// a type system type reference.</param>
/// <param name="typeAttributes">Attributes associated with the Cecil type reference.
/// This is used to support the 'dynamic' type.</param>
public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null)
{
int typeIndex = 0;
return CreateType(type, typeAttributes, ref typeIndex);
}
static AstType CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex)
{
while (type is OptionalModifierType || type is RequiredModifierType) {
type = ((TypeSpecification)type).ElementType;
}
if (type == null) {
return AstType.Null;
}
if (type is Mono.Cecil.ByReferenceType) {
typeIndex++;
// ignore by reference type (cannot be represented in C#)
return CreateType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex);
} else if (type is Mono.Cecil.PointerType) {
typeIndex++;
return CreateType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex)
.MakePointerType();
} else if (type is Mono.Cecil.ArrayType) {
typeIndex++;
return CreateType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex)
.MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
} else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type;
AstType baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex);
foreach (var typeArgument in gType.GenericArguments) {
typeIndex++;
baseType.AddChild(CreateType(typeArgument, typeAttributes, ref typeIndex), AstType.Roles.TypeArgument);
}
return baseType;
} else if (type is GenericParameter) {
return new SimpleType(type.Name);
} else if (type.IsNested) {
AstType typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex);
string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
return new MemberType { Target = typeRef, MemberName = namepart };
} else {
string ns = type.Namespace ?? string.Empty;
string name = type.Name;
if (name == null)
throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
return new PrimitiveType("dynamic");
} else {
name = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(name);
if (ns.Length == 0)
return new SimpleType(name);
string[] parts = ns.Split('.');
AstType nsType = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
nsType = new MemberType { Target = nsType, MemberName = parts[i] };
}
return new MemberType { Target = nsType, MemberName = name };
}
}
}
const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute";
static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex)
{
if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
return false;
foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) {
if (a.ConstructorArguments.Count == 1) {
CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool)
return (bool)values[typeIndex].Value;
}
return true;
}
}
return false;
}
#endregion
#region ConvertModifiers
Modifiers ConvertModifiers(TypeDefinition typeDef) Modifiers ConvertModifiers(TypeDefinition typeDef)
{ {
return return
@ -194,118 +255,107 @@ namespace Decompiler
(methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | (methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) |
(methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); (methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None);
} }
#endregion
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
{ {
// Add fields // Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) { foreach(FieldDefinition fieldDef in typeDef.Fields) {
Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List<AttributeSection>()); astType.AddChild(CreateField(fieldDef), TypeDeclaration.MemberRole);
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 // Add events
foreach(EventDefinition eventDef in typeDef.Events) { foreach(EventDefinition eventDef in typeDef.Events) {
Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
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 // Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) { foreach(PropertyDefinition propDef in typeDef.Properties) {
Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( astType.AddChild(CreateProperty(propDef), TypeDeclaration.MemberRole);
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 // Add constructors
foreach(MethodDefinition methodDef in typeDef.Methods) { foreach(MethodDefinition methodDef in typeDef.Methods) {
if (!methodDef.IsConstructor) continue; if (!methodDef.IsConstructor) continue;
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( astType.AddChild(CreateConstructor(methodDef), TypeDeclaration.MemberRole);
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 // Add methods
foreach(MethodDefinition methodDef in typeDef.Methods) { foreach(MethodDefinition methodDef in typeDef.Methods) {
if (methodDef.IsSpecialName) continue; if (methodDef.IsSpecialName) continue;
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); astType.AddChild(CreateMethod(methodDef), TypeDeclaration.MemberRole);
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(); MethodDeclaration CreateMethod(MethodDefinition methodDef)
{
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.Name = methodDef.Name;
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMetodBody(methodDef);
return astMethod;
}
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMetodBody(methodDef);
return astMethod;
}
PropertyDeclaration CreateProperty(PropertyDefinition propDef)
{
PropertyDeclaration astProp = new PropertyDeclaration();
astProp.Modifiers = ConvertModifiers(propDef.GetMethod);
astProp.Name = propDef.Name;
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMetodBody(propDef.GetMethod)
};
}
if (propDef.SetMethod != null) {
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMetodBody(propDef.SetMethod)
};
} }
return astProp;
}
EventDeclaration CreateEvent(EventDefinition eventDef)
{
EventDeclaration astEvent = new EventDeclaration();
astEvent.Name = eventDef.Name;
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
return astEvent;
}
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
FieldDeclaration astField = new FieldDeclaration();
astField.AddChild(new VariableInitializer(fieldDef.Name), FieldDeclaration.Roles.Variable);
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);
astField.Modifiers = ConvertModifiers(fieldDef);
return astField;
} }
IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> paramCol) IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
{ {
foreach(ParameterDefinition paramDef in paramCol) { foreach(ParameterDefinition paramDef in paramCol) {
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( ParameterDeclaration astParam = new ParameterDeclaration();
new Ast.TypeReference(paramDef.ParameterType.FullName), astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
paramDef.Name astParam.Name = paramDef.Name;
);
if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; if (!paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Out;
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; if (paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Ref;
if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; // TODO: params, this
yield return astParam; yield return astParam;
} }

577
ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using Ast = ICSharpCode.NRefactory.Ast; using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
@ -11,7 +11,7 @@ using Decompiler.ControlFlow;
namespace Decompiler namespace Decompiler
{ {
public class AstMetodBodyBuilder public class AstMethodBodyBuilder
{ {
MethodDefinition methodDef; MethodDefinition methodDef;
static Dictionary<string, Cecil.TypeReference> localVarTypes = new Dictionary<string, Cecil.TypeReference>(); static Dictionary<string, Cecil.TypeReference> localVarTypes = new Dictionary<string, Cecil.TypeReference>();
@ -19,7 +19,7 @@ namespace Decompiler
public static BlockStatement CreateMetodBody(MethodDefinition methodDef) public static BlockStatement CreateMetodBody(MethodDefinition methodDef)
{ {
AstMetodBodyBuilder builder = new AstMetodBodyBuilder(); AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.methodDef = methodDef; builder.methodDef = methodDef;
if (Debugger.IsAttached) { if (Debugger.IsAttached) {
return builder.CreateMethodBody(); return builder.CreateMethodBody();
@ -28,7 +28,7 @@ namespace Decompiler
return builder.CreateMethodBody(); return builder.CreateMethodBody();
} catch { } catch {
BlockStatement block = new BlockStatement(); BlockStatement block = new BlockStatement();
block.Children.Add(MakeComment("// Exception during decompilation")); block.AddChild(new Comment("// Exception during decompilation"), BlockStatement.Roles.Comment);
return block; return block;
} }
} }
@ -53,9 +53,7 @@ namespace Decompiler
public BlockStatement CreateMethodBody() public BlockStatement CreateMethodBody()
{ {
Ast.BlockStatement astBlock = new Ast.BlockStatement(); if (methodDef.Body == null) return new Ast.BlockStatement();
if (methodDef.Body == null) return astBlock;
List<ILNode> body = new ILAstBuilder().Build(methodDef, true); List<ILNode> body = new ILAstBuilder().Build(methodDef, true);
@ -106,12 +104,13 @@ namespace Decompiler
// astBlock.Children.Add(astLocalVar); // astBlock.Children.Add(astLocalVar);
} }
astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); Ast.BlockStatement astBlock = new Ast.BlockStatement();
astBlock.Statements = TransformNodes(bodyGraph.Childs);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
return astBlock; return astBlock;
} }
IEnumerable<Ast.INode> TransformNodes(IEnumerable<Node> nodes) IEnumerable<Statement> TransformNodes(IEnumerable<Node> nodes)
{ {
foreach(Node node in nodes) { foreach(Node node in nodes) {
foreach(Ast.Statement stmt in TransformNode(node)) { foreach(Ast.Statement stmt in TransformNode(node)) {
@ -120,18 +119,18 @@ namespace Decompiler
} }
} }
IEnumerable<Ast.INode> TransformNode(Node node) IEnumerable<Statement> TransformNode(Node node)
{ {
if (Options.NodeComments) { if (Options.NodeComments) {
yield return MakeComment("// " + node.Description); yield return new CommentStatement("// " + node.Description);
} }
yield return new Ast.LabelStatement(node.Label); yield return new Ast.LabelStatement { Label = node.Label };
if (node is BasicBlock) { if (node is BasicBlock) {
foreach(ILNode expr in ((BasicBlock)node).Body) { foreach(ILNode expr in ((BasicBlock)node).Body) {
if (expr is ILLabel) { if (expr is ILLabel) {
yield return new Ast.LabelStatement(((ILLabel)expr).Name); yield return new Ast.LabelStatement { Label = ((ILLabel)expr).Name };
} else { } else {
Statement stmt = TransformExpressionToStatement((ILExpression)expr); Statement stmt = TransformExpressionToStatement((ILExpression)expr);
if (stmt != null) { if (stmt != null) {
@ -139,108 +138,100 @@ namespace Decompiler
} }
} }
} }
foreach(Ast.INode inode in TransformNodes(node.Childs)) { foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode; yield return inode;
} }
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node // If there is default branch and it is not the following node
if (fallThroughNode != null) { if (fallThroughNode != null) {
yield return new Ast.GotoStatement(fallThroughNode.Label); yield return new Ast.GotoStatement { GotoType = GotoType.Label, Label = fallThroughNode.Label };
} }
} else if (node is AcyclicGraph) { } else if (node is AcyclicGraph) {
foreach(Ast.INode inode in TransformNodes(node.Childs)) { foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode; yield return inode;
} }
} else if (node is Loop) { } else if (node is Loop) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); Ast.BlockStatement blockStatement = new Ast.BlockStatement();
blockStatement.Children.AddRange(TransformNodes(node.Childs)); blockStatement.Statements = TransformNodes(node.Childs);
yield return new Ast.ForStatement( yield return new Ast.ForStatement {
null, EmbeddedStatement = blockStatement
null, };
null,
blockStatement
);
} else if (node is Block) { } else if (node is Block) {
foreach(Ast.INode inode in TransformNodes(node.Childs)) { foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode; yield return inode;
} }
} else if (node is Branch) { } else if (node is Branch) {
yield return new Ast.LabelStatement(((Branch)node).FirstBasicBlock.Label); yield return new Ast.LabelStatement { Label = ((Branch)node).FirstBasicBlock.Label };
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); Ast.BlockStatement trueBlock = new Ast.BlockStatement();
trueBlock.Children.Add(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label)); trueBlock.AddStatement(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label));
Ast.BlockStatement falseBlock = new Ast.BlockStatement(); Ast.BlockStatement falseBlock = new Ast.BlockStatement();
falseBlock.Children.Add(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label)); falseBlock.AddStatement(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label));
Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement {
MakeBranchCondition((Branch)node), Condition = MakeBranchCondition((Branch)node),
trueBlock, TrueStatement = trueBlock,
falseBlock FalseStatement = falseBlock
); };
trueBlock.Parent = ifElseStmt;
falseBlock.Parent = ifElseStmt;
yield return ifElseStmt; yield return ifElseStmt;
} else if (node is ConditionalNode) { } else if (node is ConditionalNode) {
ConditionalNode conditionalNode = (ConditionalNode)node; ConditionalNode conditionalNode = (ConditionalNode)node;
yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.Label); yield return new Ast.LabelStatement { Label = conditionalNode.Condition.FirstBasicBlock.Label };
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); Ast.BlockStatement trueBlock = new Ast.BlockStatement();
// The block entry code // The block entry code
trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label)); trueBlock.AddStatement(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label));
// Sugested content // Sugested content
trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); trueBlock.AddStatements(TransformNode(conditionalNode.TrueBody));
Ast.BlockStatement falseBlock = new Ast.BlockStatement(); Ast.BlockStatement falseBlock = new Ast.BlockStatement();
// The block entry code // The block entry code
falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label)); falseBlock.AddStatement(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label));
// Sugested content // Sugested content
falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); falseBlock.AddStatements(TransformNode(conditionalNode.FalseBody));
Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement {
// Method bodies are swapped // Method bodies are swapped
new Ast.UnaryOperatorExpression( Condition = new Ast.UnaryOperatorExpression(
new Ast.ParenthesizedExpression( UnaryOperatorType.Not,
MakeBranchCondition(conditionalNode.Condition) MakeBranchCondition(conditionalNode.Condition)
),
UnaryOperatorType.Not
), ),
falseBlock, TrueStatement = falseBlock,
trueBlock FalseStatement = trueBlock
); };
trueBlock.Parent = ifElseStmt;
falseBlock.Parent = ifElseStmt;
yield return ifElseStmt; yield return ifElseStmt;
} else if (node is TryCatchNode) { } else if (node is TryCatchNode) {
TryCatchNode tryCachNode = ((TryCatchNode)node); TryCatchNode tryCachNode = ((TryCatchNode)node);
Ast.BlockStatement tryBlock = new Ast.BlockStatement(); Ast.BlockStatement tryBlock = new Ast.BlockStatement();
tryBlock.Children.AddRange(TransformNode(tryCachNode.Childs[0])); tryBlock.Statements = TransformNode(tryCachNode.Childs[0]);
Ast.BlockStatement finallyBlock = null; Ast.BlockStatement finallyBlock = null;
if (tryCachNode.Childs[1].Childs.Count > 0) { if (tryCachNode.Childs[1].Childs.Count > 0) {
finallyBlock = new Ast.BlockStatement(); finallyBlock = new Ast.BlockStatement();
finallyBlock.Children.AddRange(TransformNode(tryCachNode.Childs[1])); finallyBlock.Statements = TransformNode(tryCachNode.Childs[1]);
} }
List<Ast.CatchClause> ccs = new List<CatchClause>(); List<Ast.CatchClause> ccs = new List<CatchClause>();
for (int i = 0; i < tryCachNode.Types.Count; i++) { for (int i = 0; i < tryCachNode.Types.Count; i++) {
Ast.BlockStatement catchBlock = new Ast.BlockStatement(); Ast.BlockStatement catchBlock = new Ast.BlockStatement();
catchBlock.Children.AddRange(TransformNode(tryCachNode.Childs[i + 2])); catchBlock.Statements = TransformNode(tryCachNode.Childs[i + 2]);
Ast.CatchClause cc = new Ast.CatchClause( Ast.CatchClause cc = new Ast.CatchClause {
new Ast.TypeReference(tryCachNode.Types[i].FullName), Type = AstBuilder.ConvertType(tryCachNode.Types[i]),
"exception", VariableName = "exception",
catchBlock Body = catchBlock
); };
ccs.Add(cc); ccs.Add(cc);
} }
Ast.TryCatchStatement tryCachStmt = new Ast.TryCatchStatement(tryBlock, ccs, finallyBlock); yield return new Ast.TryCatchStatement {
yield return tryCachStmt; TryBlock = tryBlock, CatchClauses = ccs, FinallyBlock = finallyBlock
};
} else { } else {
throw new Exception("Bad node type"); throw new Exception("Bad node type");
} }
if (Options.NodeComments) { if (Options.NodeComments) {
yield return MakeComment(""); yield return new CommentStatement("");
} }
} }
@ -266,7 +257,7 @@ namespace Decompiler
if (codeExpr == null) { if (codeExpr == null) {
return null; return null;
} else if (codeExpr is Ast.Expression) { } else if (codeExpr is Ast.Expression) {
return new Ast.ExpressionStatement((Ast.Expression)codeExpr); return new Ast.ExpressionStatement { Expression = (Ast.Expression)codeExpr };
} else if (codeExpr is Ast.Statement) { } else if (codeExpr is Ast.Statement) {
return (Ast.Statement)codeExpr; return (Ast.Statement)codeExpr;
} else { } else {
@ -274,15 +265,9 @@ namespace Decompiler
} }
} }
static Ast.ExpressionStatement MakeComment(string text)
{
text = "/***" + text + "***/";
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text));
}
Ast.Expression MakeBranchCondition(Branch branch) Ast.Expression MakeBranchCondition(Branch branch)
{ {
return new ParenthesizedExpression(MakeBranchCondition_Internal(branch)); return MakeBranchCondition_Internal(branch);
} }
Ast.Expression MakeBranchCondition_Internal(Branch branch) Ast.Expression MakeBranchCondition_Internal(Branch branch)
@ -292,20 +277,20 @@ namespace Decompiler
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch(((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]).OpCode.Code) { switch(((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]).OpCode.Code) {
case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not); case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue: return arg1; case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
case Code.Leave: return new Ast.PrimitiveExpression(true, true.ToString()); case Code.Leave: return new Ast.PrimitiveExpression(true);
default: throw new Exception("Bad opcode"); default: throw new Exception("Bad opcode");
} }
} else if (branch is ShortCircuitBranch) { } else if (branch is ShortCircuitBranch) {
ShortCircuitBranch scBranch = (ShortCircuitBranch)branch; ShortCircuitBranch scBranch = (ShortCircuitBranch)branch;
@ -313,25 +298,25 @@ namespace Decompiler
case ShortCircuitOperator.LeftAndRight: case ShortCircuitOperator.LeftAndRight:
return new BinaryOperatorExpression( return new BinaryOperatorExpression(
MakeBranchCondition(scBranch.Left), MakeBranchCondition(scBranch.Left),
BinaryOperatorType.LogicalAnd, BinaryOperatorType.ConditionalAnd,
MakeBranchCondition(scBranch.Right) MakeBranchCondition(scBranch.Right)
); );
case ShortCircuitOperator.LeftOrRight: case ShortCircuitOperator.LeftOrRight:
return new BinaryOperatorExpression( return new BinaryOperatorExpression(
MakeBranchCondition(scBranch.Left), MakeBranchCondition(scBranch.Left),
BinaryOperatorType.LogicalOr, BinaryOperatorType.ConditionalOr,
MakeBranchCondition(scBranch.Right) MakeBranchCondition(scBranch.Right)
); );
case ShortCircuitOperator.NotLeftAndRight: case ShortCircuitOperator.NotLeftAndRight:
return new BinaryOperatorExpression( return new BinaryOperatorExpression(
new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(scBranch.Left)),
BinaryOperatorType.LogicalAnd, BinaryOperatorType.ConditionalAnd,
MakeBranchCondition(scBranch.Right) MakeBranchCondition(scBranch.Right)
); );
case ShortCircuitOperator.NotLeftOrRight: case ShortCircuitOperator.NotLeftOrRight:
return new BinaryOperatorExpression( return new BinaryOperatorExpression(
new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(scBranch.Left)),
BinaryOperatorType.LogicalOr, BinaryOperatorType.ConditionalOr,
MakeBranchCondition(scBranch.Right) MakeBranchCondition(scBranch.Right)
); );
default: default:
@ -345,10 +330,7 @@ namespace Decompiler
static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args) static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
{ {
try { try {
Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args); AstNode ret = TransformByteCode_Internal(methodDef, byteCode, args);
if (ret is Ast.Expression) {
ret = new ParenthesizedExpression((Ast.Expression)ret);
}
// ret.UserData["Type"] = byteCode.Type; // ret.UserData["Type"] = byteCode.Type;
return ret; return ret;
} catch (NotImplementedException) { } catch (NotImplementedException) {
@ -356,7 +338,7 @@ namespace Decompiler
if (byteCode.Operand != null) { if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
} }
return new Ast.InvocationExpression(new IdentifierExpression(byteCode.OpCode.Name), args); return new IdentifierExpression(byteCode.OpCode.Name).Invoke(args);
} }
} }
@ -364,8 +346,8 @@ namespace Decompiler
{ {
if (operand == null) { if (operand == null) {
return string.Empty; return string.Empty;
//} else if (operand is ILExpression) { //} else if (operand is ILExpression) {
// return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset); // return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset);
} else if (operand is MethodReference) { } else if (operand is MethodReference) {
return ((MethodReference)operand).Name + "()"; return ((MethodReference)operand).Name + "()";
} else if (operand is Cecil.TypeReference) { } else if (operand is Cecil.TypeReference) {
@ -385,13 +367,13 @@ namespace Decompiler
} }
} }
static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args) static AstNode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
{ {
// throw new NotImplementedException(); // throw new NotImplementedException();
OpCode opCode = byteCode.OpCode; OpCode opCode = byteCode.OpCode;
object operand = byteCode.Operand; object operand = byteCode.Operand;
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
ILExpression operandAsByteCode = operand as ILExpression; ILExpression operandAsByteCode = operand as ILExpression;
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
@ -403,7 +385,7 @@ namespace Decompiler
} }
switch(opCode.Code) { switch(opCode.Code) {
#region Arithmetic #region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -423,43 +405,52 @@ namespace Decompiler
case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case Code.Neg: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Minus); case Code.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
case Code.Not: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.BitNot); case Code.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
#endregion #endregion
#region Arrays #region Arrays
case Code.Newarr: case Code.Newarr:
operandAsTypeRef.RankSpecifier = new int[] {0}; operandAsTypeRef = operandAsTypeRef.MakeArrayType(0);
return new Ast.ArrayCreateExpression(operandAsTypeRef, new List<Expression>(new Expression[] {arg1})); return new Ast.ArrayCreateExpression {
Type = operandAsTypeRef,
Arguments = new Expression[] {arg1}
};
case Code.Ldlen: return new Ast.MemberReferenceExpression(arg1, "Length"); case Code.Ldlen:
return arg1.Member("Length");
case Code.Ldelem_I: case Code.Ldelem_I:
case Code.Ldelem_I1: case Code.Ldelem_I1:
case Code.Ldelem_I2: case Code.Ldelem_I2:
case Code.Ldelem_I4: case Code.Ldelem_I4:
case Code.Ldelem_I8: case Code.Ldelem_I8:
case Code.Ldelem_U1: case Code.Ldelem_U1:
case Code.Ldelem_U2: case Code.Ldelem_U2:
case Code.Ldelem_U4: case Code.Ldelem_U4:
case Code.Ldelem_R4: case Code.Ldelem_R4:
case Code.Ldelem_R8: case Code.Ldelem_R8:
case Code.Ldelem_Ref: return new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})); case Code.Ldelem_Ref:
case Code.Ldelem_Any: throw new NotImplementedException(); return arg1.Indexer(arg2);
case Code.Ldelema: return new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})); case Code.Ldelem_Any:
throw new NotImplementedException();
case Code.Ldelema:
return arg1.Indexer(arg2);
case Code.Stelem_I: case Code.Stelem_I:
case Code.Stelem_I1: case Code.Stelem_I1:
case Code.Stelem_I2: case Code.Stelem_I2:
case Code.Stelem_I4: case Code.Stelem_I4:
case Code.Stelem_I8: case Code.Stelem_I8:
case Code.Stelem_R4: case Code.Stelem_R4:
case Code.Stelem_R8: case Code.Stelem_R8:
case Code.Stelem_Ref: return new Ast.AssignmentExpression(new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})), AssignmentOperatorType.Assign, arg3); case Code.Stelem_Ref:
case Code.Stelem_Any: throw new NotImplementedException(); return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
#endregion case Code.Stelem_Any:
#region Branching throw new NotImplementedException();
#endregion
#region Branching
case Code.Br: return branchCommand; case Code.Br: return branchCommand;
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand); case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), branchCommand);
case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand); case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand);
case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand); case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand);
case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
@ -471,52 +462,52 @@ namespace Decompiler
case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand); case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
#endregion #endregion
#region Comparison #region Comparison
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2)); case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));
case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion #endregion
#region Conversions #region Conversions
case Code.Conv_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO case Code.Conv_I: return arg1.CastTo(typeof(int)); // TODO
case Code.Conv_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); case Code.Conv_I1: return arg1.CastTo(typeof(SByte));
case Code.Conv_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); case Code.Conv_I2: return arg1.CastTo(typeof(Int16));
case Code.Conv_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); case Code.Conv_I4: return arg1.CastTo(typeof(Int32));
case Code.Conv_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); case Code.Conv_I8: return arg1.CastTo(typeof(Int64));
case Code.Conv_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO case Code.Conv_U: return arg1.CastTo(typeof(uint)); // TODO
case Code.Conv_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); case Code.Conv_U1: return arg1.CastTo(typeof(Byte));
case Code.Conv_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); case Code.Conv_U2: return arg1.CastTo(typeof(UInt16));
case Code.Conv_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); case Code.Conv_U4: return arg1.CastTo(typeof(UInt32));
case Code.Conv_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); case Code.Conv_U8: return arg1.CastTo(typeof(UInt64));
case Code.Conv_R4: return new Ast.CastExpression(new Ast.TypeReference(typeof(float).FullName), arg1, CastType.Cast); case Code.Conv_R4: return arg1.CastTo(typeof(float));
case Code.Conv_R8: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); case Code.Conv_R8: return arg1.CastTo(typeof(double));
case Code.Conv_R_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); // TODO case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
case Code.Conv_Ovf_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO case Code.Conv_Ovf_I: return arg1.CastTo(typeof(int));
case Code.Conv_Ovf_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I1: return arg1.CastTo(typeof(SByte));
case Code.Conv_Ovf_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I2: return arg1.CastTo(typeof(Int16));
case Code.Conv_Ovf_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I4: return arg1.CastTo(typeof(Int32));
case Code.Conv_Ovf_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I8: return arg1.CastTo(typeof(Int64));
case Code.Conv_Ovf_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO case Code.Conv_Ovf_U: return arg1.CastTo(typeof(uint));
case Code.Conv_Ovf_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U1: return arg1.CastTo(typeof(Byte));
case Code.Conv_Ovf_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U2: return arg1.CastTo(typeof(UInt16));
case Code.Conv_Ovf_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U4: return arg1.CastTo(typeof(UInt32));
case Code.Conv_Ovf_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U8: return arg1.CastTo(typeof(UInt64));
case Code.Conv_Ovf_I_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(int));
case Code.Conv_Ovf_I1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I1_Un: return arg1.CastTo(typeof(SByte));
case Code.Conv_Ovf_I2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I2_Un: return arg1.CastTo(typeof(Int16));
case Code.Conv_Ovf_I4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I4_Un: return arg1.CastTo(typeof(Int32));
case Code.Conv_Ovf_I8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_I8_Un: return arg1.CastTo(typeof(Int64));
case Code.Conv_Ovf_U_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(uint));
case Code.Conv_Ovf_U1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U1_Un: return arg1.CastTo(typeof(Byte));
case Code.Conv_Ovf_U2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U2_Un: return arg1.CastTo(typeof(UInt16));
case Code.Conv_Ovf_U4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U4_Un: return arg1.CastTo(typeof(UInt32));
case Code.Conv_Ovf_U8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); case Code.Conv_Ovf_U8_Un: return arg1.CastTo(typeof(UInt64));
#endregion #endregion
#region Indirect #region Indirect
case Code.Ldind_I: throw new NotImplementedException(); case Code.Ldind_I: throw new NotImplementedException();
case Code.Ldind_I1: throw new NotImplementedException(); case Code.Ldind_I1: throw new NotImplementedException();
case Code.Ldind_I2: throw new NotImplementedException(); case Code.Ldind_I2: throw new NotImplementedException();
@ -537,10 +528,10 @@ namespace Decompiler
case Code.Stind_R4: throw new NotImplementedException(); case Code.Stind_R4: throw new NotImplementedException();
case Code.Stind_R8: throw new NotImplementedException(); case Code.Stind_R8: throw new NotImplementedException();
case Code.Stind_Ref: throw new NotImplementedException(); case Code.Stind_Ref: throw new NotImplementedException();
#endregion #endregion
case Code.Arglist: throw new NotImplementedException(); case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException(); case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException(); case Code.Break: throw new NotImplementedException();
case Code.Call: case Code.Call:
case Code.Callvirt: case Code.Callvirt:
// TODO: Diferentiate vitual and non-vitual dispach // TODO: Diferentiate vitual and non-vitual dispach
@ -556,21 +547,21 @@ namespace Decompiler
// TODO: Constructors are ignored // TODO: Constructors are ignored
if (cecilMethod.Name == ".ctor") { if (cecilMethod.Name == ".ctor") {
return MakeComment("// Constructor"); return new CommentStatement("// Constructor");
} }
// TODO: Hack, detect properties properly // TODO: Hack, detect properties properly
if (cecilMethod.Name.StartsWith("get_")) { if (cecilMethod.Name.StartsWith("get_")) {
return new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)); return target.Member(cecilMethod.Name.Remove(0, 4));
} else if (cecilMethod.Name.StartsWith("set_")) { } else if (cecilMethod.Name.StartsWith("set_")) {
return new Ast.AssignmentExpression( return new Ast.AssignmentExpression(
new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)), target.Member(cecilMethod.Name.Remove(0, 4)),
AssignmentOperatorType.Assign,
methodArgs[0] methodArgs[0]
); );
} }
// Multi-dimensional array acces // TODO: do properly // Multi-dimensional array acces // TODO: do properly
/*
if (cecilMethod.Name == "Get") { if (cecilMethod.Name == "Get") {
return new Ast.IndexerExpression(target, methodArgs); return new Ast.IndexerExpression(target, methodArgs);
} else if (cecilMethod.Name == "Set") { } else if (cecilMethod.Name == "Set") {
@ -581,162 +572,134 @@ namespace Decompiler
AssignmentOperatorType.Assign, AssignmentOperatorType.Assign,
Convert(val, ((Cecil.ArrayType)target.UserData["Type"]).ElementType) Convert(val, ((Cecil.ArrayType)target.UserData["Type"]).ElementType)
); );
} }*/
// Default invocation // Default invocation
return new Ast.InvocationExpression( return target.Invoke(cecilMethod.Name, methodArgs);
new Ast.MemberReferenceExpression(target, cecilMethod.Name), case Code.Calli: throw new NotImplementedException();
methodArgs case Code.Castclass: return arg1.CastTo(operandAsTypeRef);
); case Code.Ckfinite: throw new NotImplementedException();
case Code.Calli: throw new NotImplementedException(); case Code.Constrained: throw new NotImplementedException();
case Code.Castclass: return new Ast.CastExpression(operandAsTypeRef, arg1, CastType.Cast); case Code.Cpblk: throw new NotImplementedException();
case Code.Ckfinite: throw new NotImplementedException(); case Code.Cpobj: throw new NotImplementedException();
case Code.Constrained: throw new NotImplementedException(); case Code.Dup: return arg1;
case Code.Cpblk: throw new NotImplementedException(); case Code.Endfilter: throw new NotImplementedException();
case Code.Cpobj: throw new NotImplementedException(); case Code.Endfinally: return null;
case Code.Dup: return arg1; case Code.Initblk: throw new NotImplementedException();
case Code.Endfilter: throw new NotImplementedException(); case Code.Initobj: throw new NotImplementedException();
case Code.Endfinally: return null; case Code.Isinst: return arg1.IsType(AstBuilder.ConvertType((Cecil.TypeReference)operand));
case Code.Initblk: throw new NotImplementedException(); case Code.Jmp: throw new NotImplementedException();
case Code.Initobj: throw new NotImplementedException();
case Code.Isinst: return new Ast.TypeOfIsExpression(arg1, new Ast.TypeReference(((Cecil.TypeReference)operand).FullName));
case Code.Jmp: throw new NotImplementedException();
case Code.Ldarg: case Code.Ldarg:
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return new Ast.ThisReferenceExpression(); return new Ast.ThisReferenceExpression();
} else { } else {
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name);
} }
case Code.Ldarga: throw new NotImplementedException(); case Code.Ldarga: throw new NotImplementedException();
case Code.Ldc_I4: case Code.Ldc_I4:
case Code.Ldc_I8: case Code.Ldc_I8:
case Code.Ldc_R4: case Code.Ldc_R4:
case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand, null); case Code.Ldc_R8:
return new Ast.PrimitiveExpression(operand);
case Code.Ldfld: case Code.Ldfld:
case Code.Ldsfld: { return arg1.Member(((FieldReference) operand).Name);
if (operand is FieldDefinition) { case Code.Ldsfld:
FieldDefinition field = (FieldDefinition) operand; return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType).Member(((FieldReference)operand).Name);
if (field.IsStatic) {
return new Ast.MemberReferenceExpression(
new Ast.IdentifierExpression(field.DeclaringType.FullName),
field.Name
);
} else {
return new Ast.MemberReferenceExpression(arg1, field.Name);
}
} else {
// TODO: Static accesses
return new Ast.MemberReferenceExpression(arg1, ((FieldReference)operand).Name);
}
}
case Code.Stfld: case Code.Stfld:
case Code.Stsfld: { return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name), arg2);
FieldDefinition field = (FieldDefinition) operand; case Code.Stsfld:
if (field.IsStatic) { return new AssignmentExpression(
return new AssignmentExpression( AstBuilder.ConvertType(((FieldReference)operand).DeclaringType).Member(((FieldReference)operand).Name),
new Ast.MemberReferenceExpression( arg2);
new Ast.IdentifierExpression(field.DeclaringType.FullName),
field.Name
),
AssignmentOperatorType.Assign,
arg1
);
} else {
return new AssignmentExpression(
new Ast.MemberReferenceExpression(arg1, field.Name),
AssignmentOperatorType.Assign,
arg2
);
}
}
case Code.Ldflda: case Code.Ldflda:
case Code.Ldsflda: throw new NotImplementedException(); case Code.Ldsflda: throw new NotImplementedException();
case Code.Ldftn: throw new NotImplementedException(); case Code.Ldftn: throw new NotImplementedException();
case Code.Ldloc: case Code.Ldloc:
if (operand is ILVariable) { if (operand is ILVariable) {
return new Ast.IdentifierExpression(((ILVariable)operand).Name); return new Ast.IdentifierExpression(((ILVariable)operand).Name);
} else { } else {
return new Ast.IdentifierExpression(((VariableDefinition)operand).Name); return new Ast.IdentifierExpression(((VariableDefinition)operand).Name);
} }
case Code.Ldloca: throw new NotImplementedException(); case Code.Ldloca: throw new NotImplementedException();
case Code.Ldnull: return new Ast.PrimitiveExpression(null, null); case Code.Ldnull: return new Ast.PrimitiveExpression(null);
case Code.Ldobj: throw new NotImplementedException(); case Code.Ldobj: throw new NotImplementedException();
case Code.Ldstr: return new Ast.PrimitiveExpression(operand, null); case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
case Code.Ldtoken: case Code.Ldtoken:
if (operand is Cecil.TypeReference) { if (operand is Cecil.TypeReference) {
return new Ast.MemberReferenceExpression( return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
new Ast.TypeOfExpression(operandAsTypeRef),
"TypeHandle"
);
} else { } else {
throw new NotImplementedException(); throw new NotImplementedException();
} }
case Code.Ldvirtftn: throw new NotImplementedException(); case Code.Ldvirtftn: throw new NotImplementedException();
case Code.Leave: return null; case Code.Leave: return null;
case Code.Localloc: throw new NotImplementedException(); case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException(); case Code.Mkrefany: throw new NotImplementedException();
case Code.Newobj: case Code.Newobj:
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
// TODO: Ensure that the corrent overloaded constructor is called // TODO: Ensure that the corrent overloaded constructor is called
if (declaringType is ArrayType) { if (declaringType is ArrayType) {
return new Ast.ArrayCreateExpression( return new Ast.ArrayCreateExpression {
new Ast.TypeReference(((ArrayType)declaringType).ElementType.FullName, new int[] {}), Type = AstBuilder.ConvertType((ArrayType)declaringType),
new List<Expression>(args) Arguments = args
); };
}
return new Ast.ObjectCreateExpression(
new Ast.TypeReference(declaringType.FullName),
new List<Expression>(args)
);
case Code.No: throw new NotImplementedException();
case Code.Nop: return null;
case Code.Or: throw new NotImplementedException();
case Code.Pop: return arg1;
case Code.Readonly: throw new NotImplementedException();
case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: {
if (methodDef.ReturnType.FullName != Constants.Void) {
arg1 = Convert(arg1, methodDef.ReturnType);
return new Ast.ReturnStatement(arg1);
} else {
return new Ast.ReturnStatement(null);
} }
} return new Ast.ObjectCreateExpression {
case Code.Rethrow: return new Ast.ThrowStatement(new IdentifierExpression("exception")); Type = AstBuilder.ConvertType(declaringType),
case Code.Sizeof: throw new NotImplementedException(); Arguments = args
case Code.Starg: throw new NotImplementedException(); };
case Code.Stloc: { case Code.No: throw new NotImplementedException();
if (operand is ILVariable) { case Code.Nop: return null;
Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(((ILVariable)operand).Name, arg1)); case Code.Or: throw new NotImplementedException();
astLocalVar.TypeReference = new Ast.TypeReference("var"); case Code.Pop: return arg1;
return astLocalVar; case Code.Readonly: throw new NotImplementedException();
} case Code.Refanytype: throw new NotImplementedException();
VariableDefinition locVar = (VariableDefinition)operand; case Code.Refanyval: throw new NotImplementedException();
string name = locVar.Name; case Code.Ret: {
arg1 = Convert(arg1, locVar.VariableType); if (methodDef.ReturnType.FullName != Constants.Void) {
if (localVarDefined.ContainsKey(name)) { arg1 = Convert(arg1, methodDef.ReturnType);
if (localVarDefined[name]) { return new Ast.ReturnStatement { Expression = arg1 };
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
} else { } else {
Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1)); return new Ast.ReturnStatement();
astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName); }
localVarDefined[name] = true; }
case Code.Rethrow: return new Ast.ThrowStatement();
case Code.Sizeof: throw new NotImplementedException();
case Code.Starg: throw new NotImplementedException();
case Code.Stloc: {
if (operand is ILVariable) {
var astLocalVar = new Ast.VariableDeclarationStatement();
astLocalVar.Type = new Ast.PrimitiveType("var");
astLocalVar.Variables = new [] {
new Ast.VariableInitializer(((ILVariable)operand).Name, arg1)
};
return astLocalVar; return astLocalVar;
} }
} else { VariableDefinition locVar = (VariableDefinition)operand;
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); string name = locVar.Name;
arg1 = Convert(arg1, locVar.VariableType);
if (localVarDefined.ContainsKey(name)) {
if (localVarDefined[name]) {
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), arg1);
} else {
var astLocalVar = new Ast.VariableDeclarationStatement();
astLocalVar.Type = AstBuilder.ConvertType(localVarTypes[name]);
astLocalVar.Variables = new[] { new Ast.VariableInitializer(name, arg1) };
localVarDefined[name] = true;
return astLocalVar;
}
} else {
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), arg1);
}
} }
} case Code.Stobj: throw new NotImplementedException();
case Code.Stobj: throw new NotImplementedException(); case Code.Switch: throw new NotImplementedException();
case Code.Switch: throw new NotImplementedException(); case Code.Tail: throw new NotImplementedException();
case Code.Tail: throw new NotImplementedException(); case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case Code.Throw: return new Ast.ThrowStatement(arg1); case Code.Unaligned: throw new NotImplementedException();
case Code.Unaligned: throw new NotImplementedException(); case Code.Unbox: throw new NotImplementedException();
case Code.Unbox: throw new NotImplementedException(); case Code.Unbox_Any: throw new NotImplementedException();
case Code.Unbox_Any: throw new NotImplementedException(); case Code.Volatile: throw new NotImplementedException();
case Code.Volatile: throw new NotImplementedException(); default: throw new Exception("Unknown OpCode: " + opCode);
default: throw new Exception("Unknown OpCode: " + opCode);
} }
} }

38
ICSharpCode.Decompiler/Ast/CommentStatement.cs

@ -0,0 +1,38 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler
{
/// <summary>
/// Allows storing comments inside IEnumerable{Statement}. Used in the AstMethodBuilder.
/// CommentStatement nodes are replaced with regular comments later on.
/// </summary>
class CommentStatement : Statement
{
string comment;
public CommentStatement(string comment)
{
if (comment == null)
throw new ArgumentNullException("comment");
this.comment = comment;
}
public override S AcceptVisitor<T, S>(AstVisitor<T, S> visitor, T data)
{
return default(S);
}
public static void ReplaceAll(AstNode tree)
{
foreach (var cs in tree.Descendants.OfType<CommentStatement>()) {
cs.Parent.InsertChildBefore(cs, new Comment(cs.comment), Roles.Comment);
cs.Remove();
}
}
}
}

89
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -0,0 +1,89 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler
{
public class TextOutputFormatter : IOutputFormatter
{
readonly ITextOutput output;
public TextOutputFormatter(ITextOutput output)
{
if (output == null)
throw new ArgumentNullException("output");
this.output = output;
}
public void WriteIdentifier(string identifier)
{
output.Write(identifier);
}
public void WriteKeyword(string keyword)
{
output.Write(keyword);
}
public void WriteToken(string token)
{
output.Write(token);
}
public void Space()
{
output.Write(' ');
}
public void OpenBrace(BraceStyle style)
{
output.MarkFoldStart();
output.WriteLine(" {");
output.Indent();
}
public void CloseBrace(BraceStyle style)
{
output.Unindent();
output.Write('}');
output.MarkFoldEnd();
}
public void Indent()
{
output.Indent();
}
public void Unindent()
{
output.Unindent();
}
public void NewLine()
{
output.WriteLine();
}
public void WriteComment(CommentType commentType, string content)
{
switch (commentType) {
case CommentType.SingleLine:
output.Write("//");
output.WriteLine(content);
break;
case CommentType.MultiLine:
output.Write("/*");
output.Write(content);
output.Write("*/");
break;
case CommentType.Documentation:
output.Write("///");
output.WriteLine(content);
break;
}
}
}
}

102
ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs

@ -1,32 +1,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast; using System.Linq;
using ICSharpCode.NRefactory.Ast; using Mono.Cecil;
using ICSharpCode.NRefactory.Visitors; using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class Idioms: AbstractAstTransformer public class Idioms: DepthFirstAstVisitor<object, object>
{ {
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{ {
base.VisitInvocationExpression(invocationExpression, data); base.VisitInvocationExpression(invocationExpression, data);
MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression; if (methodRef != null && methodRef.FullName == "System.String.Concat"
if (target != null && && methodRef.Parameters.Count >= 2)
target.MemberName == "Concat" &&
invocationExpression.Arguments.Count == 2 &&
target.TargetObject is IdentifierExpression &&
(target.TargetObject as IdentifierExpression).Identifier == "String")
{ {
ReplaceCurrentNode( var arguments = invocationExpression.Arguments.ToArray();
new BinaryOperatorExpression( invocationExpression.Arguments = null; // detach arguments from invocationExpression
invocationExpression.Arguments[0], Expression expr = arguments[0];
BinaryOperatorType.Add, for (int i = 1; i < arguments.Length; i++) {
invocationExpression.Arguments[1] expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
) }
);
} }
return null; return null;
@ -34,43 +31,68 @@ namespace Decompiler.Transforms.Ast
public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) public override object VisitAssignmentExpression(AssignmentExpression assignment, object data)
{ {
IdentifierExpression ident = assignment.Left as IdentifierExpression; base.VisitAssignmentExpression(assignment, data);
// First, combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression;
if (ident != null && binary != null) { if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression binaryLeft = binary.Left as IdentifierExpression; if (IsWithoutSideEffects(assignment.Left) && AstComparer.AreEqual(assignment.Left, binary.Left) == true) {
if (binaryLeft != null && switch (binary.Operator) {
binaryLeft.Identifier == ident.Identifier) { case BinaryOperatorType.Add:
if (binary.Right is PrimitiveExpression && assignment.Operator = AssignmentOperatorType.Add;
1.Equals((binary.Right as PrimitiveExpression).Value)) { break;
if (binary.Op == BinaryOperatorType.Add) { case BinaryOperatorType.Subtract:
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement)); assignment.Operator = AssignmentOperatorType.Subtract;
} break;
if (binary.Op == BinaryOperatorType.Subtract) { case BinaryOperatorType.Multiply:
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement)); assignment.Operator = AssignmentOperatorType.Multiply;
} break;
} else { case BinaryOperatorType.Divide:
if (binary.Op == BinaryOperatorType.Add) { assignment.Operator = AssignmentOperatorType.Divide;
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right)); break;
} case BinaryOperatorType.Modulus:
if (binary.Op == BinaryOperatorType.Subtract) { assignment.Operator = AssignmentOperatorType.Modulus;
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right)); break;
} case BinaryOperatorType.ShiftLeft:
assignment.Operator = AssignmentOperatorType.ShiftLeft;
break;
case BinaryOperatorType.ShiftRight:
assignment.Operator = AssignmentOperatorType.ShiftRight;
break;
case BinaryOperatorType.BitwiseAnd:
assignment.Operator = AssignmentOperatorType.BitwiseAnd;
break;
case BinaryOperatorType.BitwiseOr:
assignment.Operator = AssignmentOperatorType.BitwiseOr;
break;
case BinaryOperatorType.ExclusiveOr:
assignment.Operator = AssignmentOperatorType.ExclusiveOr;
break;
}
if (assignment.Operator != AssignmentOperatorType.Assign) {
// If we found a shorter operators, get rid of the BinaryOperatorExpression:
assignment.Right = binary.Right;
} }
return null;
} }
} }
return null; return null;
} }
bool IsWithoutSideEffects(Expression left)
{
return left is IdentifierExpression; // TODO
}
/*
public override object VisitCastExpression(CastExpression castExpression, object data) public override object VisitCastExpression(CastExpression castExpression, object data)
{ {
if (castExpression.CastTo.Type == "int" && MethodReference typeRef = invocationExpression.Annotation<TypeReference>();
if (typeRef.FullName == Constants.Int32 &&
castExpression.Expression is MemberReferenceExpression && castExpression.Expression is MemberReferenceExpression &&
(castExpression.Expression as MemberReferenceExpression).MemberName == "Length") { (castExpression.Expression as MemberReferenceExpression).MemberName == "Length") {
ReplaceCurrentNode(castExpression.Expression); ReplaceCurrentNode(castExpression.Expression);
return null; return null;
} }
return base.VisitCastExpression(castExpression, data); return base.VisitCastExpression(castExpression, data);
} }*/
} }
} }

100
ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

@ -1,86 +1,58 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class PushNegation: AbstractAstTransformer public class PushNegation: DepthFirstAstVisitor<object, object>
{ {
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
{ {
// Remove double negation // Remove double negation
// !!a // !!a
if (unary.Op == UnaryOperatorType.Not && if (unary.Operator == UnaryOperatorType.Not &&
unary.Expression is UnaryOperatorExpression && unary.Expression is UnaryOperatorExpression &&
(unary.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { (unary.Expression as UnaryOperatorExpression).Operator == UnaryOperatorType.Not)
Expression newParenth = new ParenthesizedExpression((unary.Expression as UnaryOperatorExpression).Expression); {
ReplaceCurrentNode(newParenth); AstNode newNode = (unary.Expression as UnaryOperatorExpression).Expression;
return newParenth.AcceptVisitor(this, data); unary.ReplaceWith(newNode);
return newNode.AcceptVisitor(this, data);
} }
// Basic assumtion is that we have something in form !(a) // Push through binary operation
if (unary.Op == UnaryOperatorType.Not && // !((a) op (b))
unary.Expression is ParenthesizedExpression) { BinaryOperatorExpression binaryOp = unary.Expression as BinaryOperatorExpression;
ParenthesizedExpression parenth = ((ParenthesizedExpression)unary.Expression); if (unary.Operator == UnaryOperatorType.Not && binaryOp != null) {
bool sucessful = true;
// Push through two parenthesis switch (binaryOp.Operator) {
// !((a)) case BinaryOperatorType.Equality: binaryOp.Operator = BinaryOperatorType.InEquality; break;
if (parenth.Expression is ParenthesizedExpression) { case BinaryOperatorType.InEquality: binaryOp.Operator = BinaryOperatorType.Equality; break;
parenth.Expression = new UnaryOperatorExpression(parenth.Expression, UnaryOperatorType.Not); // TODO: these are invalid for floats (stupid NaN)
ReplaceCurrentNode(parenth); case BinaryOperatorType.GreaterThan: binaryOp.Operator = BinaryOperatorType.LessThanOrEqual; break;
return parenth.AcceptVisitor(this, data); case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Operator = BinaryOperatorType.LessThan; break;
case BinaryOperatorType.LessThanOrEqual: binaryOp.Operator = BinaryOperatorType.GreaterThan; break;
case BinaryOperatorType.LessThan: binaryOp.Operator = BinaryOperatorType.GreaterThanOrEqual; break;
default: sucessful = false; break;
} }
if (sucessful) {
// Remove double negation unary.ReplaceWith(binaryOp);
// !(!a) return binaryOp.AcceptVisitor(this, data);
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 sucessful = true;
// !((a) op (b)) switch (binaryOp.Operator) {
BinaryOperatorExpression binaryOp = parenth.Expression as BinaryOperatorExpression; case BinaryOperatorType.ConditionalAnd: binaryOp.Operator = BinaryOperatorType.ConditionalOr; break;
if (binaryOp != null && case BinaryOperatorType.ConditionalOr: binaryOp.Operator = BinaryOperatorType.ConditionalAnd; break;
binaryOp.Left is ParenthesizedExpression && default: sucessful = false; break;
binaryOp.Right is ParenthesizedExpression) { }
if (sucessful) {
bool sucessful = true; binaryOp.Left.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
switch(binaryOp.Op) { binaryOp.Right.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
case BinaryOperatorType.Equality: binaryOp.Op = BinaryOperatorType.InEquality; break; unary.ReplaceWith(binaryOp);
case BinaryOperatorType.InEquality: binaryOp.Op = BinaryOperatorType.Equality; break; return binaryOp.AcceptVisitor(this, data);
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); return base.VisitUnaryOperatorExpression(unary, data);
} }
} }

28
ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs

@ -1,12 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class RemoveDeadLabels: AbstractAstTransformer public class RemoveDeadLabels : DepthFirstAstVisitor<object, object>
{ {
List<string> usedLabels = new List<string>(); List<string> usedLabels = new List<string>();
bool collectingUsedLabels; bool collectingUsedLabels;
@ -29,20 +27,12 @@ namespace Decompiler.Transforms.Ast
return null; return null;
} }
public override object VisitPropertyGetRegion(PropertyGetRegion propertyGetRegion, object data) public override object VisitAccessor(Accessor accessor, object data)
{ {
collectingUsedLabels = true; collectingUsedLabels = true;
base.VisitPropertyGetRegion(propertyGetRegion, data); base.VisitAccessor(accessor, data);
collectingUsedLabels = false; collectingUsedLabels = false;
return base.VisitPropertyGetRegion(propertyGetRegion, data); return base.VisitAccessor(accessor, data);
}
public override object VisitPropertySetRegion(PropertySetRegion propertySetRegion, object data)
{
collectingUsedLabels = true;
base.VisitPropertySetRegion(propertySetRegion, data);
collectingUsedLabels = false;
return base.VisitPropertySetRegion(propertySetRegion, data);
} }
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
@ -57,7 +47,7 @@ namespace Decompiler.Transforms.Ast
{ {
if (!collectingUsedLabels) { if (!collectingUsedLabels) {
if (!usedLabels.Contains(labelStatement.Label)) { if (!usedLabels.Contains(labelStatement.Label)) {
RemoveCurrentNode(); labelStatement.Remove();
} }
} }
return null; return null;

29
ICSharpCode.Decompiler/Ast/Transforms/RemoveEmptyElseBody.cs

@ -1,34 +1,17 @@
using System; using System;
using System.Linq;
using Ast = ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class RemoveEmptyElseBody: AbstractAstTransformer public class RemoveEmptyElseBody: DepthFirstAstVisitor<object, object>
{ {
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) public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data)
{ {
base.VisitIfElseStatement(ifElseStatement, data); base.VisitIfElseStatement(ifElseStatement, data);
if (ifElseStatement.FalseStatement.Count == 1 && BlockStatement block = ifElseStatement.FalseStatement as BlockStatement;
ifElseStatement.FalseStatement[0] is BlockStatement && if (block != null && !block.Statements.Any()) {
ifElseStatement.FalseStatement[0].Children.Count == 0) ifElseStatement.FalseStatement = null;
{
ifElseStatement.FalseStatement.Clear();
} }
return null; return null;
} }

24
ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs

@ -1,16 +1,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class RemoveGotos: AbstractAstTransformer /*
public class RemoveGotos: DepthFirstAstVisitor<object, object>
{ {
Stack<StatementWithEmbeddedStatement> enteredLoops = new Stack<StatementWithEmbeddedStatement>(); Stack<Statement> enteredLoops = new Stack<Statement>();
StatementWithEmbeddedStatement CurrentLoop { Statement CurrentLoop {
get { get {
if (enteredLoops.Count > 0) { if (enteredLoops.Count > 0) {
return enteredLoops.Peek(); return enteredLoops.Peek();
@ -28,10 +28,10 @@ namespace Decompiler.Transforms.Ast
return null; return null;
} }
public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) public override object VisitWhileStatement(WhileStatement whileStatement, object data)
{ {
enteredLoops.Push(doLoopStatement); enteredLoops.Push(whileStatement);
base.VisitDoLoopStatement(doLoopStatement, data); base.VisitWhileStatement(whileStatement, data);
enteredLoops.Pop(); enteredLoops.Pop();
return null; return null;
} }
@ -70,7 +70,7 @@ namespace Decompiler.Transforms.Ast
// Get the next statement that will be executed after this one // Get the next statement that will be executed after this one
// May return null // May return null
public static INode GetNextStatement(Statement statement) public static AstNode GetNextStatement(Statement statement)
{ {
if (statement == null) throw new ArgumentNullException(); if (statement == null) throw new ArgumentNullException();
@ -90,7 +90,7 @@ namespace Decompiler.Transforms.Ast
// Get the statement that will be executed once the given block exits by the end brace // Get the statement that will be executed once the given block exits by the end brace
// May return null // May return null
public static INode ExitBlockStatement(Statement statement) public static AstNode ExitBlockStatement(Statement statement)
{ {
if (statement == null) throw new ArgumentNullException(); if (statement == null) throw new ArgumentNullException();
@ -117,7 +117,7 @@ namespace Decompiler.Transforms.Ast
} }
// Get the first statement that will be executed in the given block // Get the first statement that will be executed in the given block
public static INode EnterBlockStatement(Statement statement) public static AstNode EnterBlockStatement(Statement statement)
{ {
if (statement == null) throw new ArgumentNullException(); if (statement == null) throw new ArgumentNullException();
@ -189,5 +189,5 @@ namespace Decompiler.Transforms.Ast
return null; return null;
} }
} }*/
} }

251
ICSharpCode.Decompiler/Ast/Transforms/RemoveParenthesis.cs

@ -1,251 +0,0 @@
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 VisitThrowStatement(ThrowStatement throwStatement, object data)
{
throwStatement.Expression = Deparenthesize(throwStatement.Expression);
return base.VisitThrowStatement(throwStatement, 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;
}
}
}

9
ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs

@ -1,12 +1,11 @@
using System; using System;
using Ast = ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class RestoreLoop: AbstractAstTransformer /*
public class RestoreLoop: DepthFirstAstVisitor<object, object>
{ {
public override object VisitForStatement(ForStatement forStatement, object data) public override object VisitForStatement(ForStatement forStatement, object data)
{ {
@ -71,5 +70,5 @@ namespace Decompiler.Transforms.Ast
return null; return null;
} }
} }*/
} }

68
ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs

@ -1,12 +1,10 @@
using System; using System;
using Ast = ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
public class SimplifyTypeReferences: AbstractAstTransformer public class SimplifyTypeReferences: DepthFirstAstVisitor<object, object>
{ {
string currentNamepace = string.Empty; string currentNamepace = string.Empty;
string currentClass = null; string currentClass = null;
@ -26,67 +24,5 @@ namespace Decompiler.Transforms.Ast
currentClass = null; currentClass = null;
return 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;
}
}
// we can't always remove "this", the field name might conflict with a parameter/local variable
// 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;
}
} }
} }

11
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -51,12 +51,13 @@
<ItemGroup> <ItemGroup>
<Compile Include="Ast\AstBuilder.cs" /> <Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMetodBodyBuilder.cs" /> <Compile Include="Ast\AstMetodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\Idioms.cs" /> <Compile Include="Ast\Transforms\Idioms.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" /> <Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" /> <Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" /> <Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" /> <Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RemoveParenthesis.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" /> <Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" /> <Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />
@ -96,14 +97,14 @@
<None Include="Properties\AssemblyInfo.template.cs" /> <None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup> </ItemGroup>
<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"> <ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project> <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Ast" /> <Folder Include="Ast" />

2
ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Decompiler.Mono.Cecil.Rocks;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Decompiler.Rocks;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {

2
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -2,11 +2,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Decompiler.Mono.Cecil.Rocks;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Rocks; using Mono.Cecil.Rocks;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Decompiler.Rocks;
namespace Decompiler namespace Decompiler
{ {

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

@ -11,7 +11,7 @@ using System.Collections.Generic;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
namespace Decompiler.Mono.Cecil.Rocks namespace Decompiler.Rocks
{ {
static class MyRocks static class MyRocks
{ {

12
ILSpy.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.0.1.7088 # SharpDevelop 4.0.1.7096
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}"
@ -12,8 +12,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "A
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "Decompiler\lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
EndProject EndProject
Global Global
@ -64,14 +62,6 @@ Global
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU {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.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = 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
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU

2
ILSpy/CSharpLanguage.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
output.Write(codeDomBuilder.GenerateCode()); codeDomBuilder.GenerateCode(output);
} }
} }
} }

42
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs

@ -0,0 +1,42 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Compares whether two ASTs are structurally identical.
/// </summary>
public static class AstComparer
{
static HashSet<Type> nodeTypesWithoutExtraInfo = new HashSet<Type> {
typeof(IdentifierExpression)
};
public static bool? AreEqual(AstNode node1, AstNode node2)
{
if (node1 == node2)
return true;
if (node1 == null || node1.IsNull || node2 == null || node2.IsNull)
return false;
Type nodeType = node1.GetType();
if (nodeType != node2.GetType())
return false;
if (node1.Role != node2.Role)
return false;
AstNode child1 = node1.FirstChild;
AstNode child2 = node2.FirstChild;
bool? result = true;
while (result != false && (child1 != null || child2 != null)) {
result &= AreEqual(child1, child2);
}
if (nodeTypesWithoutExtraInfo.Contains(nodeType))
return result;
if (nodeType == typeof(Identifier))
return ((Identifier)node1).Name == ((Identifier)node2).Name;
return null;
}
}
}

55
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs

@ -28,5 +28,60 @@ namespace ICSharpCode.NRefactory.CSharp
public override NodeType NodeType { public override NodeType NodeType {
get { return NodeType.TypeReference; } get { return NodeType.TypeReference; }
} }
public virtual AstType MakePointerType()
{
return new ComposedType { BaseType = this }.MakePointerType();
}
public virtual AstType MakeArrayType(int rank)
{
return new ComposedType { BaseType = this }.MakeArrayType(rank);
}
/// <summary>
/// Builds an expression that can be used to access a static member on this type.
/// </summary>
public MemberReferenceExpression Member(string memberName)
{
return new TypeReferenceExpression { Type = this }.Member(memberName);
}
public static AstType Create(Type type)
{
switch (Type.GetTypeCode(type)) {
case TypeCode.Object:
return new PrimitiveType("object");
case TypeCode.Boolean:
return new PrimitiveType("bool");
case TypeCode.Char:
return new PrimitiveType("char");
case TypeCode.SByte:
return new PrimitiveType("sbyte");
case TypeCode.Byte:
return new PrimitiveType("byte");
case TypeCode.Int16:
return new PrimitiveType("short");
case TypeCode.UInt16:
return new PrimitiveType("ushort");
case TypeCode.Int32:
return new PrimitiveType("int");
case TypeCode.UInt32:
return new PrimitiveType("uint");
case TypeCode.Int64:
return new PrimitiveType("long");
case TypeCode.UInt64:
return new PrimitiveType("ulong");
case TypeCode.Single:
return new PrimitiveType("float");
case TypeCode.Double:
return new PrimitiveType("double");
case TypeCode.Decimal:
return new PrimitiveType("decimal");
case TypeCode.String:
return new PrimitiveType("string");
}
return new SimpleType(type.FullName); // TODO: implement this correctly
}
} }
} }

39
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs

@ -55,12 +55,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildrenByRole(PointerRole).Count(); return GetChildrenByRole(PointerRole).Count();
} }
set { set {
// remove old children int d = this.PointerRank;
foreach (AstNode node in GetChildrenByRole(PointerRole)) while (d > value) {
node.Remove(); GetChildByRole(PointerRole).Remove();
// add new children d--;
for (int i = 0; i < value; i++) { }
AddChild(new CSharpTokenNode(AstLocation.Empty, 1), PointerRole); while (d < value) {
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(AstLocation.Empty, 1), PointerRole);
d++;
} }
} }
} }
@ -89,6 +91,22 @@ namespace ICSharpCode.NRefactory.CSharp
} }
return b.ToString(); return b.ToString();
} }
public override AstType MakePointerType()
{
if (ArraySpecifiers.Any()) {
return base.MakePointerType();
} else {
this.PointerRank++;
return this;
}
}
public override AstType MakeArrayType(int dimensions)
{
InsertChildBefore(this.ArraySpecifiers.FirstOrDefault(), new ArraySpecifier(dimensions), ArraySpecifierRole);
return this;
}
} }
/// <summary> /// <summary>
@ -102,6 +120,15 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public ArraySpecifier()
{
}
public ArraySpecifier(int dimensions)
{
this.Dimensions = dimensions;
}
public int Dimensions { public int Dimensions {
get { return 1 + GetChildrenByRole(Roles.Comma).Count(); } get { return 1 + GetChildrenByRole(Roles.Comma).Count(); }
set { set {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs

@ -445,6 +445,11 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (typeOfExpression, data); return VisitChildren (typeOfExpression, data);
} }
public virtual S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, T data)
{
return VisitChildren (typeReferenceExpression, data);
}
public virtual S VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression, T data) public virtual S VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression, T data)
{ {
return VisitChildren (unaryOperatorExpression, data); return VisitChildren (unaryOperatorExpression, data);

34
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs

@ -108,20 +108,54 @@ namespace ICSharpCode.NRefactory.CSharp
}; };
} }
/// <summary>
/// Builds an invocation expression using this expression as target.
/// </summary>
public InvocationExpression Invoke(IEnumerable<Expression> arguments)
{
return new InvocationExpression {
Target = this,
Arguments = arguments
};
}
/// <summary>
/// Builds an invocation expression using this expression as target.
/// </summary>
public InvocationExpression Invoke(params Expression[] arguments)
{
return Invoke(arguments.AsEnumerable());
}
public CastExpression CastTo(AstType type) public CastExpression CastTo(AstType type)
{ {
return new CastExpression { Type = type, Expression = this }; return new CastExpression { Type = type, Expression = this };
} }
public CastExpression CastTo(Type type)
{
return new CastExpression { Type = AstType.Create(type), Expression = this };
}
public AsExpression CastAs(AstType type) public AsExpression CastAs(AstType type)
{ {
return new AsExpression { Type = type, Expression = this }; return new AsExpression { Type = type, Expression = this };
} }
public AsExpression CastAs(Type type)
{
return new AsExpression { Type = AstType.Create(type), Expression = this };
}
public IsExpression IsType(AstType type) public IsExpression IsType(AstType type)
{ {
return new IsExpression { Type = type, Expression = this }; return new IsExpression { Type = type, Expression = this };
} }
public IsExpression IsType(Type type)
{
return new IsExpression { Type = AstType.Create(type), Expression = this };
}
#endregion #endregion
} }
} }

24
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs

@ -0,0 +1,24 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Represents an AstType as an expression.
/// This is used when calling a method on a primitive type: "int.Parse()"
/// </summary>
public class TypeReferenceExpression : Expression
{
public AstType Type {
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
public override S AcceptVisitor<T, S>(AstVisitor<T, S> visitor, T data)
{
return visitor.VisitTypeReferenceExpression(this, data);
}
}
}

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs

@ -69,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public Comment (string content, CommentType type = CommentType.SingleLine)
{
this.CommentType = type;
this.Content = content;
}
public Comment (CommentType commentType, AstLocation startLocation, AstLocation endLocation) public Comment (CommentType commentType, AstLocation startLocation, AstLocation endLocation)
{ {
this.CommentType = commentType; this.CommentType = commentType;

1
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/IAstVisitor.cs

@ -39,6 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitStackAllocExpression(StackAllocExpression stackAllocExpression, T data); S VisitStackAllocExpression(StackAllocExpression stackAllocExpression, T data);
S VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, T data); S VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, T data);
S VisitTypeOfExpression(TypeOfExpression typeOfExpression, T data); S VisitTypeOfExpression(TypeOfExpression typeOfExpression, T data);
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, T data);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, T data); S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, T data);
S VisitUncheckedExpression(UncheckedExpression uncheckedExpression, T data); S VisitUncheckedExpression(UncheckedExpression uncheckedExpression, T data);

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs

@ -81,6 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild(new ExpressionStatement { Expression = expression }, StatementRole); AddChild(new ExpressionStatement { Expression = expression }, StatementRole);
} }
public void AddStatements(IEnumerable<Statement> statements)
{
foreach (Statement st in statements)
AddChild(st, StatementRole);
}
public void AddAssignment(Expression left, Expression right) public void AddAssignment(Expression left, Expression right)
{ {
AddStatement(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right }); AddStatement(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right });

8
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs

@ -74,9 +74,13 @@ namespace ICSharpCode.NRefactory.CSharp
return visitor.VisitGotoStatement (this, data); return visitor.VisitGotoStatement (this, data);
} }
public GotoStatement (GotoType gotoType) public GotoStatement ()
{ {
this.GotoType = gotoType; }
public GotoStatement (string label)
{
this.Label = label;
} }
} }

11
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs

@ -73,5 +73,16 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
return visitor.VisitIfElseStatement (this, data); return visitor.VisitIfElseStatement (this, data);
} }
public IfElseStatement()
{
}
public IfElseStatement(Expression condition, Statement trueStatement, Statement falseStatement = null)
{
this.Condition = condition;
this.TrueStatement = trueStatement;
this.FalseStatement = falseStatement;
}
} }
} }

10
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs

@ -33,6 +33,16 @@ namespace ICSharpCode.NRefactory.CSharp
return NodeType.Unknown; return NodeType.Unknown;
} }
} }
public VariableInitializer()
{
}
public VariableInitializer(string name, Expression initializer = null)
{
this.Name = name;
this.Initializer = initializer;
}
public string Name { public string Name {
get { get {

7
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -893,6 +893,13 @@ namespace ICSharpCode.NRefactory.CSharp
return EndNode(typeOfExpression); return EndNode(typeOfExpression);
} }
public object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
{
StartNode(typeReferenceExpression);
typeReferenceExpression.Type.AcceptVisitor(this, data);
return EndNode(typeReferenceExpression);
}
public object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) public object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{ {
StartNode(unaryOperatorExpression); StartNode(unaryOperatorExpression);

9
NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs

@ -1009,7 +1009,8 @@ namespace ICSharpCode.NRefactory.CSharp
public override object Visit (Goto gotoStatement) public override object Visit (Goto gotoStatement)
{ {
var result = new GotoStatement (GotoType.Label); var result = new GotoStatement ();
result.GotoType = GotoType.Label;
var location = LocationsBag.GetLocations (gotoStatement); var location = LocationsBag.GetLocations (gotoStatement);
result.AddChild (new CSharpTokenNode (Convert (gotoStatement.loc), "goto".Length), GotoStatement.Roles.Keyword); result.AddChild (new CSharpTokenNode (Convert (gotoStatement.loc), "goto".Length), GotoStatement.Roles.Keyword);
result.AddChild (new Identifier (gotoStatement.Target, Convert (gotoStatement.loc)), GotoStatement.Roles.Identifier); result.AddChild (new Identifier (gotoStatement.Target, Convert (gotoStatement.loc)), GotoStatement.Roles.Identifier);
@ -1028,7 +1029,8 @@ namespace ICSharpCode.NRefactory.CSharp
public override object Visit (GotoDefault gotoDefault) public override object Visit (GotoDefault gotoDefault)
{ {
var result = new GotoStatement (GotoType.CaseDefault); var result = new GotoStatement ();
result.GotoType = GotoType.CaseDefault;
result.AddChild (new CSharpTokenNode (Convert (gotoDefault.loc), "goto".Length), GotoStatement.Roles.Keyword); result.AddChild (new CSharpTokenNode (Convert (gotoDefault.loc), "goto".Length), GotoStatement.Roles.Keyword);
var location = LocationsBag.GetLocations (gotoDefault); var location = LocationsBag.GetLocations (gotoDefault);
if (location != null) { if (location != null) {
@ -1041,7 +1043,8 @@ namespace ICSharpCode.NRefactory.CSharp
public override object Visit (GotoCase gotoCase) public override object Visit (GotoCase gotoCase)
{ {
var result = new GotoStatement (GotoType.Case); var result = new GotoStatement ();
result.GotoType = GotoType.Case;
result.AddChild (new CSharpTokenNode (Convert (gotoCase.loc), "goto".Length), GotoStatement.Roles.Keyword); result.AddChild (new CSharpTokenNode (Convert (gotoCase.loc), "goto".Length), GotoStatement.Roles.Keyword);
var location = LocationsBag.GetLocations (gotoCase); var location = LocationsBag.GetLocations (gotoCase);

2
NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -55,6 +55,8 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CSharp\Ast\AstComparer.cs" />
<Compile Include="CSharp\Ast\Expressions\TypeReferenceExpression.cs" />
<Compile Include="CSharp\Ast\IAstVisitor.cs" /> <Compile Include="CSharp\Ast\IAstVisitor.cs" />
<Compile Include="CSharp\Ast\CompilationUnit.cs" /> <Compile Include="CSharp\Ast\CompilationUnit.cs" />
<Compile Include="CSharp\Ast\CSharpModifierToken.cs" /> <Compile Include="CSharp\Ast\CSharpModifierToken.cs" />

Loading…
Cancel
Save