Browse Source

Improved variable placement.

The variable placement step now happens much later in the decompiler pipeline, which simplifies some AST transforms.
pull/100/head
Daniel Grunwald 15 years ago
parent
commit
c7bbdcd0cb
  1. 8
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 91
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  3. 255
      ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
  4. 27
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  5. 2
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  6. 190
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  7. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  8. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

8
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -22,7 +22,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -22,7 +22,6 @@ namespace ICSharpCode.Decompiler.Ast
TypeSystem typeSystem;
DecompilerContext context;
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition
HashSet<ILVariable> implicitlyDefinedVariables = new HashSet<ILVariable>(); // local variables that are implicitly defined (e.g. catch handler)
/// <summary>
/// Creates the body for the method definition.
@ -89,8 +88,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -89,8 +88,9 @@ namespace ICSharpCode.Decompiler.Ast
context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
foreach (ILVariable v in localVariablesToDefine.Except(implicitlyDefinedVariables)) {
DeclareVariableInSmallestScope.DeclareVariable(astBlock, AstBuilder.ConvertType(v.Type), v.Name);
foreach (ILVariable v in localVariablesToDefine) {
var newVarDecl = new VariableDeclarationStatement(AstBuilder.ConvertType(v.Type), v.Name);
astBlock.Statements.InsertAfter(null, newVarDecl);
}
return astBlock;
@ -158,8 +158,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -158,8 +158,6 @@ namespace ICSharpCode.Decompiler.Ast
var tryCatchStmt = new Ast.TryCatchStatement();
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable != null)
implicitlyDefinedVariables.Add(catchClause.ExceptionVariable);
tryCatchStmt.CatchClauses.Add(
new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),

91
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// Helper class for declaring variables.
/// </summary>
public static class DeclareVariableInSmallestScope
{
static readonly ExpressionStatement assignmentPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("ident", new IdentifierExpression()),
new AnyNode("init")
));
/// <summary>
/// Declares a variable in the smallest required scope.
/// </summary>
/// <param name="node">The root of the subtree being searched for the best insertion position</param>
/// <param name="type">The type of the new variable</param>
/// <param name="name">The name of the new variable</param>
/// <param name="allowPassIntoLoops">Whether the variable is allowed to be placed inside a loop</param>
public static VariableDeclarationStatement DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true)
{
VariableDeclarationStatement result = null;
AstNode pos = FindInsertPos(node, name, allowPassIntoLoops);
if (pos != null) {
Match m = assignmentPattern.Match(pos);
if (m != null && m.Get<IdentifierExpression>("ident").Single().Identifier == name) {
result = new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach());
result.Variables.Single().CopyAnnotationsFrom(((ExpressionStatement)pos).Expression);
result.CopyAnnotationsFrom(pos);
pos.ReplaceWith(result);
} else {
result = new VariableDeclarationStatement(type, name);
pos.Parent.InsertChildBefore(pos, result, BlockStatement.StatementRole);
}
}
return result;
}
static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops)
{
AstNode pos = null;
AstNode withinPos = null;
while (node != null) {
IdentifierExpression ident = node as IdentifierExpression;
if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
return node;
FixedStatement fixedStatement = node as FixedStatement;
if (fixedStatement != null) {
foreach (VariableInitializer v in fixedStatement.Variables) {
if (v.Name == name)
return null; // no need to introduce the variable here
}
}
AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops);
if (withinCurrent != null) {
if (pos == null) {
pos = node;
withinPos = withinCurrent;
} else {
return pos;
}
}
node = node.NextSibling;
}
if (withinPos != null && withinPos.Role == BlockStatement.StatementRole && AllowPassInto(pos, allowPassIntoLoops))
return withinPos;
else
return pos;
}
static bool AllowPassInto(AstNode node, bool allowPassIntoLoops)
{
if (node is AnonymousMethodExpression || node is LambdaExpression)
return false;
if (node is ForStatement || node is ForeachStatement || node is DoWhileStatement || node is WhileStatement)
return allowPassIntoLoops;
return true;
}
}
}

255
ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs

@ -0,0 +1,255 @@ @@ -0,0 +1,255 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Moves variable declarations to improved positions.
/// </summary>
public class DeclareVariables : IAstTransform
{
sealed class DeclaredVariableAnnotation {
public readonly ExpressionStatement OriginalAssignmentStatement;
public DeclaredVariableAnnotation(ExpressionStatement originalAssignmentStatement)
{
this.OriginalAssignmentStatement = originalAssignmentStatement;
}
}
static readonly DeclaredVariableAnnotation declaredVariableAnnotation = new DeclaredVariableAnnotation(null);
readonly CancellationToken cancellationToken;
public DeclareVariables(DecompilerContext context)
{
this.cancellationToken = context.CancellationToken;
}
public void Run(AstNode node)
{
Run(node, null);
}
void Run(AstNode node, DefiniteAssignmentAnalysis daa)
{
BlockStatement block = node as BlockStatement;
if (block != null) {
var variables = block.Statements.TakeWhile(stmt => stmt is VariableDeclarationStatement
&& stmt.Annotation<DeclaredVariableAnnotation>() == null)
.Cast<VariableDeclarationStatement>().ToList();
if (variables.Count > 0) {
// remove old variable declarations:
foreach (VariableDeclarationStatement varDecl in variables) {
Debug.Assert(varDecl.Variables.Single().Initializer.IsNull);
varDecl.Remove();
}
if (daa == null) {
// If possible, reuse the DefiniteAssignmentAnalysis that was created for the parent block
daa = new DefiniteAssignmentAnalysis(block, cancellationToken);
}
foreach (VariableDeclarationStatement varDecl in variables) {
string variableName = varDecl.Variables.Single().Name;
bool allowPassIntoLoops = varDecl.Variables.Single().Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null;
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, allowPassIntoLoops);
}
}
}
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
Run(child, daa);
}
}
void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, bool allowPassIntoLoops)
{
// declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
Statement declarationPoint = null;
// Check whether we can move down the variable into the sub-blocks
bool ok = true;
foreach (Statement stmt in block.Statements) {
if (UsesVariable(stmt, variableName)) {
if (declarationPoint == null)
declarationPoint = stmt;
if (!CanMoveVariableUseIntoSubBlock(stmt, variableName, allowPassIntoLoops)) {
// If it's not possible to move the variable use into a nested block,
// we need to declare the variable in this block
ok = false;
break;
}
// 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
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
// prior to the introduction of the VariableDeclarationStatement.
while (nextStatement is VariableDeclarationStatement) {
DeclaredVariableAnnotation annotation = nextStatement.Annotation<DeclaredVariableAnnotation>();
if (annotation == null)
break;
if (annotation.OriginalAssignmentStatement != null) {
nextStatement = annotation.OriginalAssignmentStatement;
break;
}
nextStatement = nextStatement.NextStatement;
}
if (nextStatement != null) {
// Analyze the range from the next statement to the end of the block
daa.SetAnalyzedRange(nextStatement, block);
daa.Analyze(variableName);
if (daa.UnassignedVariableUses.Count > 0) {
ok = false;
break;
}
}
}
}
if (declarationPoint == null) {
// The variable isn't used at all
return;
}
if (ok) {
// Declare the variable within the sub-blocks
foreach (Statement stmt in block.Statements) {
foreach (BlockStatement subBlock in stmt.Children.OfType<BlockStatement>()) {
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops);
}
}
} else {
// Try converting an assignment expression into a VariableDeclarationStatement
ExpressionStatement es = declarationPoint as ExpressionStatement;
if (es != null) {
AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) {
// convert the declarationPoint into a VariableDeclarationStatement
declarationPoint.ReplaceWith(
new VariableDeclarationStatement {
Type = (AstType)type.Clone(),
Variables = {
new VariableInitializer(variableName, ae.Right.Detach()).CopyAnnotationsFrom(ae)
}
}.CopyAnnotationsFrom(es).WithAnnotation(new DeclaredVariableAnnotation(es)));
return;
}
}
}
// Declare the variable in front of declarationPoint
block.Statements.InsertBefore(
declarationPoint,
new VariableDeclarationStatement((AstType)type.Clone(), variableName)
.WithAnnotation(declaredVariableAnnotation));
}
}
bool CanMoveVariableUseIntoSubBlock(Statement stmt, string variableName, bool allowPassIntoLoops)
{
if (!allowPassIntoLoops && (stmt is ForStatement || stmt is ForeachStatement || stmt is DoWhileStatement || stmt is WhileStatement))
return false;
ForStatement forStatement = stmt as ForStatement;
if (forStatement != null && forStatement.Initializers.Count == 1) {
// for-statement is special case: we can move variable declarations into the initializer
ExpressionStatement es = forStatement.Initializers.Single() as ExpressionStatement;
if (es != null) {
AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) {
return !UsesVariable(ae.Right, variableName);
}
}
}
}
// We can move the variable into a sub-block only if the variable is used in only that sub-block
for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) {
if (!(child is BlockStatement) && UsesVariable(child, variableName))
return false;
}
return true;
}
bool UsesVariable(AstNode node, string variableName)
{
IdentifierExpression ie = node as IdentifierExpression;
if (ie != null && ie.Identifier == variableName)
return true;
FixedStatement fixedStatement = node as FixedStatement;
if (fixedStatement != null) {
foreach (VariableInitializer v in fixedStatement.Variables) {
if (v.Name == variableName)
return false; // no need to introduce the variable here
}
}
ForeachStatement foreachStatement = node as ForeachStatement;
if (foreachStatement != null) {
if (foreachStatement.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;
}
return false;
}
#region FindInsertPos
static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops)
{
AstNode pos = null;
AstNode withinPos = null;
while (node != null) {
IdentifierExpression ident = node as IdentifierExpression;
if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
return node;
FixedStatement fixedStatement = node as FixedStatement;
if (fixedStatement != null) {
foreach (VariableInitializer v in fixedStatement.Variables) {
if (v.Name == name)
return null; // no need to introduce the variable here
}
}
ForeachStatement foreachStatement = node as ForeachStatement;
if (foreachStatement != null) {
if (foreachStatement.VariableName == name)
return null; // no need to introduce the variable here
}
AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops);
if (withinCurrent != null) {
if (pos == null) {
pos = node;
withinPos = withinCurrent;
} else {
return pos;
}
}
node = node.NextSibling;
}
if (withinPos != null && withinPos.Role == BlockStatement.StatementRole && AllowPassInto(pos, allowPassIntoLoops))
return withinPos;
else
return pos;
}
static bool AllowPassInto(AstNode node, bool allowPassIntoLoops)
{
if (node is AnonymousMethodExpression || node is LambdaExpression)
return false;
return allowPassIntoLoops;
return true;
}
#endregion
}
}

