Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
742ecf0d64
  1. 39
      Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs
  2. 5
      Debugger/ILSpy.Debugger/Services/Debugger/DebuggerHelper.cs
  3. 50
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  4. 253
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  5. 21
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  6. 158
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  7. 69
      ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs
  8. 19
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  9. 165
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  10. 76
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  11. 4
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  12. 4
      ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs
  13. 20
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  14. 9
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  15. 114
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  16. 20
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  17. 81
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  18. 424
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  19. 508
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  20. 15
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs
  21. 478
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs
  22. 359
      ICSharpCode.Decompiler/Mono.Cecil.Rocks/MyRocks.cs
  23. 41
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  24. 66
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  25. 30
      ICSharpCode.Decompiler/Tests/Loops.cs
  26. 101
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  27. 10
      ILSpy.sln
  28. 63
      ILSpy/BamlDecompiler.cs
  29. 45
      ILSpy/CSharpLanguage.cs
  30. 26
      ILSpy/ILAstLanguage.cs
  31. 2
      ILSpy/ILSpy.csproj
  32. 2
      ILSpy/TextView/DecompilerTextView.cs
  33. 3
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  34. 122
      ILSpy/TreeNodes/ResourceEntryNode.cs
  35. 23
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  36. 31
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs
  37. 156
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs
  38. 3
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs
  39. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs
  40. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs
  41. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs
  42. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs
  43. 39
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs
  44. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs
  45. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs
  46. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs
  47. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs
  48. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs
  49. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs
  50. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs
  51. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs
  52. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs
  53. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs
  54. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs
  55. 11
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs
  56. 10
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
  57. 14
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs
  58. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs
  59. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs
  60. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs
  61. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs
  62. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs
  63. 11
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs
  64. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs
  65. 15
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs
  66. 3
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs
  67. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs
  68. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs
  69. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs
  70. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs
  71. 11
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs
  72. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs
  73. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs
  74. 4
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
  75. 4
      NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs
  76. 3
      NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  77. 1
      README.txt

39
Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs

@ -79,7 +79,7 @@ namespace ICSharpCode.NRefactory.Ast
foreach(int index in indices) { foreach(int index in indices) {
args.Add(new PrimitiveExpression(index)); args.Add(new PrimitiveExpression(index));
} }
indexerExpr.Arguments = args; //indexerExpr.Arguments = args;
DebugType staticType = expression.GetStaticType(); DebugType staticType = expression.GetStaticType();
if (staticType != null && staticType.IsArray) if (staticType != null && staticType.IsArray)
@ -108,7 +108,10 @@ namespace ICSharpCode.NRefactory.Ast
if (memberInfo is MethodInfo) { if (memberInfo is MethodInfo) {
var mre = new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }; var mre = new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name };
var ie = new InvocationExpression() { Target = mre, Arguments = AddExplicitTypes((MethodInfo)memberInfo, args) }; var ie = new InvocationExpression() {
Target = mre/*,
Arguments = AddExplicitTypes((MethodInfo)memberInfo, args) */
};
return ie.SetStaticType(memberInfo.MemberType); return ie.SetStaticType(memberInfo.MemberType);
} }
@ -118,7 +121,12 @@ namespace ICSharpCode.NRefactory.Ast
if (args.Length > 0) { if (args.Length > 0) {
if (memberInfo.Name != "Item") if (memberInfo.Name != "Item")
throw new DebuggerException("Arguments expected only for the Item property"); throw new DebuggerException("Arguments expected only for the Item property");
return (new IndexerExpression() { Target = target, Arguments = AddExplicitTypes(propInfo.GetGetMethod() ?? propInfo.GetSetMethod(), args) }).SetStaticType(memberInfo.MemberType); return (new IndexerExpression() {
Target = target/*,
Arguments = AddExplicitTypes(propInfo.GetGetMethod() ?? propInfo.GetSetMethod()
, args) */
}
).SetStaticType(memberInfo.MemberType);
} else { } else {
return (new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }).SetStaticType(memberInfo.MemberType); return (new MemberReferenceExpression() { Target = target, MemberName = memberInfo.Name }).SetStaticType(memberInfo.MemberType);
} }
@ -198,19 +206,19 @@ namespace ICSharpCode.NRefactory.Ast
var outterRef = type.DeclaringType.GetTypeReference(); var outterRef = type.DeclaringType.GetTypeReference();
var innerRef = new ComposedType() { var innerRef = new ComposedType() {
PointerRank = pointerNest, PointerRank = pointerNest,
ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)), //ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)),
BaseType = new MemberType() { // BaseType = new MemberType() {
Target = outterRef, MemberName = name, TypeArguments = genTypeRefs } // Target = outterRef, MemberName = name, TypeArguments = genTypeRefs }
}; };
return innerRef.SetStaticType((DebugType)type); return innerRef.SetStaticType((DebugType)type);
} else { } else {
return (new ComposedType() { return (new ComposedType() {
PointerRank = pointerNest, PointerRank = pointerNest,
ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)), //ArraySpecifiers = arrayRanks.ConvertAll(r => new ArraySpecifier(r)),
BaseType = new SimpleType() { BaseType = new SimpleType() {
Identifier = name, Identifier = name,
TypeArguments = genTypeRefs }}).SetStaticType((DebugType)type); /*TypeArguments = genTypeRefs*/ }}).SetStaticType((DebugType)type);
} }
} }
@ -223,13 +231,14 @@ namespace ICSharpCode.NRefactory.Ast
{ {
if (expr is IdentifierExpression) { if (expr is IdentifierExpression) {
return new SimpleType() { return new SimpleType() {
Identifier = ((IdentifierExpression)expr).Identifier, Identifier = ((IdentifierExpression)expr).Identifier/*,
TypeArguments = ((IdentifierExpression)expr).TypeArguments}; TypeArguments = ((IdentifierExpression)expr).TypeArguments*/
};
} else if (expr is MemberReferenceExpression) { } else if (expr is MemberReferenceExpression) {
var outter = NormalizeTypeReference(((MemberReferenceExpression)expr).Target); var outter = NormalizeTypeReference(((MemberReferenceExpression)expr).Target);
return new MemberType() { Target = outter, return new MemberType() { Target = outter,
MemberName = ((MemberReferenceExpression)expr).MemberName, MemberName = ((MemberReferenceExpression)expr).MemberName/*,
TypeArguments = ((MemberReferenceExpression)expr).TypeArguments }; TypeArguments = ((MemberReferenceExpression)expr).TypeArguments*/ };
} else if (expr is TypeReferenceExpression) { } else if (expr is TypeReferenceExpression) {
return NormalizeTypeReference(((TypeReferenceExpression)expr).Type); return NormalizeTypeReference(((TypeReferenceExpression)expr).Type);
} else if (expr is ComposedType) { // Frist - it is also TypeReference } else if (expr is ComposedType) { // Frist - it is also TypeReference
@ -243,12 +252,12 @@ namespace ICSharpCode.NRefactory.Ast
var newRef = NormalizeTypeReference(typeRef.BaseType) as ComposedType; var newRef = NormalizeTypeReference(typeRef.BaseType) as ComposedType;
foreach(string name in names) { foreach(string name in names) {
newRef = new ComposedType() { newRef = new ComposedType() {
BaseType = new SimpleType() { Identifier = name, TypeArguments = new List<AstType>() } BaseType = new SimpleType() { Identifier = name/*, TypeArguments = new List<AstType>() */}
}; };
} }
//(((MemberType)newRef).TypeArguments as List<AstType>).AddRange(typeRef.TypeArguments); //(((MemberType)newRef).TypeArguments as List<AstType>).AddRange(typeRef.TypeArguments);
newRef.PointerRank = typeRef.PointerRank; newRef.PointerRank = typeRef.PointerRank;
newRef.ArraySpecifiers = typeRef.ArraySpecifiers; //newRef.ArraySpecifiers = typeRef.ArraySpecifiers;
return newRef; return newRef;
} }
// else if (expr is SimpleType) { // else if (expr is SimpleType) {
@ -309,7 +318,7 @@ namespace ICSharpCode.NRefactory.Ast
//FIXME genTypeRefs = ((MemberType)typeRef).CombineToNormalTypeReference().TypeArguments as List<AstType>; //FIXME genTypeRefs = ((MemberType)typeRef).CombineToNormalTypeReference().TypeArguments as List<AstType>;
} else { } else {
if (typeRef is SimpleType) { if (typeRef is SimpleType) {
genTypeRefs = ((SimpleType)typeRef).TypeArguments as List<AstType>; //genTypeRefs = ((SimpleType)typeRef).TypeArguments as List<AstType>;
} }
} }

5
Debugger/ILSpy.Debugger/Services/Debugger/DebuggerHelper.cs

@ -28,7 +28,10 @@ namespace ILSpy.Debugger.Services.Debugger
var iEnumerableType = DebugType.CreateFromType(itemType.AppDomain, typeof(IEnumerable<>), itemType); var iEnumerableType = DebugType.CreateFromType(itemType.AppDomain, typeof(IEnumerable<>), itemType);
// explicitely cast the variable to IEnumerable<T>, where T is itemType // explicitely cast the variable to IEnumerable<T>, where T is itemType
Expression iEnumerableVariableExplicitCast = new CastExpression { Expression = iEnumerableVariable , Type = iEnumerableType.GetTypeReference() }; Expression iEnumerableVariableExplicitCast = new CastExpression { Expression = iEnumerableVariable , Type = iEnumerableType.GetTypeReference() };
return new ObjectCreateExpression() { Type = listType.GetTypeReference(), Arguments = iEnumerableVariableExplicitCast.ToList() }; return new ObjectCreateExpression() {
Type = listType.GetTypeReference()/*,
Arguments = iEnumerableVariableExplicitCast.ToList() */
};
} }
/// <summary> /// <summary>

50
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -12,9 +13,17 @@ namespace Decompiler
{ {
public class AstBuilder public class AstBuilder
{ {
DecompilerContext context = new DecompilerContext();
CompilationUnit astCompileUnit = new CompilationUnit(); CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
public AstBuilder(DecompilerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void GenerateCode(ITextOutput output) public void GenerateCode(ITextOutput output)
{ {
GenerateCode(output, null); GenerateCode(output, null);
@ -22,7 +31,7 @@ namespace Decompiler
public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition) public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition)
{ {
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition); Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, context);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null); astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output); var outputFormatter = new TextOutputFormatter(output);
@ -103,6 +112,7 @@ namespace Decompiler
public TypeDeclaration CreateType(TypeDefinition typeDef) public TypeDeclaration CreateType(TypeDefinition typeDef)
{ {
TypeDeclaration astType = new TypeDeclaration(); TypeDeclaration astType = new TypeDeclaration();
astType.AddAnnotation(typeDef);
astType.Modifiers = ConvertModifiers(typeDef); astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = typeDef.Name; astType.Name = typeDef.Name;
@ -138,7 +148,7 @@ namespace Decompiler
} }
} else { } else {
// Base type // Base type
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != "System.Object") {
astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole); astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole);
} }
foreach (var i in typeDef.Interfaces) foreach (var i in typeDef.Interfaces)
@ -188,6 +198,13 @@ namespace Decompiler
.MakeArrayType((type as Mono.Cecil.ArrayType).Rank); .MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type; GenericInstanceType gType = (GenericInstanceType)type;
if (gType.ElementType.Namespace == "System" && gType.ElementType.Name == "Nullable`1" && gType.GenericArguments.Count == 1) {
typeIndex++;
return new ComposedType {
BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex),
HasNullableSpecifier = true
};
}
AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex); AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex);
foreach (var typeArgument in gType.GenericArguments) { foreach (var typeArgument in gType.GenericArguments) {
typeIndex++; typeIndex++;
@ -407,12 +424,13 @@ namespace Decompiler
MethodDeclaration CreateMethod(MethodDefinition methodDef) MethodDeclaration CreateMethod(MethodDefinition methodDef)
{ {
MethodDeclaration astMethod = new MethodDeclaration(); MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.Name = methodDef.Name; astMethod.Name = methodDef.Name;
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType); astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
if (!methodDef.DeclaringType.IsInterface) { if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
} }
return astMethod; return astMethod;
} }
@ -420,31 +438,33 @@ namespace Decompiler
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{ {
ConstructorDeclaration astMethod = new ConstructorDeclaration(); ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsStatic) { if (methodDef.IsStatic) {
// don't show visibility for static ctors // don't show visibility for static ctors
astMethod.Modifiers &= ~Modifiers.VisibilityMask; astMethod.Modifiers &= ~Modifiers.VisibilityMask;
} }
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
return astMethod; return astMethod;
} }
PropertyDeclaration CreateProperty(PropertyDefinition propDef) PropertyDeclaration CreateProperty(PropertyDefinition propDef)
{ {
PropertyDeclaration astProp = new PropertyDeclaration(); PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef);
astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod); astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod);
astProp.Name = propDef.Name; astProp.Name = propDef.Name;
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
astProp.Getter = new Accessor { astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}; }.WithAnnotation(propDef.GetMethod);
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
astProp.Setter = new Accessor { astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}; }.WithAnnotation(propDef.SetMethod);
} }
return astProp; return astProp;
} }
@ -452,18 +472,19 @@ namespace Decompiler
CustomEventDeclaration CreateEvent(EventDefinition eventDef) CustomEventDeclaration CreateEvent(EventDefinition eventDef)
{ {
CustomEventDeclaration astEvent = new CustomEventDeclaration(); CustomEventDeclaration astEvent = new CustomEventDeclaration();
astEvent.AddAnnotation(eventDef);
astEvent.Name = eventDef.Name; astEvent.Name = eventDef.Name;
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod) Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context)
}; }.WithAnnotation(eventDef.AddMethod);
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod) Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context)
}; }.WithAnnotation(eventDef.RemoveMethod);
} }
return astEvent; return astEvent;
} }
@ -471,6 +492,7 @@ namespace Decompiler
FieldDeclaration CreateField(FieldDefinition fieldDef) FieldDeclaration CreateField(FieldDefinition fieldDef)
{ {
FieldDeclaration astField = new FieldDeclaration(); FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(fieldDef.Name); VariableInitializer initializer = new VariableInitializer(fieldDef.Name);
astField.AddChild(initializer, FieldDeclaration.Roles.Variable); astField.AddChild(initializer, FieldDeclaration.Roles.Variable);
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef); astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);

253
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -2,12 +2,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading;
using Ast = ICSharpCode.NRefactory.CSharp; using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Decompiler.ControlFlow; using Decompiler.ControlFlow;
namespace Decompiler namespace Decompiler
@ -15,12 +15,20 @@ namespace Decompiler
public class AstMethodBodyBuilder public class AstMethodBodyBuilder
{ {
MethodDefinition methodDef; MethodDefinition methodDef;
TypeSystem typeSystem;
DecompilerContext context;
HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>(); HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>();
public static BlockStatement CreateMethodBody(MethodDefinition methodDef) public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context)
{ {
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
context.CurrentMethod = methodDef;
try {
AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.methodDef = methodDef; builder.methodDef = methodDef;
builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) { if (Debugger.IsAttached) {
return builder.CreateMethodBody(); return builder.CreateMethodBody();
} else { } else {
@ -32,76 +40,28 @@ namespace Decompiler
throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex);
} }
} }
} finally {
context.CurrentMethod = oldCurrentMethod;
}
} }
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> {
{ "System.Boolean", "flag" },
{ "System.Byte", "b" },
{ "System.SByte", "b" },
{ "System.Int16", "num" },
{ "System.Int32", "num" },
{ "System.Int64", "num" },
{ "System.UInt16", "num" },
{ "System.UInt32", "num" },
{ "System.UInt64", "num" },
{ "System.Single", "num" },
{ "System.Double", "num" },
{ "System.Decimal", "num" },
{ "System.String", "text" },
{ "System.Object", "obj" },
};
public BlockStatement CreateMethodBody() public BlockStatement CreateMethodBody()
{ {
if (methodDef.Body == null) return null; if (methodDef.Body == null) return null;
context.CancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder(); ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(methodDef, true); ilMethod.Body = astBuilder.Build(methodDef, true);
context.CancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer(); ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(ilMethod); bodyGraph.Optimize(context, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>();
foreach(ILVariable varDef in astBuilder.Variables) {
if (varDef.Type.FullName == Constants.Int32 && intNames.Count > 0) {
varDef.Name = intNames[0];
intNames.RemoveAt(0);
} else {
string name;
if (varDef.Type.IsArray) {
name = "array";
} else if (!typeNameToVariableNameDict.TryGetValue(varDef.Type.FullName, out name)) {
name = varDef.Type.Name;
// remove the 'I' for interfaces
if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2]))
name = name.Substring(1);
// remove the backtick (generics)
int pos = name.IndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
if (name.Length == 0)
name = "obj";
else
name = char.ToLower(name[0]) + name.Substring(1);
}
if (!typeNames.ContainsKey(name)) {
typeNames.Add(name, 0);
}
int count = ++(typeNames[name]);
if (count > 1) {
name += count.ToString();
}
varDef.Name = name;
}
// Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); NameVariables.AssignNamesToVariables(methodDef.Parameters.Select(p => p.Name), astBuilder.Variables, ilMethod);
// Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(astVar);
// astLocalVar.TypeReference = new Ast.TypeReference(varDef.VariableType.FullName);
// astBlock.Children.Add(astLocalVar);
}
context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod); Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
return astBlock; return astBlock;
@ -177,27 +137,27 @@ namespace Decompiler
ILSwitch ilSwitch = (ILSwitch)node; ILSwitch ilSwitch = (ILSwitch)node;
SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) }; SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) };
for (int i = 0; i < ilSwitch.CaseBlocks.Count; i++) { for (int i = 0; i < ilSwitch.CaseBlocks.Count; i++) {
switchStmt.AddChild(new SwitchSection() { SwitchSection section = new SwitchSection();
CaseLabels = new[] { new CaseLabel() { Expression = new PrimitiveExpression(i) } }, section.CaseLabels.Add(new CaseLabel() { Expression = new PrimitiveExpression(i) });
Statements = new[] { TransformBlock(ilSwitch.CaseBlocks[i]) } section.Statements.Add(TransformBlock(ilSwitch.CaseBlocks[i]));
}, SwitchStatement.SwitchSectionRole); switchStmt.SwitchSections.Add(section);
} }
yield return switchStmt; yield return switchStmt;
} else if (node is ILTryCatchBlock) { } else if (node is ILTryCatchBlock) {
ILTryCatchBlock tryCatchNode = ((ILTryCatchBlock)node); ILTryCatchBlock tryCatchNode = ((ILTryCatchBlock)node);
List<Ast.CatchClause> catchClauses = new List<CatchClause>(); var tryCatchStmt = new Ast.TryCatchStatement();
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) { foreach (var catchClause in tryCatchNode.CatchBlocks) {
catchClauses.Add(new Ast.CatchClause { tryCatchStmt.CatchClauses.Add(
new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType), Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = "exception", VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause) Body = TransformBlock(catchClause)
}); });
} }
yield return new Ast.TryCatchStatement { if (tryCatchNode.FinallyBlock != null)
TryBlock = TransformBlock(tryCatchNode.TryBlock), tryCatchStmt.FinallyBlock = TransformBlock(tryCatchNode.FinallyBlock);
CatchClauses = catchClauses, yield return tryCatchStmt;
FinallyBlock = tryCatchNode.FinallyBlock != null ? TransformBlock(tryCatchNode.FinallyBlock) : null
};
} else if (node is ILBlock) { } else if (node is ILBlock) {
yield return TransformBlock((ILBlock)node); yield return TransformBlock((ILBlock)node);
} else { } else {
@ -218,7 +178,7 @@ namespace Decompiler
AstNode TransformExpression(ILExpression expr) AstNode TransformExpression(ILExpression expr)
{ {
List<Ast.Expression> args = TransformExpressionArguments(expr); List<Ast.Expression> args = TransformExpressionArguments(expr);
return TransformByteCode(methodDef, expr, args); return TransformByteCode(expr, args);
} }
Ast.Expression MakeBranchCondition(ILExpression expr) Ast.Expression MakeBranchCondition(ILExpression expr)
@ -226,19 +186,42 @@ namespace Decompiler
List<Ast.Expression> args = TransformExpressionArguments(expr); List<Ast.Expression> args = TransformExpressionArguments(expr);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch(expr.OpCode.Code) { TypeReference arg1Type = args.Count >= 1 ? expr.Arguments[0].InferredType : null;
case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); switch((Code)expr.Code) {
case Code.Brtrue: return arg1; case Code.Brfalse:
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); if (arg1Type == typeSystem.Boolean)
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); else if (TypeAnalysis.IsIntegerOrEnum(typeSystem, arg1Type))
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, new PrimitiveExpression(0));
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); else
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, new NullReferenceExpression());
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); case Code.Brtrue:
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); if (arg1Type == typeSystem.Boolean)
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); return arg1;
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); else if (TypeAnalysis.IsIntegerOrEnum(typeSystem, arg1Type))
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, new PrimitiveExpression(0));
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, new NullReferenceExpression());
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);
default: throw new Exception("Bad opcode"); default: throw new Exception("Bad opcode");
} }
/* /*
@ -278,10 +261,10 @@ namespace Decompiler
*/ */
} }
AstNode TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args) AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args)
{ {
try { try {
AstNode ret = TransformByteCode_Internal(methodDef, byteCode, args); AstNode ret = TransformByteCode_Internal(byteCode, args);
// ret.UserData["Type"] = byteCode.Type; // ret.UserData["Type"] = byteCode.Type;
return ret; return ret;
} catch (NotImplementedException) { } catch (NotImplementedException) {
@ -289,7 +272,7 @@ namespace Decompiler
if (byteCode.Operand != null) { if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
} }
return new IdentifierExpression(byteCode.OpCode.Name).Invoke(args); return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args);
} }
} }
@ -318,11 +301,11 @@ namespace Decompiler
} }
} }
AstNode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args) AstNode TransformByteCode_Internal(ILExpression byteCode, List<Ast.Expression> args)
{ {
// throw new NotImplementedException(); // throw new NotImplementedException();
OpCode opCode = byteCode.OpCode; ILCode opCode = byteCode.Code;
object operand = byteCode.Operand; object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
ILExpression operandAsByteCode = operand as ILExpression; ILExpression operandAsByteCode = operand as ILExpression;
@ -336,7 +319,7 @@ namespace Decompiler
branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)); branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
} }
switch(opCode.Code) { switch((Code)opCode) {
#region Arithmetic #region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -363,15 +346,14 @@ namespace Decompiler
#endregion #endregion
#region Arrays #region Arrays
case Code.Newarr: case Code.Newarr:
operandAsTypeRef = operandAsTypeRef.MakeArrayType(0); {
return new Ast.ArrayCreateExpression { var ace = new Ast.ArrayCreateExpression();
Type = operandAsTypeRef, ace.Type = operandAsTypeRef;
Arguments = new Expression[] {arg1} ace.Arguments.Add(arg1);
}; return ace;
}
case Code.Ldlen: case Code.Ldlen:
return arg1.Member("Length"); return arg1.Member("Length");
case Code.Ldelem_I: case Code.Ldelem_I:
case Code.Ldelem_I1: case Code.Ldelem_I1:
case Code.Ldelem_I2: case Code.Ldelem_I2:
@ -493,19 +475,19 @@ namespace Decompiler
{ {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name); var expr = new Ast.IdentifierExpression(cecilMethod.Name);
expr.TypeArguments = ConvertTypeArguments(cecilMethod); expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
expr.AddAnnotation(cecilMethod); expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldftn").Invoke(expr) return new IdentifierExpression("ldftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false, methodDef.DeclaringType)); .WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
} }
case Code.Ldvirtftn: case Code.Ldvirtftn:
{ {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name); var expr = new Ast.IdentifierExpression(cecilMethod.Name);
expr.TypeArguments = ConvertTypeArguments(cecilMethod); expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
expr.AddAnnotation(cecilMethod); expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldvirtftn").Invoke(expr) return new IdentifierExpression("ldvirtftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true, methodDef.DeclaringType)); .WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
} }
case Code.Calli: throw new NotImplementedException(); case Code.Calli: throw new NotImplementedException();
@ -525,15 +507,29 @@ namespace Decompiler
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return new Ast.ThisReferenceExpression(); return new Ast.ThisReferenceExpression();
} else { } else {
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand);
} }
case Code.Ldarga: case Code.Ldarga:
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return MakeRef(new Ast.ThisReferenceExpression()); return MakeRef(new Ast.ThisReferenceExpression());
} else { } else {
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name)); return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
} }
case Code.Ldc_I4: case Code.Ldc_I4:
if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 0)
return new Ast.PrimitiveExpression(false);
else if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 1)
return new Ast.PrimitiveExpression(true);
if (byteCode.InferredType != null && byteCode.InferredType.IsValueType) {
TypeDefinition enumDefinition = byteCode.InferredType.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(field.Constant, operand))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
}
}
}
return new Ast.PrimitiveExpression(operand);
case Code.Ldc_I8: case Code.Ldc_I8:
case Code.Ldc_R4: case Code.Ldc_R4:
case Code.Ldc_R8: case Code.Ldc_R8:
@ -557,17 +553,9 @@ namespace Decompiler
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand)); .Member(((FieldReference)operand).Name).WithAnnotation(operand));
case Code.Ldloc: case Code.Ldloc:
if (operand is ILVariable) {
return new Ast.IdentifierExpression(((ILVariable)operand).Name); return new Ast.IdentifierExpression(((ILVariable)operand).Name);
} else {
return new Ast.IdentifierExpression(((VariableDefinition)operand).Name);
}
case Code.Ldloca: case Code.Ldloca:
if (operand is ILVariable) {
return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name)); return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name));
} else {
return MakeRef(new Ast.IdentifierExpression(((VariableDefinition)operand).Name));
}
case Code.Ldnull: return new Ast.NullReferenceExpression(); case Code.Ldnull: return new Ast.NullReferenceExpression();
case Code.Ldobj: throw new NotImplementedException(); case Code.Ldobj: throw new NotImplementedException();
case Code.Ldstr: return new Ast.PrimitiveExpression(operand); case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
@ -581,18 +569,21 @@ namespace Decompiler
case Code.Localloc: throw new NotImplementedException(); case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException(); case Code.Mkrefany: throw new NotImplementedException();
case Code.Newobj: case Code.Newobj:
{
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
// TODO: Ensure that the corrent overloaded constructor is called // TODO: Ensure that the corrent overloaded constructor is called
if (declaringType is ArrayType) {
/*if (declaringType is ArrayType) { shouldn't this be newarr?
return new Ast.ArrayCreateExpression { return new Ast.ArrayCreateExpression {
Type = AstBuilder.ConvertType((ArrayType)declaringType), Type = AstBuilder.ConvertType((ArrayType)declaringType),
Arguments = args Arguments = args
}; };
}*/
var oce = new Ast.ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
} }
return new Ast.ObjectCreateExpression {
Type = AstBuilder.ConvertType(declaringType),
Arguments = args
};
case Code.No: throw new NotImplementedException(); case Code.No: throw new NotImplementedException();
case Code.Nop: return null; case Code.Nop: return null;
case Code.Pop: return arg1; case Code.Pop: return arg1;
@ -600,7 +591,7 @@ namespace Decompiler
case Code.Refanytype: throw new NotImplementedException(); case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException(); case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: { case Code.Ret: {
if (methodDef.ReturnType.FullName != Constants.Void) { if (methodDef.ReturnType.FullName != "System.Void") {
arg1 = Convert(arg1, methodDef.ReturnType); arg1 = Convert(arg1, methodDef.ReturnType);
return new Ast.ReturnStatement { Expression = arg1 }; return new Ast.ReturnStatement { Expression = arg1 };
} else { } else {
@ -614,10 +605,10 @@ namespace Decompiler
ILVariable locVar = (ILVariable)operand; ILVariable locVar = (ILVariable)operand;
if (!definedLocalVars.Contains(locVar)) { if (!definedLocalVars.Contains(locVar)) {
definedLocalVars.Add(locVar); definedLocalVars.Add(locVar);
return new Ast.VariableDeclarationStatement() { return new Ast.VariableDeclarationStatement(
Type = locVar.Type != null ? AstBuilder.ConvertType(locVar.Type) : new Ast.PrimitiveType("var"), locVar.Type != null ? AstBuilder.ConvertType(locVar.Type) : new Ast.PrimitiveType("var"),
Variables = new[] { new Ast.VariableInitializer(locVar.Name, arg1) } locVar.Name,
}; arg1);
} else { } else {
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name), arg1); return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name), arg1);
} }
@ -717,25 +708,9 @@ namespace Decompiler
if (reqType == null) { if (reqType == null) {
return expr; return expr;
} else { } else {
return Convert(expr, reqType.FullName);
}
}
static Ast.Expression Convert(Ast.Expression expr, string reqType)
{
// if (expr.UserData.ContainsKey("Type")) {
// Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"];
// if (exprType == ByteCode.TypeZero &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(false, "false");
// }
// if (exprType == ByteCode.TypeOne &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(true, "true");
// }
// }
return expr; return expr;
} }
}
static Ast.Expression ConvertIntToBool(Ast.Expression astInt) static Ast.Expression ConvertIntToBool(Ast.Expression astInt)
{ {

21
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -0,0 +1,21 @@
// 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.Threading;
using Mono.Cecil;
namespace Decompiler
{
public class DecompilerContext
{
public CancellationToken CancellationToken;
public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod;
public DecompilerContext Clone()
{
return (DecompilerContext)MemberwiseClone();
}
}
}

158
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -0,0 +1,158 @@
// 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;
using System.Linq;
using Mono.Cecil;
namespace Decompiler
{
public class NameVariables
{
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> {
{ "System.Boolean", "flag" },
{ "System.Byte", "b" },
{ "System.SByte", "b" },
{ "System.Int16", "num" },
{ "System.Int32", "num" },
{ "System.Int64", "num" },
{ "System.UInt16", "num" },
{ "System.UInt32", "num" },
{ "System.UInt64", "num" },
{ "System.Single", "num" },
{ "System.Double", "num" },
{ "System.Decimal", "num" },
{ "System.String", "text" },
{ "System.Object", "obj" },
};
public static void AssignNamesToVariables(IEnumerable<string> existingNames, IEnumerable<ILVariable> variables, ILBlock methodBody)
{
NameVariables nv = new NameVariables();
nv.AddExistingNames(existingNames);
foreach (ILVariable varDef in variables) {
nv.AssignNameToVariable(varDef, methodBody.GetSelfAndChildrenRecursive<ILExpression>());
}
}
Dictionary<string, int> typeNames = new Dictionary<string, int>();
void AddExistingNames(IEnumerable<string> existingNames)
{
foreach (string name in existingNames) {
if (string.IsNullOrEmpty(name))
continue;
// First, identify whether the name already ends with a number:
int pos = name.Length;
while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9')
pos--;
if (pos < name.Length) {
int number;
if (int.TryParse(name.Substring(pos), out number)) {
string nameWithoutDigits = name.Substring(0, pos);
int existingNumber;
if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) {
typeNames[nameWithoutDigits] = Math.Max(number, existingNumber);
} else {
typeNames.Add(nameWithoutDigits, number);
}
continue;
}
}
if (!typeNames.ContainsKey(name))
typeNames.Add(name, 1);
}
}
void AssignNameToVariable(ILVariable varDef, IEnumerable<ILExpression> allExpressions)
{
string proposedName = null;
foreach (ILExpression expr in allExpressions) {
if (expr.Operand != varDef)
continue;
if (expr.Code == ILCode.Stloc) {
proposedName = GetNameFromExpression(expr.Arguments.Single());
}
if (proposedName != null)
break;
}
if (proposedName == null)
proposedName = GetNameByType(varDef.Type);
if (!typeNames.ContainsKey(proposedName)) {
typeNames.Add(proposedName, 0);
}
int count = ++typeNames[proposedName];
if (count > 1) {
varDef.Name = proposedName + count.ToString();
} else {
varDef.Name = proposedName;
}
}
static string GetNameFromExpression(ILExpression expr)
{
switch (expr.Code) {
case ILCode.Ldfld:
// Use the field name only if it's not a field on this (avoid confusion between local variables and fields)
if (!(expr.Arguments[0].Code == ILCode.Ldloc && ((ParameterDefinition)expr.Arguments[0].Operand).Index < 0))
return ((FieldReference)expr.Operand).Name;
break;
case ILCode.Ldsfld:
return ((FieldReference)expr.Operand).Name;
case ILCode.Call:
case ILCode.Callvirt:
MethodReference mr = (MethodReference)expr.Operand;
if (mr.Name.StartsWith("get_", StringComparison.Ordinal))
return CleanUpVariableName(mr.Name.Substring(4));
else if (mr.Name.StartsWith("Get", StringComparison.Ordinal) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3]))
return CleanUpVariableName(mr.Name.Substring(3));
break;
}
return null;
}
string GetNameByType(TypeReference type)
{
GenericInstanceType git = type as GenericInstanceType;
if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) {
type = ((GenericInstanceType)type).GenericArguments[0];
}
if (type.FullName == "System.Int32") {
// try i,j,k, etc.
for (char c = 'i'; c <= 'n'; c++) {
if (!typeNames.ContainsKey(c.ToString()))
return c.ToString();
}
}
string name;
if (type.IsArray) {
name = "array";
} else if (type.IsPointer) {
name = "ptr";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name;
// remove the 'I' for interfaces
if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2]))
name = name.Substring(1);
name = CleanUpVariableName(name);
}
return name;
}
static string CleanUpVariableName(string name)
{
// remove the backtick (generics)
int pos = name.IndexOf('`');
if (pos >= 0)
name = name.Substring(0, pos);
if (name.Length == 0)
return "obj";
else
return char.ToLower(name[0]) + name.Substring(1);
}
}
}

69
ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs

@ -0,0 +1,69 @@
// 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.Diagnostics;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler.Transforms
{
/// <summary>
/// Base class for AST visitors that need the current type/method context info.
/// </summary>
public abstract class ContextTrackingVisitor : DepthFirstAstVisitor<object, object>
{
protected readonly DecompilerContext context;
protected ContextTrackingVisitor(DecompilerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
TypeDefinition oldType = context.CurrentType;
try {
context.CurrentType = typeDeclaration.Annotation<TypeDefinition>();
return base.VisitTypeDeclaration(typeDeclaration, data);
} finally {
context.CurrentType = oldType;
}
}
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = methodDeclaration.Annotation<MethodDefinition>();
return base.VisitMethodDeclaration(methodDeclaration, data);
} finally {
context.CurrentMethod = null;
}
}
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = constructorDeclaration.Annotation<MethodDefinition>();
return base.VisitConstructorDeclaration(constructorDeclaration, data);
} finally {
context.CurrentMethod = null;
}
}
public override object VisitAccessor(Accessor accessor, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = accessor.Annotation<MethodDefinition>();
return base.VisitAccessor(accessor, data);
} finally {
context.CurrentMethod = null;
}
}
}
}

19
ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -28,9 +28,7 @@ namespace Decompiler.Transforms
else else
return null; return null;
// Move arguments from invocation to initializer: // Move arguments from invocation to initializer:
var arguments = invocation.Arguments.ToArray(); invocation.Arguments.MoveTo(ci.Arguments);
invocation.Arguments = null;
ci.Arguments = arguments;
// Add the initializer: // Add the initializer:
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>()); constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>());
// Remove the statement: // Remove the statement:
@ -38,5 +36,20 @@ namespace Decompiler.Transforms
} }
return null; return null;
} }
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
base.VisitTypeDeclaration(typeDeclaration, data);
// Remove single empty constructor:
var ctors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0
&& ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base
&& ctors[0].Initializer.Arguments.Count() == 0
&& ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public))
{
ctors[0].Remove();
}
return null;
}
} }
} }

165
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -2,7 +2,9 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -13,7 +15,7 @@ namespace Decompiler.Transforms
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)". /// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".
/// For anonymous methods, creates an AnonymousMethodExpression. /// For anonymous methods, creates an AnonymousMethodExpression.
/// </summary> /// </summary>
public class DelegateConstruction : DepthFirstAstVisitor<object, object> public class DelegateConstruction : ContextTrackingVisitor
{ {
internal sealed class Annotation internal sealed class Annotation
{ {
@ -22,18 +24,16 @@ namespace Decompiler.Transforms
/// </summary> /// </summary>
public readonly bool IsVirtual; public readonly bool IsVirtual;
/// <summary> public Annotation(bool isVirtual)
/// The method being decompiled.
/// </summary>
public readonly TypeDefinition ContainingType;
public Annotation(bool isVirtual, TypeDefinition containingType)
{ {
this.IsVirtual = isVirtual; this.IsVirtual = isVirtual;
this.ContainingType = containingType;
} }
} }
public DelegateConstruction(DecompilerContext context) : base(context)
{
}
public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{ {
if (objectCreateExpression.Arguments.Count() == 2) { if (objectCreateExpression.Arguments.Count() == 2) {
@ -44,14 +44,14 @@ namespace Decompiler.Transforms
IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single(); IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single();
MethodReference method = methodIdent.Annotation<MethodReference>(); MethodReference method = methodIdent.Annotation<MethodReference>();
if (method != null) { if (method != null) {
if (HandleAnonymousMethod(objectCreateExpression, obj, method, annotation.ContainingType)) if (HandleAnonymousMethod(objectCreateExpression, obj, method))
return null; return null;
// Perform the transformation to "new Action(obj.func)". // Perform the transformation to "new Action(obj.func)".
obj.Remove(); obj.Remove();
methodIdent.Remove(); methodIdent.Remove();
if (!annotation.IsVirtual && obj is ThisReferenceExpression) { if (!annotation.IsVirtual && obj is ThisReferenceExpression) {
// maybe it's getting the pointer of a base method? // maybe it's getting the pointer of a base method?
if (method.DeclaringType != annotation.ContainingType) { if (method.DeclaringType != context.CurrentType) {
obj = new BaseReferenceExpression(); obj = new BaseReferenceExpression();
} }
} }
@ -74,15 +74,13 @@ namespace Decompiler.Transforms
} }
} }
// now transform the identifier into a member reference // now transform the identifier into a member reference
var typeArguments = methodIdent.TypeArguments.ToArray(); MemberReferenceExpression mre = new MemberReferenceExpression();
methodIdent.TypeArguments = null; mre.Target = obj;
MemberReferenceExpression mre = new MemberReferenceExpression { mre.MemberName = methodIdent.Identifier;
Target = obj, methodIdent.TypeArguments.MoveTo(mre.TypeArguments);
MemberName = methodIdent.Identifier,
TypeArguments = typeArguments
};
mre.AddAnnotation(method); mre.AddAnnotation(method);
objectCreateExpression.Arguments = new [] { mre }; objectCreateExpression.Arguments.Clear();
objectCreateExpression.Arguments.Add(mre);
return null; return null;
} }
} }
@ -90,43 +88,148 @@ namespace Decompiler.Transforms
return base.VisitObjectCreateExpression(objectCreateExpression, data); return base.VisitObjectCreateExpression(objectCreateExpression, data);
} }
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef, TypeDefinition containingType) bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef)
{ {
// Anonymous methods are defined in the same assembly, so there's no need to Resolve(). // Anonymous methods are defined in the same assembly, so there's no need to Resolve().
MethodDefinition method = methodRef as MethodDefinition; MethodDefinition method = methodRef as MethodDefinition;
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal)) if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal))
return false; return false;
if (!(method.IsCompilerGenerated() || method.DeclaringType.IsCompilerGenerated())) if (!(method.IsCompilerGenerated() || IsPotentialClosure(method.DeclaringType)))
return false; return false;
TypeDefinition methodContainingType = method.DeclaringType;
// check that methodContainingType is within containingType
while (methodContainingType != containingType) {
methodContainingType = methodContainingType.DeclaringType;
if (methodContainingType == null)
return false;
}
// Decompile the anonymous method: // Decompile the anonymous method:
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction); DecompilerContext subContext = context.Clone();
subContext.CurrentMethod = method;
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext);
body.AcceptVisitor(this, null); body.AcceptVisitor(this, null);
AnonymousMethodExpression ame = new AnonymousMethodExpression(); AnonymousMethodExpression ame = new AnonymousMethodExpression();
bool isLambda = false;
if (method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) { if (method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) {
ame.HasParameterList = false; ame.HasParameterList = false;
} else { } else {
ame.HasParameterList = true; ame.HasParameterList = true;
ame.Parameters = AstBuilder.MakeParameters(method.Parameters); ame.Parameters.AddRange(AstBuilder.MakeParameters(method.Parameters));
if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) {
isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement);
} }
ame.Body = body; }
// Replace all occurrences of 'this' in the method body with the delegate's target: // Replace all occurrences of 'this' in the method body with the delegate's target:
foreach (AstNode node in body.Descendants) { foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression) if (node is ThisReferenceExpression)
node.ReplaceWith(target.Clone()); node.ReplaceWith(target.Clone());
} }
if (isLambda) {
LambdaExpression lambda = new LambdaExpression();
ame.Parameters.MoveTo(lambda.Parameters);
Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression;
returnExpr.Remove();
lambda.Body = returnExpr;
objectCreateExpression.ReplaceWith(lambda);
} else {
ame.Body = body;
objectCreateExpression.ReplaceWith(ame); objectCreateExpression.ReplaceWith(ame);
}
return true;
}
bool IsPotentialClosure(TypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGenerated())
return false;
// check that methodContainingType is within containingType
while (potentialDisplayClass != context.CurrentType) {
potentialDisplayClass = potentialDisplayClass.DeclaringType;
if (potentialDisplayClass == null)
return false;
}
return true;
}
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
base.VisitBlockStatement(blockStatement, data);
foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>()) {
if (stmt.Variables.Count() != 1)
continue;
var variable = stmt.Variables.Single();
TypeDefinition type = stmt.Type.Annotation<TypeDefinition>();
if (!IsPotentialClosure(type))
continue;
ObjectCreateExpression oce = variable.Initializer as ObjectCreateExpression;
if (oce == null || oce.Type.Annotation<TypeReference>() != type || oce.Arguments.Any() || !oce.Initializer.IsNull)
continue;
// Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
bool ok = true;
foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
if (identExpr.Identifier == variable.Name) {
if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation<FieldReference>() != null))
ok = false;
}
}
if (!ok)
continue;
Dictionary<string, Expression> dict = new Dictionary<string, Expression>();
// Delete the variable declaration statement:
AstNode cur;
AstNode next = stmt.NextSibling;
stmt.Remove();
for (cur = next; cur != null; cur = next) {
next = cur.NextSibling;
// Delete any following statements as long as they assign simple variables to the display class:
// Test for the pattern:
// "variableName.MemberName = right;"
ExpressionStatement es = cur as ExpressionStatement;
if (es == null)
break;
AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae == null || ae.Operator != AssignmentOperatorType.Assign)
break;
MemberReferenceExpression left = ae.Left as MemberReferenceExpression;
if (left == null || !IsParameter(ae.Right))
break;
if (!(left.Target is IdentifierExpression) || (left.Target as IdentifierExpression).Identifier != variable.Name)
break;
dict[left.MemberName] = ae.Right;
es.Remove();
}
// Now create variables for all fields of the display class (except for those that we already handled)
foreach (FieldDefinition field in type.Fields) {
if (dict.ContainsKey(field.Name))
continue;
VariableDeclarationStatement newVarDecl = new VariableDeclarationStatement();
newVarDecl.Type = AstBuilder.ConvertType(field.FieldType, field);
newVarDecl.Variables.Add(new VariableInitializer(field.Name));
blockStatement.InsertChildBefore(cur, newVarDecl, BlockStatement.StatementRole);
dict[field.Name] = new IdentifierExpression(field.Name);
}
// Now figure out where the closure was accessed and use the simpler replacement expression there:
foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
if (identExpr.Identifier == variable.Name) {
MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
Expression replacement;
if (dict.TryGetValue(mre.MemberName, out replacement)) {
mre.ReplaceWith(replacement.Clone());
}
}
}
}
return null;
}
bool IsParameter(Expression expr)
{
if (expr is ThisReferenceExpression)
return true; return true;
IdentifierExpression ident = expr as IdentifierExpression;
return ident != null && ident.Annotation<ParameterReference>() != null;
} }
} }
} }

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

