From 0691aee36341355f00e4389b428ab6ea22e83c13 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 23 Sep 2017 22:03:36 +0200 Subject: [PATCH] Remove foreach from PatternStatementTransform. --- .../Transforms/PatternStatementTransform.cs | 254 ------------------ 1 file changed, 254 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index 6212647e1..a346fc7bd 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -73,12 +73,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms public override AstNode VisitExpressionStatement(ExpressionStatement expressionStatement) { AstNode result; - if (context.Settings.UsingStatement) - { - result = TransformNonGenericForEach(expressionStatement); - if (result != null) - return result; - } result = TransformFor(expressionStatement); if (result != null) return result; @@ -95,16 +89,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms return base.VisitExpressionStatement(expressionStatement); } - public override AstNode VisitUsingStatement(UsingStatement usingStatement) - { - if (context.Settings.ForEachStatement) { - AstNode result = TransformForeach(usingStatement); - if (result != null) - return result; - } - return base.VisitUsingStatement(usingStatement); - } - public override AstNode VisitWhileStatement(WhileStatement whileStatement) { return TransformDoWhile(whileStatement) ?? base.VisitWhileStatement(whileStatement); @@ -165,244 +149,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms new AnyNode("initializer") )); - #region foreach (generic) - static readonly UsingStatement genericForeachPattern = new UsingStatement { - ResourceAcquisition = new VariableDeclarationStatement { - Type = new AnyNode("enumeratorType"), - Variables = { - new NamedNode( - "enumeratorVariable", - new VariableInitializer { - Name = Pattern.AnyString, - Initializer = new InvocationExpression(new MemberReferenceExpression(new AnyNode("collection").ToExpression(), "GetEnumerator")) - } - ) - } - }, - EmbeddedStatement = new BlockStatement { - new Repeat( - new VariableDeclarationStatement { Type = new AnyNode(), Variables = { new VariableInitializer(Pattern.AnyString) } }.WithName("variablesOutsideLoop") - ).ToStatement(), - new WhileStatement { - Condition = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpressionBackreference("enumeratorVariable").ToExpression(), "MoveNext")), - EmbeddedStatement = new BlockStatement { - new Repeat( - new VariableDeclarationStatement { - Type = new AnyNode(), - Variables = { new VariableInitializer(Pattern.AnyString) } - }.WithName("variablesInsideLoop") - ).ToStatement(), - new AssignmentExpression { - Left = new IdentifierExpression(Pattern.AnyString).WithName("itemVariable"), - Operator = AssignmentOperatorType.Assign, - Right = new MemberReferenceExpression(new IdentifierExpressionBackreference("enumeratorVariable").ToExpression(), "Current") - }, - new Repeat(new AnyNode("statement")).ToStatement() - } - }.WithName("loop"), - new OptionalNode(new ReturnStatement(new IdentifierExpression(Pattern.AnyString)).WithName("optionalReturn")).ToStatement() - }}; - - public ForeachStatement TransformForeach(UsingStatement node) - { - Match m = genericForeachPattern.Match(node); - if (!m.Success) - return null; - if (!(node.Parent is BlockStatement) && m.Has("variablesOutsideLoop")) { - // if there are variables outside the loop, we need to put those into the parent block, and that won't work if the direct parent isn't a block - return null; - } - VariableInitializer enumeratorVar = m.Get("enumeratorVariable").Single(); - var itemVar = m.Get("itemVariable").Single().GetILVariable(); - WhileStatement loop = m.Get("loop").Single(); - - if (!VariableCanBeDeclaredInLoop(itemVar, loop)) { - return null; - } - - // Make sure that the enumerator variable is not used inside the body - var enumeratorId = Identifier.Create(enumeratorVar.Name); - foreach (Statement stmt in m.Get("statement")) { - if (stmt.Descendants.OfType().Any(id => enumeratorId.IsMatch(id))) - return null; - } - - BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m.Get("variablesInsideLoop")) - newBody.Add(stmt.Detach()); - foreach (Statement stmt in m.Get("statement")) - newBody.Add(stmt.Detach()); - - itemVar.Kind = IL.VariableKind.ForeachLocal; - ForeachStatement foreachStatement = new ForeachStatement { - VariableType = context.Settings.AnonymousTypes && itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), - VariableName = itemVar.Name, - InExpression = m.Get("collection").Single().Detach(), - EmbeddedStatement = newBody - }.WithILVariable(itemVar); - foreachStatement.CopyAnnotationsFrom(loop); - if (foreachStatement.InExpression is BaseReferenceExpression) { - foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); - } - node.ReplaceWith(foreachStatement); - foreach (Statement stmt in m.Get("variablesOutsideLoop")) { - ((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(null, stmt.Detach()); - } - var optionalReturnAfterLoop = m.Get("optionalReturn").SingleOrDefault(); - if (optionalReturnAfterLoop != null) - ((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(foreachStatement, optionalReturnAfterLoop.Detach()); - return foreachStatement; - } - - bool VariableCanBeDeclaredInLoop(IL.ILVariable itemVar, WhileStatement loop) - { - if (itemVar == null || !(itemVar.Kind == IL.VariableKind.Local || itemVar.Kind == IL.VariableKind.StackSlot)) { - // only locals/temporaries can be converted into foreach loop variable - return false; - } - - var blockContainer = loop.Annotation(); - - if (!itemVar.IsSingleDefinition) { - // foreach variable cannot be assigned to. - // As a special case, we accept taking the address for a method call, - // but only if the call is the only use, so that any mutation by the call - // cannot be observed. - if (!AddressUsedForSingleCall(itemVar, blockContainer)) { - return false; - } - } - - if (itemVar.CaptureScope != null && itemVar.CaptureScope != blockContainer) { - // captured variables cannot be declared in the loop unless the loop is their capture scope - return false; - } - - AstNode declPoint = declareVariables.GetDeclarationPoint(itemVar); - return declPoint.Ancestors.Contains(loop); - } - - static bool AddressUsedForSingleCall(IL.ILVariable v, IL.BlockContainer loop) - { - if (v.StoreCount == 1 && v.AddressCount == 1 && v.LoadCount == 0 && v.Type.IsReferenceType == false) { - if (v.AddressInstructions[0].Parent is IL.Call call - && v.AddressInstructions[0].ChildIndex == 0 - && !call.Method.IsStatic) { - // used as this pointer for a method call - // this is OK iff the call is not within a nested loop - for (var node = call.Parent; node != null; node = node.Parent) { - if (node == loop) - return true; - else if (node is IL.BlockContainer) - break; - } - } - } - return false; - } - #endregion - - #region foreach (non-generic) - ExpressionStatement getEnumeratorPattern = new ExpressionStatement( - new AssignmentExpression( - new NamedNode("left", new IdentifierExpression(Pattern.AnyString)), - new InvocationExpression(new MemberReferenceExpression(new AnyNode("collection").ToExpression(), "GetEnumerator")) - )); - - TryCatchStatement nonGenericForeachPattern = new TryCatchStatement { - TryBlock = new BlockStatement { - new WhileStatement { - Condition = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression(Pattern.AnyString).WithName("enumerator"), "MoveNext")), - EmbeddedStatement = new BlockStatement { - new AssignmentExpression( - new IdentifierExpression(Pattern.AnyString).WithName("itemVar"), - new Choice { - new MemberReferenceExpression(new Backreference("enumerator").ToExpression(), "Current"), - new CastExpression { - Type = new AnyNode("castType"), - Expression = new MemberReferenceExpression(new Backreference("enumerator").ToExpression(), "Current") - } - } - ), - new Repeat(new AnyNode("stmt")).ToStatement() - } - }.WithName("loop") - }, - FinallyBlock = new BlockStatement { - new AssignmentExpression( - new IdentifierExpression(Pattern.AnyString).WithName("disposable"), - new AsExpression(new Backreference("enumerator").ToExpression(), new TypePattern(typeof(IDisposable))) - ), - new IfElseStatement { - Condition = new BinaryOperatorExpression { - Left = new Backreference("disposable"), - Operator = BinaryOperatorType.InEquality, - Right = new NullReferenceExpression() - }, - TrueStatement = new BlockStatement { - new InvocationExpression(new MemberReferenceExpression(new Backreference("disposable").ToExpression(), "Dispose")) - } - } - }}; - - public ForeachStatement TransformNonGenericForEach(ExpressionStatement node) - { - Match m1 = getEnumeratorPattern.Match(node); - if (!m1.Success) return null; - AstNode tryCatch = node.NextSibling; - Match m2 = nonGenericForeachPattern.Match(tryCatch); - if (!m2.Success) return null; - - IdentifierExpression enumeratorVar = m2.Get("enumerator").Single(); - var itemVar = m2.Get("itemVar").Single().GetILVariable(); - WhileStatement loop = m2.Get("loop").Single(); - - // verify that the getEnumeratorPattern assigns to the same variable as the nonGenericForeachPattern is reading from - if (!enumeratorVar.IsMatch(m1.Get("left").Single())) - return null; - - if (!VariableCanBeDeclaredInLoop(itemVar, loop)) - return null; - - itemVar.Kind = IL.VariableKind.ForeachLocal; - ForeachStatement foreachStatement = new ForeachStatement - { - VariableType = context.Settings.AnonymousTypes && itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), - VariableName = itemVar.Name, - }.WithILVariable(itemVar); - BlockStatement body = new BlockStatement(); - foreachStatement.EmbeddedStatement = body; - foreachStatement.CopyAnnotationsFrom(loop); - ((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement); - - body.Add(node.Detach()); - body.Add((Statement)tryCatch.Detach()); - - /* - // Now that we moved the whole try-catch into the foreach loop; verify that we can - // move the enumerator into the foreach loop: - CanMoveVariableDeclarationIntoStatement(enumeratorVarDecl, foreachStatement, out declarationPoint); - if (declarationPoint != foreachStatement) { - // oops, the enumerator variable can't be moved into the foreach loop - // Undo our AST changes: - ((BlockStatement)foreachStatement.Parent).Statements.InsertBefore(foreachStatement, node.Detach()); - foreachStatement.ReplaceWith(tryCatch); - return null; - } - */ - - // Now create the correct body for the foreach statement: - foreachStatement.InExpression = m1.Get("collection").Single().Detach(); - if (foreachStatement.InExpression is BaseReferenceExpression) { - foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); - } - body.Statements.Clear(); - body.Statements.AddRange(m2.Get("stmt").Select(stmt => stmt.Detach())); - - return foreachStatement; - } - #endregion - #region for static readonly WhileStatement forPattern = new WhileStatement { Condition = new BinaryOperatorExpression {