From 41d6c3f6ebf18c54933c14d36629b4167b4f05c9 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 8 Mar 2011 09:06:50 +0100 Subject: [PATCH] Don't show compiler-generated code for automatic properties. Closes #69. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 6 +- .../Transforms/PatternStatementTransform.cs | 79 ++++++++++++++++++- .../Ast/Transforms/TransformationPipeline.cs | 2 +- ICSharpCode.Decompiler/DecompilerSettings.cs | 45 +++++++++++ 4 files changed, 126 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index de016ae24..c11a9c945 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -50,8 +50,10 @@ namespace ICSharpCode.Decompiler.Ast return true; } FieldDefinition field = member as FieldDefinition; - if (field != null) { - if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal) && field.IsCompilerGenerated()) + if (field != null && field.IsCompilerGenerated()) { + if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal)) + return true; + if (settings.AutomaticProperties && field.Name.StartsWith("<", StringComparison.Ordinal) && field.Name.EndsWith("BackingField", StringComparison.Ordinal)) return true; } return false; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index f41fe43ec..641640e6f 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -14,11 +14,24 @@ namespace ICSharpCode.Decompiler.Ast.Transforms /// public class PatternStatementTransform : IAstTransform { + DecompilerContext context; + + public PatternStatementTransform(DecompilerContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + this.context = context; + } + public void Run(AstNode compilationUnit) { + if (context.Settings.UsingStatement) TransformUsings(compilationUnit); - TransformForeach(compilationUnit); + if (context.Settings.ForEachStatement) + TransformForeach(compilationUnit); TransformFor(compilationUnit); + if (context.Settings.AutomaticProperties) + TransformAutomaticProperties(compilationUnit); } /// @@ -99,7 +112,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms #endregion #region foreach - UsingStatement foreachPattern = new UsingStatement { + static readonly UsingStatement foreachPattern = new UsingStatement { ResourceAcquisition = new VariableDeclarationStatement { Type = new AnyNode("enumeratorType"), Variables = { @@ -188,7 +201,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms #endregion #region for - WhileStatement forPattern = new WhileStatement { + static readonly WhileStatement forPattern = new WhileStatement { Condition = new BinaryOperatorExpression { Left = new NamedNode("ident", new IdentifierExpression()), Operator = BinaryOperatorType.Any, @@ -237,5 +250,65 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } #endregion + + #region Automatic Properties + static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration { + Attributes = { new Repeat(new AnyNode()) }, + Modifiers = Modifiers.Any, + ReturnType = new AnyNode(), + Getter = new Accessor { + Attributes = { new Repeat(new AnyNode()) }, + Modifiers = Modifiers.Any, + Body = new BlockStatement { + new ReturnStatement { + Expression = new NamedNode("fieldReference", new MemberReferenceExpression { Target = new ThisReferenceExpression() }) + } + } + }, + Setter = new Accessor { + Attributes = { new Repeat(new AnyNode()) }, + Modifiers = Modifiers.Any, + Body = new BlockStatement { + new AssignmentExpression { + Left = new Backreference("fieldReference"), + Right = new IdentifierExpression("value") + } + }}}; + + void TransformAutomaticProperties(AstNode compilationUnit) + { + foreach (var property in compilationUnit.Descendants.OfType()) { + PropertyDefinition cecilProperty = property.Annotation(); + if (cecilProperty == null || cecilProperty.GetMethod == null || cecilProperty.SetMethod == null) + continue; + if (!(cecilProperty.GetMethod.IsCompilerGenerated() && cecilProperty.SetMethod.IsCompilerGenerated())) + continue; + Match m = automaticPropertyPattern.Match(property); + if (m != null) { + FieldDefinition field = m.Get("fieldReference").Single().Annotation(); + if (field.IsCompilerGenerated()) { + RemoveCompilerGeneratedAttribute(property.Getter.Attributes); + RemoveCompilerGeneratedAttribute(property.Setter.Attributes); + property.Getter.Body = null; + property.Setter.Body = null; + } + } + } + } + + void RemoveCompilerGeneratedAttribute(AstNodeCollection attributeSections) + { + foreach (AttributeSection section in attributeSections) { + foreach (var attr in section.Attributes) { + TypeReference tr = attr.Type.Annotation(); + if (tr != null && tr.Namespace == "System.Runtime.CompilerServices" && tr.Name == "CompilerGeneratedAttribute") { + attr.Remove(); + } + } + if (section.Attributes.Count == 0) + section.Remove(); + } + } + #endregion } } diff --git a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs b/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs index d240c7583..b4aedf175 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs @@ -19,7 +19,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return new IAstTransform[] { new PushNegation(), new DelegateConstruction(context), - new PatternStatementTransform(), + new PatternStatementTransform(context), new ConvertConstructorCallIntoInitializer(), new ReplaceMethodCallsWithOperators(), }; diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index a1770d771..541b95a53 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -41,6 +41,51 @@ namespace ICSharpCode.Decompiler } } + bool automaticProperties = true; + + /// + /// Decompile automatic properties + /// + public bool AutomaticProperties { + get { return automaticProperties; } + set { + if (automaticProperties != value) { + automaticProperties = value; + OnPropertyChanged("AutomaticProperties"); + } + } + } + + bool usingStatement = true; + + /// + /// Decompile using statements. + /// + public bool UsingStatement { + get { return usingStatement; } + set { + if (usingStatement != value) { + usingStatement = value; + OnPropertyChanged("UsingStatement"); + } + } + } + + bool forEachStatement = true; + + /// + /// Decompile foreach statements. + /// + public bool ForEachStatement { + get { return forEachStatement; } + set { + if (forEachStatement != value) { + forEachStatement = value; + OnPropertyChanged("ForEachStatement"); + } + } + } + public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName)