From cca75477891cb342a5ed42e3fbf258260aa01871 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 20 Mar 2011 14:46:28 +0100 Subject: [PATCH] Fixed some bugs in DeclareVariables. --- .../Ast/AstMethodBodyBuilder.cs | 4 +- .../Ast/Transforms/DeclareVariables.cs | 45 +++++++++++++++---- .../Ast/Transforms/DelegateConstruction.cs | 6 +-- .../Transforms/PatternStatementTransform.cs | 20 ++------- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 6bd62aad8..f36e02577 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -88,9 +88,11 @@ namespace ICSharpCode.Decompiler.Ast context.CancellationToken.ThrowIfCancellationRequested(); Ast.BlockStatement astBlock = TransformBlock(ilMethod); CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments + + Statement insertionPoint = astBlock.Statements.FirstOrDefault(); foreach (ILVariable v in localVariablesToDefine) { var newVarDecl = new VariableDeclarationStatement(AstBuilder.ConvertType(v.Type), v.Name); - astBlock.Statements.InsertAfter(null, newVarDecl); + astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); } return astBlock; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs index fe2cba560..818504751 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs @@ -92,14 +92,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName)) continue; } - foreach (BlockStatement subBlock in stmt.Children.OfType()) { - DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops); + foreach (AstNode child in stmt.Children) { + BlockStatement subBlock = child as BlockStatement; + if (subBlock != null) { + DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops); + } else if (HasNestedBlocks(child)) { + foreach (BlockStatement nestedSubBlock in child.Children.OfType()) { + DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops); + } + } } } } else { // Try converting an assignment expression into a VariableDeclarationStatement if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) { // Declare the variable in front of declarationPoint + block.Statements.InsertBefore( declarationPoint, new VariableDeclarationStatement((AstType)type.Clone(), variableName) @@ -117,9 +125,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { IdentifierExpression ident = ae.Left as IdentifierExpression; if (ident != null && ident.Identifier == variableName) { + // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, + // which might be still in use by the definite assignment graph. declarationPoint.ReplaceWith(new VariableDeclarationStatement { Type = (AstType)type.Clone(), - Variables = { new VariableInitializer(variableName, ae.Right.Detach()).CopyAnnotationsFrom(ae) } + Variables = { new VariableInitializer(variableName, ae.Right.Clone()).CopyAnnotationsFrom(ae) } }.CopyAnnotationsFrom(es).WithAnnotation(new DeclaredVariableAnnotation(es))); return true; } @@ -136,7 +146,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (ident != null && ident.Identifier == variableName) { expression.ReplaceWith(new VariableDeclarationStatement { Type = (AstType)type.Clone(), - Variables = { new VariableInitializer(variableName, ae.Right.Detach()).CopyAnnotationsFrom(ae) } + Variables = { new VariableInitializer(variableName, ae.Right.Clone()).CopyAnnotationsFrom(ae) } }.WithAnnotation(declaredVariableAnnotation)); return true; } @@ -179,7 +189,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return false; } // If we can move the variable into the sub-block, we need to ensure that the remaining code - // does not use the value that was assigend by the first sub-block + // does not use the value that was assigned by the first sub-block Statement nextStatement = stmt.NextStatement; // The next statement might be a variable declaration that we inserted, and thus does not exist // in the definite assignment graph. Thus we need to look up the corresponding instruction @@ -239,14 +249,28 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } - // We can move the variable into a sub-block only if the variable is used in only that sub-block + // We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition) for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) { - if (!(child is BlockStatement) && UsesVariable(child, variableName)) - return false; + if (!(child is BlockStatement) && UsesVariable(child, variableName)) { + if (HasNestedBlocks(child)) { + // catch clauses/switch sections can contain nested blocks + for (AstNode grandchild = child.FirstChild; grandchild != null; grandchild = grandchild.NextSibling) { + if (!(grandchild is BlockStatement) && UsesVariable(grandchild, variableName)) + return false; + } + } else { + return false; + } + } } return true; } + static bool HasNestedBlocks(AstNode node) + { + return node is CatchClause || node is SwitchSection; + } + static bool UsesVariable(AstNode node, string variableName) { IdentifierExpression ie = node as IdentifierExpression; @@ -278,6 +302,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } + CatchClause catchClause = node as CatchClause; + if (catchClause != null && catchClause.VariableName == variableName) { + return false; // no need to introduce the variable here + } + for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { if (UsesVariable(child, variableName)) return true; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index b619230a9..639198232 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -276,11 +276,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): + Statement insertionPoint = blockStatement.Statements.FirstOrDefault(); foreach (var tuple in variablesToDeclare) { var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2); - if (newVarDecl != null) - newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); - blockStatement.Statements.InsertAfter(null, newVarDecl); + newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); + blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); } } return null; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index 71c56e6a6..3b01fcb5d 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -445,19 +445,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms 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) - return null; + // TODO: verify that 'obj' variable can be removed } + // TODO: verify that 'flag' variable can be removed // transform the code into a lock statement: LockStatement l = new LockStatement(); l.Expression = enter.Detach(); @@ -487,17 +477,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms }, TrueStatement = new AnyNode("dictCreation") }, - new VariableDeclarationStatement { - Type = new PrimitiveType("int"), - Variables = { new NamedNode("intVar", new VariableInitializer()) } - }, new IfElseStatement { Condition = new Backreference("cachedDict").ToExpression().Invoke( "TryGetValue", new NamedNode("switchVar", new IdentifierExpression()), new DirectionExpression { FieldDirection = FieldDirection.Out, - Expression = new IdentifierExpressionBackreference("intVar") + Expression = new IdentifierExpression().WithName("intVar") }), TrueStatement = new BlockStatement { Statements = {