using System; using System.Collections.Generic; using System.Linq; using System.Text; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; namespace ICSharpCode.Decompiler.CSharp.Transforms { class NormalizeBlockStatements : DepthFirstAstVisitor, IAstTransform { TransformContext context; public override void VisitIfElseStatement(IfElseStatement ifElseStatement) { base.VisitIfElseStatement(ifElseStatement); DoTransform(ifElseStatement.TrueStatement, ifElseStatement); DoTransform(ifElseStatement.FalseStatement, ifElseStatement); } public override void VisitWhileStatement(WhileStatement whileStatement) { base.VisitWhileStatement(whileStatement); InsertBlock(whileStatement.EmbeddedStatement); } public override void VisitDoWhileStatement(DoWhileStatement doWhileStatement) { base.VisitDoWhileStatement(doWhileStatement); InsertBlock(doWhileStatement.EmbeddedStatement); } public override void VisitForeachStatement(ForeachStatement foreachStatement) { base.VisitForeachStatement(foreachStatement); InsertBlock(foreachStatement.EmbeddedStatement); } public override void VisitForStatement(ForStatement forStatement) { base.VisitForStatement(forStatement); InsertBlock(forStatement.EmbeddedStatement); } public override void VisitFixedStatement(FixedStatement fixedStatement) { base.VisitFixedStatement(fixedStatement); InsertBlock(fixedStatement.EmbeddedStatement); } public override void VisitLockStatement(LockStatement lockStatement) { base.VisitLockStatement(lockStatement); InsertBlock(lockStatement.EmbeddedStatement); } public override void VisitUsingStatement(UsingStatement usingStatement) { base.VisitUsingStatement(usingStatement); DoTransform(usingStatement.EmbeddedStatement, usingStatement); } void DoTransform(Statement statement, Statement parent) { if (statement.IsNull) return; if (context.Settings.AlwaysUseBraces) { if (!IsElseIf(statement, parent)) { InsertBlock(statement); } } else { if (statement is BlockStatement b && b.Statements.Count == 1 && IsAllowedAsEmbeddedStatement(b.Statements.First(), parent)) { statement.ReplaceWith(b.Statements.First().Detach()); } else if (!IsAllowedAsEmbeddedStatement(statement, parent)) { InsertBlock(statement); } } } bool IsElseIf(Statement statement, Statement parent) { return parent is IfElseStatement && statement.Role == IfElseStatement.FalseRole; } static void InsertBlock(Statement statement) { if (statement.IsNull) return; if (!(statement is BlockStatement)) { var b = new BlockStatement(); statement.ReplaceWith(b); if (statement is EmptyStatement && !statement.Children.Any()) { b.CopyAnnotationsFrom(statement); } else { b.Add(statement); } } } bool IsAllowedAsEmbeddedStatement(Statement statement, Statement parent) { switch (statement) { case IfElseStatement ies: return parent is IfElseStatement && ies.Role == IfElseStatement.FalseRole; case VariableDeclarationStatement vds: case WhileStatement ws: case DoWhileStatement dws: case SwitchStatement ss: case ForeachStatement fes: case ForStatement fs: case LockStatement ls: case FixedStatement fxs: return false; case UsingStatement us: return parent is UsingStatement; default: return !(parent?.Parent is IfElseStatement); } } void IAstTransform.Run(AstNode rootNode, TransformContext context) { this.context = context; rootNode.AcceptVisitor(this); } public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) { if (context.Settings.UseExpressionBodyForCalculatedGetterOnlyProperties) { SimplifyPropertyDeclaration(propertyDeclaration); } base.VisitPropertyDeclaration(propertyDeclaration); } static readonly PropertyDeclaration CalculatedGetterOnlyPropertyPattern = new PropertyDeclaration() { Attributes = { new Repeat(new AnyNode()) }, Modifiers = Modifiers.Any, Name = Pattern.AnyString, ReturnType = new AnyNode(), Getter = new Accessor() { Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) } } }; void SimplifyPropertyDeclaration(PropertyDeclaration propertyDeclaration) { var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration); if (!m.Success) return; propertyDeclaration.ExpressionBody = m.Get("expression").Single().Detach(); propertyDeclaration.Getter.Remove(); } } }