Browse Source

Fix "Missing variable name in created C# code". Closes #81.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
2601a4901a
  1. 5
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 415
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 2
      ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs
  4. 30
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

5
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -599,7 +599,7 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
else else
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType); astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context, astMethod.Parameters);
} }
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) { if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) {
@ -661,7 +661,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
astMethod.Name = CleanName(methodDef.DeclaringType.Name); astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
return astMethod; return astMethod;
} }
@ -793,6 +793,7 @@ namespace ICSharpCode.Decompiler.Ast
{ {
foreach(ParameterDefinition paramDef in paramCol) { foreach(ParameterDefinition paramDef in paramCol) {
ParameterDeclaration astParam = new ParameterDeclaration(); ParameterDeclaration astParam = new ParameterDeclaration();
astParam.AddAnnotation(paramDef);
astParam.Type = ConvertType(paramDef.ParameterType, paramDef); astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
astParam.Name = paramDef.Name; astParam.Name = paramDef.Name;

415
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -24,7 +24,15 @@ namespace ICSharpCode.Decompiler.Ast
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition 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) HashSet<ILVariable> implicitlyDefinedVariables = new HashSet<ILVariable>(); // local variables that are implicitly defined (e.g. catch handler)
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context) /// <summary>
/// Creates the body for the method definition.
/// </summary>
/// <param name="methodDef">Method definition to decompile.</param>
/// <param name="context">Decompilation context.</param>
/// <param name="parameters">Parameter declarations of the method being decompiled.
/// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
/// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable<ParameterDeclaration> parameters = null)
{ {
MethodDefinition oldCurrentMethod = context.CurrentMethod; MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
@ -35,10 +43,10 @@ namespace ICSharpCode.Decompiler.Ast
builder.context = context; builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem; builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) { if (Debugger.IsAttached) {
return builder.CreateMethodBody(); return builder.CreateMethodBody(parameters);
} else { } else {
try { try {
return builder.CreateMethodBody(); return builder.CreateMethodBody(parameters);
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
throw; throw;
} catch (Exception ex) { } catch (Exception ex) {
@ -50,7 +58,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
public BlockStatement CreateMethodBody() public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters)
{ {
if (methodDef.Body == null) return null; if (methodDef.Body == null) return null;
@ -69,6 +77,15 @@ namespace ICSharpCode.Decompiler.Ast
Debug.Assert(context.CurrentMethod == methodDef); Debug.Assert(context.CurrentMethod == methodDef);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod); NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod);
if (parameters != null) {
foreach (var pair in (from p in parameters
join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
select new { p, v.Name }))
{
pair.p.Name = pair.Name;
}
}
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod); Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
@ -192,48 +209,48 @@ namespace ICSharpCode.Decompiler.Ast
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(byteCode.Code) { switch(byteCode.Code) {
#region Arithmetic #region Arithmetic
case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case ILCode.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case ILCode.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case ILCode.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case ILCode.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case ILCode.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case ILCode.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case ILCode.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case ILCode.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case ILCode.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); case ILCode.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
case ILCode.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2); case ILCode.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
case ILCode.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); case ILCode.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
case ILCode.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); case ILCode.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
case ILCode.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case ILCode.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case ILCode.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1); case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
case ILCode.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1); case ILCode.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
#endregion #endregion
#region Arrays #region Arrays
case ILCode.Newarr: case ILCode.Newarr:
case ILCode.InitArray: { case ILCode.InitArray: {
var ace = new Ast.ArrayCreateExpression(); var ace = new Ast.ArrayCreateExpression();
ace.Type = operandAsTypeRef; ace.Type = operandAsTypeRef;
ComposedType ct = operandAsTypeRef as ComposedType; ComposedType ct = operandAsTypeRef as ComposedType;
if (ct != null) { if (ct != null) {
// change "new (int[,])[10] to new int[10][,]" // change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
} }
if (byteCode.Code == ILCode.InitArray) { if (byteCode.Code == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression(); ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args); ace.Initializer.Elements.AddRange(args);
} else { } else {
ace.Arguments.Add(arg1); ace.Arguments.Add(arg1);
}
return ace;
} }
return ace; case ILCode.Ldlen: return arg1.Member("Length");
}
case ILCode.Ldlen: return arg1.Member("Length");
case ILCode.Ldelem_I: case ILCode.Ldelem_I:
case ILCode.Ldelem_I1: case ILCode.Ldelem_I1:
case ILCode.Ldelem_I2: case ILCode.Ldelem_I2:
@ -247,7 +264,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Ldelem_Ref: case ILCode.Ldelem_Ref:
case ILCode.Ldelem_Any: case ILCode.Ldelem_Any:
return arg1.Indexer(arg2); return arg1.Indexer(arg2);
case ILCode.Ldelema: return MakeRef(arg1.Indexer(arg2)); case ILCode.Ldelema: return MakeRef(arg1.Indexer(arg2));
case ILCode.Stelem_I: case ILCode.Stelem_I:
case ILCode.Stelem_I1: case ILCode.Stelem_I1:
case ILCode.Stelem_I2: case ILCode.Stelem_I2:
@ -258,30 +275,30 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Stelem_Ref: case ILCode.Stelem_Ref:
case ILCode.Stelem_Any: case ILCode.Stelem_Any:
return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3); return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
#endregion #endregion
#region Comparison #region Comparison
case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case ILCode.Cgt_Un: { case ILCode.Cgt_Un: {
// can also mean Inequality, when used with object references // can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType; TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) if (arg1Type != null && !arg1Type.IsValueType)
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
else else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
} }
case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion #endregion
#region Logical #region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case ILCode.LogicAnd: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2); case ILCode.LogicAnd: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2);
case ILCode.LogicOr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2); case ILCode.LogicOr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2);
case ILCode.TernaryOp: return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 }; case ILCode.TernaryOp: return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 };
case ILCode.NullCoalescing: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.NullCoalescing, arg2); case ILCode.NullCoalescing: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.NullCoalescing, arg2);
#endregion #endregion
#region Branch #region Branch
case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case ILCode.Brtrue: case ILCode.Brtrue:
return new Ast.IfElseStatement() { return new Ast.IfElseStatement() {
Condition = arg1, Condition = arg1,
@ -289,10 +306,10 @@ namespace ICSharpCode.Decompiler.Ast
new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
} }
}; };
case ILCode.LoopOrSwitchBreak: return new Ast.BreakStatement(); case ILCode.LoopOrSwitchBreak: return new Ast.BreakStatement();
case ILCode.LoopContinue: return new Ast.ContinueStatement(); case ILCode.LoopContinue: return new Ast.ContinueStatement();
#endregion #endregion
#region Conversions #region Conversions
case ILCode.Conv_I1: case ILCode.Conv_I1:
case ILCode.Conv_I2: case ILCode.Conv_I2:
case ILCode.Conv_I4: case ILCode.Conv_I4:
@ -302,11 +319,11 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_U4: case ILCode.Conv_U4:
case ILCode.Conv_U8: case ILCode.Conv_U8:
return arg1; // conversion is handled by Convert() function using the info from type analysis return arg1; // conversion is handled by Convert() function using the info from type analysis
case ILCode.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO case ILCode.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO case ILCode.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO
case ILCode.Conv_R4: return arg1.CastTo(typeof(float)); case ILCode.Conv_R4: return arg1.CastTo(typeof(float));
case ILCode.Conv_R8: return arg1.CastTo(typeof(double)); case ILCode.Conv_R8: return arg1.CastTo(typeof(double));
case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4:
@ -324,17 +341,17 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_Ovf_U4_Un: case ILCode.Conv_Ovf_U4_Un:
case ILCode.Conv_Ovf_U8_Un: case ILCode.Conv_Ovf_U8_Un:
return arg1; // conversion was handled by Convert() function using the info from type analysis return arg1; // conversion was handled by Convert() function using the info from type analysis
case ILCode.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO case ILCode.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr)); case ILCode.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr)); case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr)); case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Castclass: return arg1.CastTo(operandAsTypeRef); case ILCode.Castclass: return arg1.CastTo(operandAsTypeRef);
case ILCode.Unbox_Any: return arg1.CastTo(operandAsTypeRef); case ILCode.Unbox_Any: return arg1.CastTo(operandAsTypeRef);
case ILCode.Isinst: return arg1.CastAs(operandAsTypeRef); case ILCode.Isinst: return arg1.CastAs(operandAsTypeRef);
case ILCode.Box: return arg1; case ILCode.Box: return arg1;
case ILCode.Unbox: return InlineAssembly(byteCode, args); case ILCode.Unbox: return InlineAssembly(byteCode, args);
#endregion #endregion
#region Indirect #region Indirect
case ILCode.Ldind_I: case ILCode.Ldind_I:
case ILCode.Ldind_I1: case ILCode.Ldind_I1:
case ILCode.Ldind_I2: case ILCode.Ldind_I2:
@ -364,36 +381,36 @@ namespace ICSharpCode.Decompiler.Ast
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]); return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]);
else else
return InlineAssembly(byteCode, args); return InlineAssembly(byteCode, args);
#endregion #endregion
case ILCode.Arglist: return InlineAssembly(byteCode, args); case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Break: return InlineAssembly(byteCode, args); case ILCode.Break: return InlineAssembly(byteCode, args);
case ILCode.Call: return TransformCall(false, operand, methodDef, args); case ILCode.Call: return TransformCall(false, operand, methodDef, args);
case ILCode.Callvirt: return TransformCall(true, operand, methodDef, args); case ILCode.Callvirt: return TransformCall(true, operand, methodDef, args);
case ILCode.Ldftn: { case ILCode.Ldftn: {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name); var expr = new Ast.IdentifierExpression(cecilMethod.Name);
expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
expr.AddAnnotation(cecilMethod); expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldftn").Invoke(expr) return new IdentifierExpression("ldftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false)); .WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
} }
case ILCode.Ldvirtftn: { case ILCode.Ldvirtftn: {
Cecil.MethodReference cecilMethod = ((MethodReference)operand); Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name); var expr = new Ast.IdentifierExpression(cecilMethod.Name);
expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
expr.AddAnnotation(cecilMethod); expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldvirtftn").Invoke(expr) return new IdentifierExpression("ldvirtftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true)); .WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
} }
case ILCode.Calli: return InlineAssembly(byteCode, args); case ILCode.Calli: return InlineAssembly(byteCode, args);
case ILCode.Ckfinite: return InlineAssembly(byteCode, args); case ILCode.Ckfinite: return InlineAssembly(byteCode, args);
case ILCode.Constrained: return InlineAssembly(byteCode, args); case ILCode.Constrained: return InlineAssembly(byteCode, args);
case ILCode.Cpblk: return InlineAssembly(byteCode, args); case ILCode.Cpblk: return InlineAssembly(byteCode, args);
case ILCode.Cpobj: return InlineAssembly(byteCode, args); case ILCode.Cpobj: return InlineAssembly(byteCode, args);
case ILCode.Dup: return arg1; case ILCode.Dup: return arg1;
case ILCode.Endfilter: return InlineAssembly(byteCode, args); case ILCode.Endfilter: return InlineAssembly(byteCode, args);
case ILCode.Endfinally: return null; case ILCode.Endfinally: return null;
case ILCode.Initblk: return InlineAssembly(byteCode, args); case ILCode.Initblk: return InlineAssembly(byteCode, args);
case ILCode.Initobj: case ILCode.Initobj:
if (args[0] is DirectionExpression) if (args[0] is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), MakeDefaultValue((TypeReference)operand)); return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), MakeDefaultValue((TypeReference)operand));
@ -401,9 +418,9 @@ namespace ICSharpCode.Decompiler.Ast
return InlineAssembly(byteCode, args); return InlineAssembly(byteCode, args);
case ILCode.DefaultValue: case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand); return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args); case ILCode.Jmp: return InlineAssembly(byteCode, args);
case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType); case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal: case ILCode.Ldc_Decimal:
@ -424,106 +441,106 @@ namespace ICSharpCode.Decompiler.Ast
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand), .Member(((FieldReference)operand).Name).WithAnnotation(operand),
arg1); arg1);
case ILCode.Ldflda: return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand)); case ILCode.Ldflda: return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
case ILCode.Ldsflda: case ILCode.Ldsflda:
return MakeRef( return MakeRef(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand)); .Member(((FieldReference)operand).Name).WithAnnotation(operand));
case ILCode.Ldloc: { case ILCode.Ldloc: {
ILVariable v = (ILVariable)operand; ILVariable v = (ILVariable)operand;
if (!v.IsParameter) if (!v.IsParameter)
localVariablesToDefine.Add((ILVariable)operand); localVariablesToDefine.Add((ILVariable)operand);
Expression expr; Expression expr;
if (v.IsParameter && v.OriginalParameter.Index < 0) if (v.IsParameter && v.OriginalParameter.Index < 0)
expr = new ThisReferenceExpression(); expr = new ThisReferenceExpression();
else else
expr = new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); expr = new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand);
return v.IsParameter && v.Type is ByReferenceType ? MakeRef(expr) : expr; return v.IsParameter && v.Type is ByReferenceType ? MakeRef(expr) : expr;
} }
case ILCode.Ldloca: { case ILCode.Ldloca: {
ILVariable v = (ILVariable)operand; ILVariable v = (ILVariable)operand;
if (v.IsParameter && v.OriginalParameter.Index < 0) if (v.IsParameter && v.OriginalParameter.Index < 0)
return MakeRef(new ThisReferenceExpression()); return MakeRef(new ThisReferenceExpression());
if (!v.IsParameter) if (!v.IsParameter)
localVariablesToDefine.Add((ILVariable)operand); localVariablesToDefine.Add((ILVariable)operand);
return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand));
} }
case ILCode.Ldnull: return new Ast.NullReferenceExpression(); case ILCode.Ldnull: return new Ast.NullReferenceExpression();
case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand); case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand);
case ILCode.Ldtoken: case ILCode.Ldtoken:
if (operand is Cecil.TypeReference) { if (operand is Cecil.TypeReference) {
return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle"); return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
} else { } else {
return InlineAssembly(byteCode, args); return InlineAssembly(byteCode, args);
} }
case ILCode.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name }; case ILCode.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name };
case ILCode.Localloc: return InlineAssembly(byteCode, args); case ILCode.Localloc: return InlineAssembly(byteCode, args);
case ILCode.Mkrefany: return InlineAssembly(byteCode, args); case ILCode.Mkrefany: return InlineAssembly(byteCode, args);
case ILCode.Newobj: { case ILCode.Newobj: {
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
if (declaringType is ArrayType) { if (declaringType is ArrayType) {
ComposedType ct = AstBuilder.ConvertType((ArrayType)declaringType) as ComposedType; ComposedType ct = AstBuilder.ConvertType((ArrayType)declaringType) as ComposedType;
if (ct != null && ct.ArraySpecifiers.Count >= 1) { if (ct != null && ct.ArraySpecifiers.Count >= 1) {
var ace = new Ast.ArrayCreateExpression(); var ace = new Ast.ArrayCreateExpression();
ct.ArraySpecifiers.First().Remove(); ct.ArraySpecifiers.First().Remove();
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
ace.Type = ct; ace.Type = ct;
ace.Arguments.AddRange(args); ace.Arguments.AddRange(args);
return ace; return ace;
}
} }
var oce = new Ast.ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
} }
var oce = new Ast.ObjectCreateExpression(); case ILCode.No: return InlineAssembly(byteCode, args);
oce.Type = AstBuilder.ConvertType(declaringType); case ILCode.Nop: return null;
oce.Arguments.AddRange(args); case ILCode.Pop: return arg1;
return oce.WithAnnotation(operand); case ILCode.Readonly: return InlineAssembly(byteCode, args);
} case ILCode.Refanytype: return InlineAssembly(byteCode, args);
case ILCode.No: return InlineAssembly(byteCode, args); case ILCode.Refanyval: return InlineAssembly(byteCode, args);
case ILCode.Nop: return null;
case ILCode.Pop: return arg1;
case ILCode.Readonly: return InlineAssembly(byteCode, args);
case ILCode.Refanytype: return InlineAssembly(byteCode, args);
case ILCode.Refanyval: return InlineAssembly(byteCode, args);
case ILCode.Ret: case ILCode.Ret:
if (methodDef.ReturnType.FullName != "System.Void") { if (methodDef.ReturnType.FullName != "System.Void") {
return new Ast.ReturnStatement { Expression = arg1 }; return new Ast.ReturnStatement { Expression = arg1 };
} else { } else {
return new Ast.ReturnStatement(); return new Ast.ReturnStatement();
} }
case ILCode.Rethrow: return new Ast.ThrowStatement(); case ILCode.Rethrow: return new Ast.ThrowStatement();
case ILCode.Sizeof: return new Ast.SizeOfExpression { Type = operandAsTypeRef }; case ILCode.Sizeof: return new Ast.SizeOfExpression { Type = operandAsTypeRef };
case ILCode.Stloc: { case ILCode.Stloc: {
ILVariable locVar = (ILVariable)operand; ILVariable locVar = (ILVariable)operand;
if (!locVar.IsParameter) if (!locVar.IsParameter)
localVariablesToDefine.Add(locVar); localVariablesToDefine.Add(locVar);
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1);
} }
case ILCode.Switch: return InlineAssembly(byteCode, args); case ILCode.Switch: return InlineAssembly(byteCode, args);
case ILCode.Tail: return InlineAssembly(byteCode, args); case ILCode.Tail: return InlineAssembly(byteCode, args);
case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case ILCode.Unaligned: return InlineAssembly(byteCode, args); case ILCode.Unaligned: return InlineAssembly(byteCode, args);
case ILCode.Volatile: return InlineAssembly(byteCode, args); case ILCode.Volatile: return InlineAssembly(byteCode, args);
case ILCode.YieldBreak: case ILCode.YieldBreak:
return new Ast.YieldBreakStatement(); return new Ast.YieldBreakStatement();
case ILCode.YieldReturn: case ILCode.YieldReturn:
return new Ast.YieldStatement { Expression = arg1 }; return new Ast.YieldStatement { Expression = arg1 };
case ILCode.InitCollection: { case ILCode.InitCollection: {
ObjectCreateExpression oce = (ObjectCreateExpression)arg1; ObjectCreateExpression oce = (ObjectCreateExpression)arg1;
oce.Initializer = new ArrayInitializerExpression(); oce.Initializer = new ArrayInitializerExpression();
for (int i = 1; i < args.Count; i++) { for (int i = 1; i < args.Count; i++) {
ArrayInitializerExpression aie = args[i] as ArrayInitializerExpression; ArrayInitializerExpression aie = args[i] as ArrayInitializerExpression;
if (aie != null && aie.Elements.Count == 1) if (aie != null && aie.Elements.Count == 1)
oce.Initializer.Elements.Add(aie.Elements.Single().Detach()); oce.Initializer.Elements.Add(aie.Elements.Single().Detach());
else else
oce.Initializer.Elements.Add(args[i]); oce.Initializer.Elements.Add(args[i]);
}
return oce;
} }
return oce; case ILCode.InitCollectionAddMethod: {
} var collectionInit = new ArrayInitializerExpression();
case ILCode.InitCollectionAddMethod: { collectionInit.Elements.AddRange(args);
var collectionInit = new ArrayInitializerExpression(); return collectionInit;
collectionInit.Elements.AddRange(args); }
return collectionInit; default: throw new Exception("Unknown OpCode: " + byteCode.Code);
}
default: throw new Exception("Unknown OpCode: " + byteCode.Code);
} }
} }

2
ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs

@ -17,7 +17,7 @@ namespace ICSharpCode.Decompiler.Ast
public static T CopyAnnotationsFrom<T>(this T node, AstNode other) where T : AstNode public static T CopyAnnotationsFrom<T>(this T node, AstNode other) where T : AstNode
{ {
foreach (var annotation in other.Annotations<object>()) { foreach (object annotation in other.Annotations) {
node.AddAnnotation(annotation); node.AddAnnotation(annotation);
} }
return node; return node;

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

@ -114,23 +114,35 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (!IsAnonymousMethod(context, method)) if (!IsAnonymousMethod(context, method))
return false; return false;
// Create AnonymousMethodExpression and prepare parameters
AnonymousMethodExpression ame = new AnonymousMethodExpression();
ame.Parameters.AddRange(AstBuilder.MakeParameters(method.Parameters));
ame.HasParameterList = true;
// Decompile the anonymous method: // Decompile the anonymous method:
DecompilerContext subContext = context.Clone(); DecompilerContext subContext = context.Clone();
subContext.CurrentMethod = method; subContext.CurrentMethod = method;
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext); BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext); TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext);
body.AcceptVisitor(this, null); body.AcceptVisitor(this, null);
AnonymousMethodExpression ame = new AnonymousMethodExpression();
bool isLambda = false; bool isLambda = false;
if (method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) { if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) {
ame.HasParameterList = false; isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement);
} else { }
ame.HasParameterList = true; // Remove the parameter list from an AnonymousMethodExpression if the original method had no names,
ame.Parameters.AddRange(AstBuilder.MakeParameters(method.Parameters)); // and the parameters are not used in the method body
if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) { if (!isLambda && method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) {
isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement); var parameterReferencingIdentifiers =
from ident in body.Descendants.OfType<IdentifierExpression>()
let v = ident.Annotation<ILVariable>()
where v != null && v.IsParameter && method.Parameters.Contains(v.OriginalParameter)
select ident;
if (!parameterReferencingIdentifiers.Any()) {
ame.Parameters.Clear();
ame.HasParameterList = false;
} }
} }

Loading…
Cancel
Save