Browse Source

Improved handling of nested display classes.

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

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

@ -296,50 +296,54 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Delete the variable declaration statement: // Delete the variable declaration statement:
AstNode cur = stmt.NextSibling; AstNode cur = stmt.NextSibling;
stmt.Remove(); 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 // 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) BlockStatement rootBlock = blockStatement.Ancestors.OfType<BlockStatement>().LastOrDefault() ?? blockStatement;
List<ILVariable> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>() List<ILVariable> parameterOccurrances = rootBlock.Descendants.OfType<IdentifierExpression>()
.Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList(); .Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
AstNode next; AstNode next;
for (; cur != null; cur = next) { for (; cur != null; cur = next) {
next = cur.NextSibling; next = cur.NextSibling;
// Test for the pattern: // Test for the pattern:
// "variableName.MemberName = right;" // "variableName.MemberName = right;"
ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement( ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
new AssignmentExpression( new AssignmentExpression(
new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }), new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }),
new AnyNode("right") new AnyNode("right")
) )
); );
Match m = closureFieldAssignmentPattern.Match(cur); Match m = closureFieldAssignmentPattern.Match(cur);
if (m != null) { if (m != null) {
AstNode right = m.Get("right").Single(); FieldDefinition fieldDef = m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule();
bool isParameter = false; AstNode right = m.Get("right").Single();
if (right is ThisReferenceExpression) { bool isParameter = false;
isParameter = true; bool isDisplayClassParentPointerAssignment = false;
} else if (right is IdentifierExpression) { if (right is ThisReferenceExpression) {
// handle parameters only if the whole method contains no other occurrance except for 'right' isParameter = true;
ILVariable param = right.Annotation<ILVariable>(); } else if (right is IdentifierExpression) {
isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1; // handle parameters only if the whole method contains no other occurrance except for 'right'
} ILVariable v = right.Annotation<ILVariable>();
if (isParameter) { isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule()] = right; if (!isParameter && TypeAnalysis.IsSameType(v.Type, fieldDef.FieldType) && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) {
cur.Remove(); isDisplayClassParentPointerAssignment = true;
} else {
break;
} }
}
if (isParameter || isDisplayClassParentPointerAssignment) {
dict[fieldDef] = right;
cur.Remove();
} else { } else {
break; break;
} }
} else {
break;
} }
} }
// Now create variables for all fields of the display class (except for those that we already handled as parameters) // 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>>(); List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>();
foreach (FieldDefinition field in type.Fields) { foreach (FieldDefinition field in type.Fields) {
if (dict.ContainsKey(field)) if (dict.ContainsKey(field)) // skip field if it already was handled as parameter
continue; continue;
EnsureVariableNameIsAvailable(blockStatement, field.Name); EnsureVariableNameIsAvailable(blockStatement, field.Name);
currentlyUsedVariableNames.Add(field.Name); currentlyUsedVariableNames.Add(field.Name);

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

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

63
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -3,43 +3,82 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
public static class DelegateConstruction 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) public static void Test(this string a)
{ {
} }
public static Action<string> ExtensionMethodUnbound() public static Action<string> ExtensionMethodUnbound()
{ {
return new Action<string>(DelegateConstruction.Test); return new Action<string>(DelegateConstruction.Test);
} }
public static Action ExtensionMethodBound() public static Action ExtensionMethodBound()
{ {
return new Action("abc".Test); return new Action("abc".Test);
} }
public static Action ExtensionMethodBoundOnNull() public static Action ExtensionMethodBoundOnNull()
{ {
return new Action(((string)null).Test); return new Action(((string)null).Test);
} }
public static object StaticMethod() public static object StaticMethod()
{ {
return new Func<Action>(DelegateConstruction.ExtensionMethodBound); return new Func<Action>(DelegateConstruction.ExtensionMethodBound);
} }
public static object InstanceMethod() public static object InstanceMethod()
{ {
return new Func<string>("hello".ToUpper); return new Func<string>("hello".ToUpper);
} }
public static object InstanceMethodOnNull() public static object InstanceMethodOnNull()
{ {
return new Func<string>(((string)null).ToUpper); return new Func<string>(((string)null).ToUpper);
} }
public static List<Action<int>> AnonymousMethodStoreWithinLoop() public static List<Action<int>> AnonymousMethodStoreWithinLoop()
{ {
List<Action<int>> list = new List<Action<int>>(); List<Action<int>> list = new List<Action<int>>();
@ -54,7 +93,7 @@ public static class DelegateConstruction
} }
return list; return list;
} }
public static List<Action<int>> AnonymousMethodStoreOutsideLoop() public static List<Action<int>> AnonymousMethodStoreOutsideLoop()
{ {
List<Action<int>> list = new List<Action<int>>(); List<Action<int>> list = new List<Action<int>>();
@ -69,7 +108,7 @@ public static class DelegateConstruction
} }
return list; return list;
} }
public static Action StaticAnonymousMethodNoClosure() public static Action StaticAnonymousMethodNoClosure()
{ {
return delegate return delegate
@ -77,7 +116,7 @@ public static class DelegateConstruction
Console.WriteLine(); Console.WriteLine();
}; };
} }
public static void NameConflict() public static void NameConflict()
{ {
// i is captured variable, // i is captured variable,
@ -98,7 +137,7 @@ public static class DelegateConstruction
} }
} }
} }
public static void NameConflict2(int j) public static void NameConflict2(int j)
{ {
List<Action<int>> list = new List<Action<int>>(); List<Action<int>> list = new List<Action<int>>();
@ -109,7 +148,7 @@ public static class DelegateConstruction
}); });
} }
} }
public static Action<int> NameConflict3(int i) public static Action<int> NameConflict3(int i)
{ {
return delegate(int j) { return delegate(int j) {

Loading…
Cancel
Save