Browse Source

Initial port to new NRefactory.

pull/10/head
Daniel Grunwald 14 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; @@ -2,11 +2,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.PrettyPrinter;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
using Mono.Cecil.Cil;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
namespace Decompiler
{
@ -15,78 +15,44 @@ namespace Decompiler @@ -15,78 +15,44 @@ namespace Decompiler
CompilationUnit astCompileUnit = new CompilationUnit();
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++) {
if (Options.ReduceAstJumps) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
}
if (Options.ReduceAstLoops) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
}
}
if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null);
}
if (Options.ReduceAstLoops) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
astCompileUnit.AcceptVisitor(csOutVisitor, null);
string code = csOutVisitor.Text;
for(int i = 10; i >= 0; i--) {
code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {");
}
code = code.Replace("\t", " ");
code = code.Replace("\"/***", "");
code = code.Replace("***/\";", "");
// Post processing commands
while(true) {
int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length;
if (endIndex != -1) {
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex);
if (startIndex != -1) {
code = code.Remove(startIndex, endIndex - startIndex);
continue;
}
}
break;
}
while(true) {
int endIndex = code.IndexOf("[Tab]");
if (endIndex != -1) {
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex);
if (startIndex != -1) {
code = code.Remove(endIndex, "[Tab]".Length);
code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex)));
continue;
}
}
break;
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
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)
{
Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System");
astCompileUnit.Children.Add(astUsing);
astCompileUnit.AddChild(
new UsingDeclaration {
Import = new SimpleType("System")
}, CompilationUnit.MemberRole);
foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
// Skip nested types - they will be added by the parent type
@ -107,8 +73,8 @@ namespace Decompiler @@ -107,8 +73,8 @@ namespace Decompiler
return astNamespaces[name];
} else {
// Create the namespace
NamespaceDeclaration astNamespace = new NamespaceDeclaration(name);
astCompileUnit.Children.Add(astNamespace);
NamespaceDeclaration astNamespace = new NamespaceDeclaration { Name = name };
astCompileUnit.AddChild(astNamespace, CompilationUnit.MemberRole);
astNamespaces[name] = astNamespace;
return astNamespace;
}
@ -119,42 +85,137 @@ namespace Decompiler @@ -119,42 +85,137 @@ namespace Decompiler
TypeDeclaration astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) {
astNS.Children.Add(astType);
astNS.AddChild(astType, NamespaceDeclaration.MemberRole);
} else {
astCompileUnit.Children.Add(astType);
astCompileUnit.AddChild(astType, CompilationUnit.MemberRole);
}
}
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;
if (typeDef.IsEnum) { // NB: Enum is value type
astType.Type = ClassType.Enum;
astType.ClassType = ClassType.Enum;
} else if (typeDef.IsValueType) {
astType.Type = ClassType.Struct;
astType.ClassType = ClassType.Struct;
} else if (typeDef.IsInterface) {
astType.Type = ClassType.Interface;
astType.ClassType = ClassType.Interface;
} else {
astType.Type = ClassType.Class;
astType.ClassType = ClassType.Class;
}
// Nested types
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
astType.Children.Add(CreateType(nestedTypeDef));
astType.AddChild(CreateType(nestedTypeDef), TypeDeclaration.MemberRole);
}
// Base type
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);
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)
{
return
@ -194,118 +255,107 @@ namespace Decompiler @@ -194,118 +255,107 @@ namespace Decompiler
(methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) |
(methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None);
}
#endregion
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
{
// Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) {
Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List<AttributeSection>());
astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name));
astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName);
astField.Modifier = ConvertModifiers(fieldDef);
astType.Children.Add(astField);
}
if (typeDef.Fields.Count > 0) {
astType.Children.Add(new IdentifierExpression("\r\n"));
astType.AddChild(CreateField(fieldDef), TypeDeclaration.MemberRole);
}
// Add events
foreach(EventDefinition eventDef in typeDef.Events) {
Ast.EventDeclaration astEvent = new Ast.EventDeclaration();
astEvent.Name = eventDef.Name;
astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName);
astEvent.Modifier = ConvertModifiers(eventDef.AddMethod);
astType.Children.Add(astEvent);
}
if (typeDef.Events.Count > 0) {
astType.Children.Add(new IdentifierExpression("\r\n"));
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
}
// Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) {
Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration(
ConvertModifiers(propDef.GetMethod),
new List<AttributeSection>(),
propDef.Name,
new List<ParameterDeclarationExpression>()
);
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName);
if (propDef.GetMethod != null) {
astProp.GetRegion = new PropertyGetRegion(
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod),
new List<AttributeSection>()
);
}
if (propDef.SetMethod != null) {
astProp.SetRegion = new PropertySetRegion(
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod),
new List<AttributeSection>()
);
}
astType.Children.Add(astProp);
}
if (typeDef.Properties.Count > 0) {
astType.Children.Add(new IdentifierExpression("\r\n"));
astType.AddChild(CreateProperty(propDef), TypeDeclaration.MemberRole);
}
// Add constructors
foreach(MethodDefinition methodDef in typeDef.Methods) {
if (!methodDef.IsConstructor) continue;
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration(
methodDef.Name,
ConvertModifiers(methodDef),
new List<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)),
new List<AttributeSection>()
);
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef);
astType.Children.Add(astMethod);
astType.Children.Add(new IdentifierExpression("\r\n"));
astType.AddChild(CreateConstructor(methodDef), TypeDeclaration.MemberRole);
}
// Add methods
foreach(MethodDefinition methodDef in typeDef.Methods) {
if (methodDef.IsSpecialName) continue;
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration();
astMethod.Name = methodDef.Name;
astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName);
astMethod.Modifier = ConvertModifiers(methodDef);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef);
astType.Children.Add(astMethod);
astType.Children.Add(new IdentifierExpression("\r\n"));
astType.AddChild(CreateMethod(methodDef), TypeDeclaration.MemberRole);
}
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) {
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression(
new Ast.TypeReference(paramDef.ParameterType.FullName),
paramDef.Name
);
ParameterDeclaration astParam = new ParameterDeclaration();
astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
astParam.Name = paramDef.Name;
if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In;
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out;
if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref;
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Out;
if (paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Ref;
// TODO: params, this
yield return astParam;
}

577
ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs

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

38
ICSharpCode.Decompiler/Ast/CommentStatement.cs

@ -0,0 +1,38 @@ @@ -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 @@ @@ -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 @@ @@ -1,32 +1,29 @@
using System;
using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using System.Linq;
using Mono.Cecil;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast
{
public class Idioms: AbstractAstTransformer
public class Idioms: DepthFirstAstVisitor<object, object>
{
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
base.VisitInvocationExpression(invocationExpression, data);
MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
// Reduce "String.Concat(a, b)" to "a + b"
MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression;
if (target != null &&
target.MemberName == "Concat" &&
invocationExpression.Arguments.Count == 2 &&
target.TargetObject is IdentifierExpression &&
(target.TargetObject as IdentifierExpression).Identifier == "String")
if (methodRef != null && methodRef.FullName == "System.String.Concat"
&& methodRef.Parameters.Count >= 2)
{
ReplaceCurrentNode(
new BinaryOperatorExpression(
invocationExpression.Arguments[0],
BinaryOperatorType.Add,
invocationExpression.Arguments[1]
)
);
var arguments = invocationExpression.Arguments.ToArray();
invocationExpression.Arguments = null; // detach arguments from invocationExpression
Expression expr = arguments[0];
for (int i = 1; i < arguments.Length; i++) {
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
}
}
return null;
@ -34,43 +31,68 @@ namespace Decompiler.Transforms.Ast @@ -34,43 +31,68 @@ namespace Decompiler.Transforms.Ast
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;
if (ident != null && binary != null) {
IdentifierExpression binaryLeft = binary.Left as IdentifierExpression;
if (binaryLeft != null &&
binaryLeft.Identifier == ident.Identifier) {
if (binary.Right is PrimitiveExpression &&
1.Equals((binary.Right as PrimitiveExpression).Value)) {
if (binary.Op == BinaryOperatorType.Add) {
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement));
}
if (binary.Op == BinaryOperatorType.Subtract) {
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement));
}
} else {
if (binary.Op == BinaryOperatorType.Add) {
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right));
}
if (binary.Op == BinaryOperatorType.Subtract) {
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right));
}
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) {
if (IsWithoutSideEffects(assignment.Left) && AstComparer.AreEqual(assignment.Left, binary.Left) == true) {
switch (binary.Operator) {
case BinaryOperatorType.Add:
assignment.Operator = AssignmentOperatorType.Add;
break;
case BinaryOperatorType.Subtract:
assignment.Operator = AssignmentOperatorType.Subtract;
break;
case BinaryOperatorType.Multiply:
assignment.Operator = AssignmentOperatorType.Multiply;
break;
case BinaryOperatorType.Divide:
assignment.Operator = AssignmentOperatorType.Divide;
break;
case BinaryOperatorType.Modulus:
assignment.Operator = AssignmentOperatorType.Modulus;
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;
}
bool IsWithoutSideEffects(Expression left)
{
return left is IdentifierExpression; // TODO
}
/*
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 as MemberReferenceExpression).MemberName == "Length") {
ReplaceCurrentNode(castExpression.Expression);
return null;
}
return base.VisitCastExpression(castExpression, data);
}
}*/
}
}

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

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

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

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

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

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

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

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

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

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

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

