Browse Source

Anonymous type create expressions: when all names can be inferred from the initializers, don't create NamedExpressions.

pull/275/merge
Daniel Grunwald 14 years ago
parent
commit
c28f6455d8
  1. 35
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 36
      ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs
  3. 79
      ICSharpCode.Decompiler/Tests/QueryExpressions.cs
  4. 2
      ICSharpCode.Decompiler/Tests/TestRunner.cs

35
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -714,21 +714,40 @@ namespace ICSharpCode.Decompiler.Ast
return ace; return ace;
} }
} }
var oce = new Ast.ObjectCreateExpression();
if (declaringType.IsAnonymousType()) { if (declaringType.IsAnonymousType()) {
MethodDefinition ctor = ((MethodReference)operand).Resolve(); MethodDefinition ctor = ((MethodReference)operand).Resolve();
if (methodDef != null) { if (methodDef != null) {
oce.Initializer = new ArrayInitializerExpression(); AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
bool allNamesCanBeInferred = true;
for (int i = 0; i < args.Count; i++) { for (int i = 0; i < args.Count; i++) {
oce.Initializer.Elements.Add( string inferredName;
new NamedExpression { if (args[i] is IdentifierExpression)
Identifier = ctor.Parameters[i].Name, inferredName = ((IdentifierExpression)args[i]).Identifier;
Expression = args[i] else if (args[i] is MemberReferenceExpression)
}); inferredName = ((MemberReferenceExpression)args[i]).MemberName;
else
inferredName = null;
if (inferredName != ctor.Parameters[i].Name) {
allNamesCanBeInferred = false;
break;
}
} }
if (allNamesCanBeInferred) {
atce.Initializers.AddRange(args);
} else {
for (int i = 0; i < args.Count; i++) {
atce.Initializers.Add(
new NamedExpression {
Identifier = ctor.Parameters[i].Name,
Expression = args[i]
});
}
}
return atce;
} }
return oce;
} }
var oce = new Ast.ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(declaringType); oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args); oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand); return oce.WithAnnotation(operand);

36
ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs

@ -78,11 +78,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause { static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new ObjectCreateExpression { Expression = new Choice {
Initializer = new ArrayInitializerExpression { new AnonymousTypeCreateExpression {
Elements = { Initializers = {
new NamedNode("nae1", new NamedExpression { Expression = new IdentifierExpression() }), new NamedNode("nae1", new NamedExpression { Expression = new IdentifierExpression() }),
new NamedNode("nae2", new NamedExpression { Expression = new AnyNode() }) new NamedNode("nae2", new NamedExpression { Expression = new AnyNode("nae2Expr") })
}
},
new AnonymousTypeCreateExpression {
Initializers = {
new NamedNode("identifier", new IdentifierExpression()),
new AnyNode("nae2Expr")
} }
} }
}}; }};
@ -100,12 +106,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (!match.Success) if (!match.Success)
return false; return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedExpression nae1 = match.Get<NamedExpression>("nae1").Single(); NamedExpression nae1 = match.Get<NamedExpression>("nae1").SingleOrDefault();
NamedExpression nae2 = match.Get<NamedExpression>("nae2").Single(); NamedExpression nae2 = match.Get<NamedExpression>("nae2").SingleOrDefault();
if (nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier) if (nae1 != null && nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
return false; return false;
IdentifierExpression nae2IdentExpr = nae2.Expression as IdentifierExpression; Expression nae2Expr = match.Get<Expression>("nae2Expr").Single();
if (nae2IdentExpr != null && nae2.Identifier == nae2IdentExpr.Identifier) { IdentifierExpression nae2IdentExpr = nae2Expr as IdentifierExpression;
if (nae2IdentExpr != null && (nae2 == null || nae2.Identifier == nae2IdentExpr.Identifier)) {
// from * in (from x in ... select new { x = x, y = y }) ... // from * in (from x in ... select new { x = x, y = y }) ...
// => // =>
// from x in ... ... // from x in ... ...
@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var clause in innerQuery.Clauses) { foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
} }
query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2.Identifier, Expression = nae2.Expression.Detach() }); string ident;
if (nae2 != null)
ident = nae2.Identifier;
else if (nae2Expr is IdentifierExpression)
ident = ((IdentifierExpression)nae2Expr).Identifier;
else if (nae2Expr is MemberReferenceExpression)
ident = ((MemberReferenceExpression)nae2Expr).MemberName;
else
throw new InvalidOperationException("Could not infer name from initializer in AnonymousTypeCreateExpression");
query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = ident, Expression = nae2Expr.Detach() });
} }
return true; return true;
} }

