Browse Source

Fixed decompilation of anonymous methods created by the VB compiler. Closes #127.

pull/194/merge
Daniel Grunwald 14 years ago
parent
commit
ae873ec18f
  1. 13
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  2. 16
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

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

@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method) internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method)
{ {
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal)) if (method == null || !(method.Name.StartsWith("<", StringComparison.Ordinal) || method.Name.Contains("$")))
return false; return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType))) if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType)))
return false; return false;
@ -388,10 +388,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
continue; // skip static fields continue; // skip static fields
if (dict.ContainsKey(field)) // skip field if it already was handled as parameter if (dict.ContainsKey(field)) // skip field if it already was handled as parameter
continue; continue;
EnsureVariableNameIsAvailable(blockStatement, field.Name); string capturedVariableName = field.Name;
currentlyUsedVariableNames.Add(field.Name); if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10)
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name)); capturedVariableName = capturedVariableName.Substring(10);
dict[field] = new IdentifierExpression(field.Name); EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName));
dict[field] = new IdentifierExpression(capturedVariableName);
} }
// Now figure out where the closure was accessed and use the simpler replacement expression there: // Now figure out where the closure was accessed and use the simpler replacement expression there:

16
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -308,6 +308,8 @@ namespace ICSharpCode.Decompiler.ILAst
/// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions. /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions.
/// ///
/// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)". /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)".
///
/// Also simplifies 'newobj(SomeDelegate, target, ldvirtftn(F, target))' to 'newobj(SomeDelegate, target, ldvirtftn(F))'
/// </summary> /// </summary>
void IntroducePropertyAccessInstructions(ILNode node) void IntroducePropertyAccessInstructions(ILNode node)
{ {
@ -365,6 +367,20 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter; expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter;
} }
} }
} else if (expr.Code == ILCode.Newobj && expr.Arguments.Count == 2) {
// Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'.
ILVariable target;
ILExpression ldvirtftnArg;
if (expr.Arguments[0].Match(ILCode.Ldloc, out target)
&& expr.Arguments[1].Code == ILCode.Ldvirtftn
&& expr.Arguments[1].Arguments.Count == 1
&& expr.Arguments[1].Arguments[0].MatchLdloc(target))
{
// Remove the 'target' argument from the ldvirtftn instruction.
// It's not needed in the translation to C#, and needs to be eliminated so that the target expression
// can be inlined.
expr.Arguments[1].Arguments.Clear();
}
} }
} }

Loading…
Cancel
Save