@ -1,12 +1,10 @@ @@ -1,12 +1,10 @@
using System;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast
{
public class SimplifyTypeReferences: AbstractAstTransformer
public class SimplifyTypeReferences: DepthFirstAstVisitor<object, object>
{
string currentNamepace = string.Empty;
string currentClass = null;
@ -26,67 +24,5 @@ namespace Decompiler.Transforms.Ast @@ -26,67 +24,5 @@ namespace Decompiler.Transforms.Ast
currentClass = null;
return null;
}
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)
{
IdentifierExpression id = memberReferenceExpression.TargetObject as IdentifierExpression;
if (id != null) {
if (id.Identifier == "System" || id.Identifier == currentClass) {
ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName));
return null;
}
if (id.Identifier.StartsWith("System.")) {
id.Identifier = id.Identifier.Replace("System.", "");
return null;
}
}
// 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 @@ @@ -51,12 +51,13 @@
<ItemGroup>
<Compile Include="Ast\AstBuilder.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\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RemoveParenthesis.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="CecilExtensions.cs" />
@ -96,14 +97,14 @@ @@ -96,14 +97,14 @@
<None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Decompiler\lib\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Ast" />

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

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

2
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

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

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

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

12
ILSpy.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

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

2
ILSpy/CSharpLanguage.cs

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

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

