diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 212ad6392..962ebdea0 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -139,6 +139,13 @@ namespace ICSharpCode.Decompiler.CSharp // e.g. DelegateDeclaration return entityDecl; } + foreach (var field in typeDef.Fields) { + var fieldDef = typeSystem.GetCecil(field) as FieldDefinition; + if (fieldDef != null) { + var memberDecl = DoDecompile(fieldDef, field, decompilationContext.WithCurrentMember(field)); + typeDecl.Members.Add(memberDecl); + } + } foreach (var method in typeDef.Methods) { var methodDef = typeSystem.GetCecil(method) as MethodDefinition; if (methodDef != null) { @@ -146,6 +153,13 @@ namespace ICSharpCode.Decompiler.CSharp typeDecl.Members.Add(memberDecl); } } + foreach (var property in typeDef.Properties) { + var propDef = typeSystem.GetCecil(property) as PropertyDefinition; + if (propDef != null) { + var propDecl = DoDecompile(propDef, property, decompilationContext.WithCurrentMember(property)); + typeDecl.Members.Add(propDecl); + } + } return typeDecl; } @@ -168,26 +182,60 @@ namespace ICSharpCode.Decompiler.CSharp var typeSystemAstBuilder = CreateAstBuilder(decompilationContext); var entityDecl = typeSystemAstBuilder.ConvertEntity(method); if (methodDefinition.HasBody) { - var ilReader = new ILReader(typeSystem); - var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken); - function.CheckInvariant(); - function.Body = function.Body.AcceptVisitor(new TransformingVisitor()); - function.CheckInvariant(); - var statementBuilder = new StatementBuilder(decompilationContext); - var body = statementBuilder.ConvertAsBlock(function.Body); - - // insert variables at start of body - Statement prevVarDecl = null; - foreach (var v in function.Variables) { - if (v.Kind == VariableKind.Local) { - var type = typeSystemAstBuilder.ConvertType(v.Type); - var varDecl = new VariableDeclarationStatement(type, v.Name); - body.Statements.InsertAfter(prevVarDecl, varDecl); - prevVarDecl = varDecl; - } + DecompileBody(methodDefinition, method, entityDecl, decompilationContext, typeSystemAstBuilder); + } + return entityDecl; + } + + void DecompileBody(MethodDefinition methodDefinition, IMethod method, EntityDeclaration entityDecl, ITypeResolveContext decompilationContext, TypeSystemAstBuilder typeSystemAstBuilder) + { + var ilReader = new ILReader(typeSystem); + var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken); + function.CheckInvariant(); + function.Body = function.Body.AcceptVisitor(new TransformingVisitor()); + function.CheckInvariant(); + var statementBuilder = new StatementBuilder(decompilationContext, method); + var body = statementBuilder.ConvertAsBlock(function.Body); + + // insert variables at start of body + Statement prevVarDecl = null; + foreach (var v in function.Variables) { + if (v.Kind == VariableKind.Local) { + var type = typeSystemAstBuilder.ConvertType(v.Type); + var varDecl = new VariableDeclarationStatement(type, v.Name); + body.Statements.InsertAfter(prevVarDecl, varDecl); + prevVarDecl = varDecl; } - - entityDecl.AddChild(body, Roles.Body); + } + + entityDecl.AddChild(body, Roles.Body); + } + + EntityDeclaration DoDecompile(FieldDefinition fieldDefinition, IField field, ITypeResolveContext decompilationContext) + { + Debug.Assert(decompilationContext.CurrentMember == field); + var typeSystemAstBuilder = CreateAstBuilder(decompilationContext); + return typeSystemAstBuilder.ConvertEntity(field); + } + + EntityDeclaration DoDecompile(PropertyDefinition propertyDefinition, IProperty property, ITypeResolveContext decompilationContext) + { + Debug.Assert(decompilationContext.CurrentMember == property); + var typeSystemAstBuilder = CreateAstBuilder(decompilationContext); + EntityDeclaration entityDecl = typeSystemAstBuilder.ConvertEntity(property); + Accessor getter, setter; + if (entityDecl is PropertyDeclaration) { + getter = ((PropertyDeclaration)entityDecl).Getter; + setter = ((PropertyDeclaration)entityDecl).Setter; + } else { + getter = ((IndexerDeclaration)entityDecl).Getter; + setter = ((IndexerDeclaration)entityDecl).Setter; + } + if (property.CanGet) { + DecompileBody(propertyDefinition.GetMethod, property.Getter, getter, decompilationContext, typeSystemAstBuilder); + } + if (property.CanSet) { + DecompileBody(propertyDefinition.SetMethod, property.Setter, setter, decompilationContext, typeSystemAstBuilder); } return entityDecl; } diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 03f9a918e..380c62d5a 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -32,12 +32,12 @@ namespace ICSharpCode.Decompiler.CSharp { readonly ExpressionBuilder exprBuilder; readonly IMethod currentMethod; - - public StatementBuilder(ITypeResolveContext decompilationContext) + + public StatementBuilder(ITypeResolveContext decompilationContext, IMethod currentMethod) { - Debug.Assert(decompilationContext != null && decompilationContext.CurrentMember is IMethod); + Debug.Assert(decompilationContext != null && currentMethod != null); this.exprBuilder = new ExpressionBuilder(decompilationContext); - this.currentMethod = (IMethod)decompilationContext.CurrentMember; + this.currentMethod = currentMethod; } public Statement Convert(ILInstruction inst) diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index cc9f72417..b84e7c4ef 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -94,6 +94,7 @@ + diff --git a/ICSharpCode.Decompiler/Tests/TestCases/PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/TestCases/PropertiesAndEvents.cs new file mode 100644 index 000000000..dd96da37b --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/TestCases/PropertiesAndEvents.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PropertiesAndEvents +{ + class Program + { + public static int Main(string[] args) + { + Index i = new Index(); + i.AutoProp = "Name"; + Console.WriteLine("AutoProp set!"); + i[0] = 5; + i[1] = 2; + Console.WriteLine("{0} {1}", i[0], i[5]); + Console.WriteLine("PI² = {0}", i.PISquare); + return -1; + } + } + + class Index + { + int thisValue; + + public int this[int i] + { + get { Console.WriteLine("get_this({0})", i); return i * i; } + set { Console.WriteLine("set_this({0}, {1})", i, value); thisValue = value; } + } + + public string AutoProp { get; set; } + + public double PISquare + { + get { Console.WriteLine("get_PISquare"); return Math.Pow(Math.PI, 2); } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index aa195eb20..3e0fd2c84 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -46,6 +46,12 @@ namespace ICSharpCode.Decompiler.Tests TestCompileDecompileCompileOutputAll("CompoundAssignment.cs"); } + [Test] + public void PropertiesAndEvents() + { + TestCompileDecompileCompileOutputAll("PropertiesAndEvents.cs"); + } + void TestCompileDecompileCompileOutputAll(string testFileName) { TestCompileDecompileCompileOutput(testFileName, CompilerOptions.None);