Browse Source

Relax rules for object and collection initializer detection to properly decompile query expressions.

pull/1108/head
Siegfried Pammer 8 years ago
parent
commit
2d427cf534
  1. 26
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs
  2. 1327
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.il
  3. 1223
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.opt.il
  4. 1526
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.opt.roslyn.il
  5. 1548
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.roslyn.il
  6. 10
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

26
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs

@ -19,11 +19,24 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
public class QueryExpressions public class QueryExpressions
{ {
public class HbmParam
{
public string Name {
get;
set;
}
public string[] Text {
get;
set;
}
}
public class Customer public class Customer
{ {
public int CustomerID; public int CustomerID;
@ -127,6 +140,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
select b + c; select b + c;
} }
public object HibernateApplyGeneratorQuery()
{
return (from pi in customers.GetType().GetProperties()
let pname = pi.Name
let pvalue = pi.GetValue(customers, null)
select new HbmParam {
Name = pname,
Text = new string[1] {
(pvalue == null) ? "null" : pvalue.ToString()
}
}).ToArray();
}
public object Join() public object Join()
{ {
return from c in customers return from c in customers

1327
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.il

File diff suppressed because it is too large Load Diff

1223
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.opt.il

File diff suppressed because it is too large Load Diff

1526
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.opt.roslyn.il

File diff suppressed because it is too large Load Diff

1548
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.roslyn.il

File diff suppressed because it is too large Load Diff

10
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -50,11 +50,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IType instType; IType instType;
switch (initInst) { switch (initInst) {
case NewObj newObjInst: case NewObj newObjInst:
if (newObjInst.ILStackWasEmpty && v.Kind == VariableKind.Local && !context.Function.Method.IsConstructor) { if (newObjInst.ILStackWasEmpty && v.Kind == VariableKind.Local && !context.Function.Method.IsConstructor && !context.Function.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) {
// on statement level (no other expressions on IL stack), // on statement level (no other expressions on IL stack),
// prefer to keep local variables (but not stack slots), // prefer to keep local variables (but not stack slots),
// unless we are in a constructor (where inlining object initializers might be critical // unless we are in a constructor (where inlining object initializers might be critical
// for the base ctor call) // for the base ctor call) or a compiler-generated delegate method, which might be used in a query expression.
return false; return false;
} }
// Do not try to transform display class usages or delegate construction. // Do not try to transform display class usages or delegate construction.
@ -119,7 +119,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (body.Instructions[i + pos]) { switch (body.Instructions[i + pos]) {
case CallInstruction call: case CallInstruction call:
if (!(call is CallVirt || call is Call)) continue; if (!(call is CallVirt || call is Call)) continue;
var newCall = (CallInstruction)call.Clone(); var newCall = call;
var newTarget = newCall.Arguments[0]; var newTarget = newCall.Arguments[0];
foreach (var load in newTarget.Descendants.OfType<IInstructionWithVariableOperand>()) foreach (var load in newTarget.Descendants.OfType<IInstructionWithVariableOperand>())
if ((load is LdLoc || load is LdLoca) && load.Variable == v) if ((load is LdLoc || load is LdLoca) && load.Variable == v)
@ -127,14 +127,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
initializerBlock.Instructions.Add(newCall); initializerBlock.Instructions.Add(newCall);
break; break;
case StObj stObj: case StObj stObj:
var newStObj = (StObj)stObj.Clone(); var newStObj = stObj;
foreach (var load in newStObj.Target.Descendants.OfType<IInstructionWithVariableOperand>()) foreach (var load in newStObj.Target.Descendants.OfType<IInstructionWithVariableOperand>())
if ((load is LdLoc || load is LdLoca) && load.Variable == v) if ((load is LdLoc || load is LdLoca) && load.Variable == v)
load.Variable = finalSlot; load.Variable = finalSlot;
initializerBlock.Instructions.Add(newStObj); initializerBlock.Instructions.Add(newStObj);
break; break;
case StLoc stLoc: case StLoc stLoc:
var newStLoc = (StLoc)stLoc.Clone(); var newStLoc = stLoc;
initializerBlock.Instructions.Add(newStLoc); initializerBlock.Instructions.Add(newStLoc);
break; break;
} }

Loading…
Cancel
Save