mirror of https://github.com/icsharpcode/ILSpy.git
13 changed files with 258 additions and 471 deletions
@ -1,56 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using ICSharpCode.NRefactory.CSharp; |
|
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
|
||||||
{ |
|
||||||
public class RemoveDeadLabels : DepthFirstAstVisitor<object, object> |
|
||||||
{ |
|
||||||
List<string> usedLabels = new List<string>(); |
|
||||||
bool collectingUsedLabels; |
|
||||||
|
|
||||||
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) |
|
||||||
{ |
|
||||||
collectingUsedLabels = true; |
|
||||||
base.VisitConstructorDeclaration(constructorDeclaration, data); |
|
||||||
collectingUsedLabels = false; |
|
||||||
base.VisitConstructorDeclaration(constructorDeclaration, data); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) |
|
||||||
{ |
|
||||||
collectingUsedLabels = true; |
|
||||||
base.VisitMethodDeclaration(methodDeclaration, data); |
|
||||||
collectingUsedLabels = false; |
|
||||||
base.VisitMethodDeclaration(methodDeclaration, data); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitAccessor(Accessor accessor, object data) |
|
||||||
{ |
|
||||||
collectingUsedLabels = true; |
|
||||||
base.VisitAccessor(accessor, data); |
|
||||||
collectingUsedLabels = false; |
|
||||||
return base.VisitAccessor(accessor, data); |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
|
||||||
{ |
|
||||||
if (collectingUsedLabels) { |
|
||||||
usedLabels.Add(gotoStatement.Label); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitLabelStatement(LabelStatement labelStatement, object data) |
|
||||||
{ |
|
||||||
if (!collectingUsedLabels) { |
|
||||||
if (!usedLabels.Contains(labelStatement.Label)) { |
|
||||||
labelStatement.Remove(); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Linq; |
|
||||||
using ICSharpCode.NRefactory.CSharp; |
|
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
|
||||||
{ |
|
||||||
public class RemoveEmptyElseBody: DepthFirstAstVisitor<object, object> |
|
||||||
{ |
|
||||||
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
|
||||||
{ |
|
||||||
base.VisitIfElseStatement(ifElseStatement, data); |
|
||||||
BlockStatement block = ifElseStatement.FalseStatement as BlockStatement; |
|
||||||
if (block != null && !block.Statements.Any()) { |
|
||||||
ifElseStatement.FalseStatement = null; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,207 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Linq; |
|
||||||
using ICSharpCode.NRefactory.CSharp; |
|
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
|
||||||
{ |
|
||||||
public class RemoveGotos: DepthFirstAstVisitor<object, object> |
|
||||||
{ |
|
||||||
Stack<Statement> enteredLoops = new Stack<Statement>(); |
|
||||||
|
|
||||||
Statement CurrentLoop { |
|
||||||
get { |
|
||||||
if (enteredLoops.Count > 0) { |
|
||||||
return enteredLoops.Peek(); |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Statement CurrentLoopBody { |
|
||||||
get { |
|
||||||
if (this.CurrentLoop == null) { |
|
||||||
return null; |
|
||||||
} else if (this.CurrentLoop is ForStatement) { |
|
||||||
return ((ForStatement)this.CurrentLoop).EmbeddedStatement; |
|
||||||
} else if (this.CurrentLoop is WhileStatement) { |
|
||||||
return ((WhileStatement)this.CurrentLoop).EmbeddedStatement; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitForStatement(ForStatement forStatement, object data) |
|
||||||
{ |
|
||||||
enteredLoops.Push(forStatement); |
|
||||||
base.VisitForStatement(forStatement, data); |
|
||||||
enteredLoops.Pop(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitWhileStatement(WhileStatement whileStatement, object data) |
|
||||||
{ |
|
||||||
enteredLoops.Push(whileStatement); |
|
||||||
base.VisitWhileStatement(whileStatement, data); |
|
||||||
enteredLoops.Pop(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitBlockStatement(BlockStatement blockStatement, object data) |
|
||||||
{ |
|
||||||
base.VisitBlockStatement(blockStatement, data); |
|
||||||
|
|
||||||
// Remove redundant jump at the end of block
|
|
||||||
AstNode lastStmt = blockStatement.Children.LastOrDefault(); |
|
||||||
// End of for loop
|
|
||||||
if (lastStmt is ContinueStatement && |
|
||||||
blockStatement.Parent is ForStatement) |
|
||||||
{ |
|
||||||
lastStmt.Remove(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
// End of method
|
|
||||||
if (lastStmt is ReturnStatement && |
|
||||||
(blockStatement.Parent is MethodDeclaration || blockStatement.Parent is ConstructorDeclaration) && |
|
||||||
((ReturnStatement)lastStmt).Expression.IsNull) |
|
||||||
{ |
|
||||||
lastStmt.Remove(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Get the next statement that will be executed after this one
|
|
||||||
// May return null
|
|
||||||
public static AstNode GetNextStatement(Statement statement) |
|
||||||
{ |
|
||||||
if (statement == null) throw new ArgumentNullException(); |
|
||||||
|
|
||||||
Statement next = (Statement)statement.NextSibling; |
|
||||||
|
|
||||||
if (next != null) { |
|
||||||
return EnterBlockStatement(next); |
|
||||||
} else { |
|
||||||
if (statement.Parent is BlockStatement && |
|
||||||
statement.Parent.Parent is Statement) { |
|
||||||
return ExitBlockStatement((Statement)statement.Parent.Parent); |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Get the statement that will be executed once the given block exits by the end brace
|
|
||||||
// May return null
|
|
||||||
public static AstNode ExitBlockStatement(Statement statement) |
|
||||||
{ |
|
||||||
if (statement == null) throw new ArgumentNullException(); |
|
||||||
|
|
||||||
// When an 'if' body is finished the execution continues with the
|
|
||||||
// next statement after the 'if' statement
|
|
||||||
if (statement is IfElseStatement) { |
|
||||||
return GetNextStatement((IfElseStatement)statement); |
|
||||||
} |
|
||||||
|
|
||||||
// When a 'for' body is finished the execution continues by:
|
|
||||||
// Iterator; Condition; Body
|
|
||||||
if (statement is ForStatement) { |
|
||||||
ForStatement forLoop = statement as ForStatement; |
|
||||||
if (forLoop.Iterators.Any()) { |
|
||||||
return forLoop.Iterators.First(); |
|
||||||
} else if (!forLoop.Condition.IsNull) { |
|
||||||
return forLoop.Condition; |
|
||||||
} else { |
|
||||||
return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.FirstChild); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Get the first statement that will be executed in the given block
|
|
||||||
public static AstNode EnterBlockStatement(Statement statement) |
|
||||||
{ |
|
||||||
if (statement == null) throw new ArgumentNullException(); |
|
||||||
|
|
||||||
// For loop starts as follows: Initializers; Condition; Body
|
|
||||||
if (statement is ForStatement) { |
|
||||||
ForStatement forLoop = statement as ForStatement; |
|
||||||
if (forLoop.Initializers.Any()) { |
|
||||||
return forLoop.Initializers.First(); |
|
||||||
} else if (!forLoop.Condition.IsNull) { |
|
||||||
return forLoop.Condition; |
|
||||||
} else if (forLoop.EmbeddedStatement.Children.FirstOrDefault() is Statement) { |
|
||||||
return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.FirstChild); // Simplify again
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return statement; // Can not simplify
|
|
||||||
} |
|
||||||
|
|
||||||
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
|
||||||
{ |
|
||||||
// Remove redundant goto which goes to a label that imideately follows
|
|
||||||
AstNode fallthoughTarget = GetNextStatement(gotoStatement); |
|
||||||
while(true) { |
|
||||||
if (fallthoughTarget is LabelStatement) { |
|
||||||
if ((fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { |
|
||||||
gotoStatement.Remove(); |
|
||||||
return null; |
|
||||||
} else { |
|
||||||
fallthoughTarget = GetNextStatement((LabelStatement)fallthoughTarget); |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Replace goto with 'break'
|
|
||||||
// Break statement moves right outside the looop
|
|
||||||
if (CurrentLoop != null) { |
|
||||||
AstNode breakTarget = GetNextStatement(CurrentLoop); |
|
||||||
if ((breakTarget is LabelStatement) && |
|
||||||
(breakTarget as LabelStatement).Label == gotoStatement.Label) { |
|
||||||
gotoStatement.ReplaceWith(new BreakStatement()); |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Replace goto with 'continue'
|
|
||||||
// Continue statement which moves at the very end of loop
|
|
||||||
if (CurrentLoop != null && |
|
||||||
(CurrentLoopBody is BlockStatement) && |
|
||||||
((CurrentLoopBody as BlockStatement).LastChild as LabelStatement) != null && |
|
||||||
((CurrentLoopBody as BlockStatement).LastChild as LabelStatement).Label == gotoStatement.Label) { |
|
||||||
gotoStatement.ReplaceWith(new ContinueStatement()); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Replace goto with 'continue'
|
|
||||||
// Jump before while
|
|
||||||
if (CurrentLoop is WhileStatement && |
|
||||||
CurrentLoop.PrevSibling != null && |
|
||||||
CurrentLoop.PrevSibling is LabelStatement && |
|
||||||
(CurrentLoop.PrevSibling as LabelStatement).Label == gotoStatement.Label) { |
|
||||||
gotoStatement.ReplaceWith(new ContinueStatement()); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
// Replace goto with 'continue'
|
|
||||||
// Continue statement which moves at the very start of for loop
|
|
||||||
if (CurrentLoop != null) { |
|
||||||
AstNode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop
|
|
||||||
if ((continueTarget is LabelStatement) && |
|
||||||
(continueTarget as LabelStatement).Label == gotoStatement.Label) { |
|
||||||
gotoStatement.ReplaceWith(new ContinueStatement()); |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Linq; |
|
||||||
using ICSharpCode.NRefactory.CSharp; |
|
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
|
||||||
{ |
|
||||||
public class RestoreLoop: DepthFirstAstVisitor<object, object> |
|
||||||
{ |
|
||||||
public override object VisitForStatement(ForStatement forStatement, object data) |
|
||||||
{ |
|
||||||
base.VisitForStatement(forStatement, data); |
|
||||||
|
|
||||||
// Restore loop initializer
|
|
||||||
if (!forStatement.Initializers.Any()) { |
|
||||||
VariableDeclarationStatement varDeclr = forStatement.PrevSibling as VariableDeclarationStatement; |
|
||||||
if (varDeclr != null) { |
|
||||||
varDeclr.ReplaceWith(Statement.Null); |
|
||||||
forStatement.Initializers.Add(varDeclr); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Restore loop condition
|
|
||||||
if (forStatement.Condition.IsNull && |
|
||||||
forStatement.EmbeddedStatement.Children.Count() >= 3) |
|
||||||
{ |
|
||||||
IfElseStatement condition = forStatement.EmbeddedStatement.Children.First() as IfElseStatement; |
|
||||||
BreakStatement breakStmt = forStatement.EmbeddedStatement.Children.Skip(1).First() as BreakStatement; |
|
||||||
LabelStatement label = forStatement.EmbeddedStatement.Children.Skip(2).First() as LabelStatement; |
|
||||||
if (condition != null && breakStmt != null && label != null && |
|
||||||
condition.TrueStatement.Children.Count() == 1) |
|
||||||
{ |
|
||||||
GotoStatement gotoStmt = condition.TrueStatement.FirstChild as GotoStatement; |
|
||||||
if (gotoStmt != null && gotoStmt.Label == label.Label) { |
|
||||||
condition.Remove(); |
|
||||||
breakStmt.Remove(); |
|
||||||
forStatement.Condition = condition.Condition; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Restore loop condition (version 2)
|
|
||||||
if (forStatement.Condition.IsNull) { |
|
||||||
IfElseStatement condition = forStatement.EmbeddedStatement.FirstChild as IfElseStatement; |
|
||||||
if (condition != null && |
|
||||||
condition.TrueStatement.Children.Any() && |
|
||||||
condition.TrueStatement.FirstChild is BlockStatement && |
|
||||||
condition.TrueStatement.Children.Count() == 1 && |
|
||||||
condition.TrueStatement.FirstChild.FirstChild is BreakStatement && |
|
||||||
condition.FalseStatement.Children.Any() && |
|
||||||
condition.FalseStatement.FirstChild is BlockStatement && |
|
||||||
condition.FalseStatement.Children.Count() == 0) |
|
||||||
{ |
|
||||||
condition.Remove(); |
|
||||||
forStatement.Condition = new UnaryOperatorExpression() { Expression = condition.Condition, Operator = UnaryOperatorType.Not }; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Restore loop iterator
|
|
||||||
if (forStatement.EmbeddedStatement.Children.Any() && |
|
||||||
!forStatement.Iterators.Any()) |
|
||||||
{ |
|
||||||
ExpressionStatement lastStmt = forStatement.EmbeddedStatement.LastChild as ExpressionStatement; |
|
||||||
if (lastStmt != null && |
|
||||||
(lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { |
|
||||||
lastStmt.Remove(); |
|
||||||
forStatement.Iterators.Add(lastStmt); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,202 @@ |
|||||||
|
using System; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using Decompiler.ControlFlow; |
||||||
|
|
||||||
|
namespace Decompiler |
||||||
|
{ |
||||||
|
public class GotoRemoval |
||||||
|
{ |
||||||
|
Dictionary<ILNode, ILNode> parent = new Dictionary<ILNode, ILNode>(); |
||||||
|
Dictionary<ILNode, ILNode> nextSibling = new Dictionary<ILNode, ILNode>(); |
||||||
|
|
||||||
|
public bool RemoveGotos(ILBlock method) |
||||||
|
{ |
||||||
|
// Build the navigation data
|
||||||
|
parent[method] = null; |
||||||
|
foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) { |
||||||
|
ILNode previousChild = null; |
||||||
|
foreach (ILNode child in node.GetChildren()) { |
||||||
|
Debug.Assert(!parent.ContainsKey(child)); |
||||||
|
parent[child] = node; |
||||||
|
if (previousChild != null) |
||||||
|
nextSibling[previousChild] = child; |
||||||
|
previousChild = child; |
||||||
|
} |
||||||
|
if (previousChild != null) |
||||||
|
nextSibling[previousChild] = null; |
||||||
|
} |
||||||
|
|
||||||
|
// Simplify gotos
|
||||||
|
bool modified = false; |
||||||
|
foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>().Where(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) { |
||||||
|
modified |= TrySimplifyGoto(gotoExpr); |
||||||
|
} |
||||||
|
|
||||||
|
// Remove dead lables and nops
|
||||||
|
HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets())); |
||||||
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { |
||||||
|
int oldBodyCount = block.Body.Count; |
||||||
|
block.Body = block.Body.Where(n => !n.Matches(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList(); |
||||||
|
modified |= block.Body.Count < oldBodyCount; |
||||||
|
} |
||||||
|
|
||||||
|
// Remove redundant continue
|
||||||
|
foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<ILWhileLoop>()) { |
||||||
|
var body = loop.BodyBlock.Body; |
||||||
|
if (body.Count > 0 && body.Last().Matches(ILCode.LoopContinue)) { |
||||||
|
body.RemoveAt(body.Count - 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Remove redundant return
|
||||||
|
if (method.Body.Count > 0 && method.Body.Last().Matches(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { |
||||||
|
method.Body.RemoveAt(method.Body.Count - 1); |
||||||
|
} |
||||||
|
|
||||||
|
return modified; |
||||||
|
} |
||||||
|
|
||||||
|
bool TrySimplifyGoto(ILExpression gotoExpr) |
||||||
|
{ |
||||||
|
Debug.Assert(gotoExpr.Code == ILCode.Br || gotoExpr.Code == ILCode.Leave); |
||||||
|
Debug.Assert(gotoExpr.Prefixes == null); |
||||||
|
Debug.Assert(gotoExpr.Operand != null); |
||||||
|
|
||||||
|
ILExpression target = Enter(gotoExpr, new HashSet<ILNode>()); |
||||||
|
if (target == null) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (target == Exit(gotoExpr, new HashSet<ILNode>())) { |
||||||
|
gotoExpr.Code = ILCode.Nop; |
||||||
|
gotoExpr.Operand = null; |
||||||
|
target.ILRanges.AddRange(gotoExpr.ILRanges); |
||||||
|
gotoExpr.ILRanges.Clear(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
ILWhileLoop loop = null; |
||||||
|
ILNode current = gotoExpr; |
||||||
|
while(loop == null && current != null) { |
||||||
|
current = parent[current]; |
||||||
|
loop = current as ILWhileLoop; |
||||||
|
} |
||||||
|
|
||||||
|
if (loop != null && target == Exit(loop, new HashSet<ILNode>())) { |
||||||
|
gotoExpr.Code = ILCode.LoopBreak; |
||||||
|
gotoExpr.Operand = null; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (loop != null && target == Enter(loop, new HashSet<ILNode>())) { |
||||||
|
gotoExpr.Code = ILCode.LoopContinue; |
||||||
|
gotoExpr.Operand = null; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the first expression to be excecuted if the instruction pointer is at the start of the given node
|
||||||
|
/// </summary>
|
||||||
|
ILExpression Enter(ILNode node, HashSet<ILNode> visitedNodes) |
||||||
|
{ |
||||||
|
if (node == null) |
||||||
|
throw new ArgumentNullException(); |
||||||
|
|
||||||
|
if (!visitedNodes.Add(node)) |
||||||
|
return null; // Infinite loop
|
||||||
|
|
||||||
|
ILLabel label = node as ILLabel; |
||||||
|
if (label != null) { |
||||||
|
return Exit(label, visitedNodes); |
||||||
|
} |
||||||
|
|
||||||
|
ILExpression expr = node as ILExpression; |
||||||
|
if (expr != null) { |
||||||
|
if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave) { |
||||||
|
return Enter((ILLabel)expr.Operand, visitedNodes); |
||||||
|
} else if (expr.Code == ILCode.Nop) { |
||||||
|
return Exit(expr, visitedNodes); |
||||||
|
} else { |
||||||
|
return expr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ILBlock block = node as ILBlock; |
||||||
|
if (block != null) { |
||||||
|
if (block.EntryGoto != null) { |
||||||
|
return Enter(block.EntryGoto, visitedNodes); |
||||||
|
} else if (block.Body.Count > 0) { |
||||||
|
return Enter(block.Body[0], visitedNodes); |
||||||
|
} else { |
||||||
|
return Exit(block, visitedNodes); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ILCondition cond = node as ILCondition; |
||||||
|
if (cond != null) { |
||||||
|
return cond.Condition; |
||||||
|
} |
||||||
|
|
||||||
|
ILWhileLoop loop = node as ILWhileLoop; |
||||||
|
if (loop != null) { |
||||||
|
if (loop.Condition != null) { |
||||||
|
return loop.Condition; |
||||||
|
} else { |
||||||
|
return Enter(loop.BodyBlock, visitedNodes); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ILTryCatchBlock tryCatch = node as ILTryCatchBlock; |
||||||
|
if (tryCatch != null) { |
||||||
|
return Enter(tryCatch.TryBlock, visitedNodes); |
||||||
|
} |
||||||
|
|
||||||
|
ILSwitch ilSwitch = node as ILSwitch; |
||||||
|
if (ilSwitch != null) { |
||||||
|
return ilSwitch.Condition; |
||||||
|
} |
||||||
|
|
||||||
|
throw new NotSupportedException(node.GetType().ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the first expression to be excecuted if the instruction pointer is at the end of the given node
|
||||||
|
/// </summary>
|
||||||
|
ILExpression Exit(ILNode node, HashSet<ILNode> visitedNodes) |
||||||
|
{ |
||||||
|
if (node == null) |
||||||
|
throw new ArgumentNullException(); |
||||||
|
|
||||||
|
ILNode nodeParent = parent[node]; |
||||||
|
if (nodeParent == null) |
||||||
|
return null; // Exited main body
|
||||||
|
|
||||||
|
if (nodeParent is ILBlock) { |
||||||
|
ILNode nextNode = nextSibling[node]; |
||||||
|
if (nextNode != null) { |
||||||
|
return Enter(nextNode, visitedNodes); |
||||||
|
} else { |
||||||
|
return Exit(nodeParent, visitedNodes); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (nodeParent is ILCondition || |
||||||
|
nodeParent is ILTryCatchBlock || |
||||||
|
nodeParent is ILSwitch) |
||||||
|
{ |
||||||
|
return Exit(nodeParent, visitedNodes); |
||||||
|
} |
||||||
|
|
||||||
|
if (nodeParent is ILWhileLoop) { |
||||||
|
return Enter(nodeParent, visitedNodes); |
||||||
|
} |
||||||
|
|
||||||
|
throw new NotSupportedException(nodeParent.GetType().ToString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,14 +0,0 @@ |
|||||||
using System; |
|
||||||
|
|
||||||
namespace Decompiler |
|
||||||
{ |
|
||||||
public static class Options |
|
||||||
{ |
|
||||||
public static readonly bool NodeComments = false; |
|
||||||
public static readonly bool ReduceLoops = true; |
|
||||||
public static readonly bool ReduceConditonals = true; |
|
||||||
public static readonly bool ReduceAstJumps = true; |
|
||||||
public static readonly bool ReduceAstLoops = true; |
|
||||||
public static readonly bool ReduceAstOther = true; |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue