Browse Source

Improved handling of nested display classes.

pull/124/head
Daniel Grunwald 14 years ago
parent
commit
542bb9db2f
  1. 22
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  2. 2
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  3. 39
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

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

@ -296,10 +296,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -296,10 +296,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Delete the variable declaration statement:
AstNode cur = stmt.NextSibling;
stmt.Remove();
if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor) {
// Delete any following statements as long as they assign parameters to the display class
// Do parameter handling only for closures created in the top scope (direct child of method/accessor)
List<ILVariable> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>()
BlockStatement rootBlock = blockStatement.Ancestors.OfType<BlockStatement>().LastOrDefault() ?? blockStatement;
List<ILVariable> parameterOccurrances = rootBlock.Descendants.OfType<IdentifierExpression>()
.Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
AstNode next;
for (; cur != null; cur = next) {
@ -315,17 +315,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -315,17 +315,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
);
Match m = closureFieldAssignmentPattern.Match(cur);
if (m != null) {
FieldDefinition fieldDef = m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule();
AstNode right = m.Get("right").Single();
bool isParameter = false;
bool isDisplayClassParentPointerAssignment = false;
if (right is ThisReferenceExpression) {
isParameter = true;
} else if (right is IdentifierExpression) {
// handle parameters only if the whole method contains no other occurrance except for 'right'
ILVariable param = right.Annotation<ILVariable>();
isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1;
ILVariable v = right.Annotation<ILVariable>();
isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
if (!isParameter && TypeAnalysis.IsSameType(v.Type, fieldDef.FieldType) && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) {
isDisplayClassParentPointerAssignment = true;
}
}
if (isParameter) {
dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule()] = right;
if (isParameter || isDisplayClassParentPointerAssignment) {
dict[fieldDef] = right;
cur.Remove();
} else {
break;
@ -334,12 +339,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -334,12 +339,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
break;
}
}
}
// Now create variables for all fields of the display class (except for those that we already handled as parameters)
List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>();
foreach (FieldDefinition field in type.Fields) {
if (dict.ContainsKey(field))
if (dict.ContainsKey(field)) // skip field if it already was handled as parameter
continue;
EnsureVariableNameIsAvailable(blockStatement, field.Name);
currentlyUsedVariableNames.Add(field.Name);

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

@ -299,6 +299,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -299,6 +299,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
};
if (foreachStatement.InExpression is BaseReferenceExpression)
foreachStatement.InExpression = new ThisReferenceExpression();
node.ReplaceWith(foreachStatement);
foreach (Statement stmt in m.Get<Statement>("variablesOutsideLoop")) {
((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(null, stmt.Detach());

39
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -3,9 +3,48 @@ @@ -3,9 +3,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
public static class DelegateConstruction
{
class InstanceTests
{
public Action CaptureOfThis()
{
return delegate {
CaptureOfThis();
};
}
public Action CaptureOfThisAndParameter(int a)
{
return delegate {
CaptureOfThisAndParameter(a);
};
}
public Action CaptureOfThisAndParameterInForEach(int a)
{
foreach (var item in Enumerable.Empty<int>()) {
return delegate {
CaptureOfThisAndParameter(item + a);
};
}
return null;
}
public Action CaptureOfThisAndParameterInForEachWithItemCopy(int a)
{
foreach (var item in Enumerable.Empty<int>()) {
int copyOfItem = item;
return delegate {
CaptureOfThisAndParameter(item + a + copyOfItem);
};
}
return null;
}
}
public static void Test(this string a)
{
}

Loading…
Cancel
Save