From 039483ddbd8e711cbec6bd344d895b7ce9145672 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 18 Mar 2011 13:34:46 +0100 Subject: [PATCH] Optimize PatternStatementTransform. --- .../Ast/Transforms/ContextTrackingVisitor.cs | 32 +- .../Ast/Transforms/DelegateConstruction.cs | 2 +- .../Transforms/PatternStatementTransform.cs | 587 ++++++++++-------- 3 files changed, 353 insertions(+), 268 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs b/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs index a9b3f3fc6..236b95711 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms /// /// Base class for AST visitors that need the current type/method context info. /// - public abstract class ContextTrackingVisitor : DepthFirstAstVisitor, IAstTransform + public abstract class ContextTrackingVisitor : DepthFirstAstVisitor, IAstTransform { protected readonly DecompilerContext context; @@ -22,7 +22,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms this.context = context; } - public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) + public override TResult VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) { TypeDefinition oldType = context.CurrentType; try { @@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } - public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) + public override TResult VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) { Debug.Assert(context.CurrentMethod == null); try { @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } - public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) + public override TResult VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) { Debug.Assert(context.CurrentMethod == null); try { @@ -55,7 +55,29 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } - public override object VisitAccessor(Accessor accessor, object data) + public override TResult VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data) + { + Debug.Assert(context.CurrentMethod == null); + try { + context.CurrentMethod = destructorDeclaration.Annotation(); + return base.VisitDestructorDeclaration(destructorDeclaration, data); + } finally { + context.CurrentMethod = null; + } + } + + public override TResult VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) + { + Debug.Assert(context.CurrentMethod == null); + try { + context.CurrentMethod = operatorDeclaration.Annotation(); + return base.VisitOperatorDeclaration(operatorDeclaration, data); + } finally { + context.CurrentMethod = null; + } + } + + public override TResult VisitAccessor(Accessor accessor, object data) { Debug.Assert(context.CurrentMethod == null); try { diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index c44200bf3..6eb8f4d98 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms /// For anonymous methods, creates an AnonymousMethodExpression. /// Also gets rid of any "Display Classes" left over after inlining an anonymous method. /// - public class DelegateConstruction : ContextTrackingVisitor + public class DelegateConstruction : ContextTrackingVisitor { internal sealed class Annotation { diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index cb9581624..e2d6536d3 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.PatternMatching; @@ -13,38 +14,106 @@ namespace ICSharpCode.Decompiler.Ast.Transforms /// /// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement. /// - public class PatternStatementTransform : IAstTransform + public sealed class PatternStatementTransform : ContextTrackingVisitor, IAstTransform { - DecompilerContext context; + public PatternStatementTransform(DecompilerContext context) : base(context) + { + } - public PatternStatementTransform(DecompilerContext context) + #region Visitor Overrides + protected override AstNode VisitChildren(AstNode node, object data) { - if (context == null) - throw new ArgumentNullException("context"); - this.context = context; + // Go through the children, and keep visiting a node as long as it changes. + // Because some transforms delete/replace nodes before and after the node being transformed, we rely + // on the transform's return value to know where we need to keep iterating. + for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { + AstNode oldChild; + do { + oldChild = child; + child = child.AcceptVisitor(this, data); + Debug.Assert(child != null && child.Parent == node); + } while (child != oldChild); + } + return node; } - public void Run(AstNode compilationUnit) + public override AstNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data) { - if (context.Settings.UsingStatement) - TransformUsings(compilationUnit); - if (context.Settings.ForEachStatement) - TransformForeach(compilationUnit); - TransformFor(compilationUnit); - TransformDoWhile(compilationUnit); - if (context.Settings.LockStatement) - TransformLock(compilationUnit); - if (context.Settings.SwitchStatementOnString) - TransformSwitchOnString(compilationUnit); - if (context.Settings.AutomaticProperties) - TransformAutomaticProperties(compilationUnit); - if (context.Settings.AutomaticEvents) - TransformAutomaticEvents(compilationUnit); - - TransformDestructor(compilationUnit); - TransformTryCatchFinally(compilationUnit); + AstNode result; + if (context.Settings.UsingStatement) { + result = TransformUsings(variableDeclarationStatement); + if (result != null) + return result; + } + result = TransformFor(variableDeclarationStatement); + if (result != null) + return result; + if (context.Settings.LockStatement) { + result = TransformLock(variableDeclarationStatement); + if (result != null) + return result; + } + return base.VisitVariableDeclarationStatement(variableDeclarationStatement, data); + } + + public override AstNode VisitUsingStatement(UsingStatement usingStatement, object data) + { + if (context.Settings.ForEachStatement) { + AstNode result = TransformForeach(usingStatement); + if (result != null) + return result; + } + return base.VisitUsingStatement(usingStatement, data); + } + + public override AstNode VisitWhileStatement(WhileStatement whileStatement, object data) + { + return TransformDoWhile(whileStatement) ?? base.VisitWhileStatement(whileStatement, data); + } + + public override AstNode VisitIfElseStatement(IfElseStatement ifElseStatement, object data) + { + if (context.Settings.SwitchStatementOnString) { + AstNode result = TransformSwitchOnString(ifElseStatement); + if (result != null) + return result; + } + return base.VisitIfElseStatement(ifElseStatement, data); + } + + public override AstNode VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) + { + if (context.Settings.AutomaticProperties) { + AstNode result = TransformAutomaticProperties(propertyDeclaration); + if (result != null) + return result; + } + return base.VisitPropertyDeclaration(propertyDeclaration, data); + } + + public override AstNode VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration, object data) + { + // first apply transforms to the accessor bodies + base.VisitCustomEventDeclaration(eventDeclaration, data); + if (context.Settings.AutomaticEvents) { + AstNode result = TransformAutomaticEvents(eventDeclaration); + if (result != null) + return result; + } + return eventDeclaration; + } + + public override AstNode VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) + { + return TransformDestructor(methodDeclaration) ?? base.VisitMethodDeclaration(methodDeclaration, data); } + public override AstNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data) + { + return TransformTryCatchFinally(tryCatchStatement) ?? base.VisitTryCatchStatement(tryCatchStatement, data); + } + #endregion + /// /// $type $variable = $initializer; /// @@ -94,31 +163,30 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }; - public void TransformUsings(AstNode compilationUnit) + public UsingStatement TransformUsings(VariableDeclarationStatement node) { - foreach (AstNode node in compilationUnit.Descendants.OfType().ToArray()) { - Match m1 = variableDeclPattern.Match(node); - if (m1 == null) continue; - AstNode tryCatch = node.NextSibling; - while (simpleVariableDefinition.Match(tryCatch) != null) - tryCatch = tryCatch.NextSibling; - Match m2 = usingTryCatchPattern.Match(tryCatch); - if (m2 == null) continue; - if (m1.Get("variable").Single().Name == m2.Get("ident").Single().Identifier) { - if (m2.Has("valueType")) { - // if there's no if(x!=null), then it must be a value type - TypeReference tr = m1.Get("type").Single().Annotation(); - if (tr == null || !tr.IsValueType) - continue; - } - BlockStatement body = m2.Get("body").Single(); - tryCatch.ReplaceWith( - new UsingStatement { - ResourceAcquisition = node.Detach(), - EmbeddedStatement = body.Detach() - }); + Match m1 = variableDeclPattern.Match(node); + if (m1 == null) return null; + AstNode tryCatch = node.NextSibling; + while (simpleVariableDefinition.Match(tryCatch) != null) + tryCatch = tryCatch.NextSibling; + Match m2 = usingTryCatchPattern.Match(tryCatch); + if (m2 == null) return null; + if (m1.Get("variable").Single().Name == m2.Get("ident").Single().Identifier) { + if (m2.Has("valueType")) { + // if there's no if(x!=null), then it must be a value type + TypeReference tr = m1.Get("type").Single().Annotation(); + if (tr == null || !tr.IsValueType) + return null; } + BlockStatement body = m2.Get("body").Single(); + UsingStatement usingStatement = new UsingStatement(); + usingStatement.ResourceAcquisition = node.Detach(); + usingStatement.EmbeddedStatement = body.Detach(); + tryCatch.ReplaceWith(usingStatement); + return usingStatement; } + return null; } #endregion @@ -185,29 +253,28 @@ namespace ICSharpCode.Decompiler.Ast.Transforms }.ToStatement() }; - public void TransformForeach(AstNode compilationUnit) + public ForeachStatement TransformForeach(UsingStatement node) { - foreach (AstNode node in compilationUnit.Descendants.OfType().ToArray()) { - Match m = foreachPattern.Match(node); - if (m == null) - continue; - VariableInitializer enumeratorVar = m.Get("enumeratorVariable").Single(); - VariableInitializer itemVar = m.Get("itemVariable").Single(); - if (m.Has("itemVariableInsideLoop") && itemVar.Annotation() != null) { - // cannot move captured variables out of loops - continue; - } - BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m.Get("statement")) - newBody.Add(stmt.Detach()); - node.ReplaceWith( - new ForeachStatement { - VariableType = m.Get("itemType").Single().Detach(), - VariableName = itemVar.Name, - InExpression = m.Get("collection").Single().Detach(), - EmbeddedStatement = newBody - }); + Match m = foreachPattern.Match(node); + if (m == null) + return null; + VariableInitializer enumeratorVar = m.Get("enumeratorVariable").Single(); + VariableInitializer itemVar = m.Get("itemVariable").Single(); + if (m.Has("itemVariableInsideLoop") && itemVar.Annotation() != null) { + // cannot move captured variables out of loops + return null; } + BlockStatement newBody = new BlockStatement(); + foreach (Statement stmt in m.Get("statement")) + newBody.Add(stmt.Detach()); + ForeachStatement foreachStatement = new ForeachStatement { + VariableType = m.Get("itemType").Single().Detach(), + VariableName = itemVar.Name, + InExpression = m.Get("collection").Single().Detach(), + EmbeddedStatement = newBody + }; + node.ReplaceWith(foreachStatement); + return foreachStatement; } #endregion @@ -232,32 +299,30 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }}; - public void TransformFor(AstNode compilationUnit) + public ForStatement TransformFor(VariableDeclarationStatement node) { - foreach (AstNode node in compilationUnit.Descendants.OfType().ToArray()) { - Match m1 = variableDeclPattern.Match(node); - if (m1 == null) continue; - AstNode next = node.NextSibling; - while (simpleVariableDefinition.Match(next) != null) - next = next.NextSibling; - Match m2 = forPattern.Match(next); - if (m2 == null) continue; - // ensure the variable in the for pattern is the same as in the declaration - if (m1.Get("variable").Single().Name != m2.Get("ident").Single().Identifier) - continue; - WhileStatement loop = (WhileStatement)next; - node.Remove(); - BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m2.Get("statement")) - newBody.Add(stmt.Detach()); - loop.ReplaceWith( - new ForStatement { - Initializers = { (VariableDeclarationStatement)node }, - Condition = loop.Condition.Detach(), - Iterators = { m2.Get("increment").Single().Detach() }, - EmbeddedStatement = newBody - }); - } + Match m1 = variableDeclPattern.Match(node); + if (m1 == null) return null; + AstNode next = node.NextSibling; + while (simpleVariableDefinition.Match(next) != null) + next = next.NextSibling; + Match m2 = forPattern.Match(next); + if (m2 == null) return null; + // ensure the variable in the for pattern is the same as in the declaration + if (m1.Get("variable").Single().Name != m2.Get("ident").Single().Identifier) + return null; + WhileStatement loop = (WhileStatement)next; + node.Remove(); + BlockStatement newBody = new BlockStatement(); + foreach (Statement stmt in m2.Get("statement")) + newBody.Add(stmt.Detach()); + ForStatement forStatement = new ForStatement(); + forStatement.Initializers.Add(node); + forStatement.Condition = loop.Condition.Detach(); + forStatement.Iterators.Add(m2.Get("increment").Single().Detach()); + forStatement.EmbeddedStatement = newBody; + loop.ReplaceWith(forStatement); + return forStatement; } #endregion @@ -274,37 +339,37 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }}; - public void TransformDoWhile(AstNode compilationUnit) + public DoWhileStatement TransformDoWhile(WhileStatement whileLoop) { - foreach (WhileStatement whileLoop in compilationUnit.Descendants.OfType().ToArray()) { - Match m = doWhilePattern.Match(whileLoop); - if (m != null) { - DoWhileStatement doLoop = new DoWhileStatement(); - doLoop.Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, m.Get("condition").Single().Detach()); - doLoop.Condition.AcceptVisitor(new PushNegation(), null); - BlockStatement block = (BlockStatement)whileLoop.EmbeddedStatement; - block.Statements.Last().Remove(); // remove if statement - doLoop.EmbeddedStatement = block.Detach(); - whileLoop.ReplaceWith(doLoop); - - // we may have to extract variable definitions out of the loop if they were used in the condition: - foreach (var varDecl in block.Statements.OfType()) { - VariableInitializer v = varDecl.Variables.Single(); - if (doLoop.Condition.DescendantsAndSelf.OfType().Any(i => i.Identifier == v.Name)) { - AssignmentExpression assign = new AssignmentExpression(new IdentifierExpression(v.Name), v.Initializer.Detach()); - // move annotations from v to assign: - assign.CopyAnnotationsFrom(v); - v.RemoveAnnotations(); - // remove varDecl with assignment; and move annotations from varDecl to the ExpressionStatement: - varDecl.ReplaceWith(new ExpressionStatement(assign).CopyAnnotationsFrom(varDecl)); - varDecl.RemoveAnnotations(); - - // insert the varDecl above the do-while loop: - doLoop.Parent.InsertChildBefore(doLoop, varDecl, BlockStatement.StatementRole); - } + Match m = doWhilePattern.Match(whileLoop); + if (m != null) { + DoWhileStatement doLoop = new DoWhileStatement(); + doLoop.Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, m.Get("condition").Single().Detach()); + doLoop.Condition.AcceptVisitor(new PushNegation(), null); + BlockStatement block = (BlockStatement)whileLoop.EmbeddedStatement; + block.Statements.Last().Remove(); // remove if statement + doLoop.EmbeddedStatement = block.Detach(); + whileLoop.ReplaceWith(doLoop); + + // we may have to extract variable definitions out of the loop if they were used in the condition: + foreach (var varDecl in block.Statements.OfType()) { + VariableInitializer v = varDecl.Variables.Single(); + if (doLoop.Condition.DescendantsAndSelf.OfType().Any(i => i.Identifier == v.Name)) { + AssignmentExpression assign = new AssignmentExpression(new IdentifierExpression(v.Name), v.Initializer.Detach()); + // move annotations from v to assign: + assign.CopyAnnotationsFrom(v); + v.RemoveAnnotations(); + // remove varDecl with assignment; and move annotations from varDecl to the ExpressionStatement: + varDecl.ReplaceWith(new ExpressionStatement(assign).CopyAnnotationsFrom(varDecl)); + varDecl.RemoveAnnotations(); + + // insert the varDecl above the do-while loop: + doLoop.Parent.InsertChildBefore(doLoop, varDecl, BlockStatement.StatementRole); } } + return doLoop; } + return null; } #endregion @@ -339,49 +404,49 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }}; - public void TransformLock(AstNode compilationUnit) + public LockStatement TransformLock(VariableDeclarationStatement node) { - foreach (AstNode node in compilationUnit.Descendants.OfType().ToArray()) { - Match m1 = lockFlagInitPattern.Match(node); - if (m1 == null) continue; - AstNode tryCatch = node.NextSibling; - while (simpleVariableDefinition.Match(tryCatch) != null) - tryCatch = tryCatch.NextSibling; - Match m2 = lockTryCatchPattern.Match(tryCatch); - if (m2 == null) continue; - if (m1.Get("variable").Single().Name == m2.Get("flag").Single().Identifier) { - Expression enter = m2.Get("enter").Single(); - IdentifierExpression exit = m2.Get("exit").Single(); - if (exit.Match(enter) == null) { - // If exit and enter are not the same, then enter must be "exit = ..." - AssignmentExpression assign = enter as AssignmentExpression; - if (assign == null) - continue; - if (exit.Match(assign.Left) == null) - continue; - enter = assign.Right; - // Remove 'exit' variable: - bool ok = false; - for (AstNode tmp = node.NextSibling; tmp != tryCatch; tmp = tmp.NextSibling) { - VariableDeclarationStatement v = (VariableDeclarationStatement)tmp; - if (v.Variables.Single().Name == exit.Identifier) { - ok = true; - v.Remove(); - break; - } + Match m1 = lockFlagInitPattern.Match(node); + if (m1 == null) return null; + AstNode tryCatch = node.NextSibling; + while (simpleVariableDefinition.Match(tryCatch) != null) + tryCatch = tryCatch.NextSibling; + Match m2 = lockTryCatchPattern.Match(tryCatch); + if (m2 == null) return null; + if (m1.Get("variable").Single().Name == m2.Get("flag").Single().Identifier) { + Expression enter = m2.Get("enter").Single(); + IdentifierExpression exit = m2.Get("exit").Single(); + if (exit.Match(enter) == null) { + // If exit and enter are not the same, then enter must be "exit = ..." + AssignmentExpression assign = enter as AssignmentExpression; + if (assign == null) + return null; + if (exit.Match(assign.Left) == null) + return null; + enter = assign.Right; + // Remove 'exit' variable: + bool ok = false; + for (AstNode tmp = node.NextSibling; tmp != tryCatch; tmp = tmp.NextSibling) { + VariableDeclarationStatement v = (VariableDeclarationStatement)tmp; + if (v.Variables.Single().Name == exit.Identifier) { + ok = true; + v.Remove(); + break; } - if (!ok) - continue; } - // transform the code into a lock statement: - LockStatement l = new LockStatement(); - l.Expression = enter.Detach(); - l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach(); - ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call - tryCatch.ReplaceWith(l); - node.Remove(); // remove flag variable + if (!ok) + return null; } + // transform the code into a lock statement: + LockStatement l = new LockStatement(); + l.Expression = enter.Detach(); + l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach(); + ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call + tryCatch.ReplaceWith(l); + node.Remove(); // remove flag variable + return l; } + return null; } #endregion @@ -428,60 +493,59 @@ namespace ICSharpCode.Decompiler.Ast.Transforms FalseStatement = new OptionalNode("nullStmt", new BlockStatement { Statements = { new Repeat(new AnyNode()) } }) }; - public void TransformSwitchOnString(AstNode compilationUnit) + public SwitchStatement TransformSwitchOnString(IfElseStatement node) { - foreach (AstNode node in compilationUnit.Descendants.OfType().ToArray()) { - Match m = switchOnStringPattern.Match(node); - if (m == null) - continue; - if (m.Has("nonNullDefaultStmt") && !m.Has("nullStmt")) - continue; - // switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment - if (m.Get("switchVar").Single().Match(m.Get("switchExpr").Single()) == null) { - AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression; - if (m.Get("switchVar").Single().Match(assign.Left) == null) + Match m = switchOnStringPattern.Match(node); + if (m == null) + return null; + if (m.Has("nonNullDefaultStmt") && !m.Has("nullStmt")) + return null; + // switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment + if (m.Get("switchVar").Single().Match(m.Get("switchExpr").Single()) == null) { + AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression; + if (m.Get("switchVar").Single().Match(assign.Left) == null) + return null; + } + FieldReference cachedDictField = m.Get("cachedDict").Single().Annotation(); + if (cachedDictField == null || !cachedDictField.DeclaringType.Name.StartsWith("", StringComparison.Ordinal)) + return null; + List dictCreation = m.Get("dictCreation").Single().Statements.ToList(); + List> dict = BuildDictionary(dictCreation); + SwitchStatement sw = m.Get("switch").Single(); + sw.Expression = m.Get("switchExpr").Single().Detach(); + foreach (SwitchSection section in sw.SwitchSections) { + List labels = section.CaseLabels.ToList(); + section.CaseLabels.Clear(); + foreach (CaseLabel label in labels) { + PrimitiveExpression expr = label.Expression as PrimitiveExpression; + if (expr == null || !(expr.Value is int)) continue; - } - FieldReference cachedDictField = m.Get("cachedDict").Single().Annotation(); - if (cachedDictField == null || !cachedDictField.DeclaringType.Name.StartsWith("", StringComparison.Ordinal)) - continue; - List dictCreation = m.Get("dictCreation").Single().Statements.ToList(); - List> dict = BuildDictionary(dictCreation); - SwitchStatement sw = m.Get("switch").Single(); - sw.Expression = m.Get("switchExpr").Single().Detach(); - foreach (SwitchSection section in sw.SwitchSections) { - List labels = section.CaseLabels.ToList(); - section.CaseLabels.Clear(); - foreach (CaseLabel label in labels) { - PrimitiveExpression expr = label.Expression as PrimitiveExpression; - if (expr == null || !(expr.Value is int)) - continue; - int val = (int)expr.Value; - foreach (var pair in dict) { - if (pair.Value == val) - section.CaseLabels.Add(new CaseLabel { Expression = new PrimitiveExpression(pair.Key) }); - } + int val = (int)expr.Value; + foreach (var pair in dict) { + if (pair.Value == val) + section.CaseLabels.Add(new CaseLabel { Expression = new PrimitiveExpression(pair.Key) }); } } - if (m.Has("nullStmt")) { - SwitchSection section = new SwitchSection(); - section.CaseLabels.Add(new CaseLabel { Expression = new NullReferenceExpression() }); - BlockStatement block = m.Get("nullStmt").Single(); - block.Statements.Add(new BreakStatement()); - section.Statements.Add(block.Detach()); + } + if (m.Has("nullStmt")) { + SwitchSection section = new SwitchSection(); + section.CaseLabels.Add(new CaseLabel { Expression = new NullReferenceExpression() }); + BlockStatement block = m.Get("nullStmt").Single(); + block.Statements.Add(new BreakStatement()); + section.Statements.Add(block.Detach()); + sw.SwitchSections.Add(section); + if (m.Has("nonNullDefaultStmt")) { + section = new SwitchSection(); + section.CaseLabels.Add(new CaseLabel()); + block = new BlockStatement(); + block.Statements.AddRange(m.Get("nonNullDefaultStmt").Select(s => s.Detach())); + block.Add(new BreakStatement()); + section.Statements.Add(block); sw.SwitchSections.Add(section); - if (m.Has("nonNullDefaultStmt")) { - section = new SwitchSection(); - section.CaseLabels.Add(new CaseLabel()); - block = new BlockStatement(); - block.Statements.AddRange(m.Get("nonNullDefaultStmt").Select(s => s.Detach())); - block.Add(new BreakStatement()); - section.Statements.Add(block); - sw.SwitchSections.Add(section); - } } - node.ReplaceWith(sw); } + node.ReplaceWith(sw); + return sw; } List> BuildDictionary(List dictCreation) @@ -527,25 +591,25 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }}}; - void TransformAutomaticProperties(AstNode compilationUnit) + PropertyDeclaration TransformAutomaticProperties(PropertyDeclaration property) { - 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().ResolveWithinSameModule(); - if (field.IsCompilerGenerated()) { - RemoveCompilerGeneratedAttribute(property.Getter.Attributes); - RemoveCompilerGeneratedAttribute(property.Setter.Attributes); - property.Getter.Body = null; - property.Setter.Body = null; - } + PropertyDefinition cecilProperty = property.Annotation(); + if (cecilProperty == null || cecilProperty.GetMethod == null || cecilProperty.SetMethod == null) + return null; + if (!(cecilProperty.GetMethod.IsCompilerGenerated() && cecilProperty.SetMethod.IsCompilerGenerated())) + return null; + Match m = automaticPropertyPattern.Match(property); + if (m != null) { + FieldDefinition field = m.Get("fieldReference").Single().Annotation().ResolveWithinSameModule(); + if (field.IsCompilerGenerated()) { + RemoveCompilerGeneratedAttribute(property.Getter.Attributes); + RemoveCompilerGeneratedAttribute(property.Setter.Attributes); + property.Getter.Body = null; + property.Setter.Body = null; } } + // Since the event instance is not changed, we can continue in the visitor as usual, so return null + return null; } void RemoveCompilerGeneratedAttribute(AstNodeCollection attributeSections) @@ -625,33 +689,32 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return combineMethod.DeclaringType.FullName == "System.Delegate"; } - void TransformAutomaticEvents(AstNode compilationUnit) + EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev) { - foreach (var ev in compilationUnit.Descendants.OfType().ToArray()) { - Match m1 = automaticEventPatternV4.Match(ev.AddAccessor); - if (!CheckAutomaticEventV4Match(m1, ev, true)) - continue; - Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor); - if (!CheckAutomaticEventV4Match(m2, ev, false)) - continue; - EventDeclaration ed = new EventDeclaration(); - ev.Attributes.MoveTo(ed.Attributes); - ed.ReturnType = ev.ReturnType.Detach(); - ed.Modifiers = ev.Modifiers; - ed.Variables.Add(new VariableInitializer(ev.Name)); - ed.CopyAnnotationsFrom(ev); - - EventDefinition eventDef = ev.Annotation(); - if (eventDef != null) { - FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name); - if (field != null) { - ed.AddAnnotation(field); - AstBuilder.ConvertAttributes(ed, field, AttributeTarget.Field); - } + Match m1 = automaticEventPatternV4.Match(ev.AddAccessor); + if (!CheckAutomaticEventV4Match(m1, ev, true)) + return null; + Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor); + if (!CheckAutomaticEventV4Match(m2, ev, false)) + return null; + EventDeclaration ed = new EventDeclaration(); + ev.Attributes.MoveTo(ed.Attributes); + ed.ReturnType = ev.ReturnType.Detach(); + ed.Modifiers = ev.Modifiers; + ed.Variables.Add(new VariableInitializer(ev.Name)); + ed.CopyAnnotationsFrom(ev); + + EventDefinition eventDef = ev.Annotation(); + if (eventDef != null) { + FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name); + if (field != null) { + ed.AddAnnotation(field); + AstBuilder.ConvertAttributes(ed, field, AttributeTarget.Field); } - - ev.ReplaceWith(ed); } + + ev.ReplaceWith(ed); + return ed; } #endregion @@ -671,19 +734,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } }; - void TransformDestructor(AstNode compilationUnit) + DestructorDeclaration TransformDestructor(MethodDeclaration methodDef) { - foreach (var methodDef in compilationUnit.Descendants.OfType()) { - Match m = destructorPattern.Match(methodDef); - if (m != null) { - DestructorDeclaration dd = new DestructorDeclaration(); - methodDef.Attributes.MoveTo(dd.Attributes); - dd.Modifiers = methodDef.Modifiers & ~(Modifiers.Protected | Modifiers.Override); - dd.Body = m.Get("body").Single().Detach(); - dd.Name = AstBuilder.CleanName(context.CurrentType.Name); - methodDef.ReplaceWith(dd); - } + Match m = destructorPattern.Match(methodDef); + if (m != null) { + DestructorDeclaration dd = new DestructorDeclaration(); + methodDef.Attributes.MoveTo(dd.Attributes); + dd.Modifiers = methodDef.Modifiers & ~(Modifiers.Protected | Modifiers.Override); + dd.Body = m.Get("body").Single().Detach(); + dd.Name = AstBuilder.CleanName(context.CurrentType.Name); + methodDef.ReplaceWith(dd); + return dd; } + return null; } #endregion @@ -702,15 +765,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms /// Simplify nested 'try { try {} catch {} } finally {}'. /// This transformation must run after the using/lock tranformations. /// - void TransformTryCatchFinally(AstNode compilationUnit) + TryCatchStatement TransformTryCatchFinally(TryCatchStatement tryFinally) { - foreach (var tryFinally in compilationUnit.Descendants.OfType()) { - if (tryCatchFinallyPattern.Match(tryFinally) != null) { - TryCatchStatement tryCatch = (TryCatchStatement)tryFinally.TryBlock.Statements.Single(); - tryFinally.TryBlock = tryCatch.TryBlock.Detach(); - tryCatch.CatchClauses.MoveTo(tryFinally.CatchClauses); - } + if (tryCatchFinallyPattern.Match(tryFinally) != null) { + TryCatchStatement tryCatch = (TryCatchStatement)tryFinally.TryBlock.Statements.Single(); + tryFinally.TryBlock = tryCatch.TryBlock.Detach(); + tryCatch.CatchClauses.MoveTo(tryFinally.CatchClauses); } + // Since the tryFinally instance is not changed, we can continue in the visitor as usual, so return null + return null; } #endregion