27
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -179,23 +179,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -179,23 +179,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return true;
}
static readonly ExpressionStatement displayClassAssignmentPattern =
new ExpressionStatement(new AssignmentExpression(
new NamedNode("variable", new IdentifierExpression()),
new ObjectCreateExpression { Type = new AnyNode("type") }
));
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
base.VisitBlockStatement(blockStatement, data);
foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>().ToArray()) {
if (stmt.Variables.Count() != 1)
foreach (ExpressionStatement stmt in blockStatement.Statements.OfType<ExpressionStatement>().ToArray()) {
Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
if (displayClassAssignmentMatch == null)
continue;
ILVariable variable = displayClassAssignmentMatch.Get("variable").Single().Annotation<ILVariable>();
if (variable == null)
continue;
var variable = stmt.Variables.Single();
TypeDefinition type = stmt.Type.Annotation<TypeReference>().ResolveWithinSameModule();
TypeDefinition type = variable.Type.ResolveWithinSameModule();
if (!IsPotentialClosure(context, type))
continue;
ObjectCreateExpression oce = variable.Initializer as ObjectCreateExpression;
if (oce == null || oce.Type.Annotation<TypeReference>().ResolveWithinSameModule() != type || oce.Arguments.Any() || !oce.Initializer.IsNull)
if (displayClassAssignmentMatch.Get("type").Single().Annotation<TypeReference>().ResolveWithinSameModule() != type)
continue;
// Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
bool ok = true;
foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
if (identExpr.Identifier == variable.Name) {
if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single()) {
if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation<FieldReference>() != null))
ok = false;
}
@ -267,9 +277,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -267,9 +277,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
foreach (var tuple in variablesToDeclare) {
var newVarDecl = DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false);
var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2);
if (newVarDecl != null)
newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
blockStatement.Statements.InsertAfter(null, newVarDecl);
}
}
return null;

