From f1a34c6a31e18af6e85ba88cf1d9177d9983e557 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 25 May 2011 22:28:45 +0200 Subject: [PATCH] Fix #202: Decompilation of multiple catch clauses sharing the same variable name --- .../ILAst/ILAstOptimizer.cs | 27 ++++++++++++++++--- .../ILAst/PeepholeTransform.cs | 4 +-- .../Tests/ExceptionHandling.cs | 20 ++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index ef6ab4e54..2bb2f21df 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -575,16 +575,35 @@ namespace ICSharpCode.Decompiler.ILAst // This ensures that a single IL variable is a single C# variable (gets assigned only one name) // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes. Dictionary dict = new Dictionary(); - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - ILVariable v = expr.Operand as ILVariable; - if (v != null && v.OriginalVariable != null) { + ReplaceVariables( + method, + delegate(ILVariable v) { ILVariable combinedVariable; if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable)) { dict.Add(v.OriginalVariable, v); combinedVariable = v; } - expr.Operand = combinedVariable; + return combinedVariable; + }); + } + + public static void ReplaceVariables(ILNode node, Func variableMapping) + { + ILExpression expr = node as ILExpression; + if (expr != null) { + ILVariable v = expr.Operand as ILVariable; + if (v != null) + expr.Operand = variableMapping(v); + foreach (ILExpression child in expr.Arguments) + ReplaceVariables(child, variableMapping); + } else { + var catchBlock = node as ILTryCatchBlock.CatchBlock; + if (catchBlock != null && catchBlock.ExceptionVariable != null) { + catchBlock.ExceptionVariable = variableMapping(catchBlock.ExceptionVariable); } + + foreach (ILNode child in node.GetChildren()) + ReplaceVariables(child, variableMapping); } } diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs index f9e596514..88900a73b 100644 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -523,8 +523,8 @@ namespace ICSharpCode.Decompiler.ILAst if (recombineVariable) { // Split local variable, unsplit these two instances - foreach (var ilExpression in method.GetSelfAndChildrenRecursive(expression => expression.Operand == nextExpr.Operand)) - ilExpression.Operand = exprInit.Operand; + // replace nextExpr.Operand with exprInit.Operand + ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar); } switch (loadInstruction) { diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs index 45b5d72ca..0db35e357 100644 --- a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs +++ b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs @@ -105,4 +105,24 @@ public class ExceptionHandling cancellationTokenSource = new CancellationTokenSource(); } } + + public void TwoCatchBlocksWithSameVariable() + { + try + { + Console.WriteLine("Try1"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + try + { + Console.WriteLine("Try2"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } }