Skip to content

Commit

Permalink
Fix conditional expressions for classes with a common ancestor (#212)
Browse files Browse the repository at this point in the history
Fixes #107 

+semver:fix
  • Loading branch information
hazzik authored Oct 20, 2022
1 parent d6dfc9e commit 6da7a6f
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 32 deletions.
35 changes: 19 additions & 16 deletions src/DelegateDecompiler.Tests/Employee.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,18 @@ public class Employee
public int To;

[Computed]
public string FullName
{
get { return FirstName + " " + LastName; }
}
public string FullName => FirstName + " " + LastName;

public string FullNameWithoutAttribute
{
get { return FirstName + " " + LastName; }
}
public string FullNameWithoutAttribute => FirstName + " " + LastName;

[Computed]
public string FromTo
{
get { return From + "-" + To; }
}
public string FromTo => From + "-" + To;

[Computed]
public bool IsActive
{
get { return true; }
}
public bool IsActive => true;

[Computed]
public IEmployeeStatus Status => IsActive ? (IEmployeeStatus)new Active() : new Terminated();

[Computed]
public int Count
Expand Down Expand Up @@ -151,4 +142,16 @@ public static string FullName(this Employee e)
return e.FirstName + " " + e.LastName;
}
}

public interface IEmployeeStatus
{
}

public class Active : IEmployeeStatus
{
}

public class Terminated : IEmployeeStatus
{
}
}
16 changes: 16 additions & 0 deletions src/DelegateDecompiler.Tests/QueryableExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,5 +352,21 @@ public void Issue78()

AssertAreEqual(expected.Expression, actual.Expression);
}

[Test]
public void Issue127()
{
var employees = new[] { new Employee { FirstName = "Test", LastName = "User" } };

var expected = (from employee in employees.AsQueryable()
where ((IEmployeeStatus)new Active()) is Active
select employee);

var actual = (from employee in employees.AsQueryable()
where employee.Status is Active
select employee).Decompile();

AssertAreEqual(expected.Expression, actual.Expression);
}
}
}
2 changes: 1 addition & 1 deletion src/DelegateDecompiler/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public Address Clone(IDictionary<Address, Address> map)
{
if (map.ContainsKey(this))
return map[this];
var result = new Address() { Expression = this.Expression };
var result = new Address { Expression = this.Expression };
map[this] = result;
return result;
}
Expand Down
6 changes: 3 additions & 3 deletions src/DelegateDecompiler/DecompiledQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ public virtual IQueryable CreateQuery(Expression expression)

public virtual IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
var decompiled = expression.Decompile();
var decompiled = expression.Decompile().Optimize();
return new DecompiledQueryable<TElement>(this, Inner.CreateQuery<TElement>(decompiled));
}

public object Execute(Expression expression)
{
var decompiled = expression.Decompile();
var decompiled = expression.Decompile().Optimize();
return Inner.Execute(decompiled);
}

public TResult Execute<TResult>(Expression expression)
{
var decompiled = expression.Decompile();
var decompiled = expression.Decompile().Optimize();
return Inner.Execute<TResult>(decompiled);
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/DelegateDecompiler/OptimizeExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ protected override Expression VisitConditional(ConditionalExpression node)
var test = Visit(node.Test);
var ifTrue = Visit(node.IfTrue);
var ifFalse = Visit(node.IfFalse);

if (test is ConstantExpression constant && constant.Value is bool boolValue)
{
return boolValue ? ifTrue : ifFalse;
}

if (IsCoalesce(test, ifTrue, out var expression))
{
Expand Down
31 changes: 19 additions & 12 deletions src/DelegateDecompiler/Processor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -955,43 +955,48 @@ internal static Expression AdjustType(Expression expression, Type type)
return expression;
}

var constantExpression = expression as ConstantExpression;
if (constantExpression != null)
if (expression is ConstantExpression constant)
{
if (constantExpression.Value == null)
if (constant.Value == null)
{
return Expression.Constant(null, type);
}

if (constantExpression.Type == typeof(int))
if (constant.Type == typeof(int))
{
if (type.IsEnum)
{
return Expression.Constant(Enum.ToObject(type, constantExpression.Value));
return Expression.Constant(Enum.ToObject(type, constant.Value));
}

if (type == typeof(bool))
{
return Expression.Constant(Convert.ToBoolean(constantExpression.Value));
return Expression.Constant(Convert.ToBoolean(constant.Value));
}

if (type == typeof(byte))
{
return Expression.Constant(Convert.ToByte(constantExpression.Value));
return Expression.Constant(Convert.ToByte(constant.Value));
}

if (type == typeof(sbyte))
{
return Expression.Constant(Convert.ToSByte(constantExpression.Value));
return Expression.Constant(Convert.ToSByte(constant.Value));
}

if (type == typeof(short))
{
return Expression.Constant(Convert.ToInt16(constantExpression.Value));
return Expression.Constant(Convert.ToInt16(constant.Value));
}

if (type == typeof(ushort))
{
return Expression.Constant(Convert.ToUInt16(constantExpression.Value));
return Expression.Constant(Convert.ToUInt16(constant.Value));
}

if (type == typeof(uint))
{
return Expression.Constant(Convert.ToUInt32(constantExpression.Value));
return Expression.Constant(Convert.ToUInt32(constant.Value));
}
}
}
Expand All @@ -1002,6 +1007,7 @@ internal static Expression AdjustType(Expression expression, Type type)
return Expression.NotEqual(expression, Expression.Constant(0));
}
}

if (!type.IsAssignableFrom(expression.Type) && expression.Type.IsEnum && expression.Type.GetEnumUnderlyingType() == type)
{
return Expression.Convert(expression, type);
Expand Down Expand Up @@ -1420,7 +1426,8 @@ static void LdLoc(ProcessorState state, int index)
static void StLoc(ProcessorState state, int index)
{
var info = state.Locals[index];
info.Address = AdjustType(state.Stack.Pop(), info.Type);
var expression = AdjustType(state.Stack.Pop(), info.Type);
info.Address = expression.Type == info.Type ? expression : Expression.Convert(expression, info.Type);
}

static void LdArg(ProcessorState state, int index)
Expand Down

0 comments on commit 6da7a6f

Please sign in to comment.