@ -3,7 +3,7 @@ using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms
{ {
public class PushNegation: DepthFirstAstVisitor<object, object> public class PushNegation: DepthFirstAstVisitor<object, object>
{ {
@ -24,29 +24,48 @@ namespace Decompiler.Transforms.Ast
// !((a) op (b)) // !((a) op (b))
BinaryOperatorExpression binaryOp = unary.Expression as BinaryOperatorExpression; BinaryOperatorExpression binaryOp = unary.Expression as BinaryOperatorExpression;
if (unary.Operator == UnaryOperatorType.Not && binaryOp != null) { if (unary.Operator == UnaryOperatorType.Not && binaryOp != null) {
bool sucessful = true; bool successful = true;
switch (binaryOp.Operator) { switch (binaryOp.Operator) {
case BinaryOperatorType.Equality: binaryOp.Operator = BinaryOperatorType.InEquality; break; case BinaryOperatorType.Equality:
case BinaryOperatorType.InEquality: binaryOp.Operator = BinaryOperatorType.Equality; break; binaryOp.Operator = BinaryOperatorType.InEquality;
// TODO: these are invalid for floats (stupid NaN) break;
case BinaryOperatorType.GreaterThan: binaryOp.Operator = BinaryOperatorType.LessThanOrEqual; break; case BinaryOperatorType.InEquality:
case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Operator = BinaryOperatorType.LessThan; break; binaryOp.Operator = BinaryOperatorType.Equality;
case BinaryOperatorType.LessThanOrEqual: binaryOp.Operator = BinaryOperatorType.GreaterThan; break; break;
case BinaryOperatorType.LessThan: binaryOp.Operator = BinaryOperatorType.GreaterThanOrEqual; break; case BinaryOperatorType.GreaterThan: // TODO: these are invalid for floats (stupid NaN)
default: sucessful = false; break; binaryOp.Operator = BinaryOperatorType.LessThanOrEqual;
} break;
if (sucessful) { 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:
successful = false;
break;
}
if (successful) {
unary.ReplaceWith(binaryOp); unary.ReplaceWith(binaryOp);
return binaryOp.AcceptVisitor(this, data); return binaryOp.AcceptVisitor(this, data);
} }
sucessful = true; successful = true;
switch (binaryOp.Operator) { switch (binaryOp.Operator) {
case BinaryOperatorType.ConditionalAnd: binaryOp.Operator = BinaryOperatorType.ConditionalOr; break; case BinaryOperatorType.ConditionalAnd:
case BinaryOperatorType.ConditionalOr: binaryOp.Operator = BinaryOperatorType.ConditionalAnd; break; binaryOp.Operator = BinaryOperatorType.ConditionalOr;
default: sucessful = false; break; break;
case BinaryOperatorType.ConditionalOr:
binaryOp.Operator = BinaryOperatorType.ConditionalAnd;
break;
default:
successful = false;
break;
} }
if (sucessful) { if (successful) {
binaryOp.Left.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e)); binaryOp.Left.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
binaryOp.Right.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e)); binaryOp.Right.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
unary.ReplaceWith(binaryOp); unary.ReplaceWith(binaryOp);
@ -55,5 +74,28 @@ namespace Decompiler.Transforms.Ast
} }
return base.VisitUnaryOperatorExpression(unary, data); return base.VisitUnaryOperatorExpression(unary, data);
} }
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
BinaryOperatorType op = binaryOperatorExpression.Operator;
bool? rightOperand = null;
if (binaryOperatorExpression.Right is PrimitiveExpression)
rightOperand = ((PrimitiveExpression)binaryOperatorExpression.Right).Value as bool?;
if (op == BinaryOperatorType.Equality && rightOperand == true || op == BinaryOperatorType.InEquality && rightOperand == false) {
// 'b == true' or 'b != false' is useless
binaryOperatorExpression.Left.AcceptVisitor(this, data);
binaryOperatorExpression.ReplaceWith(binaryOperatorExpression.Left);
return null;
} else if (op == BinaryOperatorType.Equality && rightOperand == false || op == BinaryOperatorType.InEquality && rightOperand == true) {
// 'b == false' or 'b != true' is a negation:
Expression left = binaryOperatorExpression.Left;
left.Remove();
UnaryOperatorExpression uoe = new UnaryOperatorExpression(UnaryOperatorType.Not, left);
binaryOperatorExpression.ReplaceWith(uoe);
return uoe.AcceptVisitor(this, data);
} else {
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
}
}
} }
} }

4
ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

@ -25,7 +25,7 @@ namespace Decompiler.Transforms
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
if (methodRef != null && methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2) if (methodRef != null && methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2)
{ {
invocationExpression.Arguments = null; // detach arguments from invocationExpression invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression
Expression expr = arguments[0]; Expression expr = arguments[0];
for (int i = 1; i < arguments.Length; i++) { for (int i = 1; i < arguments.Length; i++) {
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
@ -48,7 +48,7 @@ namespace Decompiler.Transforms
BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(methodRef.Name); BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(methodRef.Name);
if (bop != null && arguments.Length == 2) { if (bop != null && arguments.Length == 2) {
invocationExpression.Arguments = null; // detach arguments from invocationExpression invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression
invocationExpression.ReplaceWith( invocationExpression.ReplaceWith(
new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef) new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef)
); );

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

@ -15,7 +15,7 @@ namespace Decompiler.Transforms.Ast
VariableDeclarationStatement varDeclr = forStatement.PrevSibling as VariableDeclarationStatement; VariableDeclarationStatement varDeclr = forStatement.PrevSibling as VariableDeclarationStatement;
if (varDeclr != null) { if (varDeclr != null) {
varDeclr.ReplaceWith(Statement.Null); varDeclr.ReplaceWith(Statement.Null);
forStatement.Initializers = new Statement[] { varDeclr }; forStatement.Initializers.Add(varDeclr);
} }
} }
@ -63,7 +63,7 @@ namespace Decompiler.Transforms.Ast
if (lastStmt != null && if (lastStmt != null &&
(lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { (lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) {
lastStmt.Remove(); lastStmt.Remove();
forStatement.Iterators = new Statement[] { lastStmt }; forStatement.Iterators.Add(lastStmt);
} }
} }

20
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -2,31 +2,29 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
using System.Threading;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms namespace Decompiler.Transforms
{ {
public static class TransformationPipeline public static class TransformationPipeline
{ {
public static IAstVisitor<object, object>[] CreatePipeline() public static IAstVisitor<object, object>[] CreatePipeline(DecompilerContext context)
{ {
return new IAstVisitor<object, object>[] { return new IAstVisitor<object, object>[] {
new DelegateConstruction(), new PushNegation(),
new DelegateConstruction(context),
new ConvertConstructorCallIntoInitializer(), new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators() new ReplaceMethodCallsWithOperators(),
}; };
} }
public static void RunTransformations(AstNode node) public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition, DecompilerContext context)
{
RunTransformationsUntil(node, null);
}
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition)
{ {
if (node == null) if (node == null)
return; return;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
context.CancellationToken.ThrowIfCancellationRequested();
if (Options.ReduceAstJumps) { if (Options.ReduceAstJumps) {
node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
@ -36,11 +34,11 @@ namespace Decompiler.Transforms
} }
if (Options.ReduceAstOther) { if (Options.ReduceAstOther) {
node.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); node.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null);
node.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
} }
} }
foreach (var visitor in CreatePipeline()) { foreach (var visitor in CreatePipeline(context)) {
context.CancellationToken.ThrowIfCancellationRequested();
if (abortCondition != null && abortCondition(visitor)) if (abortCondition != null && abortCondition(visitor))
return; return;
node.AcceptVisitor(visitor, null); node.AcceptVisitor(visitor, null);

9
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -52,8 +52,11 @@
<Compile Include="Ast\AstBuilder.cs" /> <Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMethodBodyBuilder.cs" /> <Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" /> <Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" /> <Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" /> <Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" /> <Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" /> <Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" /> <Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
@ -88,10 +91,9 @@
<Compile Include="ILAst\ILAstBuilder.cs" /> <Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" /> <Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" /> <Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="Options.cs" /> <Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" /> <Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -112,7 +114,6 @@
<Folder Include="Ast\Transforms" /> <Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" /> <Folder Include="Disassembler" />
<Folder Include="ILAst" /> <Folder Include="ILAst" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

114
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -4,9 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
using Decompiler.Rocks;
namespace Decompiler namespace Decompiler
{ {
@ -33,7 +31,7 @@ namespace Decompiler
public ILLabel Label; // Non-null only if needed public ILLabel Label; // Non-null only if needed
public int Offset; public int Offset;
public int EndOffset; public int EndOffset;
public OpCode OpCode; public ILCode Code;
public object Operand; public object Operand;
public int? PopCount; // Null means pop all public int? PopCount; // Null means pop all
public int PushCount; public int PushCount;
@ -59,7 +57,7 @@ namespace Decompiler
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}:{1} {2} {3}", this.Name, this.Label != null ? " *" : "", this.OpCode, this.Operand); sb.AppendFormat("{0}:{1} {2} {3}", this.Name, this.Label != null ? " *" : "", this.Code.GetName(), this.Operand);
if (this.StackBefore != null) { if (this.StackBefore != null) {
sb.Append(" StackBefore = {"); sb.Append(" StackBefore = {");
bool first = true; bool first = true;
@ -95,6 +93,9 @@ namespace Decompiler
Dictionary<Instruction, ByteCode> instrToByteCode = new Dictionary<Instruction, ByteCode>(); Dictionary<Instruction, ByteCode> instrToByteCode = new Dictionary<Instruction, ByteCode>();
Dictionary<ILVariable, bool> allowInline = new Dictionary<ILVariable, bool>(); Dictionary<ILVariable, bool> allowInline = new Dictionary<ILVariable, bool>();
// Virtual instructions to load exception on stack
Dictionary<ExceptionHandler, ByteCode> ldexceptions = new Dictionary<ExceptionHandler, ILAstBuilder.ByteCode>();
public List<ILVariable> Variables; public List<ILVariable> Variables;
public List<ILNode> Build(MethodDefinition methodDef, bool optimize) public List<ILNode> Build(MethodDefinition methodDef, bool optimize)
@ -116,13 +117,13 @@ namespace Decompiler
// Create temporary structure for the stack analysis // Create temporary structure for the stack analysis
List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count); List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count);
foreach(Instruction inst in methodDef.Body.Instructions) { foreach(Instruction inst in methodDef.Body.Instructions) {
OpCode opCode = inst.OpCode; ILCode code = (ILCode)inst.OpCode.Code;
object operand = inst.Operand; object operand = inst.Operand;
MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body); ILCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body);
ByteCode byteCode = new ByteCode() { ByteCode byteCode = new ByteCode() {
Offset = inst.Offset, Offset = inst.Offset,
EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize, EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
OpCode = opCode, Code = code,
Operand = operand, Operand = operand,
PopCount = inst.GetPopCount(), PopCount = inst.GetPopCount(),
PushCount = inst.GetPushCount() PushCount = inst.GetPushCount()
@ -149,7 +150,14 @@ namespace Decompiler
ByteCode handlerStart = instrToByteCode[ex.HandlerType == ExceptionHandlerType.Filter ? ex.FilterStart : ex.HandlerStart]; ByteCode handlerStart = instrToByteCode[ex.HandlerType == ExceptionHandlerType.Filter ? ex.FilterStart : ex.HandlerStart];
handlerStart.StackBefore = new List<StackSlot>(); handlerStart.StackBefore = new List<StackSlot>();
if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) { if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) {
handlerStart.StackBefore.Add(new StackSlot(null)); ByteCode ldexception = new ByteCode() {
Code = ILCode.Ldexception,
Operand = ex.CatchType,
PopCount = 0,
PushCount = 1
};
ldexceptions[ex] = ldexception;
handlerStart.StackBefore.Add(new StackSlot(ldexception));
} }
agenda.Enqueue(handlerStart); agenda.Enqueue(handlerStart);
@ -173,10 +181,9 @@ namespace Decompiler
// Apply the state to any successors // Apply the state to any successors
List<ByteCode> branchTargets = new List<ByteCode>(); List<ByteCode> branchTargets = new List<ByteCode>();
if (byteCode.OpCode.CanFallThough()) { if (byteCode.Code.CanFallThough()) {
branchTargets.Add(byteCode.Next); branchTargets.Add(byteCode.Next);
} }
if (byteCode.OpCode.IsBranch()) {
if (byteCode.Operand is Instruction[]) { if (byteCode.Operand is Instruction[]) {
foreach(Instruction inst in (Instruction[])byteCode.Operand) { foreach(Instruction inst in (Instruction[])byteCode.Operand) {
ByteCode target = instrToByteCode[inst]; ByteCode target = instrToByteCode[inst];
@ -186,7 +193,7 @@ namespace Decompiler
target.Label = new ILLabel() { Name = target.Name }; target.Label = new ILLabel() { Name = target.Name };
} }
} }
} else { } else if (byteCode.Operand is Instruction) {
ByteCode target = instrToByteCode[(Instruction)byteCode.Operand]; ByteCode target = instrToByteCode[(Instruction)byteCode.Operand];
branchTargets.Add(target); branchTargets.Add(target);
// The target of a branch must have label // The target of a branch must have label
@ -194,7 +201,6 @@ namespace Decompiler
target.Label = new ILLabel() { Name = target.Name }; target.Label = new ILLabel() { Name = target.Name };
} }
} }
}
foreach (ByteCode branchTarget in branchTargets) { foreach (ByteCode branchTarget in branchTargets) {
if (branchTarget.StackBefore == null) { if (branchTarget.StackBefore == null) {
branchTarget.StackBefore = newStack; branchTarget.StackBefore = newStack;
@ -235,14 +241,11 @@ namespace Decompiler
ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true }; ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true };
arg.LoadFrom = tmpVar; arg.LoadFrom = tmpVar;
foreach(ByteCode pushedBy in arg.PushedBy) { foreach(ByteCode pushedBy in arg.PushedBy) {
// TODO: Handle exception variables
if (pushedBy != null) {
if (pushedBy.StoreTo == null) { if (pushedBy.StoreTo == null) {
pushedBy.StoreTo = new List<ILVariable>(1); pushedBy.StoreTo = new List<ILVariable>(1);
} }
pushedBy.StoreTo.Add(tmpVar); pushedBy.StoreTo.Add(tmpVar);
} }
}
if (arg.PushedBy.Count == 1) { if (arg.PushedBy.Count == 1) {
allowInline[tmpVar] = true; allowInline[tmpVar] = true;
} }
@ -255,15 +258,20 @@ namespace Decompiler
int[] numReads = new int[Variables.Count]; int[] numReads = new int[Variables.Count];
int[] numWrites = new int[Variables.Count]; int[] numWrites = new int[Variables.Count];
foreach(ByteCode byteCode in body) { foreach(ByteCode byteCode in body) {
if (byteCode.OpCode == OpCodes.Ldloc) { if (byteCode.Code == ILCode.Ldloc) {
int index = ((VariableDefinition)byteCode.Operand).Index; int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = Variables[index]; byteCode.Operand = Variables[index];
numReads[index]++; numReads[index]++;
} } else if (byteCode.Code == ILCode.Stloc) {
if (byteCode.OpCode == OpCodes.Stloc) {
int index = ((VariableDefinition)byteCode.Operand).Index; int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = Variables[index]; byteCode.Operand = Variables[index];
numWrites[index]++; numWrites[index]++;
} else if (byteCode.Code == ILCode.Ldloca) {
int index = ((VariableDefinition)byteCode.Operand).Index;
byteCode.Operand = Variables[index];
// ldloca leads to an unknown numbers of reads/writes, so ensure we don't inline the variable
numReads[index] += 2;
numWrites[index] += 2;
} }
} }
@ -333,12 +341,38 @@ namespace Decompiler
ehs.ExceptWith(nestedEHs); ehs.ExceptWith(nestedEHs);
List<ILNode> handlerAst = ConvertToAst(body.CutRange(startIndex, count), nestedEHs); List<ILNode> handlerAst = ConvertToAst(body.CutRange(startIndex, count), nestedEHs);
if (eh.HandlerType == ExceptionHandlerType.Catch) { if (eh.HandlerType == ExceptionHandlerType.Catch) {
tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() {
ExceptionType = eh.CatchType, ExceptionType = eh.CatchType,
Body = handlerAst Body = handlerAst
}); };
// Handle the automatically pushed exception on the stack
ByteCode ldexception = ldexceptions[eh];
if (ldexception.StoreTo.Count == 0) {
throw new Exception("Exception should be consumed by something");
} else if (ldexception.StoreTo.Count == 1) {
ILExpression first = catchBlock.Body[0] as ILExpression;
if (first != null &&
first.Code == ILCode.Pop &&
first.Arguments[0].Code == ILCode.Ldloc &&
first.Arguments[0].Operand == ldexception.StoreTo[0])
{
// The exception is just poped - optimize it all away;
catchBlock.ExceptionVariable = null;
catchBlock.Body.RemoveAt(0);
} else {
catchBlock.ExceptionVariable = ldexception.StoreTo[0];
}
} else {
ILVariable exTemp = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true };
catchBlock.ExceptionVariable = exTemp;
foreach(ILVariable storeTo in ldexception.StoreTo) {
catchBlock.Body.Insert(0, new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, exTemp)));
}
}
tryCatchBlock.CatchBlocks.Add(catchBlock);
} else if (eh.HandlerType == ExceptionHandlerType.Finally) { } else if (eh.HandlerType == ExceptionHandlerType.Finally) {
tryCatchBlock.FinallyBlock = new ILBlock(handlerAst); tryCatchBlock.FinallyBlock = new ILBlock(handlerAst);
// TODO: ldexception
} else { } else {
// TODO // TODO
} }
@ -361,12 +395,7 @@ namespace Decompiler
// Convert stack-based IL code to ILAst tree // Convert stack-based IL code to ILAst tree
foreach(ByteCode byteCode in body) { foreach(ByteCode byteCode in body) {
OpCode opCode = byteCode.OpCode; ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
object operand = byteCode.Operand;
MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);
ILExpression expr = new ILExpression(opCode, operand);
expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset }); expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset });
// Label for this instruction // Label for this instruction
@ -378,25 +407,19 @@ namespace Decompiler
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
StackSlot slot = byteCode.StackBefore[i]; StackSlot slot = byteCode.StackBefore[i];
if (slot.PushedBy != null) { expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom));
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, slot.LoadFrom);
expr.Arguments.Add(ldExpr);
} else {
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true });
expr.Arguments.Add(ldExpr);
}
} }
// Store the result to temporary variable(s) if needed // Store the result to temporary variable(s) if needed
if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
ast.Add(expr); ast.Add(expr);
} else if (byteCode.StoreTo.Count == 1) { } else if (byteCode.StoreTo.Count == 1) {
ast.Add(new ILExpression(OpCodes.Stloc, byteCode.StoreTo[0], expr)); ast.Add(new ILExpression(ILCode.Stloc, byteCode.StoreTo[0], expr));
} else { } else {
ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true }; ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true };
ast.Add(new ILExpression(OpCodes.Stloc, tmpVar, expr)); ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr));
foreach(ILVariable storeTo in byteCode.StoreTo) { foreach(ILVariable storeTo in byteCode.StoreTo) {
ast.Add(new ILExpression(OpCodes.Stloc, storeTo, new ILExpression(OpCodes.Ldloc, tmpVar))); ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar)));
} }
} }
} }
@ -408,10 +431,10 @@ namespace Decompiler
ILExpression currExpr = ast[i] as ILExpression; ILExpression currExpr = ast[i] as ILExpression;
ILExpression nextExpr = ast[i + 1] as ILExpression; ILExpression nextExpr = ast[i + 1] as ILExpression;
if (currExpr != null && nextExpr != null && currExpr.OpCode.Code == Code.Stloc) { if (currExpr != null && nextExpr != null && currExpr.Code == ILCode.Stloc) {
// If the next expression is generated stloc, look inside // If the next expression is generated stloc, look inside
if (nextExpr.OpCode.Code == Code.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) { if (nextExpr.Code == ILCode.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) {
nextExpr = nextExpr.Arguments[0]; nextExpr = nextExpr.Arguments[0];
} }
@ -421,7 +444,7 @@ namespace Decompiler
// We are moving the expression evaluation past the other aguments. // We are moving the expression evaluation past the other aguments.
// It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value // It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value
if (arg.OpCode.Code == Code.Ldloc) { if (arg.Code == ILCode.Ldloc) {
bool canInline; bool canInline;
allowInline.TryGetValue((ILVariable)arg.Operand, out canInline); allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
if (arg.Operand == currExpr.Operand && canInline) { if (arg.Operand == currExpr.Operand && canInline) {
@ -443,4 +466,17 @@ namespace Decompiler
return ast; return ast;
} }
} }
public static class ILAstBuilderExtensionMethods
{
public static List<T> CutRange<T>(this List<T> list, int start, int count)
{
List<T> ret = new List<T>(count);
for (int i = 0; i < count; i++) {
ret.Add(list[start + i]);
}
list.RemoveRange(start, count);
return ret;
}
}
} }

