Skip to content

Commit 12dcd79

Browse files
authored
Add support for simple nested expressions (#188)
1 parent aa9b83c commit 12dcd79

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using NUnit.Framework;
5+
6+
namespace DelegateDecompiler.Tests
7+
{
8+
public class NestedExpressionsTests : DecompilerTestsBase
9+
{
10+
readonly int f1 = 0;
11+
static readonly int f2 = 0;
12+
int p1 => 0;
13+
static int p2 => 0;
14+
int M1() => 0;
15+
static int M2() => 0;
16+
17+
[Test]
18+
public void TestNestedExpression()
19+
{
20+
Test<Func<IQueryable<int>, int>>(
21+
ints => ints.SingleOrDefault(i => i == 0),
22+
ints => ints.SingleOrDefault(i => i == 0)
23+
);
24+
}
25+
26+
[Test, Ignore("Not supported yet")]
27+
public void TestExpressionWithClosure()
28+
{
29+
var v = 0;
30+
Test<Func<IQueryable<int>, int>>(
31+
ints => ints.SingleOrDefault(i => i == v),
32+
ints => ints.SingleOrDefault(i => i == v)
33+
);
34+
}
35+
36+
[Test, Ignore("Not supported yet")]
37+
public void TestExpressionWithFieldClosure()
38+
{
39+
Test<Func<IQueryable<int>, int>>(
40+
ints => ints.SingleOrDefault(i => i == f1),
41+
ints => ints.SingleOrDefault(i => i == f1)
42+
);
43+
}
44+
45+
[Test]
46+
public void TestExpressionWithStaticFieldClosure()
47+
{
48+
Test<Func<IQueryable<int>, int>>(
49+
ints => ints.SingleOrDefault(i => i == f2),
50+
ints => ints.SingleOrDefault(i => i == f2)
51+
);
52+
}
53+
54+
[Test, Ignore("Not supported yet")]
55+
public void TestExpressionWithPropertyClosure()
56+
{
57+
Test<Func<IQueryable<int>, int>>(
58+
ints => ints.SingleOrDefault(i => i == p1),
59+
ints => ints.SingleOrDefault(i => i == p1)
60+
);
61+
}
62+
63+
[Test]
64+
public void TestExpressionWithStaticPropertyClosure()
65+
{
66+
Test<Func<IQueryable<int>, int>>(
67+
ints => ints.SingleOrDefault(i => i == p2),
68+
ints => ints.SingleOrDefault(i => i == p2)
69+
);
70+
}
71+
72+
[Test, Ignore("Not supported yet")]
73+
public void TestExpressionWithMethodClosure()
74+
{
75+
Test<Func<IQueryable<int>, int>>(
76+
ints => ints.SingleOrDefault(i => i == M1()),
77+
ints => ints.SingleOrDefault(i => i == M1())
78+
);
79+
}
80+
81+
[Test]
82+
public void TestExpressionWithStaticMethodClosure()
83+
{
84+
Test<Func<IQueryable<int>, int>>(
85+
ints => ints.SingleOrDefault(i => i == M2()),
86+
ints => ints.SingleOrDefault(i => i == M2())
87+
);
88+
}
89+
90+
[Test]
91+
public void TestNestedFunc()
92+
{
93+
Test<Func<IEnumerable<int>, int>>(
94+
ints => ints.SingleOrDefault(i => i == 0),
95+
ints => ints.SingleOrDefault(i => i == 0)
96+
);
97+
}
98+
99+
[Test]
100+
public void TestFuncWithClosure()
101+
{
102+
var v = 0;
103+
Test<Func<IEnumerable<int>, int>>(
104+
ints => ints.SingleOrDefault(i => i == v),
105+
ints => ints.SingleOrDefault(i => i == v)
106+
);
107+
}
108+
109+
[Test]
110+
public void TestFuncWithFieldClosure()
111+
{
112+
Test<Func<IEnumerable<int>, int>>(
113+
ints => ints.SingleOrDefault(i => i == f1),
114+
ints => ints.SingleOrDefault(i => i == f1)
115+
);
116+
}
117+
118+
[Test]
119+
public void TestFuncWithStaticFieldClosure()
120+
{
121+
Test<Func<IEnumerable<int>, int>>(
122+
ints => ints.SingleOrDefault(i => i == f2),
123+
ints => ints.SingleOrDefault(i => i == f2)
124+
);
125+
}
126+
127+
[Test]
128+
public void TestFuncWithPropertyClosure()
129+
{
130+
Test<Func<IEnumerable<int>, int>>(
131+
ints => ints.SingleOrDefault(i => i == p1),
132+
ints => ints.SingleOrDefault(i => i == p1)
133+
);
134+
}
135+
136+
[Test]
137+
public void TestFuncWithStaticPropertyClosure()
138+
{
139+
Test<Func<IEnumerable<int>, int>>(
140+
ints => ints.SingleOrDefault(i => i == p2),
141+
ints => ints.SingleOrDefault(i => i == p2)
142+
);
143+
}
144+
145+
[Test]
146+
public void TestFuncWithMethodClosure()
147+
{
148+
Test<Func<IEnumerable<int>, int>>(
149+
ints => ints.SingleOrDefault(i => i == M1()),
150+
ints => ints.SingleOrDefault(i => i == M1())
151+
);
152+
}
153+
154+
[Test]
155+
public void TestFuncWithStaticMethodClosure()
156+
{
157+
Test<Func<IEnumerable<int>, int>>(
158+
ints => ints.SingleOrDefault(i => i == M2()),
159+
ints => ints.SingleOrDefault(i => i == M2())
160+
);
161+
}
162+
}
163+
}

src/DelegateDecompiler/OptimizeExpressionVisitor.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,23 @@ node.Operand is BinaryExpression binary &&
334334
return base.VisitUnary(node);
335335
}
336336

337+
protected override Expression VisitMethodCall(MethodCallExpression node)
338+
{
339+
if (node.Method.DeclaringType == typeof(Expression))
340+
{
341+
// Execute nested lambda expression methods
342+
var fun = Expression.Lambda<Func<object>>(node).Compile();
343+
var value = fun();
344+
if (value is LambdaExpression expression)
345+
{
346+
return Expression.Quote(expression);
347+
}
348+
349+
return Expression.Constant(value);
350+
}
351+
352+
return base.VisitMethodCall(node);
353+
}
337354

338355
static bool Invert(ref BinaryExpression expression)
339356
{

0 commit comments

Comments
 (0)