From 8ee23f52435df76b8b9ac85e95df1b203fad2d97 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 10 Apr 2011 21:12:22 +0200 Subject: [PATCH] Add support for query continuations. --- .../Ast/Transforms/CombineQueryExpressions.cs | 18 ++++++++ .../Transforms/IntroduceQueryExpressions.cs | 41 +++++++++++-------- .../Tests/QueryExpressions.cs | 25 +++++++++-- ICSharpCode.Decompiler/Tests/TestRunner.cs | 6 +++ 4 files changed, 68 insertions(+), 22 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs b/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs index 98af72df1..5d9407416 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs @@ -27,6 +27,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms CombineQueries(compilationUnit); } + static readonly InvocationExpression castPattern = new InvocationExpression { + Target = new MemberReferenceExpression { + Target = new AnyNode("inExpr"), + MemberName = "Cast", + TypeArguments = { new AnyNode("targetType") } + }}; + void CombineQueries(AstNode node) { for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { @@ -39,6 +46,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (innerQuery != null) { if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery)) { RemoveTransparentIdentifierReferences(query); + } else { + QueryContinuationClause continuation = new QueryContinuationClause(); + continuation.PrecedingQuery = innerQuery.Detach(); + continuation.Identifier = fromClause.Identifier; + fromClause.ReplaceWith(continuation); + } + } else { + Match m = castPattern.Match(fromClause.Expression); + if (m != null) { + fromClause.Type = m.Get("targetType").Single().Detach(); + fromClause.Expression = m.Get("inExpr").Single().Detach(); } } } diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs index 141217318..aad6afa6d 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs @@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms void DecompileQueries(AstNode node) { QueryExpression query = DecompileQuery(node as InvocationExpression); + if (query != null) + node.ReplaceWith(query); for (AstNode child = (query ?? node).FirstChild; child != null; child = child.NextSibling) { DecompileQueries(child); } @@ -87,26 +89,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); query.Clauses.Add(new QuerySelectClause { Expression = body.Detach() }); - invocation.ReplaceWith(query); return query; } return null; } case "GroupBy": { - if (invocation.Arguments.Count != 2) - return null; - string parameterName1, parameterName2; - Expression keySelector, elementSelector; - if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector) - && MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector) - && parameterName1 == parameterName2) - { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() }); - invocation.ReplaceWith(query); - return query; + if (invocation.Arguments.Count == 2) { + string parameterName1, parameterName2; + Expression keySelector, elementSelector; + if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector) + && MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector) + && parameterName1 == parameterName2) + { + QueryExpression query = new QueryExpression(); + query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() }); + query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() }); + return query; + } + } else if (invocation.Arguments.Count == 1) { + string parameterName; + Expression keySelector; + if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out keySelector)) { + QueryExpression query = new QueryExpression(); + query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); + query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameterName), Key = keySelector.Detach() }); + return query; + } } return null; } @@ -127,7 +136,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms query.Clauses.Add(new QueryFromClause { Identifier = p1.Name, Expression = mre.Target.Detach() }); query.Clauses.Add(new QueryFromClause { Identifier = p2.Name, Expression = collectionSelector.Detach() }); query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }); - invocation.ReplaceWith(query); return query; } } @@ -143,7 +151,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() }); - invocation.ReplaceWith(query); return query; } return null; @@ -183,7 +190,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); query.Clauses.Add(orderClause); - invocation.ReplaceWith(query); return query; } } @@ -219,7 +225,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } query.Clauses.Add(joinClause); query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }); - invocation.ReplaceWith(query); return query; } } diff --git a/ICSharpCode.Decompiler/Tests/QueryExpressions.cs b/ICSharpCode.Decompiler/Tests/QueryExpressions.cs index 010291d5e..7f3680c88 100644 --- a/ICSharpCode.Decompiler/Tests/QueryExpressions.cs +++ b/ICSharpCode.Decompiler/Tests/QueryExpressions.cs @@ -10,9 +10,10 @@ public class QueryExpressions public class Customer { public int CustomerID; - public IEnumerable Orders; + public IEnumerable Orders; public string Name; public string Country; + public string City; } public class Order @@ -22,7 +23,7 @@ public class QueryExpressions public Customer Customer; public int CustomerID; public decimal Total; - public IEnumerable Details; + public IEnumerable Details; } public class OrderDetail @@ -31,8 +32,8 @@ public class QueryExpressions public int Quantity; } - public IEnumerable customers; - public IEnumerable orders; + public IEnumerable customers; + public IEnumerable orders; public object MultipleWhere() { @@ -129,4 +130,20 @@ public class QueryExpressions from c in customers group c.Name by c.Country; } + + public object ExplicitType() + { + return + from Customer c in customers + where c.City == "London" + select c; + } + + public object QueryContinuation() + { + return + from c in customers + group c by c.Country into g + select new { Country = g.Key, CustCount = g.Count() }; + } } diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 4ac77b536..1befefed0 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -94,6 +94,12 @@ namespace ICSharpCode.Decompiler.Tests TestFile(@"..\..\Tests\YieldReturn.cs"); } + [Test, Ignore("Formatting differences")] + public void QueryExpressions() + { + TestFile(@"..\..\Tests\QueryExpressions.cs"); + } + static void TestFile(string fileName) { string code = File.ReadAllText(fileName);