20
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -4,7 +4,6 @@ using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Decompiler.Rocks;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {
@ -16,6 +15,7 @@ namespace Decompiler.ControlFlow
FlattenNestedMovableBlocks, FlattenNestedMovableBlocks,
SimpleGotoRemoval, SimpleGotoRemoval,
RemoveDeadLabels, RemoveDeadLabels,
TypeInference,
None None
} }
@ -23,7 +23,7 @@ namespace Decompiler.ControlFlow
{ {
Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>(); Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
public void Optimize(ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{ {
if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
@ -55,6 +55,8 @@ namespace Decompiler.ControlFlow
SimpleGotoRemoval(method); SimpleGotoRemoval(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return; if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
RemoveDeadLabels(method); RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method);
} }
class ILMoveableBlock: ILBlock class ILMoveableBlock: ILBlock
@ -73,7 +75,7 @@ namespace Decompiler.ControlFlow
{ {
// Remve no-ops // Remve no-ops
// TODO: Assign the no-op range to someting // TODO: Assign the no-op range to someting
block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).OpCode == OpCodes.Nop)).ToList(); block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).Code == ILCode.Nop)).ToList();
List<ILNode> moveableBlocks = new List<ILNode>(); List<ILNode> moveableBlocks = new List<ILNode>();
@ -93,8 +95,8 @@ namespace Decompiler.ControlFlow
if ((currNode is ILLabel && !(lastNode is ILLabel)) || if ((currNode is ILLabel && !(lastNode is ILLabel)) ||
lastNode is ILTryCatchBlock || lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock || currNode is ILTryCatchBlock ||
(lastNode is ILExpression) && ((ILExpression)lastNode).OpCode.IsBranch() || (lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() ||
(currNode is ILExpression) && ((ILExpression)currNode).OpCode.IsBranch()) (currNode is ILExpression) && ((ILExpression)currNode).IsBranch())
{ {
ILBlock lastBlock = moveableBlock; ILBlock lastBlock = moveableBlock;
moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) }; moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
@ -102,9 +104,9 @@ namespace Decompiler.ControlFlow
// Explicit branch from one block to other // Explicit branch from one block to other
// (unless the last expression was unconditional branch) // (unless the last expression was unconditional branch)
if (!(lastNode is ILExpression) || ((ILExpression)lastNode).OpCode.CanFallThough()) { if (!(lastNode is ILExpression) || ((ILExpression)lastNode).Code.CanFallThough()) {
ILLabel blockLabel = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder }; ILLabel blockLabel = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder };
lastBlock.Body.Add(new ILExpression(OpCodes.Br, blockLabel)); lastBlock.Body.Add(new ILExpression(ILCode.Br, blockLabel));
moveableBlock.Body.Add(blockLabel); moveableBlock.Body.Add(blockLabel);
} }
} }
@ -463,7 +465,7 @@ namespace Decompiler.ControlFlow
if (block != null) { if (block != null) {
List<ILNode> flatBody = new List<ILNode>(); List<ILNode> flatBody = new List<ILNode>();
if (block.EntryPoint != null) { if (block.EntryPoint != null) {
flatBody.Add(new ILExpression(OpCodes.Br, block.EntryPoint)); flatBody.Add(new ILExpression(ILCode.Br, block.EntryPoint));
block.EntryPoint = null; block.EntryPoint = null;
} }
foreach (ILNode child in block.Body) { foreach (ILNode child in block.Body) {
@ -493,7 +495,7 @@ namespace Decompiler.ControlFlow
for (int i = 0; i < block.Body.Count; i++) { for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression; ILExpression expr = block.Body[i] as ILExpression;
// Uncoditional branch // Uncoditional branch
if (expr != null && (expr.OpCode == OpCodes.Br || expr.OpCode == OpCodes.Br_S)) { if (expr != null && (expr.Code == ILCode.Br)) {
// Check that branch is followed by its label (allow multiple labels) // Check that branch is followed by its label (allow multiple labels)
for (int j = i + 1; j < block.Body.Count; j++) { for (int j = i + 1; j < block.Body.Count; j++) {
ILLabel label = block.Body[j] as ILLabel; ILLabel label = block.Body[j] as ILLabel;

81
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -3,9 +3,11 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Decompiler.ControlFlow; using Decompiler.ControlFlow;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
@ -16,31 +18,7 @@ namespace Decompiler
{ {
public IEnumerable<T> GetSelfAndChildrenRecursive<T>() where T: ILNode public IEnumerable<T> GetSelfAndChildrenRecursive<T>() where T: ILNode
{ {
if (this is T) return TreeTraversal.PreOrder(this, c => c != null ? c.GetChildren() : null).OfType<T>();
yield return (T)this;
Stack<IEnumerator<ILNode>> stack = new Stack<IEnumerator<ILNode>>();
try {
stack.Push(GetChildren().GetEnumerator());
while (stack.Count > 0) {
while (stack.Peek().MoveNext()) {
ILNode element = stack.Peek().Current;
if (element != null) {
if (element is T)
yield return (T)element;
IEnumerable<ILNode> children = element.GetChildren();
if (children != null) {
stack.Push(children.GetEnumerator());
}
}
}
stack.Pop().Dispose();
}
} finally {
while (stack.Count > 0) {
stack.Pop().Dispose();
}
}
} }
public virtual IEnumerable<ILNode> GetChildren() public virtual IEnumerable<ILNode> GetChildren()
@ -77,6 +55,7 @@ namespace Decompiler
public override IEnumerable<ILNode> GetChildren() public override IEnumerable<ILNode> GetChildren()
{ {
if (EntryPoint != null)
yield return EntryPoint; yield return EntryPoint;
foreach(ILNode child in this.Body) { foreach(ILNode child in this.Body) {
yield return child; yield return child;
@ -109,13 +88,16 @@ namespace Decompiler
public class CatchBlock: ILBlock public class CatchBlock: ILBlock
{ {
public TypeReference ExceptionType; public TypeReference ExceptionType;
public ILVariable ExceptionVariable;
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write("catch "); output.Write("catch ");
output.WriteReference(ExceptionType.FullName, ExceptionType); output.WriteReference(ExceptionType.FullName, ExceptionType);
output.WriteLine(" {"); output.WriteLine(" {");
output.Indent();
base.WriteTo(output); base.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
} }
} }
@ -137,14 +119,18 @@ namespace Decompiler
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.WriteLine(".try {"); output.WriteLine(".try {");
output.Indent();
TryBlock.WriteTo(output); TryBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
foreach (CatchBlock block in CatchBlocks) { foreach (CatchBlock block in CatchBlocks) {
block.WriteTo(output); block.WriteTo(output);
} }
if (FinallyBlock != null) { if (FinallyBlock != null) {
output.WriteLine("finally {"); output.WriteLine("finally {");
output.Indent();
FinallyBlock.WriteTo(output); FinallyBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
} }
} }
@ -175,20 +161,27 @@ namespace Decompiler
public class ILExpression : ILNode public class ILExpression : ILNode
{ {
public OpCode OpCode { get; set; } public ILCode Code { get; set; }
public object Operand { get; set; } public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; } public List<ILExpression> Arguments { get; set; }
// Mapping to the original instructions (useful for debugging) // Mapping to the original instructions (useful for debugging)
public List<ILRange> ILRanges { get; set; } public List<ILRange> ILRanges { get; set; }
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) public TypeReference InferredType { get; set; }
public ILExpression(ILCode code, object operand, params ILExpression[] args)
{ {
this.OpCode = opCode; this.Code = code;
this.Operand = operand; this.Operand = operand;
this.Arguments = new List<ILExpression>(args); this.Arguments = new List<ILExpression>(args);
this.ILRanges = new List<ILRange>(1); this.ILRanges = new List<ILRange>(1);
} }
public bool IsBranch()
{
return this.Operand is ILLabel || this.Operand is ILLabel[];
}
public IEnumerable<ILLabel> GetBranchTargets() public IEnumerable<ILLabel> GetBranchTargets()
{ {
if (this.Operand is ILLabel) { if (this.Operand is ILLabel) {
@ -229,28 +222,43 @@ namespace Decompiler
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) { if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {
if (OpCode.Name == "stloc") { if (Code == ILCode.Stloc && this.InferredType == null) {
output.Write(((ILVariable)Operand).Name + " = "); output.Write(((ILVariable)Operand).Name);
output.Write(" = ");
Arguments.First().WriteTo(output); Arguments.First().WriteTo(output);
return; return;
} else if (OpCode.Name == "ldloc") { } else if (Code == ILCode.Ldloc) {
output.Write(((ILVariable)Operand).Name); output.Write(((ILVariable)Operand).Name);
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
}
return; return;
} }
} }
output.Write(OpCode.Name); output.Write(Code.GetName());
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
}
output.Write('('); output.Write('(');
bool first = true; bool first = true;
if (Operand != null) { if (Operand != null) {
if (Operand is ILLabel) if (Operand is ILLabel) {
output.Write(((ILLabel)Operand).Name); output.WriteReference(((ILLabel)Operand).Name, Operand);
else } else if (Operand is MethodReference) {
MethodReference method = (MethodReference)Operand;
method.DeclaringType.WriteTo(output, true, true);
output.Write("::");
output.WriteReference(method.Name, method);
} else {
DisassemblerHelpers.WriteOperand(output, Operand); DisassemblerHelpers.WriteOperand(output, Operand);
}
first = false; first = false;
} }
foreach (ILExpression arg in this.Arguments) { foreach (ILExpression arg in this.Arguments) {
if (!first) output.Write(','); if (!first) output.Write(", ");
arg.WriteTo(output); arg.WriteTo(output);
first = false; first = false;
} }
@ -287,6 +295,7 @@ namespace Decompiler
{ {
yield return Condition; yield return Condition;
yield return TrueBlock; yield return TrueBlock;
if (FalseBlock != null)
yield return FalseBlock; yield return FalseBlock;
} }

424
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -0,0 +1,424 @@
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2010 Jb Evain
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public enum ILCode
{
// For convenience, the start is exactly identical to Mono.Cecil.Cil.Code
// The macro instructions should never be used and are therefore prepended by __
Nop,
Break,
__Ldarg_0,
__Ldarg_1,
__Ldarg_2,
__Ldarg_3,
__Ldloc_0,
__Ldloc_1,
__Ldloc_2,
__Ldloc_3,
__Stloc_0,
__Stloc_1,
__Stloc_2,
__Stloc_3,
__Ldarg_S,
__Ldarga_S,
__Starg_S,
__Ldloc_S,
__Ldloca_S,
__Stloc_S,
Ldnull,
__Ldc_I4_M1,
__Ldc_I4_0,
__Ldc_I4_1,
__Ldc_I4_2,
__Ldc_I4_3,
__Ldc_I4_4,
__Ldc_I4_5,
__Ldc_I4_6,
__Ldc_I4_7,
__Ldc_I4_8,
__Ldc_I4_S,
Ldc_I4,
Ldc_I8,
Ldc_R4,
Ldc_R8,
Dup,
Pop,
Jmp,
Call,
Calli,
Ret,
__Br_S,
__Brfalse_S,
__Brtrue_S,
__Beq_S,
__Bge_S,
__Bgt_S,
__Ble_S,
__Blt_S,
__Bne_Un_S,
__Bge_Un_S,
__Bgt_Un_S,
__Ble_Un_S,
__Blt_Un_S,
Br,
Brfalse,
Brtrue,
Beq,
Bge,
Bgt,
Ble,
Blt,
Bne_Un,
Bge_Un,
Bgt_Un,
Ble_Un,
Blt_Un,
Switch,
Ldind_I1,
Ldind_U1,
Ldind_I2,
Ldind_U2,
Ldind_I4,
Ldind_U4,
Ldind_I8,
Ldind_I,
Ldind_R4,
Ldind_R8,
Ldind_Ref,
Stind_Ref,
Stind_I1,
Stind_I2,
Stind_I4,
Stind_I8,
Stind_R4,
Stind_R8,
Add,
Sub,
Mul,
Div,
Div_Un,
Rem,
Rem_Un,
And,
Or,
Xor,
Shl,
Shr,
Shr_Un,
Neg,
Not,
Conv_I1,
Conv_I2,
Conv_I4,
Conv_I8,
Conv_R4,
Conv_R8,
Conv_U4,
Conv_U8,
Callvirt,
Cpobj,
Ldobj,
Ldstr,
Newobj,
Castclass,
Isinst,
Conv_R_Un,
Unbox,
Throw,
Ldfld,
Ldflda,
Stfld,
Ldsfld,
Ldsflda,
Stsfld,
Stobj,
Conv_Ovf_I1_Un,
Conv_Ovf_I2_Un,
Conv_Ovf_I4_Un,
Conv_Ovf_I8_Un,
Conv_Ovf_U1_Un,
Conv_Ovf_U2_Un,
Conv_Ovf_U4_Un,
Conv_Ovf_U8_Un,
Conv_Ovf_I_Un,
Conv_Ovf_U_Un,
Box,
Newarr,
Ldlen,
Ldelema,
Ldelem_I1,
Ldelem_U1,
Ldelem_I2,
Ldelem_U2,
Ldelem_I4,
Ldelem_U4,
Ldelem_I8,
Ldelem_I,
Ldelem_R4,
Ldelem_R8,
Ldelem_Ref,
Stelem_I,
Stelem_I1,
Stelem_I2,
Stelem_I4,
Stelem_I8,
Stelem_R4,
Stelem_R8,
Stelem_Ref,
Ldelem_Any,
Stelem_Any,
Unbox_Any,
Conv_Ovf_I1,
Conv_Ovf_U1,
Conv_Ovf_I2,
Conv_Ovf_U2,
Conv_Ovf_I4,
Conv_Ovf_U4,
Conv_Ovf_I8,
Conv_Ovf_U8,
Refanyval,
Ckfinite,
Mkrefany,
Ldtoken,
Conv_U2,
Conv_U1,
Conv_I,
Conv_Ovf_I,
Conv_Ovf_U,
Add_Ovf,
Add_Ovf_Un,
Mul_Ovf,
Mul_Ovf_Un,
Sub_Ovf,
Sub_Ovf_Un,
Endfinally,
Leave,
__Leave_S,
Stind_I,
Conv_U,
Arglist,
Ceq,
Cgt,
Cgt_Un,
Clt,
Clt_Un,
Ldftn,
Ldvirtftn,
Ldarg,
Ldarga,
Starg,
Ldloc,
Ldloca,
Stloc,
Localloc,
Endfilter,
Unaligned,
Volatile,
Tail,
Initobj,
Constrained,
Cpblk,
Initblk,
No,
Rethrow,
Sizeof,
Refanytype,
Readonly,
// Virtual codes - defined for convenience
Ldexception, // Operand holds the CatchType for catch handler, null for filter
}
public static class ILCodeUtil
{
public static string GetName(this ILCode code)
{
return code.ToString().ToLowerInvariant().Replace('_','.');
}
public static bool CanFallThough(this ILCode code)
{
switch(code) {
case ILCode.Br:
case ILCode.__Br_S:
case ILCode.Leave:
case ILCode.__Leave_S:
case ILCode.Ret:
case ILCode.Endfilter:
case ILCode.Endfinally:
case ILCode.Throw:
case ILCode.Rethrow:
return false;
default:
return true;
}
}
public static int? GetPopCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null;
case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
}
}
public static int GetPushCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == "System.Void") {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{
switch (code) {
case ILCode.__Ldarg_0: code = ILCode.Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break;
case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.Ldarga; break;
case ILCode.__Starg_S: code = ILCode.Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break;
case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break;
case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break;
case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break;
case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break;
case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
}
}
public static ParameterDefinition GetParameter (this MethodBody self, int index)
{
var method = self.Method;
if (method.HasThis) {
if (index == 0)
return self.ThisParameter;
index--;
}
var parameters = method.Parameters;
if (index < 0 || index >= parameters.Count)
return null;
return parameters [index];
}
}
}

508
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -0,0 +1,508 @@
// 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;
using System.Diagnostics;
using System.Linq;
using Decompiler;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
/// <summary>
/// Assigns C# types to IL expressions.
/// </summary>
/// <remarks>
/// Types are inferred in a bidirectional manner:
/// The expected type flows from the outside to the inside, the actual inferred type flows from the inside to the outside.
/// </remarks>
public class TypeAnalysis
{
public static void Run(DecompilerContext context, ILNode node)
{
TypeAnalysis ta = new TypeAnalysis();
ta.context = context;
ta.module = context.CurrentMethod.Module;
ta.typeSystem = ta.module.TypeSystem;
ta.InferTypes(node);
}
DecompilerContext context;
TypeSystem typeSystem;
ModuleDefinition module;
List<ILExpression> storedToGeneratedVariables = new List<ILExpression>();
void InferTypes(ILNode node)
{
foreach (ILNode child in node.GetChildren()) {
ILExpression expr = child as ILExpression;
if (expr != null) {
ILVariable v = expr.Operand as ILVariable;
if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc) {
// don't deal with this node or its children yet,
// wait for the expected type to be inferred first
storedToGeneratedVariables.Add(expr);
continue;
}
bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null);
if (expr.InferredType == null || anyArgumentIsMissingType)
expr.InferredType = InferTypeForExpression(expr, null, forceInferChildren: anyArgumentIsMissingType);
}
InferTypes(child);
}
}
/// <summary>
/// Infers the C# type of <paramref name="expr"/>.
/// </summary>
/// <param name="expr">The expression</param>
/// <param name="expectedType">The expected type of the expression</param>
/// <param name="forceInferChildren">Whether direct children should be inferred even if its not necessary. (does not apply to nested children!)</param>
/// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
if (forceInferChildren || expr.InferredType == null)
expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
return expr.InferredType;
}
TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
switch ((Code)expr.Code) {
#region Variable load/store
case Code.Stloc:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), ((ILVariable)expr.Operand).Type);
return null;
case Code.Ldloc:
return ((ILVariable)expr.Operand).Type;
case Code.Starg:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), ((ParameterReference)expr.Operand).ParameterType);
return null;
case Code.Ldarg:
return ((ParameterReference)expr.Operand).ParameterType;
case Code.Ldloca:
return new ByReferenceType(((ILVariable)expr.Operand).Type);
case Code.Ldarga:
return new ByReferenceType(((ParameterReference)expr.Operand).ParameterType);
#endregion
#region Call / NewObj
case Code.Call:
case Code.Callvirt:
{
MethodReference method = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis)
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
else
InferTypeForExpression(expr.Arguments[i], method.Parameters[method.HasThis ? i - 1: i].ParameterType);
}
}
return method.ReturnType;
}
case Code.Newobj:
{
MethodReference ctor = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < ctor.Parameters.Count; i++) {
InferTypeForExpression(expr.Arguments[i], ctor.Parameters[i].ParameterType);
}
}
return ctor.DeclaringType;
}
#endregion
#region Load/Store Fields
case Code.Ldfld:
return UnpackModifiers(((FieldReference)expr.Operand).FieldType);
case Code.Ldsfld:
return UnpackModifiers(((FieldReference)expr.Operand).FieldType);
case Code.Ldflda:
case Code.Ldsflda:
return new ByReferenceType(UnpackModifiers(((FieldReference)expr.Operand).FieldType));
case Code.Stfld:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], ((FieldReference)expr.Operand).FieldType);
return null;
case Code.Stsfld:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).FieldType);
return null;
#endregion
#region Reference/Pointer instructions
case Code.Ldind_I:
case Code.Ldind_I1:
case Code.Ldind_I2:
case Code.Ldind_I4:
case Code.Ldind_I8:
case Code.Ldind_U1:
case Code.Ldind_U2:
case Code.Ldind_U4:
case Code.Ldind_R4:
case Code.Ldind_R8:
case Code.Ldind_Ref:
return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
case Code.Stind_I1:
case Code.Stind_I2:
case Code.Stind_I4:
case Code.Stind_I8:
case Code.Stind_R4:
case Code.Stind_R8:
case Code.Stind_I:
case Code.Stind_Ref:
if (forceInferChildren) {
TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
InferTypeForExpression(expr.Arguments[1], elementType);
}
return null;
case Code.Ldobj:
return (TypeReference)expr.Operand;
case Code.Stobj:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand);
}
return null;
case Code.Initobj:
return null;
case Code.Localloc:
return typeSystem.IntPtr;
#endregion
#region Arithmetic instructions
case Code.Not: // bitwise complement
case Code.Neg:
return InferTypeForExpression(expr.Arguments.Single(), expectedType);
case Code.Add:
case Code.Sub:
case Code.Mul:
case Code.Or:
case Code.And:
case Code.Xor:
return InferArgumentsInBinaryOperator(expr, null);
case Code.Add_Ovf:
case Code.Sub_Ovf:
case Code.Mul_Ovf:
case Code.Div:
case Code.Rem:
return InferArgumentsInBinaryOperator(expr, true);
case Code.Add_Ovf_Un:
case Code.Sub_Ovf_Un:
case Code.Mul_Ovf_Un:
case Code.Div_Un:
case Code.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false);
case Code.Shl:
case Code.Shr:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
case Code.Shr_Un:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32);
#endregion
#region Constant loading instructions
case Code.Ldnull:
return typeSystem.Object;
case Code.Ldstr:
return typeSystem.String;
case Code.Ldftn:
case Code.Ldvirtftn:
return typeSystem.IntPtr;
case Code.Ldc_I4:
return (IsIntegerOrEnum(expectedType) || expectedType == typeSystem.Boolean) ? expectedType : typeSystem.Int32;
case Code.Ldc_I8:
return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64;
case Code.Ldc_R4:
return typeSystem.Single;
case Code.Ldc_R8:
return typeSystem.Double;
case Code.Ldtoken:
if (expr.Operand is TypeReference)
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);
else if (expr.Operand is FieldReference)
return new TypeReference("System", "RuntimeFieldHandle", module, module, true);
else
return new TypeReference("System", "RuntimeMethodHandle", module, module, true);
case Code.Arglist:
return new TypeReference("System", "RuntimeArgumentHandle", module, module, true);
#endregion
#region Array instructions
case Code.Newarr:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
return new ArrayType((TypeReference)expr.Operand);
case Code.Ldlen:
return typeSystem.Int32;
case Code.Ldelem_U1:
case Code.Ldelem_U2:
case Code.Ldelem_U4:
case Code.Ldelem_I1:
case Code.Ldelem_I2:
case Code.Ldelem_I4:
case Code.Ldelem_I8:
case Code.Ldelem_I:
case Code.Ldelem_Ref:
{
ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], new ArrayType(typeSystem.Byte));
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
}
return arrayType != null ? arrayType.ElementType : null;
}
case Code.Ldelem_Any:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
}
return (TypeReference)expr.Operand;
case Code.Ldelema:
{
ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return arrayType != null ? new ByReferenceType(arrayType.ElementType) : null;
}
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:
case Code.Stelem_Any:
if (forceInferChildren) {
ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
if (arrayType != null) {
InferTypeForExpression(expr.Arguments[2], arrayType.ElementType);
}
}
return null;
#endregion
#region Conversion instructions
case Code.Conv_I1:
case Code.Conv_Ovf_I1:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte;
case Code.Conv_I2:
case Code.Conv_Ovf_I2:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16;
case Code.Conv_I4:
case Code.Conv_Ovf_I4:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32;
case Code.Conv_I8:
case Code.Conv_Ovf_I8:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64;
case Code.Conv_U1:
case Code.Conv_Ovf_U1:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte;
case Code.Conv_U2:
case Code.Conv_Ovf_U2:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16;
case Code.Conv_U4:
case Code.Conv_Ovf_U4:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32;
case Code.Conv_U8:
case Code.Conv_Ovf_U8:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64;
case Code.Conv_I:
case Code.Conv_Ovf_I:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr;
case Code.Conv_U:
case Code.Conv_Ovf_U:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr;
case Code.Conv_R4:
return typeSystem.Single;
case Code.Conv_R8:
return typeSystem.Double;
case Code.Conv_R_Un:
return (expectedType == typeSystem.Single) ? typeSystem.Single : typeSystem.Double;
case Code.Castclass:
case Code.Isinst:
case Code.Unbox_Any:
return (TypeReference)expr.Operand;
case Code.Box:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand);
return (TypeReference)expr.Operand;
#endregion
#region Comparison instructions
case Code.Ceq:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return typeSystem.Boolean;
case Code.Clt:
case Code.Cgt:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true);
return typeSystem.Boolean;
case Code.Clt_Un:
case Code.Cgt_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false);
return typeSystem.Boolean;
#endregion
#region Branch instructions
case Code.Beq:
case Code.Bne_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return null;
case Code.Brtrue:
case Code.Brfalse:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
return null;
case Code.Blt:
case Code.Ble:
case Code.Bgt:
case Code.Bge:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true);
return null;
case Code.Blt_Un:
case Code.Ble_Un:
case Code.Bgt_Un:
case Code.Bge_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false);
return null;
case Code.Br:
case Code.Leave:
case Code.Endfinally:
case Code.Switch:
case Code.Throw:
case Code.Rethrow:
return null;
case Code.Ret:
if (forceInferChildren && expr.Arguments.Count == 1)
InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType);
return null;
#endregion
case Code.Pop:
return null;
case Code.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType);
default:
Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
return null;
}
}
TypeReference UnpackPointer(TypeReference pointerOrManagedReference)
{
ByReferenceType refType = pointerOrManagedReference as ByReferenceType;
if (refType != null)
return refType.ElementType;
PointerType ptrType = pointerOrManagedReference as PointerType;
if (ptrType != null)
return ptrType.ElementType;
return null;
}
static TypeReference UnpackModifiers(TypeReference type)
{
while (type is OptionalModifierType || type is RequiredModifierType)
type = ((TypeSpecification)type).ElementType;
return type;
}
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned)
{
ILExpression left = expr.Arguments[0];
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, null);
TypeReference rightPreferred = DoInferTypeForExpression(right, null);
if (leftPreferred == rightPreferred) {
return left.InferredType = right.InferredType = leftPreferred;
} else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
return left.InferredType = right.InferredType = rightPreferred;
} else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
return left.InferredType = right.InferredType = leftPreferred;
} else {
return left.InferredType = right.InferredType = TypeWithMoreInformation(leftPreferred, rightPreferred);
}
}
TypeReference TypeWithMoreInformation(TypeReference leftPreferred, TypeReference rightPreferred)
{
int left = GetInformationAmount(typeSystem, leftPreferred);
int right = GetInformationAmount(typeSystem, rightPreferred);
if (left < right)
return rightPreferred;
else
return leftPreferred;
}
int GetInformationAmount(TypeReference type)
{
return GetInformationAmount(typeSystem, type);
}
const int nativeInt = 33; // treat native int as between int32 and int64
static int GetInformationAmount(TypeSystem typeSystem, TypeReference type)
{
if (type == null)
return 0;
if (type.IsValueType) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return GetInformationAmount(typeDef.Module.TypeSystem, underlyingType);
}
}
if (type == typeSystem.Boolean)
return 1;
else if (type == typeSystem.Byte || type == typeSystem.SByte)
return 8;
else if (type == typeSystem.Int16 || type == typeSystem.UInt16)
return 16;
else if (type == typeSystem.Int32 || type == typeSystem.UInt32)
return 32;
else if (type == typeSystem.IntPtr || type == typeSystem.UIntPtr)
return nativeInt;
else if (type == typeSystem.Int64 || type == typeSystem.UInt64)
return 64;
return 100; // we consider structs/objects to have more information than any primitives
}
bool IsIntegerOrEnum(TypeReference type)
{
return IsIntegerOrEnum(typeSystem, type);
}
public static bool IsIntegerOrEnum(TypeSystem typeSystem, TypeReference type)
{
return IsSigned(typeSystem, type) != null;
}
bool? IsSigned(TypeReference type)
{
return IsSigned(typeSystem, type);
}
static bool? IsSigned(TypeSystem typeSystem, TypeReference type)
{
if (type == null)
return null;
if (type.IsValueType) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return IsSigned(typeDef.Module.TypeSystem, underlyingType);
}
}
if (type == typeSystem.Byte || type == typeSystem.UInt16 || type == typeSystem.UInt32 || type == typeSystem.UInt64 || type == typeSystem.UIntPtr)
return false;
if (type == typeSystem.SByte || type == typeSystem.Int16 || type == typeSystem.Int32 || type == typeSystem.Int64 || type == typeSystem.IntPtr)
return true;
return null;
}
}
}