2
ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -25,7 +25,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void Run(AstNode compilationUnit)
{
// Don't show using when decompiling a single method or nested types:
if (context.CurrentMethod != null || (context.CurrentType != null && context.CurrentType.IsNested))
if (context.CurrentType != null)
return;
// First determine all the namespaces that need to be imported:

190
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -5,6 +5,7 @@ using System; @@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil;
@ -37,23 +38,23 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -37,23 +38,23 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return node;
}
public override AstNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data)
public override AstNode VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
{
AstNode result;
if (context.Settings.UsingStatement) {
result = TransformUsings(variableDeclarationStatement);
result = TransformUsings(expressionStatement);
if (result != null)
return result;
}
result = TransformFor(variableDeclarationStatement);
result = TransformFor(expressionStatement);
if (result != null)
return result;
if (context.Settings.LockStatement) {
result = TransformLock(variableDeclarationStatement);
result = TransformLock(expressionStatement);
if (result != null)
return result;
}
return base.VisitVariableDeclarationStatement(variableDeclarationStatement, data);
return base.VisitExpressionStatement(expressionStatement, data);
}
public override AstNode VisitUsingStatement(UsingStatement usingStatement, object data)
@ -117,27 +118,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -117,27 +118,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
/// <summary>
/// $type $variable = $initializer;
/// </summary>
static readonly AstNode variableDeclPattern = new VariableDeclarationStatement {
Type = new AnyNode("type"),
Variables = {
new NamedNode(
"variable",
new VariableInitializer {
Initializer = new AnyNode("initializer")
}
)
}
};
/// <summary>
/// Variable declaration without initializer.
/// </summary>
static readonly AstNode simpleVariableDefinition = new VariableDeclarationStatement {
Type = new AnyNode(),
Variables = {
new VariableInitializer() // any name but no initializer
}
};
static readonly AstNode variableAssignPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("variable", new IdentifierExpression()),
new AnyNode("initializer")
));
#region using
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
@ -163,20 +148,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -163,20 +148,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
};
public UsingStatement TransformUsings(VariableDeclarationStatement node)
public UsingStatement TransformUsings(ExpressionStatement node)
{
Match m1 = variableDeclPattern.Match(node);
Match m1 = variableAssignPattern.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<VariableInitializer>("variable").Single().Name == m2.Get<IdentifierExpression>("ident").Single().Identifier) {
if (m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("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<AstType>("type").Single().Annotation<TypeReference>();
if (tr == null || !tr.IsValueType)
ILVariable v = m1.Get("variable").Single().Annotation<ILVariable>();
if (v == null || v.Type == null || !v.Type.IsValueType)
return null;
}
BlockStatement body = m2.Get<BlockStatement>("body").Single();
@ -184,6 +167,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -184,6 +167,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
usingStatement.ResourceAcquisition = node.Detach();
usingStatement.EmbeddedStatement = body.Detach();
tryCatch.ReplaceWith(usingStatement);
// TODO: Move the variable declaration into the resource acquisition, if possible
// This is necessary for the foreach-pattern to work on the result of the using-pattern
return usingStatement;
}
return null;
@ -203,55 +188,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -203,55 +188,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
)
}
},
EmbeddedStatement = new Choice {
// There are two forms of the foreach statement:
// one where the item variable is declared inside the loop,
// and one where it is declared outside of the loop.
// In the former case, we can apply the foreach pattern only if the variable wasn't captured.
{ "itemVariableInsideLoop",
new BlockStatement {
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType"),
Variables = {
new NamedNode(
"itemVariable",
new VariableInitializer {
Initializer = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
}
)
}
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}
},
{ "itemVariableOutsideLoop",
new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType"),
Variables = {
new NamedNode("itemVariable", new VariableInitializer())
}
EmbeddedStatement = new BlockStatement {
new Repeat(
new NamedNode("variableDeclaration", new VariableDeclarationStatement { Type = new AnyNode(), Variables = { new AnyNode() } })
).ToStatement(),
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new AssignmentExpression {
Left = new NamedNode("itemVariable", new IdentifierExpression()),
Operator = AssignmentOperatorType.Assign,
Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
},
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("itemVariable"),
Operator = AssignmentOperatorType.Assign,
Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}.ToStatement()
};
}};
public ForeachStatement TransformForeach(UsingStatement node)
{
@ -259,14 +211,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -259,14 +211,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (m == null)
return null;
VariableInitializer enumeratorVar = m.Get<VariableInitializer>("enumeratorVariable").Single();
VariableInitializer itemVar = m.Get<VariableInitializer>("itemVariable").Single();
if (m.Has("itemVariableInsideLoop") && itemVar.Annotation<DelegateConstruction.CapturedVariableAnnotation>() != null) {
// cannot move captured variables out of loops
ILVariable itemVar = m.Get("itemVariable").Single().Annotation<ILVariable>();
if (itemVar == null)
return null;
}
return null; // TODO
// if (m.Has("itemVariableInsideLoop") && itemVar.Annotation<DelegateConstruction.CapturedVariableAnnotation>() != null) {
// // cannot move captured variables out of loops
// return null;
// }
BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m.Get<Statement>("statement"))
newBody.Add(stmt.Detach());
ForeachStatement foreachStatement = new ForeachStatement {
VariableType = m.Get<AstType>("itemType").Single().Detach(),
VariableName = itemVar.Name,
@ -299,17 +255,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -299,17 +255,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}};
public ForStatement TransformFor(VariableDeclarationStatement node)
public ForStatement TransformFor(ExpressionStatement node)
{
Match m1 = variableDeclPattern.Match(node);
Match m1 = variableAssignPattern.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<VariableInitializer>("variable").Single().Name != m2.Get<IdentifierExpression>("ident").Single().Identifier)
if (m1.Get<IdentifierExpression>("variable").Single().Identifier != m2.Get<IdentifierExpression>("ident").Single().Identifier)
return null;
WhileStatement loop = (WhileStatement)next;
node.Remove();
@ -374,16 +328,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -374,16 +328,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion
#region lock
static readonly AstNode lockFlagInitPattern = new VariableDeclarationStatement {
Type = new PrimitiveType("bool"),
Variables = {
new NamedNode(
"variable",
new VariableInitializer {
Initializer = new PrimitiveExpression(false)
}
)
}};
static readonly AstNode lockFlagInitPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("variable", new IdentifierExpression()),
new PrimitiveExpression(false)
));
static readonly AstNode lockTryCatchPattern = new TryCatchStatement {
TryBlock = new BlockStatement {
@ -404,16 +353,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -404,16 +353,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}};
public LockStatement TransformLock(VariableDeclarationStatement node)
public LockStatement TransformLock(ExpressionStatement node)
{
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<VariableInitializer>("variable").Single().Name == m2.Get<IdentifierExpression>("flag").Single().Identifier) {
if (m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier) {
Expression enter = m2.Get<Expression>("enter").Single();
IdentifierExpression exit = m2.Get<IdentifierExpression>("exit").Single();
if (exit.Match(enter) == null) {
@ -630,32 +577,25 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -630,32 +577,25 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#region Automatic Events
static readonly Accessor automaticEventPatternV4 = new Accessor {
Body = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("type"),
Variables = {
new NamedNode(
"var1", new VariableInitializer {
Initializer = new NamedNode("field", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
})}
},
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = { new NamedNode("var2", new VariableInitializer()) }
new VariableDeclarationStatement { Type = new AnyNode("type"), Variables = { new AnyNode() } },
new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } },
new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } },
new AssignmentExpression {
Left = new NamedNode("var1", new IdentifierExpression()),
Operator = AssignmentOperatorType.Assign,
Right = new NamedNode("field", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
},
new DoWhileStatement {
EmbeddedStatement = new BlockStatement {
new AssignmentExpression(new IdentifierExpressionBackreference("var2"), new IdentifierExpressionBackreference("var1")),
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = {
new NamedNode(
"var3", new VariableInitializer {
Initializer = new AnyNode("delegateCombine").ToExpression().Invoke(
new IdentifierExpressionBackreference("var2"),
new IdentifierExpression("value")
).CastTo(new Backreference("type"))
})
}},
new AssignmentExpression(new NamedNode("var2", new IdentifierExpression()), new IdentifierExpressionBackreference("var1")),
new AssignmentExpression {
Left = new NamedNode("var3", new IdentifierExpression()),
Operator = AssignmentOperatorType.Assign,
Right = new AnyNode("delegateCombine").ToExpression().Invoke(
new IdentifierExpressionBackreference("var2"),
new IdentifierExpression("value")
).CastTo(new Backreference("type"))
},
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("var1"),
Right = new TypePattern(typeof(System.Threading.Interlocked)).ToType().Invoke(

1
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -23,6 +23,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -23,6 +23,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
new DeclareVariables(context),
new IntroduceUsingDeclarations(context)
};
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -53,13 +53,13 @@ @@ -53,13 +53,13 @@
<Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CecilTypeResolveContext.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DeclareVariableInSmallestScope.cs" />
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DeclareVariables.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="Ast\Transforms\IntroduceUsingDeclarations.cs" />

Loading…
Cancel
Save