Browse Source

Fix #1249: Bug in detection of multiple nested expression trees in query expressions.

pull/1253/head
Siegfried Pammer 7 years ago
parent
commit
4fab913bf6
  1. 358
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs
  2. 5553
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.il
  3. 5043
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.opt.il
  4. 5204
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.opt.roslyn.il
  5. 5339
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.roslyn.il
  6. 29
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

358
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs

@ -48,6 +48,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -48,6 +48,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
internal class GenericClassWithCtor<T>
{
}
internal class GenericClassWithMultipleCtors<T>
{
public GenericClassWithMultipleCtors()
{
}
public GenericClassWithMultipleCtors(int x)
{
}
}
private class AssertTest
{
private struct DataStruct
@ -78,7 +93,218 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -78,7 +93,218 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public class Administrator
{
public int ID {
get;
set;
}
public string TrueName {
get;
set;
}
public string Phone {
get;
set;
}
}
public class Contract
{
public int ID {
get;
set;
}
public string ContractNo {
get;
set;
}
public string HouseAddress {
get;
set;
}
public DateTime SigningTime {
get;
set;
}
public string BuyerName {
get;
set;
}
public string BuyerTelephone {
get;
set;
}
public string Customer {
get;
set;
}
public string CustTelephone {
get;
set;
}
public int AdminID {
get;
set;
}
public int StoreID {
get;
set;
}
}
public class Database
{
public IQueryable<Contract> Contracts {
get;
set;
}
public IQueryable<Loan> Loan {
get;
set;
}
public IQueryable<Administrator> Administrator {
get;
set;
}
public IQueryable<Store> Store {
get;
set;
}
}
public class Loan
{
public string ContractNo {
get;
set;
}
public DateTime? ShenDate {
get;
set;
}
public DateTime? LoanDate {
get;
set;
}
public string Credit {
get;
set;
}
public string LoanBank {
get;
set;
}
public string Remarks {
get;
set;
}
}
public class Store
{
public int ID {
get;
set;
}
public string Name {
get;
set;
}
}
internal class MyClass
{
public static MyClass operator +(MyClass a, MyClass b)
{
return new MyClass();
}
}
internal class SimpleType
{
public const int ConstField = 1;
public static readonly int StaticReadonlyField = 2;
public static int StaticField = 3;
public readonly int ReadonlyField = 2;
public int Field = 3;
#if CS60
public static int StaticReadonlyProperty => 0;
#else
public static int StaticReadonlyProperty {
get {
return 0;
}
}
#endif
public static int StaticProperty {
get;
set;
}
#if CS60
public int ReadonlyProperty => 0;
#else
public int ReadonlyProperty {
get {
return 0;
}
}
#endif
public int Property {
get;
set;
}
}
internal class SimpleTypeWithCtor
{
public SimpleTypeWithCtor(int i)
{
}
}
internal class SimpleTypeWithMultipleCtors
{
public SimpleTypeWithMultipleCtors()
{
}
public SimpleTypeWithMultipleCtors(int i)
{
}
}
private int field;
private Database db;
private dynamic ViewBag;
public static readonly object[] SupportedMethods = new object[2] {
ToCode(null, () => ((IQueryable<object>)null).Aggregate((object o1, object o2) => null)),
@ -92,6 +318,53 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -92,6 +318,53 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
ToCode(null, () => ((IEnumerable<object>)null).Aggregate((object)null, (Func<object, object, object>)((object o1, object o2) => null), (Func<object, object>)((object o) => null)))
};
private void Issue1249(int ID)
{
if (ID == 0) {
ViewBag.data = "''";
} else {
var model = (from a in db.Contracts
where a.ID == ID
select new {
ID = a.ID,
ContractNo = a.ContractNo,
HouseAddress = a.HouseAddress,
AdminID = (from b in db.Administrator
where b.ID == a.AdminID
select b.TrueName).FirstOrDefault(),
StoreID = (from b in db.Store
where b.ID == a.StoreID
select b.Name).FirstOrDefault(),
SigningTime = a.SigningTime,
YeWuPhone = (from b in db.Administrator
where b.ID == a.AdminID
select b.Phone).FirstOrDefault(),
BuyerName = a.BuyerName,
BuyerTelephone = a.BuyerTelephone,
Customer = a.Customer,
CustTelephone = a.CustTelephone,
Credit = (from b in db.Loan
where b.ContractNo == a.ContractNo
select b.Credit).FirstOrDefault(),
LoanBank = (from b in db.Loan
where b.ContractNo == a.ContractNo
select b.LoanBank).FirstOrDefault(),
Remarks = (from b in db.Loan
where b.ContractNo == a.ContractNo
select b.Remarks).FirstOrDefault()
}).FirstOrDefault();
ViewBag.data = model.ToJson();
DateTime? dateTime = (from b in db.Loan
where b.ContractNo == model.ContractNo
select b.ShenDate).FirstOrDefault();
DateTime? dateTime2 = (from b in db.Loan
where b.ContractNo == model.ContractNo
select b.LoanDate).FirstOrDefault();
ViewBag.ShenDate = ((!dateTime.HasValue) ? "" : dateTime.ParseDateTime().ToString("yyyy-MM-dd"));
ViewBag.LoanDate = ((!dateTime2.HasValue) ? "" : dateTime2.ParseDateTime().ToString("yyyy-MM-dd"));
}
}
private static object ToCode<R>(object x, Expression<Action<R>> expr)
{
return expr;
@ -721,91 +994,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -721,91 +994,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
internal class MyClass
internal static class Extensions
{
public static MyClass operator +(MyClass a, MyClass b)
{
return new MyClass();
}
}
internal class SimpleType
{
public const int ConstField = 1;
public static readonly int StaticReadonlyField = 2;
public static int StaticField = 3;
public readonly int ReadonlyField = 2;
public int Field = 3;
#if CS60
public static int StaticReadonlyProperty => 0;
#else
public static int StaticReadonlyProperty {
get {
return 0;
}
}
#endif
public static int StaticProperty {
get;
set;
}
#if CS60
public int ReadonlyProperty => 0;
#else
public int ReadonlyProperty {
get {
return 0;
}
}
#endif
public int Property {
get;
set;
}
}
internal class SimpleTypeWithCtor
{
public SimpleTypeWithCtor(int i)
{
}
}
internal class SimpleTypeWithMultipleCtors
{
public SimpleTypeWithMultipleCtors()
{
}
public SimpleTypeWithMultipleCtors(int i)
{
}
}
internal class GenericClassWithCtor<T>
{
}
internal class GenericClassWithMultipleCtors<T>
{
public GenericClassWithMultipleCtors()
public static dynamic ToJson(this object o)
{
return null;
}
public GenericClassWithMultipleCtors(int x)
public static DateTime ParseDateTime(this object str)
{
return default(DateTime);
}
}
internal class GenericClass<T>
{
}
}

5553
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.il

File diff suppressed because it is too large Load Diff

5043
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.opt.il

File diff suppressed because it is too large Load Diff

5204
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.opt.roslyn.il

File diff suppressed because it is too large Load Diff

5339
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.roslyn.il

File diff suppressed because it is too large Load Diff

29
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -164,6 +164,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -164,6 +164,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
container.ExpectedResultType = bodyInstruction.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } });
// Replace all other usages of the parameter variable
foreach (var mapping in parameterMapping) {
foreach (var load in mapping.Key.LoadInstructions.ToArray()) {
if (load.IsDescendantOf(instruction))
continue;
load.ReplaceWith(new LdLoc(mapping.Value));
}
}
return (function, function.DelegateType);
}
@ -333,9 +341,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -333,9 +341,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (function, function.DelegateType);
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (null, SpecialType.UnknownType);
return (new LdLoc(v), v.Type);
// Replace an already mapped parameter with the actual ILVariable,
// we generated earlier.
if (parameterMapping.TryGetValue(ldloc.Variable, out var v))
return (new LdLoc(v), v.Type);
// This is a parameter variable from an outer scope.
// We can't replace these variables just yet, because the transform works backwards.
// We simply return the same instruction again, but return the actual expected type,
// so our transform can continue normally.
// Later, we will replace all references to unmapped variables,
// with references to mapped parameters.
if (ldloc.Variable.IsSingleDefinition && ldloc.Variable.StoreInstructions[0] is ILInstruction inst) {
if (MatchParameterVariableAssignment(inst, out _, out var type, out _))
return (ldloc, type);
}
}
return (null, SpecialType.UnknownType);
default:
@ -1017,7 +1036,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1017,7 +1036,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return null;
return ldloc;
if (context is CallInstruction parentCall
&& parentCall.Method.FullName == "System.Linq.Expressions.Expression.Call"
&& v.StackType.IsIntegerType())
@ -1025,7 +1044,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1025,7 +1044,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null;
} else {
if (ldloc.Variable.Kind != VariableKind.StackSlot)
return new LdLoc(ldloc.Variable);
return ldloc;
return null;
}
default:

Loading…
Cancel
Save