15
ICSharpCode.Decompiler/Mono.Cecil.Rocks/Constants.cs

@ -1,15 +0,0 @@
// 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 Decompiler
{
public class Constants
{
public const string Object = "System.Object";
public const string Int32 = "System.Int32";
public const string Boolean = "System.Boolean";
public const string Void = "System.Void";
}
}

478
ICSharpCode.Decompiler/Mono.Cecil.Rocks/MethodBodyRocks.cs

@ -1,478 +0,0 @@
//
// MethodBodyRocks.cs
//
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2010 Jb Evain
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using Mono.Cecil.Cil;
namespace Mono.Cecil.Rocks {
#if INSIDE_ROCKS
public
#endif
static class MethodBodyRocks {
public static ParameterDefinition GetParameter (this MethodBody self, int index)
{
var method = self.Method;
if (method.HasThis) {
if (index == 0)
return self.ThisParameter;
index--;
}
var parameters = method.Parameters;
if (index < 0 || index >= parameters.Count)
return null;
return parameters [index];
}
public static void SimplifyMacros (this MethodBody self)
{
if (self == null)
throw new ArgumentNullException ("self");
foreach (var instruction in self.Instructions) {
if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
continue;
switch (instruction.OpCode.Code) {
case Code.Ldarg_0:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0));
break;
case Code.Ldarg_1:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1));
break;
case Code.Ldarg_2:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2));
break;
case Code.Ldarg_3:
ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3));
break;
case Code.Ldloc_0:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]);
break;
case Code.Ldloc_1:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]);
break;
case Code.Ldloc_2:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]);
break;
case Code.Ldloc_3:
ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]);
break;
case Code.Stloc_0:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]);
break;
case Code.Stloc_1:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]);
break;
case Code.Stloc_2:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]);
break;
case Code.Stloc_3:
ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]);
break;
case Code.Ldarg_S:
instruction.OpCode = OpCodes.Ldarg;
break;
case Code.Ldarga_S:
instruction.OpCode = OpCodes.Ldarga;
break;
case Code.Starg_S:
instruction.OpCode = OpCodes.Starg;
break;
case Code.Ldloc_S:
instruction.OpCode = OpCodes.Ldloc;
break;
case Code.Ldloca_S:
instruction.OpCode = OpCodes.Ldloca;
break;
case Code.Stloc_S:
instruction.OpCode = OpCodes.Stloc;
break;
case Code.Ldc_I4_M1:
ExpandMacro (instruction, OpCodes.Ldc_I4, -1);
break;
case Code.Ldc_I4_0:
ExpandMacro (instruction, OpCodes.Ldc_I4, 0);
break;
case Code.Ldc_I4_1:
ExpandMacro (instruction, OpCodes.Ldc_I4, 1);
break;
case Code.Ldc_I4_2:
ExpandMacro (instruction, OpCodes.Ldc_I4, 2);
break;
case Code.Ldc_I4_3:
ExpandMacro (instruction, OpCodes.Ldc_I4, 3);
break;
case Code.Ldc_I4_4:
ExpandMacro (instruction, OpCodes.Ldc_I4, 4);
break;
case Code.Ldc_I4_5:
ExpandMacro (instruction, OpCodes.Ldc_I4, 5);
break;
case Code.Ldc_I4_6:
ExpandMacro (instruction, OpCodes.Ldc_I4, 6);
break;
case Code.Ldc_I4_7:
ExpandMacro (instruction, OpCodes.Ldc_I4, 7);
break;
case Code.Ldc_I4_8:
ExpandMacro (instruction, OpCodes.Ldc_I4, 8);
break;
case Code.Ldc_I4_S:
ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand);
break;
case Code.Br_S:
instruction.OpCode = OpCodes.Br;
break;
case Code.Brfalse_S:
instruction.OpCode = OpCodes.Brfalse;
break;
case Code.Brtrue_S:
instruction.OpCode = OpCodes.Brtrue;
break;
case Code.Beq_S:
instruction.OpCode = OpCodes.Beq;
break;
case Code.Bge_S:
instruction.OpCode = OpCodes.Bge;
break;
case Code.Bgt_S:
instruction.OpCode = OpCodes.Bgt;
break;
case Code.Ble_S:
instruction.OpCode = OpCodes.Ble;
break;
case Code.Blt_S:
instruction.OpCode = OpCodes.Blt;
break;
case Code.Bne_Un_S:
instruction.OpCode = OpCodes.Bne_Un;
break;
case Code.Bge_Un_S:
instruction.OpCode = OpCodes.Bge_Un;
break;
case Code.Bgt_Un_S:
instruction.OpCode = OpCodes.Bgt_Un;
break;
case Code.Ble_Un_S:
instruction.OpCode = OpCodes.Ble_Un;
break;
case Code.Blt_Un_S:
instruction.OpCode = OpCodes.Blt_Un;
break;
case Code.Leave_S:
instruction.OpCode = OpCodes.Leave;
break;
}
}
}
public static void ExpandMacro(ref OpCode opCode, ref object operand, MethodBody methodBody)
{
if (opCode.OpCodeType != OpCodeType.Macro)
return;
switch (opCode.Code) {
case Code.Ldarg_0: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(0); break;
case Code.Ldarg_1: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(1); break;
case Code.Ldarg_2: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(2); break;
case Code.Ldarg_3: opCode = OpCodes.Ldarg; operand = methodBody.GetParameter(3); break;
case Code.Ldloc_0: opCode = OpCodes.Ldloc; operand = methodBody.Variables[0]; break;
case Code.Ldloc_1: opCode = OpCodes.Ldloc; operand = methodBody.Variables[1]; break;
case Code.Ldloc_2: opCode = OpCodes.Ldloc; operand = methodBody.Variables[2]; break;
case Code.Ldloc_3: opCode = OpCodes.Ldloc; operand = methodBody.Variables[3]; break;
case Code.Stloc_0: opCode = OpCodes.Stloc; operand = methodBody.Variables[0]; break;
case Code.Stloc_1: opCode = OpCodes.Stloc; operand = methodBody.Variables[1]; break;
case Code.Stloc_2: opCode = OpCodes.Stloc; operand = methodBody.Variables[2]; break;
case Code.Stloc_3: opCode = OpCodes.Stloc; operand = methodBody.Variables[3]; break;
case Code.Ldarg_S: opCode = OpCodes.Ldarg; break;
case Code.Ldarga_S: opCode = OpCodes.Ldarga; break;
case Code.Starg_S: opCode = OpCodes.Starg; break;
case Code.Ldloc_S: opCode = OpCodes.Ldloc; break;
case Code.Ldloca_S: opCode = OpCodes.Ldloca; break;
case Code.Stloc_S: opCode = OpCodes.Stloc; break;
case Code.Ldc_I4_M1: opCode = OpCodes.Ldc_I4; operand = -1; break;
case Code.Ldc_I4_0: opCode = OpCodes.Ldc_I4; operand = 0; break;
case Code.Ldc_I4_1: opCode = OpCodes.Ldc_I4; operand = 1; break;
case Code.Ldc_I4_2: opCode = OpCodes.Ldc_I4; operand = 2; break;
case Code.Ldc_I4_3: opCode = OpCodes.Ldc_I4; operand = 3; break;
case Code.Ldc_I4_4: opCode = OpCodes.Ldc_I4; operand = 4; break;
case Code.Ldc_I4_5: opCode = OpCodes.Ldc_I4; operand = 5; break;
case Code.Ldc_I4_6: opCode = OpCodes.Ldc_I4; operand = 6; break;
case Code.Ldc_I4_7: opCode = OpCodes.Ldc_I4; operand = 7; break;
case Code.Ldc_I4_8: opCode = OpCodes.Ldc_I4; operand = 8; break;
case Code.Ldc_I4_S: opCode = OpCodes.Ldc_I4; operand = (int) (sbyte) operand; break;
case Code.Br_S: opCode = OpCodes.Br; break;
case Code.Brfalse_S: opCode = OpCodes.Brfalse; break;
case Code.Brtrue_S: opCode = OpCodes.Brtrue; break;
case Code.Beq_S: opCode = OpCodes.Beq; break;
case Code.Bge_S: opCode = OpCodes.Bge; break;
case Code.Bgt_S: opCode = OpCodes.Bgt; break;
case Code.Ble_S: opCode = OpCodes.Ble; break;
case Code.Blt_S: opCode = OpCodes.Blt; break;
case Code.Bne_Un_S: opCode = OpCodes.Bne_Un; break;
case Code.Bge_Un_S: opCode = OpCodes.Bge_Un; break;
case Code.Bgt_Un_S: opCode = OpCodes.Bgt_Un; break;
case Code.Ble_Un_S: opCode = OpCodes.Ble_Un; break;
case Code.Blt_Un_S: opCode = OpCodes.Blt_Un; break;
case Code.Leave_S: opCode = OpCodes.Leave; break;
}
}
static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
{
instruction.OpCode = opcode;
instruction.Operand = operand;
}
static void MakeMacro (Instruction instruction, OpCode opcode)
{
instruction.OpCode = opcode;
instruction.Operand = null;
}
public static void OptimizeMacros (this MethodBody self)
{
if (self == null)
throw new ArgumentNullException ("self");
var method = self.Method;
foreach (var instruction in self.Instructions) {
int index;
switch (instruction.OpCode.Code) {
case Code.Ldarg:
index = ((ParameterDefinition) instruction.Operand).Index;
if (index == -1 && instruction.Operand == self.ThisParameter)
index = 0;
else if (method.HasThis)
index++;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Ldarg_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldarg_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldarg_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldarg_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand);
break;
}
break;
case Code.Ldloc:
index = ((VariableDefinition) instruction.Operand).Index;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Ldloc_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldloc_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldloc_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldloc_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand);
break;
}
break;
case Code.Stloc:
index = ((VariableDefinition) instruction.Operand).Index;
switch (index) {
case 0:
MakeMacro (instruction, OpCodes.Stloc_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Stloc_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Stloc_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Stloc_3);
break;
default:
if (index < 256)
ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand);
break;
}
break;
case Code.Ldarga:
index = ((ParameterDefinition) instruction.Operand).Index;
if (index == -1 && instruction.Operand == self.ThisParameter)
index = 0;
else if (method.HasThis)
index++;
if (index < 256)
ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand);
break;
case Code.Ldloca:
if (((VariableDefinition) instruction.Operand).Index < 256)
ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand);
break;
case Code.Ldc_I4:
int i = (int) instruction.Operand;
switch (i) {
case -1:
MakeMacro (instruction, OpCodes.Ldc_I4_M1);
break;
case 0:
MakeMacro (instruction, OpCodes.Ldc_I4_0);
break;
case 1:
MakeMacro (instruction, OpCodes.Ldc_I4_1);
break;
case 2:
MakeMacro (instruction, OpCodes.Ldc_I4_2);
break;
case 3:
MakeMacro (instruction, OpCodes.Ldc_I4_3);
break;
case 4:
MakeMacro (instruction, OpCodes.Ldc_I4_4);
break;
case 5:
MakeMacro (instruction, OpCodes.Ldc_I4_5);
break;
case 6:
MakeMacro (instruction, OpCodes.Ldc_I4_6);
break;
case 7:
MakeMacro (instruction, OpCodes.Ldc_I4_7);
break;
case 8:
MakeMacro (instruction, OpCodes.Ldc_I4_8);
break;
default:
if (i >= -128 && i < 128)
ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i);
break;
}
break;
}
}
OptimizeBranches (self);
}
static void OptimizeBranches (MethodBody body)
{
ComputeOffsets (body);
foreach (var instruction in body.Instructions) {
if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
continue;
if (OptimizeBranch (instruction))
ComputeOffsets (body);
}
}
static bool OptimizeBranch (Instruction instruction)
{
var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
if (!(offset >= -128 && offset <= 127))
return false;
switch (instruction.OpCode.Code) {
case Code.Br:
instruction.OpCode = OpCodes.Br_S;
break;
case Code.Brfalse:
instruction.OpCode = OpCodes.Brfalse_S;
break;
case Code.Brtrue:
instruction.OpCode = OpCodes.Brtrue_S;
break;
case Code.Beq:
instruction.OpCode = OpCodes.Beq_S;
break;
case Code.Bge:
instruction.OpCode = OpCodes.Bge_S;
break;
case Code.Bgt:
instruction.OpCode = OpCodes.Bgt_S;
break;
case Code.Ble:
instruction.OpCode = OpCodes.Ble_S;
break;
case Code.Blt:
instruction.OpCode = OpCodes.Blt_S;
break;
case Code.Bne_Un:
instruction.OpCode = OpCodes.Bne_Un_S;
break;
case Code.Bge_Un:
instruction.OpCode = OpCodes.Bge_Un_S;
break;
case Code.Bgt_Un:
instruction.OpCode = OpCodes.Bgt_Un_S;
break;
case Code.Ble_Un:
instruction.OpCode = OpCodes.Ble_Un_S;
break;
case Code.Blt_Un:
instruction.OpCode = OpCodes.Blt_Un_S;
break;
case Code.Leave:
instruction.OpCode = OpCodes.Leave_S;
break;
}
return true;
}
static void ComputeOffsets (MethodBody body)
{
var offset = 0;
foreach (var instruction in body.Instructions) {
instruction.Offset = offset;
offset += instruction.GetSize ();
}
}
}
}

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