@ -0,0 +1,42 @@ @@ -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 @@ -28,5 +28,60 @@ namespace ICSharpCode.NRefactory.CSharp
public override NodeType NodeType {
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 @@ -55,12 +55,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildrenByRole(PointerRole).Count();
}
set {
// remove old children
foreach (AstNode node in GetChildrenByRole(PointerRole))
node.Remove();
// add new children
for (int i = 0; i < value; i++) {
AddChild(new CSharpTokenNode(AstLocation.Empty, 1), PointerRole);
int d = this.PointerRank;
while (d > value) {
GetChildByRole(PointerRole).Remove();
d--;
}
while (d < value) {
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(AstLocation.Empty, 1), PointerRole);
d++;
}
}
}
@ -89,6 +91,22 @@ namespace ICSharpCode.NRefactory.CSharp @@ -89,6 +91,22 @@ namespace ICSharpCode.NRefactory.CSharp
}
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>
@ -102,6 +120,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -102,6 +120,15 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
public ArraySpecifier()
{
}
public ArraySpecifier(int dimensions)
{
this.Dimensions = dimensions;
}
public int Dimensions {
get { return 1 + GetChildrenByRole(Roles.Comma).Count(); }
set {

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

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

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

@ -108,20 +108,54 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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)
{
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)
{
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)
{
return new IsExpression { Type = type, Expression = this };
}
public IsExpression IsType(Type type)
{
return new IsExpression { Type = AstType.Create(type), Expression = this };
}
#endregion
}
}

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

@ -0,0 +1,24 @@ @@ -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 @@ -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)
{
this.CommentType = commentType;

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

@ -39,6 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -39,6 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitStackAllocExpression(StackAllocExpression stackAllocExpression, T data);
S VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, T data);
S VisitTypeOfExpression(TypeOfExpression typeOfExpression, T data);
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, T data);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, 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 @@ -81,6 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp
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)
{
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 @@ -74,9 +74,13 @@ namespace ICSharpCode.NRefactory.CSharp
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 @@ -73,5 +73,16 @@ namespace ICSharpCode.NRefactory.CSharp
{
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 @@ -33,6 +33,16 @@ namespace ICSharpCode.NRefactory.CSharp
return NodeType.Unknown;
}
}
public VariableInitializer()
{
}
public VariableInitializer(string name, Expression initializer = null)
{
this.Name = name;
this.Initializer = initializer;
}
public string Name {
get {

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

@ -893,6 +893,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -893,6 +893,13 @@ namespace ICSharpCode.NRefactory.CSharp
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)
{
StartNode(unaryOperatorExpression);

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

@ -1009,7 +1009,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1009,7 +1009,8 @@ namespace ICSharpCode.NRefactory.CSharp
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);
result.AddChild (new CSharpTokenNode (Convert (gotoStatement.loc), "goto".Length), GotoStatement.Roles.Keyword);
result.AddChild (new Identifier (gotoStatement.Target, Convert (gotoStatement.loc)), GotoStatement.Roles.Identifier);
@ -1028,7 +1029,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1028,7 +1029,8 @@ namespace ICSharpCode.NRefactory.CSharp
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);
var location = LocationsBag.GetLocations (gotoDefault);
if (location != null) {
@ -1041,7 +1043,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1041,7 +1043,8 @@ namespace ICSharpCode.NRefactory.CSharp
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);
var location = LocationsBag.GetLocations (gotoCase);

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

@ -55,6 +55,8 @@ @@ -55,6 +55,8 @@
</Reference>
</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\CompilationUnit.cs" />
<Compile Include="CSharp\Ast\CSharpModifierToken.cs" />

Loading…
Cancel
Save