Browse Source

Make pattern in TryRemoveTransparentIdentifier more flexible. Allow multiple let expressions per anonymous type declaration.

pull/1405/head
Siegfried Pammer 7 years ago
parent
commit
9487d0a714
  1. 99
      ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

99
ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

@ -69,29 +69,23 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
} }
} }
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause { static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new Choice { Expression = new AnonymousTypeCreateExpression {
new AnonymousTypeCreateExpression { Initializers = {
Initializers = { new Repeat(
new NamedExpression { new Choice {
Name = Pattern.AnyString, new IdentifierExpression(Pattern.AnyString).WithName("expr"), // capture variable with same name
Expression = new IdentifierExpression(Pattern.AnyString) new NamedExpression {
}.WithName("nae1"), Name = Pattern.AnyString,
new NamedExpression { Expression = new AnyNode()
Name = Pattern.AnyString, }.WithName("expr")
Expression = new AnyNode("nae2Expr") }
}.WithName("nae2") ) { MinCount = 1 }
}
},
new AnonymousTypeCreateExpression {
Initializers = {
new NamedNode("identifier", new IdentifierExpression(Pattern.AnyString)),
new AnyNode("nae2Expr")
}
} }
}}; }
};
bool IsTransparentIdentifier(string identifier) bool IsTransparentIdentifier(string identifier)
{ {
return identifier.StartsWith("<>", StringComparison.Ordinal) && (identifier.Contains("TransparentIdentifier") || identifier.Contains("TranspIdent")); return identifier.StartsWith("<>", StringComparison.Ordinal) && (identifier.Contains("TransparentIdentifier") || identifier.Contains("TranspIdent"));
@ -101,48 +95,33 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
if (!IsTransparentIdentifier(fromClause.Identifier)) if (!IsTransparentIdentifier(fromClause.Identifier))
return false; return false;
Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); QuerySelectClause selectClause = innerQuery.Clauses.Last() as QuerySelectClause;
Match match = selectTransparentIdentifierPattern.Match(selectClause);
if (!match.Success) if (!match.Success)
return false; return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedExpression nae1 = match.Get<NamedExpression>("nae1").SingleOrDefault(); // from * in (from x in ... select new { members of anonymous type }) ...
NamedExpression nae2 = match.Get<NamedExpression>("nae2").SingleOrDefault(); // =>
if (nae1 != null && nae1.Name != ((IdentifierExpression)nae1.Expression).Identifier) // from x in ... { let x = ... } ...
return false; fromClause.Remove();
Expression nae2Expr = match.Get<Expression>("nae2Expr").Single(); selectClause.Remove();
IdentifierExpression nae2IdentExpr = nae2Expr as IdentifierExpression; // Move clauses from innerQuery to query
if (nae2IdentExpr != null && (nae2 == null || nae2.Name == nae2IdentExpr.Identifier)) { QueryClause insertionPos = null;
// from * in (from x in ... select new { x = x, y = y }) ... foreach (var clause in innerQuery.Clauses) {
// => query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
// from x in ... ... }
fromClause.Remove();
selectClause.Remove(); foreach (var expr in match.Get<Expression>("expr")) {
// Move clauses from innerQuery to query switch (expr) {
QueryClause insertionPos = null; case IdentifierExpression identifier:
foreach (var clause in innerQuery.Clauses) { // nothing to add
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); continue;
} case NamedExpression namedExpression:
} else { if (namedExpression.Expression is IdentifierExpression identifierExpression && namedExpression.Name == identifierExpression.Identifier)
// from * in (from x in ... select new { x = x, y = expr }) ... continue;
// => query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = namedExpression.Name, Expression = namedExpression.Expression.Detach() });
// from x in ... let y = expr ... break;
fromClause.Remove();
selectClause.Remove();
// Move clauses from innerQuery to query
QueryClause insertionPos = null;
foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
} }
string ident;
if (nae2 != null)
ident = nae2.Name;
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;
} }

Loading…
Cancel
Save