@ -1,359 +0,0 @@
/*
* Created by SharpDevelop.
* User: User
* Date: 05/02/2011
* Time: 10:10
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler.Rocks
{
static class MyRocks
{
static public TypeReference TypeVoid = GetCecilType(typeof(void));
static public TypeReference TypeObject = GetCecilType(typeof(Object));
static public TypeReference TypeException = GetCecilType(typeof(Exception));
static public TypeReference TypeBool = GetCecilType(typeof(bool));
static public TypeReference TypeInt32 = GetCecilType(typeof(Int32));
static public TypeReference TypeString = GetCecilType(typeof(string));
static public TypeReference TypeZero = GetCecilType(typeof(Int32));
static public TypeReference TypeOne = GetCecilType(typeof(Int32));
public static List<T> CutRange<T>(this List<T> list, int start, int count)
{
List<T> ret = new List<T>(count);
for (int i = 0; i < count; i++) {
ret.Add(list[start + i]);
}
list.RemoveRange(start, count);
return ret;
}
public static bool CanFallThough(this OpCode opCode)
{
switch(opCode.FlowControl) {
case FlowControl.Branch: return false;
case FlowControl.Cond_Branch: return true;
case FlowControl.Next: return true;
case FlowControl.Call: return true;
case FlowControl.Return: return false;
case FlowControl.Throw: return false;
case FlowControl.Meta: return true;
default: throw new NotImplementedException();
}
}
public static bool IsBranch(this OpCode opCode)
{
return opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch;
}
public static int? GetPopCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null;
case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
}
}
public static int GetPushCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
static public TypeReference GetCecilType(Type type)
{
return new TypeReference(type.Name, type.Namespace, null, null, type.IsValueType);
}
static public TypeReference GetTypeInternal(this Instruction inst, MethodDefinition methodDef, List<TypeReference> args)
{
OpCode opCode = inst.OpCode;
object operand = inst.Operand;
TypeReference operandAsTypeRef = operand as TypeReference;
//ByteCode operandAsByteCode = operand as ByteCode;
//string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null;
TypeReference arg1 = args.Count >= 1 ? args[0] : null;
TypeReference arg2 = args.Count >= 2 ? args[1] : null;
TypeReference arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode.Code) {
#region Arithmetic
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.And:
case Code.Xor:
case Code.Shl:
case Code.Shr:
case Code.Shr_Un: return TypeInt32;
case Code.Neg: return TypeInt32;
case Code.Not: return TypeInt32;
#endregion
#region Arrays
case Code.Newarr:
return new ArrayType(operandAsTypeRef);
case Code.Ldlen: return TypeInt32;
case Code.Ldelem_I:
case Code.Ldelem_I1:
case Code.Ldelem_I2:
case Code.Ldelem_I4:
case Code.Ldelem_I8: return TypeInt32;
case Code.Ldelem_U1:
case Code.Ldelem_U2:
case Code.Ldelem_U4:
case Code.Ldelem_R4:
case Code.Ldelem_R8: throw new NotImplementedException();
case Code.Ldelem_Ref:
if (arg1 is ArrayType) {
return ((ArrayType)arg1).ElementType;
} else {
throw new NotImplementedException();
}
case Code.Ldelem_Any:
case Code.Ldelema: throw new NotImplementedException();
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:
case Code.Stelem_Any: return TypeVoid;
#endregion
#region Branching
case Code.Br:
case Code.Brfalse:
case Code.Brtrue:
case Code.Beq:
case Code.Bge:
case Code.Bge_Un:
case Code.Bgt:
case Code.Bgt_Un:
case Code.Ble:
case Code.Ble_Un:
case Code.Blt:
case Code.Blt_Un:
case Code.Bne_Un: return TypeVoid;
#endregion
#region Comparison
case Code.Ceq:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Clt:
case Code.Clt_Un: return TypeBool;
#endregion
#region Conversions
case Code.Conv_I:
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_R_Un:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_I_Un:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U_Un:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8_Un: return TypeInt32;
#endregion
#region Indirect
case Code.Ldind_I: throw new NotImplementedException();
case Code.Ldind_I1: throw new NotImplementedException();
case Code.Ldind_I2: throw new NotImplementedException();
case Code.Ldind_I4: throw new NotImplementedException();
case Code.Ldind_I8: throw new NotImplementedException();
case Code.Ldind_U1: throw new NotImplementedException();
case Code.Ldind_U2: throw new NotImplementedException();
case Code.Ldind_U4: throw new NotImplementedException();
case Code.Ldind_R4: throw new NotImplementedException();
case Code.Ldind_R8: throw new NotImplementedException();
case Code.Ldind_Ref: throw new NotImplementedException();
case Code.Stind_I: throw new NotImplementedException();
case Code.Stind_I1: throw new NotImplementedException();
case Code.Stind_I2: throw new NotImplementedException();
case Code.Stind_I4: throw new NotImplementedException();
case Code.Stind_I8: throw new NotImplementedException();
case Code.Stind_R4: throw new NotImplementedException();
case Code.Stind_R8: throw new NotImplementedException();
case Code.Stind_Ref: throw new NotImplementedException();
#endregion
case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException();
case Code.Call: return ((MethodReference)operand).ReturnType;
case Code.Calli: throw new NotImplementedException();
case Code.Callvirt: return ((MethodReference)operand).ReturnType;
case Code.Castclass: throw new NotImplementedException();
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: throw new NotImplementedException();
case Code.Endfilter: throw new NotImplementedException();
case Code.Endfinally: throw new NotImplementedException();
case Code.Initblk: throw new NotImplementedException();
case Code.Initobj: throw new NotImplementedException();
case Code.Isinst: throw new NotImplementedException();
case Code.Jmp: throw new NotImplementedException();
case Code.Ldarg:
TypeReference typeRef = ((ParameterDefinition)operand).ParameterType;
// 'this' returns null; TODO: Return proper type of this
return typeRef ?? TypeObject;
case Code.Ldarga: throw new NotImplementedException();
case Code.Ldc_I4:
if ((int)operand == 0) {
return TypeZero;
} else if ((int)operand == 1) {
return TypeOne;
} else {
return TypeInt32;
}
case Code.Ldc_I8: throw new NotImplementedException();
case Code.Ldc_R4: throw new NotImplementedException();
case Code.Ldc_R8: throw new NotImplementedException();
case Code.Ldfld: return ((FieldDefinition)operand).FieldType;
case Code.Ldflda: throw new NotImplementedException();
case Code.Ldftn: throw new NotImplementedException();
case Code.Ldloc: return ((VariableDefinition)operand).VariableType;
case Code.Ldloca: throw new NotImplementedException();
case Code.Ldnull: throw new NotImplementedException();
case Code.Ldobj: throw new NotImplementedException();
case Code.Ldsfld: throw new NotImplementedException();
case Code.Ldsflda: throw new NotImplementedException();
case Code.Ldstr: return TypeString;
case Code.Ldtoken: throw new NotImplementedException();
case Code.Ldvirtftn: throw new NotImplementedException();
case Code.Leave: throw new NotImplementedException();
case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException();
case Code.Newobj: throw new NotImplementedException();
case Code.No: throw new NotImplementedException();
case Code.Nop: return TypeVoid;
case Code.Or: throw new NotImplementedException();
case Code.Pop: throw new NotImplementedException();
case Code.Readonly: throw new NotImplementedException();
case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: return TypeVoid;
case Code.Rethrow: throw new NotImplementedException();
case Code.Sizeof: throw new NotImplementedException();
case Code.Starg: throw new NotImplementedException();
case Code.Stfld: throw new NotImplementedException();
case Code.Stloc: return TypeVoid;
case Code.Stobj: throw new NotImplementedException();
case Code.Stsfld: throw new NotImplementedException();
case Code.Switch: throw new NotImplementedException();
case Code.Tail: throw new NotImplementedException();
case Code.Throw: throw new NotImplementedException();
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);
}
}
}
}

41
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -0,0 +1,41 @@
// 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;
public static class DelegateConstruction
{
public static void Test(this string a)
{
}
public static Action<string> ExtensionMethodUnbound()
{
return new Action<string>(DelegateConstruction.Test);
}
public static Action ExtensionMethodBound()
{
return new Action("abc".Test);
}
public static Action ExtensionMethodBoundOnNull()
{
return new Action(((string)null).Test);
}
public static object StaticMethod()
{
return new Func<Action>(DelegateConstruction.ExtensionMethodBound);
}
public static object InstanceMethod()
{
return new Func<string>("hello".ToUpper);
}
public static object InstanceMethodOnNull()
{
return new Func<string>(((string)null).ToUpper);
}
}

66
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Exe</OutputType>
<RootNamespace>ICSharpCode.Decompiler.Tests</RootNamespace>
<AssemblyName>ICSharpCode.Decompiler.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\bin\Release\</OutputPath>
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="DelegateConstruction.cs" />
<Compile Include="Loops.cs" />
<Compile Include="TestRunner.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\ICSharpCode.Decompiler.csproj">
<Project>{984CC812-9470-4A13-AFF9-CC44068D666C}</Project>
<Name>ICSharpCode.Decompiler</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

30
ICSharpCode.Decompiler/Tests/Loops.cs

@ -0,0 +1,30 @@
// 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;
public class Loops
{
public void ForEach(IEnumerable<string> enumerable)
{
foreach (string text in enumerable) {
text.ToLower();
}
}
public void ForEachOverArray(string[] array)
{
foreach (string text in array) {
text.ToLower();
}
}
public void ForOverArray(string[] array)
{
for (int i = 0; i < array.Length; i++) {
array[i].ToLower();
}
}
}

101
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -0,0 +1,101 @@
// 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.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Decompiler;
using Microsoft.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Tests
{
public class TestRunner
{
public static void Main()
{
Test(@"..\..\Tests\DelegateConstruction.cs");
Console.ReadKey();
}
static void Test(string fileName)
{
string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext());
decompiler.AddAssembly(assembly);
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
StringWriter diff = new StringWriter();
if (!Compare(code, output.ToString(), diff)) {
throw new Exception("Test failure." + Environment.NewLine + diff.ToString());
}
}
static bool Compare(string input1, string input2, StringWriter diff)
{
bool ok = true;
int numberOfContinuousMistakes = 0;
StringReader r1 = new StringReader(input1);
StringReader r2 = new StringReader(input2);
string line1, line2;
while ((line1 = r1.ReadLine()) != null) {
string trimmed = line1.Trim();
if (trimmed.Length == 0 || trimmed.StartsWith("//", StringComparison.Ordinal) || line1.StartsWith("using ", StringComparison.Ordinal)) {
diff.WriteLine(" " + line1);
continue;
}
line2 = r2.ReadLine();
while (line2 != null && (line2.StartsWith("using ", StringComparison.Ordinal) || line2.Trim().Length == 0))
line2 = r2.ReadLine();
if (line2 == null) {
ok = false;
diff.WriteLine("-" + line1);
continue;
}
if (line1 != line2) {
ok = false;
if (numberOfContinuousMistakes++ > 5)
return false;
diff.WriteLine("-" + line1);
diff.WriteLine("+" + line2);
} else {
if (numberOfContinuousMistakes > 0)
numberOfContinuousMistakes--;
diff.WriteLine(" " + line1);
}
}
while ((line2 = r2.ReadLine()) != null) {
ok = false;
diff.WriteLine("+" + line1);
}
return ok;
}
static AssemblyDefinition Compile(string code)
{
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> {{ "CompilerVersion", "v4.0" }});
CompilerParameters options = new CompilerParameters();
options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try {
if (results.Errors.Count > 0) {
StringBuilder b = new StringBuilder("Compiler error:");
foreach (var error in results.Errors) {
b.AppendLine(error.ToString());
}
throw new Exception(b.ToString());
}
return AssemblyDefinition.ReadAssembly(results.PathToAssembly);
} finally {
File.Delete(results.PathToAssembly);
results.TempFiles.Delete();
}
}
}
}

10
ILSpy.sln

@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "I
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Tests", "ICSharpCode.Decompiler\Tests\ICSharpCode.Decompiler.Tests.csproj", "{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
@ -78,6 +80,14 @@ Global
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.ActiveCfg = Debug|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.ActiveCfg = Release|x86
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.Build.0 = Debug|Any CPU {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.Build.0 = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.ActiveCfg = Debug|Any CPU {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU

63
ILSpy/BamlDecompiler.cs

@ -0,0 +1,63 @@
// 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.IO;
using System.Reflection;
using System.Windows.Baml2006;
using System.Xaml;
using System.Xml;
namespace ICSharpCode.ILSpy
{
/// <remarks>Caution: use in separate AppDomain only!</remarks>
public class BamlDecompiler : MarshalByRefObject
{
public BamlDecompiler()
{
}
public string DecompileBaml(MemoryStream bamlCode, string containingAssemblyFile)
{
bamlCode.Position = 0;
TextWriter w = new StringWriter();
Assembly assembly = Assembly.LoadFile(containingAssemblyFile);
Baml2006Reader reader = new Baml2006Reader(bamlCode, new XamlReaderSettings() { ValuesMustBeString = true, LocalAssembly = assembly });
XamlXmlWriter writer = new XamlXmlWriter(new XmlTextWriter(w) { Formatting = Formatting.Indented }, reader.SchemaContext);
while (reader.Read()) {
switch (reader.NodeType) {
case XamlNodeType.None:
break;
case XamlNodeType.StartObject:
writer.WriteStartObject(reader.Type);
break;
case XamlNodeType.GetObject:
writer.WriteGetObject();
break;
case XamlNodeType.EndObject:
writer.WriteEndObject();
break;
case XamlNodeType.StartMember:
writer.WriteStartMember(reader.Member);
break;
case XamlNodeType.EndMember:
writer.WriteEndMember();
break;
case XamlNodeType.Value:
// requires XamlReaderSettings.ValuesMustBeString = true to work properly
writer.WriteValue(reader.Value);
break;
case XamlNodeType.NamespaceDeclaration:
writer.WriteNamespace(reader.Namespace);
break;
default:
throw new Exception("Invalid value for XamlNodeType");
}
}
return w.ToString();
}
}
}

45
ILSpy/CSharpLanguage.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using Decompiler; using Decompiler;
using Decompiler.Transforms; using Decompiler.Transforms;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
@ -34,7 +35,8 @@ namespace ICSharpCode.ILSpy
public class CSharpLanguage : Language public class CSharpLanguage : Language
{ {
string name = "C#"; string name = "C#";
Predicate<IAstVisitor<object, object>> transformAbortCondition; bool showAllMembers;
Predicate<IAstVisitor<object, object>> transformAbortCondition = null;
public CSharpLanguage() public CSharpLanguage()
{ {
@ -44,16 +46,18 @@ namespace ICSharpCode.ILSpy
internal static IEnumerable<CSharpLanguage> GetDebugLanguages() internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{ {
string lastTransformName = "no transforms"; string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline().Select(v => v.GetType()).Distinct()) { foreach (Type _transformType in TransformationPipeline.CreatePipeline(new DecompilerContext()).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda Type transformType = _transformType; // copy for lambda
yield return new CSharpLanguage { yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v), transformAbortCondition = v => transformType.IsInstanceOfType(v),
name = "C# - " + lastTransformName name = "C# - " + lastTransformName,
showAllMembers = true
}; };
lastTransformName = "after " + transformType.Name; lastTransformName = "after " + transformType.Name;
} }
yield return new CSharpLanguage { yield return new CSharpLanguage {
name = "C# - " + lastTransformName name = "C# - " + lastTransformName,
showAllMembers = true
}; };
} }
#endif #endif
@ -68,35 +72,35 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, method.DeclaringType);
codeDomBuilder.AddMethod(method); codeDomBuilder.AddMethod(method);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, property.DeclaringType);
codeDomBuilder.AddProperty(property); codeDomBuilder.AddProperty(property);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, field.DeclaringType);
codeDomBuilder.AddField(field); codeDomBuilder.AddField(field);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, ev.DeclaringType);
codeDomBuilder.AddEvent(ev); codeDomBuilder.AddEvent(ev);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
@ -105,7 +109,7 @@ namespace ICSharpCode.ILSpy
{ {
if (options.FullDecompilation) { if (options.FullDecompilation) {
foreach (TypeDefinition type in assembly.MainModule.Types) { foreach (TypeDefinition type in assembly.MainModule.Types) {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
output.WriteLine(); output.WriteLine();
@ -115,6 +119,15 @@ namespace ICSharpCode.ILSpy
} }
} }
AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType)
{
return new AstBuilder(
new DecompilerContext {
CancellationToken = options.CancellationToken,
CurrentType = currentType
});
}
public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes) public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes)
{ {
AstType astType = AstBuilder.ConvertType(type, typeAttributes); AstType astType = AstBuilder.ConvertType(type, typeAttributes);
@ -144,9 +157,9 @@ namespace ICSharpCode.ILSpy
base.VisitMemberType(memberType, data); base.VisitMemberType(memberType, data);
SimpleType st = memberType.Target as SimpleType; SimpleType st = memberType.Target as SimpleType;
if (st != null && !st.TypeArguments.Any()) { if (st != null && !st.TypeArguments.Any()) {
var ta = memberType.TypeArguments.ToArray(); SimpleType newSt = new SimpleType(memberType.MemberName);
memberType.TypeArguments = null; memberType.TypeArguments.MoveTo(newSt.TypeArguments);
memberType.ReplaceWith(new SimpleType { Identifier = memberType.MemberName, TypeArguments = ta }); memberType.ReplaceWith(newSt);
} }
return null; return null;
} }
@ -154,9 +167,15 @@ namespace ICSharpCode.ILSpy
public override bool ShowMember(MemberReference member) public override bool ShowMember(MemberReference member)
{ {
if (showAllMembers) {
return true;
}
MethodDefinition method = member as MethodDefinition; MethodDefinition method = member as MethodDefinition;
if (method != null && (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn)) if (method != null && (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn))
return false; return false;
TypeDefinition type = member as TypeDefinition;
if (type != null && type.Name.StartsWith("<>c__DisplayClass", StringComparison.Ordinal) && type.IsCompilerGenerated())
return false;
return true; return true;
} }
} }

26
ILSpy/ILAstLanguage.cs

@ -24,6 +24,7 @@ using Decompiler;
using Decompiler.ControlFlow; using Decompiler.ControlFlow;
using Decompiler.Transforms; using Decompiler.Transforms;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -46,13 +47,27 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
ILAstBuilder astBuilder = new ILAstBuilder();
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ilMethod.Body = new ILAstBuilder().Build(method, inlineVariables); ilMethod.Body = astBuilder.Build(method, inlineVariables);
if (abortBeforeStep != null) { if (abortBeforeStep != null) {
new ILAstOptimizer().Optimize(ilMethod, abortBeforeStep.Value); DecompilerContext context = new DecompilerContext { CurrentType = method.DeclaringType, CurrentMethod = method };
new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
} }
var allVariables = astBuilder.Variables
.Concat(ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable).Where(v => v != null)).Distinct();
foreach (ILVariable v in allVariables) {
output.WriteDefinition(v.Name, v);
if (v.Type != null) {
output.Write(" : ");
v.Type.WriteTo(output, true, true);
}
output.WriteLine();
}
output.WriteLine();
foreach (ILNode node in ilMethod.Body) { foreach (ILNode node in ilMethod.Body) {
node.WriteTo(output); node.WriteTo(output);
output.WriteLine(); output.WriteLine();
@ -77,5 +92,12 @@ namespace ICSharpCode.ILSpy
return ".il"; return ".il";
} }
} }
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)
{
PlainTextOutput output = new PlainTextOutput();
t.WriteTo(output, true, shortName: !includeNamespace);
return output.ToString();
}
} }
} }

2
ILSpy/ILSpy.csproj

@ -85,6 +85,7 @@
</Compile> </Compile>
<Compile Include="AssemblyList.cs" /> <Compile Include="AssemblyList.cs" />
<Compile Include="AssemblyListManager.cs" /> <Compile Include="AssemblyListManager.cs" />
<Compile Include="BamlDecompiler.cs" />
<Compile Include="Commands\RoutedUICommands.cs" /> <Compile Include="Commands\RoutedUICommands.cs" />
<Compile Include="Controls\SearchBox.cs" /> <Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" /> <Compile Include="Controls\SortableGridViewColumn.cs" />
@ -154,6 +155,7 @@
<Compile Include="TreeNodes\NamespaceTreeNode.cs" /> <Compile Include="TreeNodes\NamespaceTreeNode.cs" />
<Compile Include="TreeNodes\PropertyTreeNode.cs" /> <Compile Include="TreeNodes\PropertyTreeNode.cs" />
<Compile Include="TreeNodes\ReferenceFolderTreeNode.cs" /> <Compile Include="TreeNodes\ReferenceFolderTreeNode.cs" />
<Compile Include="TreeNodes\ResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceListTreeNode.cs" /> <Compile Include="TreeNodes\ResourceListTreeNode.cs" />
<Compile Include="TreeNodes\ThreadedTreeNode.cs" /> <Compile Include="TreeNodes\ThreadedTreeNode.cs" />
<Compile Include="TreeNodes\TypeTreeNode.cs" /> <Compile Include="TreeNodes\TypeTreeNode.cs" />

2
ILSpy/TextView/DecompilerTextView.cs

@ -100,7 +100,7 @@ namespace ICSharpCode.ILSpy.TextView
/// When the task is cancelled before completing, the callback is not called; and any result /// When the task is cancelled before completing, the callback is not called; and any result
/// of the task (including exceptions) are ignored. /// of the task (including exceptions) are ignored.
/// </summary> /// </summary>
void RunWithCancellation<T>(Func<CancellationToken, Task<T>> taskCreation, Action<Task<T>> taskCompleted) public void RunWithCancellation<T>(Func<CancellationToken, Task<T>> taskCreation, Action<Task<T>> taskCompleted)
{ {
if (waitAdorner.Visibility != Visibility.Visible) { if (waitAdorner.Visibility != Visibility.Visible) {
waitAdorner.Visibility = Visibility.Visible; waitAdorner.Visibility = Visibility.Visible;

3
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -157,8 +157,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
void EnsureChildrenFiltered() void EnsureChildrenFiltered()
{ {
// No need to ensure lazy children here: EnsureLazyChildren();
// if the children get lazy-loaded later, they'll still be filtered.
if (childrenNeedFiltering) { if (childrenNeedFiltering) {
childrenNeedFiltering = false; childrenNeedFiltering = false;
foreach (ILSpyTreeNode node in this.Children.OfType<ILSpyTreeNode>()) foreach (ILSpyTreeNode node in this.Children.OfType<ILSpyTreeNode>())

122
ILSpy/TreeNodes/ResourceEntryNode.cs

@ -0,0 +1,122 @@
// 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.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using Microsoft.Win32;
namespace ICSharpCode.ILSpy.TreeNodes
{
class ResourceEntryNode : ILSpyTreeNode
{
string key;
Stream value;
public override object Text {
get { return key.ToString(); }
}
public override object Icon {
get { return Images.Resource; }
}
public ResourceEntryNode(string key, Stream value)
{
this.key = key;
this.value = value;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, string.Format("{0} = {1}", key, value));
}
internal override bool View(DecompilerTextView textView)
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
IHighlightingDefinition highlighting = null;
if (LoadImage(output)) {
textView.Show(output, highlighting);
} else {
textView.RunWithCancellation(
token => Task.Factory.StartNew(
() => {
try {
if (LoadBaml(output))
highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
} catch (Exception ex) {
output.Write(ex.ToString());
}
return output;
}),
t => textView.Show(t.Result, highlighting)
);
}
return true;
}
bool LoadImage(AvalonEditTextOutput output)
{
try {
value.Position = 0;
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = value;
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(); });
} catch (Exception) {
return false;
}
return true;
}
bool LoadBaml(AvalonEditTextOutput output)
{
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
// Construct and initialize settings for a second AppDomain.
AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup();
bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(asm.FileName);
bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false;
bamlDecompilerAppDomainSetup.DisallowCodeDownload = true;
bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
// Create the second AppDomain.
AppDomain bamlDecompilerAppDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup);
BamlDecompiler decompiler = (BamlDecompiler)bamlDecompilerAppDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName);
MemoryStream bamlStream = new MemoryStream();
value.Position = 0;
value.CopyTo(bamlStream);
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName));
return true;
}
public override bool Save()
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key));
if (dlg.ShowDialog() == true) {
value.Position = 0;
using (var fs = dlg.OpenFile()) {
value.CopyTo(fs);
}
}
return true;
}
}
}

23
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -2,8 +2,12 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
using System.Collections;
using System.IO; using System.IO;
using System.Linq;
using System.Resources;
using System.Text; using System.Text;
using System.Windows;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
@ -66,6 +70,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public ResourceTreeNode(Resource r) public ResourceTreeNode(Resource r)
{ {
this.LazyLoading = true;
this.r = r; this.r = r;
} }
@ -144,5 +149,23 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
return false; return false;
} }
protected override void LoadChildren()
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
try {
Stream s = er.GetResourceStream();
if (er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) {
ResourceSet set = new ResourceSet(s);
foreach (DictionaryEntry entry in set.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) {
if (entry.Value is Stream)
Children.Add(new ResourceEntryNode(entry.Key.ToString(), (Stream)entry.Value));
}
}
} catch (ArgumentException) {
}
}
}
} }
} }

31
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs

@ -1,4 +1,4 @@
// //
// AstNode.cs // AstNode.cs
// //
// Author: // Author:
@ -164,16 +164,9 @@ namespace ICSharpCode.NRefactory.CSharp
return role.NullObject; return role.NullObject;
} }
public IEnumerable<T> GetChildrenByRole<T>(Role<T> role) where T : AstNode public AstNodeCollection<T> GetChildrenByRole<T>(Role<T> role) where T : AstNode
{ {
AstNode next; return new AstNodeCollection<T>(this, role);
for (AstNode cur = firstChild; cur != null; cur = next) {
// Remember next before yielding cur.
// This allows removing/replacing nodes while iterating through the list.
next = cur.nextSibling;
if (cur.role == role)
yield return (T)cur;
}
} }
protected void SetChildByRole<T>(Role<T> role, T newChild) where T : AstNode protected void SetChildByRole<T>(Role<T> role, T newChild) where T : AstNode
@ -185,24 +178,6 @@ namespace ICSharpCode.NRefactory.CSharp
oldChild.ReplaceWith(newChild); oldChild.ReplaceWith(newChild);
} }
protected void SetChildrenByRole<T>(Role<T> role, IEnumerable<T> newChildren) where T : AstNode
{
// Evaluate 'newChildren' first, since it might change when we remove the old children
// Example: SetChildren(role, GetChildrenByRole(role));
if (newChildren != null)
newChildren = newChildren.ToList();
// remove old children
foreach (AstNode node in GetChildrenByRole(role))
node.Remove();
// add new children
if (newChildren != null) {
foreach (T node in newChildren) {
AddChild(node, role);
}
}
}
public void AddChild<T>(T child, Role<T> role) where T : AstNode public void AddChild<T>(T child, Role<T> role) where T : AstNode
{ {
if (role == null) if (role == null)

156
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs

@ -0,0 +1,156 @@
// 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;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Represents the children of an AstNode that have a specific role.
/// </summary>
public struct AstNodeCollection<T> : ICollection<T> where T : AstNode
{
readonly AstNode node;
readonly Role<T> role;
public AstNodeCollection(AstNode node, Role<T> role)
{
if (node == null)
throw new ArgumentNullException("node");
if (role == null)
throw new ArgumentNullException("role");
this.node = node;
this.role = role;
}
public int Count {
get {
var e = GetEnumerator();
int count = 0;
while (e.MoveNext())
count++;
return count;
}
}
public void Add(T element)
{
node.AddChild(element, role);
}
public void AddRange(IEnumerable<T> nodes)
{
// Evaluate 'nodes' first, since it might change when we add the new children
// Example: collection.AddRange(collection);
if (nodes != null) {
foreach (T node in nodes.ToList())
Add(node);
}
}
public void AddRange(T[] nodes)
{
// Fast overload for arrays - we don't need to create a copy
if (nodes != null) {
foreach (T node in nodes)
Add(node);
}
}
public void ReplaceWith(IEnumerable<T> nodes)
{
// Evaluate 'nodes' first, since it might change when we call Clear()
// Example: collection.ReplaceWith(collection);
if (nodes != null)
nodes = nodes.ToList();
Clear();
foreach (T node in nodes)
Add(node);
}
public void MoveTo(ICollection<T> targetCollection)
{
foreach (T node in this) {
node.Remove();
targetCollection.Add(node);
}
}
public bool Contains(T element)
{
return element != null && element.Parent == node && element.Role == role;
}
public bool Remove(T element)
{
if (Contains(element)) {
element.Remove();
return true;
} else {
return false;
}
}
public void CopyTo(T[] array, int arrayIndex)
{
foreach (T item in this)
array[arrayIndex++] = item;
}
public void Clear()
{
foreach (T item in this)
item.Remove();
}
bool ICollection<T>.IsReadOnly {
get { return false; }
}
public IEnumerator<T> GetEnumerator()
{
AstNode next;
for (AstNode cur = node.FirstChild; cur != null; cur = next) {
// Remember next before yielding cur.
// This allows removing/replacing nodes while iterating through the list.
next = cur.NextSibling;
if (cur.Role == role)
yield return (T)cur;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
if (obj is AstNodeCollection<T>) {
return ((AstNodeCollection<T>)obj) == this;
} else {
return false;
}
}
public override int GetHashCode()
{
return node.GetHashCode() ^ role.GetHashCode();
}
public static bool operator ==(AstNodeCollection<T> left, AstNodeCollection<T> right)
{
return left.role == right.role && left.node == right.node;
}
public static bool operator !=(AstNodeCollection<T> left, AstNodeCollection<T> right)
{
return !(left.role == right.role && left.node == right.node);
}
#endregion
}
}

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

@ -67,9 +67,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<ArraySpecifier> ArraySpecifiers { public AstNodeCollection<ArraySpecifier> ArraySpecifiers {
get { return GetChildrenByRole (ArraySpecifierRole); } get { return GetChildrenByRole (ArraySpecifierRole); }
set { SetChildrenByRole (ArraySpecifierRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs

@ -1,4 +1,4 @@
// //
// AnonymousMethodExpression.cs // AnonymousMethodExpression.cs
// //
// Author: // Author:
@ -47,9 +47,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs

@ -1,4 +1,4 @@
// //
// ArgListExpression.cs // ArgListExpression.cs
// //
// Author: // Author:
@ -45,9 +45,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole(Roles.Argument); } get { return GetChildrenByRole(Roles.Argument); }
set { SetChildrenByRole(Roles.Argument, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs

@ -16,18 +16,16 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole (Roles.Argument); } get { return GetChildrenByRole (Roles.Argument); }
set { SetChildrenByRole (Roles.Argument, value); }
} }
/// <summary> /// <summary>
/// Gets additional array ranks (those without size info). /// Gets additional array ranks (those without size info).
/// Empty for "new int[5,1]"; will contain a single element for "new int[5][]". /// Empty for "new int[5,1]"; will contain a single element for "new int[5][]".
/// </summary> /// </summary>
public IEnumerable<ArraySpecifier> AdditionalArraySpecifiers { public AstNodeCollection<ArraySpecifier> AdditionalArraySpecifiers {
get { return GetChildrenByRole(AdditionalArraySpecifierRole); } get { return GetChildrenByRole(AdditionalArraySpecifierRole); }
set { SetChildrenByRole (AdditionalArraySpecifierRole, value); }
} }
public ArrayInitializerExpression Initializer { public ArrayInitializerExpression Initializer {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs

@ -1,4 +1,4 @@
// //
// ArrayInitializerExpression.cs // ArrayInitializerExpression.cs
// //
// Author: // Author:
@ -55,9 +55,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBrace); } get { return GetChildByRole (Roles.LBrace); }
} }
public IEnumerable<Expression> Elements { public AstNodeCollection<Expression> Elements {
get { return GetChildrenByRole(Roles.Expression); } get { return GetChildrenByRole(Roles.Expression); }
set { SetChildrenByRole(Roles.Expression, value); }
} }
public CSharpTokenNode RBraceToken { public CSharpTokenNode RBraceToken {

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

@ -66,7 +66,10 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public IndexerExpression Indexer(IEnumerable<Expression> arguments) public IndexerExpression Indexer(IEnumerable<Expression> arguments)
{ {
return new IndexerExpression { Target = this, Arguments = arguments }; IndexerExpression expr = new IndexerExpression();
expr.Target = this;
expr.Arguments.AddRange(arguments);
return expr;
} }
/// <summary> /// <summary>
@ -74,7 +77,10 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public IndexerExpression Indexer(params Expression[] arguments) public IndexerExpression Indexer(params Expression[] arguments)
{ {
return new IndexerExpression { Target = this, Arguments = arguments }; IndexerExpression expr = new IndexerExpression();
expr.Target = this;
expr.Arguments.AddRange(arguments);
return expr;
} }
/// <summary> /// <summary>
@ -98,14 +104,14 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public InvocationExpression Invoke(string methodName, IEnumerable<AstType> typeArguments, IEnumerable<Expression> arguments) public InvocationExpression Invoke(string methodName, IEnumerable<AstType> typeArguments, IEnumerable<Expression> arguments)
{ {
return new InvocationExpression { InvocationExpression ie = new InvocationExpression();
Target = new MemberReferenceExpression { MemberReferenceExpression mre = new MemberReferenceExpression();
Target = this, mre.Target = this;
MemberName = methodName, mre.MemberName = methodName;
TypeArguments = typeArguments mre.TypeArguments.AddRange(typeArguments);
}, ie.Target = mre;
Arguments = arguments ie.Arguments.AddRange(arguments);
}; return ie;
} }
/// <summary> /// <summary>
@ -113,10 +119,10 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public InvocationExpression Invoke(IEnumerable<Expression> arguments) public InvocationExpression Invoke(IEnumerable<Expression> arguments)
{ {
return new InvocationExpression { InvocationExpression ie = new InvocationExpression();
Target = this, ie.Target = this;
Arguments = arguments ie.Arguments.AddRange(arguments);
}; return ie;
} }
/// <summary> /// <summary>
@ -124,7 +130,10 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public InvocationExpression Invoke(params Expression[] arguments) public InvocationExpression Invoke(params Expression[] arguments)
{ {
return Invoke(arguments.AsEnumerable()); InvocationExpression ie = new InvocationExpression();
ie.Target = this;
ie.Arguments.AddRange(arguments);
return ie;
} }
public CastExpression CastTo(AstType type) public CastExpression CastTo(AstType type)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs

@ -1,4 +1,4 @@
// //
// IdentifierExpression.cs // IdentifierExpression.cs
// //
// Author: // Author:
@ -56,9 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<AstType> TypeArguments { public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
set { SetChildrenByRole (Roles.TypeArgument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs

@ -1,4 +1,4 @@
// //
// IndexerExpression.cs // IndexerExpression.cs
// //
// Author: // Author:
@ -42,9 +42,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBracket); } get { return GetChildByRole (Roles.LBracket); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole<Expression>(Roles.Argument); } get { return GetChildrenByRole<Expression>(Roles.Argument); }
set { SetChildrenByRole(Roles.Argument, value); }
} }
public CSharpTokenNode RBracketToken { public CSharpTokenNode RBracketToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs

@ -1,4 +1,4 @@
// //
// InvocationExpression.cs // InvocationExpression.cs
// //
// Author: // Author:
@ -42,9 +42,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole<Expression>(Roles.Argument); } get { return GetChildrenByRole<Expression>(Roles.Argument); }
set { SetChildrenByRole(Roles.Argument, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs

@ -1,4 +1,4 @@
// //
// LambdaExpression.cs // LambdaExpression.cs
// //
// Author: // Author:
@ -36,9 +36,8 @@ namespace ICSharpCode.NRefactory.CSharp
public readonly static Role<CSharpTokenNode> ArrowRole = new Role<CSharpTokenNode>("Arrow", CSharpTokenNode.Null); public readonly static Role<CSharpTokenNode> ArrowRole = new Role<CSharpTokenNode>("Arrow", CSharpTokenNode.Null);
public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null); public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null);
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode ArrowToken { public CSharpTokenNode ArrowToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs

@ -1,4 +1,4 @@
// //
// MemberReferenceExpression.cs // MemberReferenceExpression.cs
// //
// Author: // Author:
@ -51,9 +51,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LChevron); } get { return GetChildByRole (Roles.LChevron); }
} }
public IEnumerable<AstType> TypeArguments { public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
set { SetChildrenByRole (Roles.TypeArgument, value); }
} }
public CSharpTokenNode RChevronToken { public CSharpTokenNode RChevronToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs

@ -1,4 +1,4 @@
// //
// ObjectCreateExpression.cs // ObjectCreateExpression.cs
// //
// Author: // Author:
@ -48,9 +48,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole (Roles.Argument); } get { return GetChildrenByRole (Roles.Argument); }
set { SetChildrenByRole (Roles.Argument, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs

@ -1,4 +1,4 @@
// //
// PointerReferenceExpression.cs // PointerReferenceExpression.cs
// //
// Author: // Author:
@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<AstType> TypeArguments { public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
set { SetChildrenByRole (Roles.TypeArgument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs

@ -28,9 +28,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
#endregion #endregion
public IEnumerable<QueryClause> Clauses { public AstNodeCollection<QueryClause> Clauses {
get { return GetChildrenByRole(ClauseRole); } get { return GetChildrenByRole(ClauseRole); }
set { SetChildrenByRole(ClauseRole, value); }
} }
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
@ -260,9 +259,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Keyword); } get { return GetChildByRole (Roles.Keyword); }
} }
public IEnumerable<QueryOrdering> Orderings { public AstNodeCollection<QueryOrdering> Orderings {
get { return GetChildrenByRole (OrderingRole); } get { return GetChildrenByRole (OrderingRole); }
set { SetChildrenByRole (OrderingRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs

@ -1,4 +1,4 @@
// //
// Attribute.cs // Attribute.cs
// //
// Author: // Author:
@ -44,9 +44,8 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return base.GetChildrenByRole (Roles.Argument); } get { return base.GetChildrenByRole (Roles.Argument); }
set { SetChildrenByRole (Roles.Argument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs

@ -1,4 +1,4 @@
// //
// AttributeSection.cs // AttributeSection.cs
// //
// Author: // Author:
@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp
set; set;
} }
public IEnumerable<Attribute> Attributes { public AstNodeCollection<Attribute> Attributes {
get { return base.GetChildrenByRole (AttributeRole); } get { return base.GetChildrenByRole (AttributeRole); }
set { SetChildrenByRole (AttributeRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs

@ -1,4 +1,4 @@
// //
// Constraint.cs // Constraint.cs
// //
// Author: // Author:
@ -53,9 +53,8 @@ namespace ICSharpCode.NRefactory.CSharp
// TODO: what about new(), struct and class constraints? // TODO: what about new(), struct and class constraints?
public IEnumerable<AstType> BaseTypes { public AstNodeCollection<AstType> BaseTypes {
get { return GetChildrenByRole (BaseTypeRole); } get { return GetChildrenByRole (BaseTypeRole); }
set { SetChildrenByRole (BaseTypeRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

11
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs

@ -1,4 +1,4 @@
// //
// DelegateDeclaration.cs // DelegateDeclaration.cs
// //
// Author: // Author:
@ -54,27 +54,24 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
} }
public IEnumerable<TypeParameterDeclaration> TypeParameters { public AstNodeCollection<TypeParameterDeclaration> TypeParameters {
get { return GetChildrenByRole (Roles.TypeParameter); } get { return GetChildrenByRole (Roles.TypeParameter); }
set { SetChildrenByRole (Roles.TypeParameter, value); }
} }
public CSharpTokenNode LParToken { public CSharpTokenNode LParToken {
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {
get { return GetChildByRole (Roles.RPar); } get { return GetChildByRole (Roles.RPar); }
} }
public IEnumerable<Constraint> Constraints { public AstNodeCollection<Constraint> Constraints {
get { return GetChildrenByRole (Roles.Constraint); } get { return GetChildrenByRole (Roles.Constraint); }
set { SetChildrenByRole (Roles.Constraint, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

10
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs

@ -1,4 +1,4 @@
// //
// NamespaceDeclaration.cs // NamespaceDeclaration.cs
// //
// Author: // Author:
@ -54,13 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp
return builder.ToString (); return builder.ToString ();
} }
set { set {
SetChildrenByRole (Roles.Identifier, value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty))); GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty)));
} }
} }
public IEnumerable<Identifier> Identifiers { public AstNodeCollection<Identifier> Identifiers {
get { return GetChildrenByRole (Roles.Identifier); } get { return GetChildrenByRole (Roles.Identifier); }
set { SetChildrenByRole (Roles.Identifier, value); }
} }
/// <summary> /// <summary>
@ -79,9 +78,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBrace); } get { return GetChildByRole (Roles.LBrace); }
} }
public IEnumerable<AstNode> Members { public AstNodeCollection<AstNode> Members {
get { return GetChildrenByRole(MemberRole); } get { return GetChildrenByRole(MemberRole); }
set { SetChildrenByRole(MemberRole, value); }
} }
public CSharpTokenNode RBraceToken { public CSharpTokenNode RBraceToken {

14
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs

@ -1,4 +1,4 @@
// //
// TypeDeclaration.cs // TypeDeclaration.cs
// //
// Author: // Author:
@ -59,28 +59,24 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<TypeParameterDeclaration> TypeParameters { public AstNodeCollection<TypeParameterDeclaration> TypeParameters {
get { return GetChildrenByRole (Roles.TypeParameter); } get { return GetChildrenByRole (Roles.TypeParameter); }
set { SetChildrenByRole (Roles.TypeParameter, value); }
} }
public IEnumerable<AstType> BaseTypes { public AstNodeCollection<AstType> BaseTypes {
get { return GetChildrenByRole (BaseTypeRole); } get { return GetChildrenByRole (BaseTypeRole); }
set { SetChildrenByRole (BaseTypeRole, value); }
} }
public IEnumerable<Constraint> Constraints { public AstNodeCollection<Constraint> Constraints {
get { return GetChildrenByRole (Roles.Constraint); } get { return GetChildrenByRole (Roles.Constraint); }
set { SetChildrenByRole (Roles.Constraint, value); }
} }
public CSharpTokenNode LBraceToken { public CSharpTokenNode LBraceToken {
get { return GetChildByRole (Roles.LBrace); } get { return GetChildByRole (Roles.LBrace); }
} }
public IEnumerable<AttributedNode> Members { public AstNodeCollection<AttributedNode> Members {
get { return GetChildrenByRole (MemberRole); } get { return GetChildrenByRole (MemberRole); }
set { SetChildrenByRole (MemberRole, value); }
} }
public CSharpTokenNode RBraceToken { public CSharpTokenNode RBraceToken {

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

@ -1,4 +1,4 @@
// //
// FullTypeName.cs // FullTypeName.cs
// //
// Author: // Author:
@ -51,9 +51,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<AstType> TypeArguments { public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
set { SetChildrenByRole (Roles.TypeArgument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

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

@ -1,4 +1,4 @@
// //
// FullTypeName.cs // FullTypeName.cs
// //
// Author: // Author:
@ -56,9 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<AstType> TypeArguments { public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
set { SetChildrenByRole (Roles.TypeArgument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

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

@ -1,4 +1,4 @@
// //
// BlockStatement.cs // BlockStatement.cs
// //
// Author: // Author:
@ -56,9 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBrace); } get { return GetChildByRole (Roles.LBrace); }
} }
public IEnumerable<Statement> Statements { public AstNodeCollection<Statement> Statements {
get { return GetChildrenByRole (StatementRole); } get { return GetChildrenByRole (StatementRole); }
set { SetChildrenByRole (StatementRole, value); }
} }
public CSharpTokenNode RBraceToken { public CSharpTokenNode RBraceToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs

@ -1,4 +1,4 @@
// //
// FixedStatement.cs // FixedStatement.cs
// //
// Author: // Author:
@ -46,9 +46,8 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
} }
public IEnumerable<VariableInitializer> Variables { public AstNodeCollection<VariableInitializer> Variables {
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
set { SetChildrenByRole (Roles.Variable, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

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

@ -1,4 +1,4 @@
// //
// ForStatement.cs // ForStatement.cs
// //
// Author: // Author:
@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp
/// Note: this contains multiple statements for "for (a = 2, b = 1; a > b; a--)", but contains /// Note: this contains multiple statements for "for (a = 2, b = 1; a > b; a--)", but contains
/// only a single statement for "for (int a = 2, b = 1; a > b; a--)" (a single VariableDeclarationStatement with two variables) /// only a single statement for "for (int a = 2, b = 1; a > b; a--)" (a single VariableDeclarationStatement with two variables)
/// </summary> /// </summary>
public IEnumerable<Statement> Initializers { public AstNodeCollection<Statement> Initializers {
get { return GetChildrenByRole (InitializerRole); } get { return GetChildrenByRole (InitializerRole); }
set { SetChildrenByRole (InitializerRole, value); }
} }
public Expression Condition { public Expression Condition {
@ -59,9 +58,8 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Condition, value); } set { SetChildByRole (Roles.Condition, value); }
} }
public IEnumerable<Statement> Iterators { public AstNodeCollection<Statement> Iterators {
get { return GetChildrenByRole (IteratorRole); } get { return GetChildrenByRole (IteratorRole); }
set { SetChildrenByRole (IteratorRole, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

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

@ -1,4 +1,4 @@
// //
// SwitchStatement.cs // SwitchStatement.cs
// //
// Author: // Author:
@ -57,9 +57,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBrace); } get { return GetChildByRole (Roles.LBrace); }
} }
public IEnumerable<SwitchSection> SwitchSections { public AstNodeCollection<SwitchSection> SwitchSections {
get { return GetChildrenByRole (SwitchSectionRole); } get { return GetChildrenByRole (SwitchSectionRole); }
set { SetChildrenByRole (SwitchSectionRole, value); }
} }
public CSharpTokenNode RBraceToken { public CSharpTokenNode RBraceToken {
@ -82,14 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<CaseLabel> CaseLabels { public AstNodeCollection<CaseLabel> CaseLabels {
get { return GetChildrenByRole (CaseLabelRole); } get { return GetChildrenByRole (CaseLabelRole); }
set { SetChildrenByRole (CaseLabelRole, value); }
} }
public IEnumerable<Statement> Statements { public AstNodeCollection<Statement> Statements {
get { return GetChildrenByRole (Roles.EmbeddedStatement); } get { return GetChildrenByRole (Roles.EmbeddedStatement); }
set { SetChildrenByRole (Roles.EmbeddedStatement, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs

@ -1,4 +1,4 @@
// //
// TryCatchStatement.cs // TryCatchStatement.cs
// //
// Author: // Author:
@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (TryBlockRole, value); } set { SetChildByRole (TryBlockRole, value); }
} }
public IEnumerable<CatchClause> CatchClauses { public AstNodeCollection<CatchClause> CatchClauses {
get { return GetChildrenByRole (CatchClauseRole); } get { return GetChildrenByRole (CatchClauseRole); }
set { SetChildrenByRole (CatchClauseRole, value); }
} }
public CSharpTokenNode FinallyToken { public CSharpTokenNode FinallyToken {

15
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs

@ -1,4 +1,4 @@
// //
// VariableDeclarationStatement.cs // VariableDeclarationStatement.cs
// //
// Author: // Author:
@ -33,6 +33,16 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public static readonly Role<CSharpModifierToken> ModifierRole = AttributedNode.ModifierRole; public static readonly Role<CSharpModifierToken> ModifierRole = AttributedNode.ModifierRole;
public VariableDeclarationStatement()
{
}
public VariableDeclarationStatement(AstType type, string name, Expression initializer = null)
{
this.Type = type;
this.Variables.Add(new VariableInitializer(name, initializer));
}
public Modifiers Modifiers { public Modifiers Modifiers {
get { return AttributedNode.GetModifiers(this); } get { return AttributedNode.GetModifiers(this); }
set { AttributedNode.SetModifiers(this, value); } set { AttributedNode.SetModifiers(this, value); }
@ -43,9 +53,8 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Type, value); } set { SetChildByRole (Roles.Type, value); }
} }
public IEnumerable<VariableInitializer> Variables { public AstNodeCollection<VariableInitializer> Variables {
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
set { SetChildrenByRole (Roles.Variable, value); }
} }
public CSharpTokenNode SemicolonToken { public CSharpTokenNode SemicolonToken {

3
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs

@ -11,9 +11,8 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute"); public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute");
public static readonly Role<CSharpModifierToken> ModifierRole = new Role<CSharpModifierToken>("Modifier"); public static readonly Role<CSharpModifierToken> ModifierRole = new Role<CSharpModifierToken>("Modifier");
public IEnumerable<AttributeSection> Attributes { public AstNodeCollection<AttributeSection> Attributes {
get { return base.GetChildrenByRole (AttributeRole); } get { return base.GetChildrenByRole (AttributeRole); }
set { SetChildrenByRole (AttributeRole, value); }
} }
public Modifiers Modifiers { public Modifiers Modifiers {

8
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs

@ -1,4 +1,4 @@
// //
// ConstructorDeclaration.cs // ConstructorDeclaration.cs
// //
// Author: // Author:
@ -37,9 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {
@ -105,9 +104,8 @@ namespace ICSharpCode.NRefactory.CSharp
set; set;
} }
public IEnumerable<Expression> Arguments { public AstNodeCollection<Expression> Arguments {
get { return GetChildrenByRole (Roles.Argument); } get { return GetChildrenByRole (Roles.Argument); }
set { SetChildrenByRole (Roles.Argument, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs

@ -1,4 +1,4 @@
// //
// EventDeclaration.cs // EventDeclaration.cs
// //
// Author: // Author:
@ -30,9 +30,8 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public class EventDeclaration : MemberDeclaration public class EventDeclaration : MemberDeclaration
{ {
public IEnumerable<VariableInitializer> Variables { public AstNodeCollection<VariableInitializer> Variables {
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
set { SetChildrenByRole (Roles.Variable, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs

@ -1,4 +1,4 @@
// //
// FieldDeclaration.cs // FieldDeclaration.cs
// //
// Author: // Author:
@ -31,9 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public class FieldDeclaration : MemberDeclaration public class FieldDeclaration : MemberDeclaration
{ {
public IEnumerable<VariableInitializer> Variables { public AstNodeCollection<VariableInitializer> Variables {
get { return GetChildrenByRole (Roles.Variable); } get { return GetChildrenByRole (Roles.Variable); }
set { SetChildrenByRole (Roles.Variable, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs

@ -1,4 +1,4 @@
// //
// IndexerDeclaration.cs // IndexerDeclaration.cs
// //
// Author: // Author:
@ -35,9 +35,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LBracket); } get { return GetChildByRole (Roles.LBracket); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RBracketToken { public CSharpTokenNode RBracketToken {

11
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs

@ -1,4 +1,4 @@
// //
// MethodDeclaration.cs // MethodDeclaration.cs
// //
// Author: // Author:
@ -31,27 +31,24 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public class MethodDeclaration : MemberDeclaration public class MethodDeclaration : MemberDeclaration
{ {
public IEnumerable<TypeParameterDeclaration> TypeParameters { public AstNodeCollection<TypeParameterDeclaration> TypeParameters {
get { return GetChildrenByRole (Roles.TypeParameter); } get { return GetChildrenByRole (Roles.TypeParameter); }
set { SetChildrenByRole (Roles.TypeParameter, value); }
} }
public CSharpTokenNode LParToken { public CSharpTokenNode LParToken {
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {
get { return GetChildByRole (Roles.RPar); } get { return GetChildByRole (Roles.RPar); }
} }
public IEnumerable<Constraint> Constraints { public AstNodeCollection<Constraint> Constraints {
get { return GetChildrenByRole (Roles.Constraint); } get { return GetChildrenByRole (Roles.Constraint); }
set { SetChildrenByRole (Roles.Constraint, value); }
} }
public BlockStatement Body { public BlockStatement Body {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs

@ -1,4 +1,4 @@
// //
// OperatorDeclaration.cs // OperatorDeclaration.cs
// //
// Author: // Author:
@ -80,9 +80,8 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public IEnumerable<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
set { SetChildrenByRole (Roles.Parameter, value); }
} }
public CSharpTokenNode RParToken { public CSharpTokenNode RParToken {

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs

@ -1,4 +1,4 @@
// //
// ParameterDeclarationExpression.cs // ParameterDeclarationExpression.cs
// //
// Author: // Author:
@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public IEnumerable<AttributeSection> Attributes { public AstNodeCollection<AttributeSection> Attributes {
get { return GetChildrenByRole (AttributeRole); } get { return GetChildrenByRole (AttributeRole); }
set { SetChildrenByRole (AttributeRole, value); }
} }
public ParameterModifier ParameterModifier { public ParameterModifier ParameterModifier {

4
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -675,10 +675,10 @@ namespace ICSharpCode.NRefactory.CSharp
bool LambdaNeedsParenthesis(LambdaExpression lambdaExpression) bool LambdaNeedsParenthesis(LambdaExpression lambdaExpression)
{ {
if (lambdaExpression.Parameters.Count() != 1) if (lambdaExpression.Parameters.Count != 1)
return true; return true;
var p = lambdaExpression.Parameters.Single(); var p = lambdaExpression.Parameters.Single();
return p.Type.IsNull && p.ParameterModifier == ParameterModifier.None; return !(p.Type.IsNull && p.ParameterModifier == ParameterModifier.None);
} }
public object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) public object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)

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

@ -122,9 +122,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (location != null) if (location != null)
spec.AddChild (new CSharpTokenNode (Convert (location[0]), 1), FieldDeclaration.Roles.RBracket); spec.AddChild (new CSharpTokenNode (Convert (location[0]), 1), FieldDeclaration.Roles.RBracket);
result.ArraySpecifiers = new ArraySpecifier[] { result.ArraySpecifiers.Add(spec);
spec
};
} }
return result; return result;
} }

3
NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup> <PropertyGroup>
<ProjectGuid>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</ProjectGuid> <ProjectGuid>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</ProjectGuid>
@ -56,6 +56,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CSharp\Ast\AstComparer.cs" /> <Compile Include="CSharp\Ast\AstComparer.cs" />
<Compile Include="CSharp\Ast\AstNodeCollection.cs" />
<Compile Include="CSharp\Ast\Expressions\TypeReferenceExpression.cs" /> <Compile Include="CSharp\Ast\Expressions\TypeReferenceExpression.cs" />
<Compile Include="CSharp\Ast\IAstVisitor.cs" /> <Compile Include="CSharp\Ast\IAstVisitor.cs" />
<Compile Include="CSharp\Ast\CompilationUnit.cs" /> <Compile Include="CSharp\Ast\CompilationUnit.cs" />

1
README.txt

@ -13,3 +13,4 @@ Included open-source libraries:
ILSpy Contributors: ILSpy Contributors:
Daniel Grunwald Daniel Grunwald
David Srbecky David Srbecky
Siegfried Pammer

Loading…
Cancel
Save