79
ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -35,7 +35,7 @@ public class QueryExpressions
{ {
public int OrderID; public int OrderID;
public DateTime OrderDate; public DateTime OrderDate;
public Customer Customer; public QueryExpressions.Customer Customer;
public int CustomerID; public int CustomerID;
public decimal Total; public decimal Total;
public IEnumerable<QueryExpressions.OrderDetail> Details; public IEnumerable<QueryExpressions.OrderDetail> Details;
@ -54,7 +54,7 @@ public class QueryExpressions
{ {
return return
from c in this.customers from c in this.customers
where c.Orders.Count() > 10 where c.Orders.Count<QueryExpressions.Order>() > 10
where c.Country == "DE" where c.Country == "DE"
select c; select c;
} }
@ -64,7 +64,12 @@ public class QueryExpressions
return return
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
select new { c.Name, o.OrderID, o.Total }; select new
{
c.Name,
o.OrderID,
o.Total
};
} }
public object SelectManyFollowedByOrderBy() public object SelectManyFollowedByOrderBy()
@ -73,7 +78,12 @@ public class QueryExpressions
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
orderby o.Total descending orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }; select new
{
c.Name,
o.OrderID,
o.Total
};
} }
public object MultipleSelectManyFollowedBySelect() public object MultipleSelectManyFollowedBySelect()
@ -82,7 +92,12 @@ public class QueryExpressions
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
from d in o.Details from d in o.Details
select new { c.Name, o.OrderID, d.Quantity }; select new
{
c.Name,
o.OrderID,
d.Quantity
};
} }
public object MultipleSelectManyFollowedByLet() public object MultipleSelectManyFollowedByLet()
@ -92,16 +107,25 @@ public class QueryExpressions
from o in c.Orders from o in c.Orders
from d in o.Details from d in o.Details
let x = d.Quantity * d.UnitPrice let x = d.Quantity * d.UnitPrice
select new { c.Name, o.OrderID, x }; select new
{
c.Name,
o.OrderID,
x
};
} }
public object FromLetWhereSelect() public object FromLetWhereSelect()
{ {
return return
from o in this.orders from o in this.orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity) let t = o.Details.Sum((QueryExpressions.OrderDetail d) => d.UnitPrice * d.Quantity)
where t >= 1000 where t >= 1000m
select new { o.OrderID, Total = t }; select new
{
OrderID = o.OrderID,
Total = t
};
} }
public object MultipleLet() public object MultipleLet()
@ -116,25 +140,34 @@ public class QueryExpressions
public object Join() public object Join()
{ {
return return
from c in customers from c in this.customers
join o in orders on c.CustomerID equals o.CustomerID join o in this.orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }; select new
{
c.Name,
o.OrderDate,
o.Total
};
} }
public object JoinInto() public object JoinInto()
{ {
return return
from c in customers from c in this.customers
join o in orders on c.CustomerID equals o.CustomerID into co join o in this.orders on c.CustomerID equals o.CustomerID into co
let n = co.Count() let n = co.Count<QueryExpressions.Order>()
where n >= 10 where n >= 10
select new { c.Name, OrderCount = n }; select new
{
Name = c.Name,
OrderCount = n
};
} }
public object OrderBy() public object OrderBy()
{ {
return return
from o in orders from o in this.orders
orderby o.Customer.Name, o.Total descending orderby o.Customer.Name, o.Total descending
select o; select o;
} }
@ -142,14 +175,14 @@ public class QueryExpressions
public object GroupBy() public object GroupBy()
{ {
return return
from c in customers from c in this.customers
group c.Name by c.Country; group c.Name by c.Country;
} }
public object ExplicitType() public object ExplicitType()
{ {
return return
from Customer c in customers from QueryExpressions.Customer c in this.customers
where c.City == "London" where c.City == "London"
select c; select c;
} }
@ -157,8 +190,12 @@ public class QueryExpressions
public object QueryContinuation() public object QueryContinuation()
{ {
return return
from c in customers from c in this.customers
group c by c.Country into g group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }; select new
{
Country = g.Key,
CustCount = g.Count<QueryExpressions.Customer>()
};
} }
} }

2
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\PropertiesAndEvents.cs"); TestFile(@"..\..\Tests\PropertiesAndEvents.cs");
} }
[Test, Ignore("Formatting differences in anonymous method create expressions")] [Test]
public void QueryExpressions() public void QueryExpressions()
{ {
TestFile(@"..\..\Tests\QueryExpressions.cs"); TestFile(@"..\..\Tests\QueryExpressions.cs");

Loading…
Cancel
Save