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

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

@ -78,11 +78,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -78,11 +78,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new ObjectCreateExpression {
Initializer = new ArrayInitializerExpression {
Elements = {
Expression = new Choice {
new AnonymousTypeCreateExpression {
Initializers = {
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 @@ -100,12 +106,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (!match.Success)
return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedExpression nae1 = match.Get<NamedExpression>("nae1").Single();
NamedExpression nae2 = match.Get<NamedExpression>("nae2").Single();
if (nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
NamedExpression nae1 = match.Get<NamedExpression>("nae1").SingleOrDefault();
NamedExpression nae2 = match.Get<NamedExpression>("nae2").SingleOrDefault();
if (nae1 != null && nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
return false;
IdentifierExpression nae2IdentExpr = nae2.Expression as IdentifierExpression;
if (nae2IdentExpr != null && nae2.Identifier == nae2IdentExpr.Identifier) {
Expression nae2Expr = match.Get<Expression>("nae2Expr").Single();
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 x in ... ...
@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var clause in innerQuery.Clauses) {
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;
}

79
ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -35,7 +35,7 @@ public class QueryExpressions @@ -35,7 +35,7 @@ public class QueryExpressions
{
public int OrderID;
public DateTime OrderDate;
public Customer Customer;
public QueryExpressions.Customer Customer;
public int CustomerID;
public decimal Total;
public IEnumerable<QueryExpressions.OrderDetail> Details;
@ -54,7 +54,7 @@ public class QueryExpressions @@ -54,7 +54,7 @@ public class QueryExpressions
{
return
from c in this.customers
where c.Orders.Count() > 10
where c.Orders.Count<QueryExpressions.Order>() > 10
where c.Country == "DE"
select c;
}
@ -64,7 +64,12 @@ public class QueryExpressions @@ -64,7 +64,12 @@ public class QueryExpressions
return
from c in this.customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total };
select new
{
c.Name,
o.OrderID,
o.Total
};
}
public object SelectManyFollowedByOrderBy()
@ -73,7 +78,12 @@ public class QueryExpressions @@ -73,7 +78,12 @@ public class QueryExpressions
from c in this.customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total };
select new
{
c.Name,
o.OrderID,
o.Total
};
}
public object MultipleSelectManyFollowedBySelect()
@ -82,7 +92,12 @@ public class QueryExpressions @@ -82,7 +92,12 @@ public class QueryExpressions
from c in this.customers
from o in c.Orders
from d in o.Details
select new { c.Name, o.OrderID, d.Quantity };
select new
{
c.Name,
o.OrderID,
d.Quantity
};
}
public object MultipleSelectManyFollowedByLet()
@ -92,16 +107,25 @@ public class QueryExpressions @@ -92,16 +107,25 @@ public class QueryExpressions
from o in c.Orders
from d in o.Details
let x = d.Quantity * d.UnitPrice
select new { c.Name, o.OrderID, x };
select new
{
c.Name,
o.OrderID,
x
};
}
public object FromLetWhereSelect()
{
return
from o in this.orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t };
let t = o.Details.Sum((QueryExpressions.OrderDetail d) => d.UnitPrice * d.Quantity)
where t >= 1000m
select new
{
OrderID = o.OrderID,
Total = t
};
}
public object MultipleLet()
@ -116,25 +140,34 @@ public class QueryExpressions @@ -116,25 +140,34 @@ public class QueryExpressions
public object Join()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total };
from c in this.customers
join o in this.orders on c.CustomerID equals o.CustomerID
select new
{
c.Name,
o.OrderDate,
o.Total
};
}
public object JoinInto()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
from c in this.customers
join o in this.orders on c.CustomerID equals o.CustomerID into co
let n = co.Count<QueryExpressions.Order>()
where n >= 10
select new { c.Name, OrderCount = n };
select new
{
Name = c.Name,
OrderCount = n
};
}
public object OrderBy()
{
return
from o in orders
from o in this.orders
orderby o.Customer.Name, o.Total descending
select o;
}
@ -142,14 +175,14 @@ public class QueryExpressions @@ -142,14 +175,14 @@ public class QueryExpressions
public object GroupBy()
{
return
from c in customers
from c in this.customers
group c.Name by c.Country;
}
public object ExplicitType()
{
return
from Customer c in customers
from QueryExpressions.Customer c in this.customers
where c.City == "London"
select c;
}
@ -157,8 +190,12 @@ public class QueryExpressions @@ -157,8 +190,12 @@ public class QueryExpressions
public object QueryContinuation()
{
return
from c in customers
from c in this.customers
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 @@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\PropertiesAndEvents.cs");
}
[Test, Ignore("Formatting differences in anonymous method create expressions")]
[Test]
public void QueryExpressions()
{
TestFile(@"..\..\Tests\QueryExpressions.cs");

Loading…
Cancel
Save