Browse Source

Merge pull request #1165 from icsharpcode/dynamic

Dynamic support
pull/1176/head
Siegfried Pammer 8 years ago committed by GitHub
parent
commit
58c174c87d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 5
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  4. 378
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
  5. 13137
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.il
  6. 12574
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.il
  7. 11806
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.roslyn.il
  8. 12589
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.roslyn.il
  9. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs
  10. 14
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il
  11. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il
  12. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il
  13. 14
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il
  14. 5
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
  15. 177
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il
  16. 191
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il
  17. 4
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  18. 61
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  19. 284
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  20. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  21. 16
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  22. 2
      ICSharpCode.Decompiler/CSharp/Resolver/DynamicInvocationResolveResult.cs
  23. 19
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  24. 31
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs
  25. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
  26. 14
      ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs
  27. 7
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  28. 5
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  29. 14
      ICSharpCode.Decompiler/IL/ILReader.cs
  30. 1400
      ICSharpCode.Decompiler/IL/Instructions.cs
  31. 34
      ICSharpCode.Decompiler/IL/Instructions.tt
  32. 67
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  33. 529
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  34. 0
      ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs
  35. 2
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  36. 2
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  37. 572
      ICSharpCode.Decompiler/IL/Transforms/DynamicCallSiteTransform.cs
  38. 112
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  39. 18
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  40. 51
      ICSharpCode.Decompiler/IL/Transforms/IntroduceDynamicTypeOnLocals.cs
  41. 28
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  42. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  43. 5
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  44. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  45. 7
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
  46. 3
      ILSpy/Languages/CSharpHighlightingTokenWriter.cs
  47. 2
      ILSpy/Languages/ILAstLanguage.cs

2
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -179,6 +179,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -179,6 +179,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Core.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Xml.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "Microsoft.CSharp.dll")),
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
});
@ -306,6 +307,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -306,6 +307,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
options.ReferencedAssemblies.Add("System.dll");
options.ReferencedAssemblies.Add("System.Core.dll");
options.ReferencedAssemblies.Add("System.Xml.dll");
options.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFileNames.ToArray());
if (results.Errors.Cast<CompilerError>().Any(e => !e.IsWarning)) {
StringBuilder b = new StringBuilder("Compiler error:");

5
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -67,6 +67,7 @@ @@ -67,6 +67,7 @@
<Compile Include="Semantics\OverloadResolutionTests.cs" />
<Compile Include="DataFlowTest.cs" />
<Compile Include="TestCases\Correctness\RefLocalsAndReturns.cs" />
<Compile Include="TestCases\Pretty\DynamicTests.cs" />
<Compile Include="TestCases\Pretty\Issue1080.cs" />
<Compile Include="TestCases\Pretty\NamedArguments.cs" />
<Compile Include="TestCases\Pretty\QualifierTests.cs" />
@ -184,6 +185,10 @@ @@ -184,6 +185,10 @@
<None Include="TestCases\VBPretty\Async.vb" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -213,6 +213,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -213,6 +213,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void DynamicTests([ValueSource("defaultOptions")] CSharpCompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void ExpressionTrees([ValueSource("defaultOptions")] CSharpCompilerOptions cscOptions)
{

378
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs

@ -0,0 +1,378 @@ @@ -0,0 +1,378 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal static class Extension
{
public static dynamic ToDynamic(this int i, dynamic info)
{
throw null;
}
}
internal class DynamicTests
{
private class Base
{
public Base(object baseObj)
{
}
}
private class Derived : Base
{
public Derived(dynamic d)
: base((object)d)
{
}
}
private struct MyValueType
{
private readonly dynamic _getOnlyProperty;
public dynamic Field;
#if CS60
public dynamic GetOnlyProperty => _getOnlyProperty;
#else
public dynamic GetOnlyProperty {
get {
return _getOnlyProperty;
}
}
#endif
public dynamic Property {
get;
set;
}
public void Method(dynamic a)
{
}
}
private static dynamic field;
private static object objectField;
public dynamic Property {
get;
set;
}
public DynamicTests()
{
}
public DynamicTests(dynamic test)
{
}
public DynamicTests(DynamicTests test)
{
}
private static void InvokeConstructor()
{
DynamicTests dynamicTests = new DynamicTests();
dynamic val = new DynamicTests();
val.Test(new UnauthorizedAccessException());
dynamic val2 = new DynamicTests(val);
val2.Get(new DynamicTests((DynamicTests)val));
val2.Call(new DynamicTests((dynamic)dynamicTests));
}
private static dynamic InlineAssign(object a, out dynamic b)
{
return b = ((dynamic)a).Test;
}
private static dynamic SelfReference(dynamic d)
{
return d[d, d] = d;
}
private static dynamic LongArgumentListFunc(dynamic d)
{
// Func`13
return d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
private static void LongArgumentListAction(dynamic d)
{
// Action`13
d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
}
private static void DynamicThrow()
{
try {
throw (Exception)field;
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw;
}
}
private static void MemberAccess(dynamic a)
{
a.Test1();
a.GenericTest<int, int>();
a.Test2(1);
a.Test3(a.InnerTest(1, 2, 3, 4, 5));
a.Test4(2, null, a.Index[0]);
a.Test5(a, a.Number, a.String);
a[0] = 3;
a.Index[a.Number] = 5;
a.Index[a.Number] += 5;
a.Setter = new DynamicTests();
a.Setter2 = 5;
}
private static void StructMemberAccess(MyValueType valueType)
{
valueType.Field = 0;
valueType.Field += 5;
valueType.Field[1] = 5;
valueType.Field.CallMe();
DynamicTests.Casts(valueType.GetOnlyProperty);
valueType.GetOnlyProperty.CallMe();
valueType.Property = 0;
valueType.Property += 5;
valueType.Property[1] = 5;
valueType.Property.CallMe(5.ToDynamic((object)valueType.Property.Call()));
valueType.Method(valueType.GetOnlyProperty + valueType.Field);
}
private static void RequiredCasts()
{
((dynamic)objectField).A = 5;
((dynamic)objectField).B += 5;
((dynamic)objectField).Call();
((object)field).ToString();
field.Call("Hello World");
field.Call((object)"Hello World");
field.Call((dynamic)"Hello World");
}
private static void DynamicCallWithString()
{
field.Call("Hello World");
}
private static void DynamicCallWithNamedArgs()
{
field.Call(a: "Hello World");
}
private static void DynamicCallWithRefOutArg(int a, out int b)
{
field.Call(ref a, out b);
}
private static void DynamicCallWithStringCastToObj()
{
field.Call((object)"Hello World");
}
private static void DynamicCallWithStringCastToDynamic()
{
field.Call((dynamic)"Hello World");
}
private static void DynamicCallWithStringCastToDynamic2()
{
field.Call((dynamic)"Hello World", 5, null);
}
private static void DynamicCallWithStringCastToDynamic3()
{
field.Call((dynamic)"Hello World", 5u, null);
}
private static void Invocation(dynamic a, dynamic b)
{
a(null, b.Test());
}
private static dynamic Test1(dynamic a)
{
dynamic val = a.IndexedProperty;
return val[0];
}
private static dynamic Test2(dynamic a)
{
return a.IndexedProperty[0];
}
private static void ArithmeticBinaryOperators(dynamic a, dynamic b)
{
DynamicTests.MemberAccess(a + b);
DynamicTests.MemberAccess(a + 1);
DynamicTests.MemberAccess(a + null);
DynamicTests.MemberAccess(a - b);
DynamicTests.MemberAccess(a - 1);
DynamicTests.MemberAccess(a - null);
DynamicTests.MemberAccess(a * b);
DynamicTests.MemberAccess(a * 1);
DynamicTests.MemberAccess(a * null);
DynamicTests.MemberAccess(a / b);
DynamicTests.MemberAccess(a / 1);
DynamicTests.MemberAccess(a / null);
DynamicTests.MemberAccess(a % b);
DynamicTests.MemberAccess(a % 1);
DynamicTests.MemberAccess(a % null);
}
private static void CheckedArithmeticBinaryOperators(dynamic a, dynamic b)
{
checked {
DynamicTests.MemberAccess(a + b);
DynamicTests.MemberAccess(a + 1);
DynamicTests.MemberAccess(a + null);
DynamicTests.MemberAccess(a - b);
DynamicTests.MemberAccess(a - 1);
DynamicTests.MemberAccess(a - null);
DynamicTests.MemberAccess(a * b);
DynamicTests.MemberAccess(a * 1);
DynamicTests.MemberAccess(a * null);
DynamicTests.MemberAccess(a / b);
DynamicTests.MemberAccess(a / 1);
DynamicTests.MemberAccess(a / null);
DynamicTests.MemberAccess(a % b);
DynamicTests.MemberAccess(a % 1);
DynamicTests.MemberAccess(a % null);
}
}
private static void UncheckedArithmeticBinaryOperators(dynamic a, dynamic b)
{
checked {
DynamicTests.MemberAccess(a + b);
DynamicTests.MemberAccess(a + 1);
DynamicTests.MemberAccess(a + null);
DynamicTests.MemberAccess(unchecked(a - b));
DynamicTests.MemberAccess(a - 1);
DynamicTests.MemberAccess(a - null);
DynamicTests.MemberAccess(unchecked(a * b));
DynamicTests.MemberAccess(a * 1);
DynamicTests.MemberAccess(a * null);
DynamicTests.MemberAccess(a / b);
DynamicTests.MemberAccess(a / 1);
DynamicTests.MemberAccess(a / null);
DynamicTests.MemberAccess(a % b);
DynamicTests.MemberAccess(a % 1);
DynamicTests.MemberAccess(a % null);
}
}
private static void RelationalOperators(dynamic a, dynamic b)
{
DynamicTests.MemberAccess(a == b);
DynamicTests.MemberAccess(a == 1);
DynamicTests.MemberAccess(a == null);
DynamicTests.MemberAccess(a != b);
DynamicTests.MemberAccess(a != 1);
DynamicTests.MemberAccess(a != null);
DynamicTests.MemberAccess(a < b);
DynamicTests.MemberAccess(a < 1);
DynamicTests.MemberAccess(a < null);
DynamicTests.MemberAccess(a > b);
DynamicTests.MemberAccess(a > 1);
DynamicTests.MemberAccess(a > null);
DynamicTests.MemberAccess(a >= b);
DynamicTests.MemberAccess(a >= 1);
DynamicTests.MemberAccess(a >= null);
DynamicTests.MemberAccess(a <= b);
DynamicTests.MemberAccess(a <= 1);
DynamicTests.MemberAccess(a <= null);
}
private static void Casts(dynamic a)
{
Console.WriteLine();
MemberAccess((int)a);
MemberAccess(checked((int)a));
}
private static void M(object o)
{
}
private static void M2(dynamic d)
{
}
private static void M3(int i)
{
}
private static void NotDynamicDispatch(dynamic d)
{
DynamicTests.M(d);
M((object)d);
DynamicTests.M2(d);
M2((object)d);
}
private static void CompoundAssignment(dynamic a, dynamic b)
{
a.Setter2 += 5;
a.Setter2 -= 1;
a.Setter2 *= 2;
a.Setter2 /= 5;
a.Setter2 += b;
a.Setter2 -= b;
a.Setter2 *= b;
a.Setter2 /= b;
field.Setter += 5;
field.Setter -= 5;
}
private static void InlineCompoundAssignment(dynamic a, dynamic b)
{
Console.WriteLine(a.Setter2 += 5);
Console.WriteLine(a.Setter2 -= 1);
Console.WriteLine(a.Setter2 *= 2);
Console.WriteLine(a.Setter2 /= 5);
Console.WriteLine(a.Setter2 += b);
Console.WriteLine(a.Setter2 -= b);
Console.WriteLine(a.Setter2 *= b);
Console.WriteLine(a.Setter2 /= b);
}
private static void UnaryOperators(dynamic a)
{
// TODO : beautify inc/dec on locals and fields
//a--;
//a++;
//--a;
//++a;
DynamicTests.Casts(-a);
DynamicTests.Casts(+a);
}
private static void Loops(dynamic list)
{
foreach (dynamic item in list) {
DynamicTests.UnaryOperators(item);
}
}
private static void If(dynamic a, dynamic b)
{
if (a == b) {
Console.WriteLine("Equal");
}
}
private static void If2(dynamic a, dynamic b)
{
// TODO : beautify complex conditions
//if (a == null || b == null) {
// Console.WriteLine("Equal");
//}
}
}
}

13137
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.il

File diff suppressed because it is too large Load Diff

12574
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.il

File diff suppressed because it is too large Load Diff

11806
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.roslyn.il

File diff suppressed because it is too large Load Diff

12589
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.roslyn.il

File diff suppressed because it is too large Load Diff

6
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
@ -76,6 +77,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -76,6 +77,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return new T();
}
public T NotNew<T>()
{
return Activator.CreateInstance<T>();
}
public bool IsNull<T>(T t)
{
return t == null;

14
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il

@ -237,6 +237,20 @@ @@ -237,6 +237,20 @@
IL_0026: ret
} // end of method Generics::New
.method public hidebysig instance !!T NotNew<T>() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.locals init (!!T V_0)
IL_0000: nop
IL_0001: call !!0 [mscorlib]System.Activator::CreateInstance<!!0>()
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method Generics::NotNew
.method public hidebysig instance bool
IsNull<T>(!!T t) cil managed
{

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il

@ -188,6 +188,14 @@ @@ -188,6 +188,14 @@
IL_001f: ret
} // end of method Generics::New
.method public hidebysig instance !!T NotNew<T>() cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: call !!0 [mscorlib]System.Activator::CreateInstance<!!0>()
IL_0005: ret
} // end of method Generics::NotNew
.method public hidebysig instance bool
IsNull<T>(!!T t) cil managed
{

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il

@ -179,6 +179,14 @@ @@ -179,6 +179,14 @@
IL_0005: ret
} // end of method Generics::New
.method public hidebysig instance !!T NotNew<T>() cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: call !!0 [mscorlib]System.Activator::CreateInstance<!!0>()
IL_0005: ret
} // end of method Generics::NotNew
.method public hidebysig instance bool
IsNull<T>(!!T t) cil managed
{

14
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il

@ -231,6 +231,20 @@ @@ -231,6 +231,20 @@
IL_000a: ret
} // end of method Generics::New
.method public hidebysig instance !!T NotNew<T>() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.locals init (!!T V_0)
IL_0000: nop
IL_0001: call !!0 [mscorlib]System.Activator::CreateInstance<!!0>()
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method Generics::NotNew
.method public hidebysig instance bool
IsNull<T>(!!T t) cil managed
{

5
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs

@ -257,5 +257,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -257,5 +257,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return t?.Int();
}
private static dynamic DynamicNullProp(dynamic a)
{
return a?.b.c(1)?.d[10];
}
}
}

177
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il

@ -8,6 +8,16 @@ @@ -8,6 +8,16 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern Microsoft.CSharp
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 4:0:0:0
}
.assembly NullPropagation
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
@ -228,6 +238,16 @@ @@ -228,6 +238,16 @@
} // end of class ITest
.class abstract auto ansi sealed nested private beforefieldinit '<>o__26'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> '<>p__0'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> '<>p__1'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> '<>p__2'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> '<>p__3'
} // end of class '<>o__26'
.method private hidebysig instance int32
GetInt() cil managed
{
@ -976,6 +996,163 @@ @@ -976,6 +996,163 @@
IL_002c: ret
} // end of method NullPropagation::GenericRefStructConstraintInt
.method private hidebysig static object
DynamicNullProp(object a) cil managed
{
.param [0]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 )
.param [1]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 )
// Code size 332 (0x14c)
.maxstack 10
.locals init (object V_0,
object V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: brtrue.s IL_0007
IL_0005: ldnull
IL_0006: ret
IL_0007: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_000c: brtrue.s IL_0048
IL_000e: ldc.i4.0
IL_000f: ldstr "c"
IL_0014: ldnull
IL_0015: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_001a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_001f: ldc.i4.2
IL_0020: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0025: dup
IL_0026: ldc.i4.0
IL_0027: ldc.i4.0
IL_0028: ldnull
IL_0029: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_002e: stelem.ref
IL_002f: dup
IL_0030: ldc.i4.1
IL_0031: ldc.i4.3
IL_0032: ldnull
IL_0033: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_0038: stelem.ref
IL_0039: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_003e: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_0043: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_0048: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_004d: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Target
IL_0052: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_0057: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_005c: brtrue.s IL_008d
IL_005e: ldc.i4.0
IL_005f: ldstr "b"
IL_0064: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_0069: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_006e: ldc.i4.1
IL_006f: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0074: dup
IL_0075: ldc.i4.0
IL_0076: ldc.i4.0
IL_0077: ldnull
IL_0078: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_007d: stelem.ref
IL_007e: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_0083: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_0088: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_008d: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_0092: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
IL_0097: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_009c: ldloc.0
IL_009d: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
!1)
IL_00a2: ldc.i4.1
IL_00a3: callvirt instance !3 class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>::Invoke(!0,
!1,
!2)
IL_00a8: stloc.1
IL_00a9: ldloc.1
IL_00aa: brtrue.s IL_00ae
IL_00ac: ldnull
IL_00ad: ret
IL_00ae: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00b3: brtrue.s IL_00e9
IL_00b5: ldc.i4.0
IL_00b6: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_00bb: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00c0: ldc.i4.2
IL_00c1: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_00c6: dup
IL_00c7: ldc.i4.0
IL_00c8: ldc.i4.0
IL_00c9: ldnull
IL_00ca: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_00cf: stelem.ref
IL_00d0: dup
IL_00d1: ldc.i4.1
IL_00d2: ldc.i4.3
IL_00d3: ldnull
IL_00d4: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_00d9: stelem.ref
IL_00da: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetIndex(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_00df: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_00e4: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00e9: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00ee: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Target
IL_00f3: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00f8: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_00fd: brtrue.s IL_012f
IL_00ff: ldc.i4.s 64
IL_0101: ldstr "d"
IL_0106: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_010b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0110: ldc.i4.1
IL_0111: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0116: dup
IL_0117: ldc.i4.0
IL_0118: ldc.i4.0
IL_0119: ldnull
IL_011a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_011f: stelem.ref
IL_0120: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_0125: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_012a: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_012f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_0134: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
IL_0139: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_013e: ldloc.1
IL_013f: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
!1)
IL_0144: ldc.i4.s 10
IL_0146: callvirt instance !3 class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>::Invoke(!0,
!1,
!2)
IL_014b: ret
} // end of method NullPropagation::DynamicNullProp
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

191
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il

@ -8,6 +8,16 @@ @@ -8,6 +8,16 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern Microsoft.CSharp
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 4:0:0:0
}
.assembly NullPropagation
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
@ -262,6 +272,16 @@ @@ -262,6 +272,16 @@
} // end of class ITest
.class abstract auto ansi sealed nested private beforefieldinit '<>o__26'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> '<>p__0'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> '<>p__1'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> '<>p__2'
.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> '<>p__3'
} // end of class '<>o__26'
.method private hidebysig instance int32
GetInt() cil managed
{
@ -1154,6 +1174,177 @@ @@ -1154,6 +1174,177 @@
IL_0032: ret
} // end of method NullPropagation::GenericRefStructConstraintInt
.method private hidebysig static object
DynamicNullProp(object a) cil managed
{
.param [0]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 )
.param [1]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor() = ( 01 00 00 00 )
// Code size 353 (0x161)
.maxstack 10
.locals init (object V_0,
object V_1,
object V_2)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: brtrue.s IL_000c
IL_0006: ldnull
IL_0007: br IL_015c
IL_000c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_0011: brfalse.s IL_0015
IL_0013: br.s IL_004f
IL_0015: ldc.i4.0
IL_0016: ldstr "c"
IL_001b: ldnull
IL_001c: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_0021: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0026: ldc.i4.2
IL_0027: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_002c: dup
IL_002d: ldc.i4.0
IL_002e: ldc.i4.0
IL_002f: ldnull
IL_0030: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_0035: stelem.ref
IL_0036: dup
IL_0037: ldc.i4.1
IL_0038: ldc.i4.3
IL_0039: ldnull
IL_003a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_003f: stelem.ref
IL_0040: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [mscorlib]System.Type>,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_0045: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_004a: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_004f: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_0054: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Target
IL_0059: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__1'
IL_005e: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_0063: brfalse.s IL_0067
IL_0065: br.s IL_0096
IL_0067: ldc.i4.0
IL_0068: ldstr "b"
IL_006d: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_0072: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0077: ldc.i4.1
IL_0078: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_007d: dup
IL_007e: ldc.i4.0
IL_007f: ldc.i4.0
IL_0080: ldnull
IL_0081: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_0086: stelem.ref
IL_0087: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_008c: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_0091: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_0096: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_009b: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
IL_00a0: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__0'
IL_00a5: ldloc.0
IL_00a6: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
!1)
IL_00ab: ldc.i4.1
IL_00ac: callvirt instance !3 class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>::Invoke(!0,
!1,
!2)
IL_00b1: stloc.1
IL_00b2: ldloc.1
IL_00b3: brtrue.s IL_00bb
IL_00b5: ldnull
IL_00b6: br IL_015c
IL_00bb: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00c0: brfalse.s IL_00c4
IL_00c2: br.s IL_00f8
IL_00c4: ldc.i4.0
IL_00c5: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_00ca: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_00cf: ldc.i4.2
IL_00d0: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_00d5: dup
IL_00d6: ldc.i4.0
IL_00d7: ldc.i4.0
IL_00d8: ldnull
IL_00d9: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_00de: stelem.ref
IL_00df: dup
IL_00e0: ldc.i4.1
IL_00e1: ldc.i4.3
IL_00e2: ldnull
IL_00e3: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_00e8: stelem.ref
IL_00e9: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetIndex(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_00ee: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_00f3: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00f8: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_00fd: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>>::Target
IL_0102: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__3'
IL_0107: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_010c: brfalse.s IL_0110
IL_010e: br.s IL_0140
IL_0110: ldc.i4.s 64
IL_0112: ldstr "d"
IL_0117: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
IL_011c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0121: ldc.i4.1
IL_0122: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0127: dup
IL_0128: ldc.i4.0
IL_0129: ldc.i4.0
IL_012a: ldnull
IL_012b: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,
string)
IL_0130: stelem.ref
IL_0131: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,
string,
class [mscorlib]System.Type,
class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)
IL_0136: call class [System.Core]System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)
IL_013b: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_0140: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_0145: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>>::Target
IL_014a: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/'<>o__26'::'<>p__2'
IL_014f: ldloc.1
IL_0150: callvirt instance !2 class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,object>::Invoke(!0,
!1)
IL_0155: ldc.i4.s 10
IL_0157: callvirt instance !3 class [mscorlib]System.Func`4<class [System.Core]System.Runtime.CompilerServices.CallSite,object,int32,object>::Invoke(!0,
!1,
!2)
IL_015c: stloc.2
IL_015d: br.s IL_015f
IL_015f: ldloc.2
IL_0160: ret
} // end of method NullPropagation::DynamicNullProp
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

4
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -87,6 +87,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -87,6 +87,7 @@ namespace ICSharpCode.Decompiler.CSharp
// is already collapsed into stloc(V, ...).
new RemoveDeadVariableInit(),
new SplitVariables(), // split variables once again, because the stobj(ldloca V, ...) may open up new replacements
new DynamicCallSiteTransform(),
new SwitchDetection(),
new SwitchOnStringTransform(),
new SwitchOnNullableTransform(),
@ -141,6 +142,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -141,6 +142,7 @@ namespace ICSharpCode.Decompiler.CSharp
new ProxyCallReplacer(),
new DelegateConstruction(),
new HighLevelLoopTransform(),
new IntroduceDynamicTypeOnLocals(),
new AssignVariableNames(),
};
}
@ -229,6 +231,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -229,6 +231,8 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
if (settings.AnonymousTypes && type.IsAnonymousType())
return true;
if (settings.Dynamic && type.IsDelegate() && (type.Name.StartsWith("<>A", StringComparison.Ordinal) || type.Name.StartsWith("<>F", StringComparison.Ordinal)))
return true;
}
if (settings.ArrayInitializers && settings.SwitchStatementOnString && type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
return true;

61
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -167,16 +167,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -167,16 +167,17 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
arg = arg.ConvertTo(parameter.Type, expressionBuilder, allowImplicitConversion: true);
if (parameter.IsOut && arg.Expression is DirectionExpression dirExpr && arg.ResolveResult is ByReferenceResolveResult brrr) {
dirExpr.FieldDirection = FieldDirection.Out;
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
else
brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
dirExpr.AddAnnotation(brrr);
arg = new TranslatedExpression(dirExpr);
IType parameterType;
if (parameter.Type.Kind == TypeKind.Dynamic) {
parameterType = expressionBuilder.compilation.FindType(KnownTypeCode.Object);
} else {
parameterType = parameter.Type;
}
arg = arg.ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: arg.Type.Kind != TypeKind.Dynamic);
if (parameter.IsOut) {
arg = ExpressionBuilder.ChangeDirectionExpressionToOut(arg);
}
arguments.Add(arg);
@ -222,15 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -222,15 +223,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(rr);
} else {
if (IsUnambiguousCall(expectedTargetDetails, method, null, Empty<IType>.Array, arguments, argumentNames, out _) != OverloadResolutionErrors.None) {
for (int i = 0; i < arguments.Count; i++) {
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
}
}
CastArguments(arguments, expectedParameters);
}
return new ObjectCreateExpression(
expressionBuilder.ConvertType(method.DeclaringType),
@ -285,15 +278,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -285,15 +278,7 @@ namespace ICSharpCode.Decompiler.CSharp
// is best in this case. Additionally we should not cast all arguments at once, but step-by-step try to add only a minimal number of casts.
if (!argumentsCasted) {
argumentsCasted = true;
for (int i = 0; i < arguments.Count; i++) {
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
}
}
CastArguments(arguments, expectedParameters);
} else if (!requireTarget) {
requireTarget = true;
targetResolveResult = target.ResolveResult;
@ -344,6 +329,26 @@ namespace ICSharpCode.Decompiler.CSharp @@ -344,6 +329,26 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private void CastArguments(List<TranslatedExpression> arguments, List<IParameter> expectedParameters)
{
for (int i = 0; i < arguments.Count; i++) {
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
IType parameterType;
if (expectedParameters[i].Type.Kind == TypeKind.Dynamic) {
parameterType = expressionBuilder.compilation.FindType(KnownTypeCode.Object);
} else {
parameterType = expectedParameters[i].Type;
}
arguments[i] = arguments[i].ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: false);
}
}
}
private IEnumerable<Expression> GetArgumentExpressions(List<TranslatedExpression> arguments, string[] argumentNames)
{
if (argumentNames == null) {

284
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -614,7 +614,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -614,7 +614,8 @@ namespace ICSharpCode.Decompiler.CSharp
as OperatorResolveResult;
}
if (rr == null || rr.IsError || rr.UserDefinedOperatorMethod != null
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType)
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType
|| !rr.Type.IsKnownType(KnownTypeCode.Boolean))
{
IType targetType;
if (inst.InputType == StackType.O) {
@ -641,7 +642,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -641,7 +642,8 @@ namespace ICSharpCode.Decompiler.CSharp
rr = resolver.ResolveBinaryOperator(inst.Kind.ToBinaryOperatorType(),
left.ResolveResult, right.ResolveResult) as OperatorResolveResult;
if (rr == null || rr.IsError || rr.UserDefinedOperatorMethod != null
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType)
|| NullableType.GetUnderlyingType(rr.Operands[0].Type).GetStackType() != inst.InputType
|| !rr.Type.IsKnownType(KnownTypeCode.Boolean))
{
// If converting one input wasn't sufficient, convert both:
left = left.ConvertTo(targetType, this);
@ -2337,6 +2339,284 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2337,6 +2339,284 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ResolveResult(NullableType.GetUnderlyingType(arg.Type)));
}
protected internal override TranslatedExpression VisitDynamicConvertInstruction(DynamicConvertInstruction inst, TranslationContext context)
{
// TODO : make conversions implicit, if !inst.IsExplicit
// currently this leads to stack type mismatch assertions, if the expected type is not O
return Translate(inst.Argument).ConvertTo(inst.Type, this, inst.IsChecked, allowImplicitConversion: false);
}
protected internal override TranslatedExpression VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst, TranslationContext context)
{
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
return new IndexerExpression(target, arguments.Select(a => a.Expression))
.WithILInstruction(inst)
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Indexing, arguments.Select(a => a.ResolveResult).ToArray()));
}
protected internal override TranslatedExpression VisitDynamicGetMemberInstruction(DynamicGetMemberInstruction inst, TranslationContext context)
{
var target = TranslateDynamicTarget(inst.Target, inst.TargetArgumentInfo);
return new MemberReferenceExpression(target, inst.Name)
.WithILInstruction(inst)
.WithRR(new DynamicMemberResolveResult(target.ResolveResult, inst.Name));
}
protected internal override TranslatedExpression VisitDynamicInvokeConstructorInstruction(DynamicInvokeConstructorInstruction inst, TranslationContext context)
{
if (!(inst.ArgumentInfo[0].HasFlag(CSharpArgumentInfoFlags.IsStaticType) && IL.Transforms.TransformExpressionTrees.MatchGetTypeFromHandle(inst.Arguments[0], out var constructorType)))
return ErrorExpression("Could not detect static type for DynamicInvokeConstructorInstruction");
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
//var names = inst.ArgumentInfo.Skip(1).Select(a => a.Name).ToArray();
return new ObjectCreateExpression(ConvertType(constructorType), arguments.Select(a => a.Expression))
.WithILInstruction(inst).WithRR(new ResolveResult(constructorType));
}
protected internal override TranslatedExpression VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst, TranslationContext context)
{
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
return new InvocationExpression(new MemberReferenceExpression(target, inst.Name, inst.TypeArguments.Select(ConvertType)), arguments.Select(a => a.Expression))
.WithILInstruction(inst)
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Invocation, arguments.Select(a => a.ResolveResult).ToArray()));
}
protected internal override TranslatedExpression VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst, TranslationContext context)
{
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
return new InvocationExpression(target, arguments.Select(a => a.Expression))
.WithILInstruction(inst)
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Invocation, arguments.Select(a => a.ResolveResult).ToArray()));
}
TranslatedExpression TranslateDynamicTarget(ILInstruction inst, CSharpArgumentInfo argumentInfo)
{
Debug.Assert(!argumentInfo.HasFlag(CSharpArgumentInfoFlags.NamedArgument));
Debug.Assert(!argumentInfo.HasFlag(CSharpArgumentInfoFlags.IsOut));
Debug.Assert(!argumentInfo.HasFlag(CSharpArgumentInfoFlags.Constant));
if (argumentInfo.HasFlag(CSharpArgumentInfoFlags.IsStaticType) && IL.Transforms.TransformExpressionTrees.MatchGetTypeFromHandle(inst, out var callTargetType)) {
return new TypeReferenceExpression(ConvertType(callTargetType))
.WithoutILInstruction()
.WithRR(new TypeResolveResult(callTargetType));
}
IType targetType = SpecialType.Dynamic;
if (argumentInfo.HasFlag(CSharpArgumentInfoFlags.UseCompileTimeType)) {
targetType = argumentInfo.CompileTimeType;
}
var translatedTarget = Translate(inst, targetType).ConvertTo(targetType, this);
if (argumentInfo.HasFlag(CSharpArgumentInfoFlags.IsRef) && translatedTarget.Expression is DirectionExpression) {
// (ref x).member => x.member
translatedTarget = translatedTarget.UnwrapChild(((DirectionExpression)translatedTarget).Expression);
}
return translatedTarget;
}
IEnumerable<TranslatedExpression> TranslateDynamicArguments(IEnumerable<ILInstruction> arguments, IEnumerable<CSharpArgumentInfo> argumentInfo)
{
foreach (var (argument, info) in arguments.Zip(argumentInfo)) {
yield return TranslateDynamicArgument(argument, info);
}
}
TranslatedExpression TranslateDynamicArgument(ILInstruction argument, CSharpArgumentInfo info)
{
Debug.Assert(!info.HasFlag(CSharpArgumentInfoFlags.IsStaticType));
IType typeHint = SpecialType.Dynamic;
if (info.HasFlag(CSharpArgumentInfoFlags.UseCompileTimeType)) {
typeHint = info.CompileTimeType;
}
var translatedExpression = Translate(argument, typeHint);
if (!(typeHint.Equals(SpecialType.Dynamic) && translatedExpression.Type.Equals(SpecialType.NullType))) {
translatedExpression = translatedExpression.ConvertTo(typeHint, this);
}
if (info.HasFlag(CSharpArgumentInfoFlags.IsOut)) {
translatedExpression = ChangeDirectionExpressionToOut(translatedExpression);
}
if (info.HasFlag(CSharpArgumentInfoFlags.NamedArgument) && !string.IsNullOrWhiteSpace(info.Name)) {
translatedExpression = new TranslatedExpression(new NamedArgumentExpression(info.Name, translatedExpression.Expression));
}
return translatedExpression;
}
internal static TranslatedExpression ChangeDirectionExpressionToOut(TranslatedExpression input)
{
if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input;
dirExpr.FieldDirection = FieldDirection.Out;
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
else
brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
dirExpr.AddAnnotation(brrr);
return new TranslatedExpression(dirExpr);
}
protected internal override TranslatedExpression VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst, TranslationContext context)
{
Debug.Assert(inst.Arguments.Count >= 3);
var target = TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]);
var arguments = TranslateDynamicArguments(inst.Arguments.Skip(1), inst.ArgumentInfo.Skip(1)).ToList();
var value = new TranslatedExpression(arguments.Last());
var indexer = new IndexerExpression(target, arguments.SkipLast(1).Select(a => a.Expression))
.WithoutILInstruction()
.WithRR(new DynamicInvocationResolveResult(target.ResolveResult, DynamicInvocationType.Indexing, arguments.SkipLast(1).Select(a => a.ResolveResult).ToArray()));
return Assignment(indexer, value).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst, TranslationContext context)
{
var target = TranslateDynamicTarget(inst.Target, inst.TargetArgumentInfo);
var value = TranslateDynamicArgument(inst.Value, inst.ValueArgumentInfo);
var member = new MemberReferenceExpression(target, inst.Name)
.WithoutILInstruction()
.WithRR(new DynamicMemberResolveResult(target.ResolveResult, inst.Name));
return Assignment(member, value).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst, TranslationContext context)
{
switch (inst.Operation) {
case ExpressionType.Add:
case ExpressionType.AddAssign:
return CreateBinaryOperator(BinaryOperatorType.Add, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.AddChecked:
case ExpressionType.AddAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Add, isChecked: true);
case ExpressionType.Subtract:
case ExpressionType.SubtractAssign:
return CreateBinaryOperator(BinaryOperatorType.Subtract, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.SubtractChecked:
case ExpressionType.SubtractAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Subtract, isChecked: true);
case ExpressionType.Multiply:
case ExpressionType.MultiplyAssign:
return CreateBinaryOperator(BinaryOperatorType.Multiply, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.MultiplyChecked:
case ExpressionType.MultiplyAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Multiply, isChecked: true);
case ExpressionType.Divide:
case ExpressionType.DivideAssign:
return CreateBinaryOperator(BinaryOperatorType.Divide);
case ExpressionType.Modulo:
case ExpressionType.ModuloAssign:
return CreateBinaryOperator(BinaryOperatorType.Modulus);
case ExpressionType.Equal:
return CreateBinaryOperator(BinaryOperatorType.Equality);
case ExpressionType.NotEqual:
return CreateBinaryOperator(BinaryOperatorType.InEquality);
case ExpressionType.LessThan:
return CreateBinaryOperator(BinaryOperatorType.LessThan);
case ExpressionType.LessThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.LessThanOrEqual);
case ExpressionType.GreaterThan:
return CreateBinaryOperator(BinaryOperatorType.GreaterThan);
case ExpressionType.GreaterThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.GreaterThanOrEqual);
case ExpressionType.And:
case ExpressionType.AndAssign:
return CreateBinaryOperator(BinaryOperatorType.BitwiseAnd);
case ExpressionType.Or:
case ExpressionType.OrAssign:
return CreateBinaryOperator(BinaryOperatorType.BitwiseOr);
case ExpressionType.ExclusiveOr:
case ExpressionType.ExclusiveOrAssign:
return CreateBinaryOperator(BinaryOperatorType.ExclusiveOr);
case ExpressionType.LeftShift:
case ExpressionType.LeftShiftAssign:
return CreateBinaryOperator(BinaryOperatorType.ShiftLeft);
case ExpressionType.RightShift:
case ExpressionType.RightShiftAssign:
return CreateBinaryOperator(BinaryOperatorType.ShiftRight);
default:
return base.VisitDynamicBinaryOperatorInstruction(inst, context);
}
TranslatedExpression CreateBinaryOperator(BinaryOperatorType operatorType, bool? isChecked = null)
{
var left = TranslateDynamicArgument(inst.Left, inst.LeftArgumentInfo);
var right = TranslateDynamicArgument(inst.Right, inst.RightArgumentInfo);
var boe = new BinaryOperatorExpression(left.Expression, operatorType, right.Expression);
if (isChecked == true)
boe.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else if (isChecked == false)
boe.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return boe.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
}
protected internal override TranslatedExpression VisitDynamicUnaryOperatorInstruction(DynamicUnaryOperatorInstruction inst, TranslationContext context)
{
switch (inst.Operation) {
case ExpressionType.Not:
return CreateUnaryOperator(UnaryOperatorType.Not);
case ExpressionType.Decrement:
return CreateUnaryOperator(UnaryOperatorType.Decrement, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.Increment:
return CreateUnaryOperator(UnaryOperatorType.Increment, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.Negate:
return CreateUnaryOperator(UnaryOperatorType.Minus, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.NegateChecked:
return CreateUnaryOperator(UnaryOperatorType.Minus, isChecked: true);
case ExpressionType.UnaryPlus:
return CreateUnaryOperator(UnaryOperatorType.Plus, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.IsTrue:
var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
Expression expr;
if (inst.SlotInfo == IfInstruction.ConditionSlot) {
// We rely on the context implicitly invoking "operator true".
expr = new UnaryOperatorExpression(UnaryOperatorType.IsTrue, operand);
} else {
// Create a dummy conditional to ensure "operator true" will be invoked.
expr = new ConditionalExpression(operand, new PrimitiveExpression(true), new PrimitiveExpression(false));
}
return expr.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
case ExpressionType.IsFalse:
operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
// Create a dummy conditional to ensure "operator false" will be invoked.
expr = new ConditionalExpression(operand, new PrimitiveExpression(false), new PrimitiveExpression(true));
return expr.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
default:
return base.VisitDynamicUnaryOperatorInstruction(inst, context);
}
TranslatedExpression CreateUnaryOperator(UnaryOperatorType operatorType, bool? isChecked = null)
{
var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
var uoe = new UnaryOperatorExpression(operatorType, operand.Expression);
if (isChecked == true)
uoe.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else if (isChecked == false)
uoe.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return uoe.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
}
protected internal override TranslatedExpression VisitDynamicCompoundAssign(DynamicCompoundAssign inst, TranslationContext context)
{
var target = TranslateDynamicArgument(inst.Target, inst.TargetArgumentInfo);
var value = TranslateDynamicArgument(inst.Value, inst.ValueArgumentInfo);
var ae = new AssignmentExpression(target, AssignmentExpression.GetAssignmentOperatorTypeFromExpressionType(inst.Operation).Value, value);
if (inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext))
ae.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else
ae.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return ae.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(SpecialType.Dynamic, inst.Operation, new[] { target.ResolveResult, value.ResolveResult }));
}
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{
string message = "Error";

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1102,7 +1102,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1102,7 +1102,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) {
WriteKeyword(opSymbol);
} else if (!IsPostfixOperator(opType) && opType != UnaryOperatorType.NullConditionalRewrap) {
} else if (!IsPostfixOperator(opType) && opSymbol != null) {
WriteToken(opSymbol);
}
unaryOperatorExpression.Expression.AcceptVisitor(this);

16
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return Primary;
case UnaryOperatorType.NullConditionalRewrap:
return NullableRewrap;
case UnaryOperatorType.IsTrue:
return Conditional;
default:
return Unary;
}
@ -270,12 +272,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -270,12 +272,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
if (InsertParenthesesForReadability && precedence < Equality) {
// In readable mode, boost the priority of the left-hand side if the operator
// there isn't the same as the operator on this expression.
int boostTo = IsBitwise(binaryOperatorExpression.Operator) ? Unary : Equality;
if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) {
ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
} else {
ParenthesizeIfRequired(binaryOperatorExpression.Left, Equality);
ParenthesizeIfRequired(binaryOperatorExpression.Left, boostTo);
}
ParenthesizeIfRequired(binaryOperatorExpression.Right, Equality);
ParenthesizeIfRequired(binaryOperatorExpression.Right, boostTo);
} else {
// all other binary operators are left-associative
ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
@ -284,7 +287,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -284,7 +287,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
base.VisitBinaryOperatorExpression(binaryOperatorExpression);
}
static bool IsBitwise(BinaryOperatorType op)
{
return op == BinaryOperatorType.BitwiseAnd
|| op == BinaryOperatorType.BitwiseOr
|| op == BinaryOperatorType.ExclusiveOr;
}
BinaryOperatorType? GetBinaryOperatorType(Expression expr)
{
BinaryOperatorExpression boe = expr as BinaryOperatorExpression;

2
ICSharpCode.Decompiler/CSharp/Resolver/DynamicInvocationResolveResult.cs

@ -36,7 +36,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -36,7 +36,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Indexing,
/// <summary>
/// The invocation is an object creation ( 'new a(b)' ). Also used when invoking a base constructor ( ' : base(a) ' ) and chaining constructors ( ' : this(a) ').
/// The invocation is an object creation ( 'new a(b)' ).
/// </summary>
ObjectCreation,
}

19
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -446,6 +446,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -446,6 +446,8 @@ namespace ICSharpCode.Decompiler.CSharp
// but a base reference is not valid in this context.
if (collectionExpr is BaseReferenceExpression) {
collectionExpr = new ThisReferenceExpression().CopyAnnotationsFrom(collectionExpr);
} else if (IsDynamicCastToIEnumerable(collectionExpr, out var dynamicExpr)) {
collectionExpr = dynamicExpr.Detach();
}
// Handle explicit casts:
// This is the case if an explicit type different from the collection-item-type was used.
@ -465,7 +467,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -465,7 +467,8 @@ namespace ICSharpCode.Decompiler.CSharp
// Handle the required foreach-variable transformation:
switch (transformation) {
case RequiredGetCurrentTransformation.UseExistingVariable:
foreachVariable.Type = type;
if (foreachVariable.Type.Kind != TypeKind.Dynamic)
foreachVariable.Type = type;
foreachVariable.Kind = VariableKind.ForeachLocal;
foreachVariable.Name = AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), foreachVariable);
break;
@ -526,6 +529,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -526,6 +529,20 @@ namespace ICSharpCode.Decompiler.CSharp
return foreachStmt;
}
private bool IsDynamicCastToIEnumerable(Expression expr, out Expression dynamicExpr)
{
if (!(expr is CastExpression cast)) {
dynamicExpr = null;
return false;
}
dynamicExpr = cast.Expression;
if (!(expr.GetResolveResult() is ConversionResolveResult crr))
return false;
if (!crr.Type.IsKnownType(KnownTypeCode.IEnumerable))
return false;
return crr.Input.Type.Kind == TypeKind.Dynamic;
}
/// <summary>
/// Unwraps a nested BlockContainer, if container contains only a single block,
/// and that single block contains only a BlockContainer followed by a Leave instruction.

31
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs

@ -202,6 +202,37 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -202,6 +202,37 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new NotSupportedException("Invalid value for AssignmentOperatorType");
}
}
public static AssignmentOperatorType? GetAssignmentOperatorTypeFromExpressionType(ExpressionType expressionType)
{
switch (expressionType) {
case ExpressionType.AddAssign:
case ExpressionType.AddAssignChecked:
return AssignmentOperatorType.Add;
case ExpressionType.AndAssign:
return AssignmentOperatorType.BitwiseAnd;
case ExpressionType.DivideAssign:
return AssignmentOperatorType.Divide;
case ExpressionType.ExclusiveOrAssign:
return AssignmentOperatorType.ExclusiveOr;
case ExpressionType.LeftShiftAssign:
return AssignmentOperatorType.ShiftLeft;
case ExpressionType.ModuloAssign:
return AssignmentOperatorType.Modulus;
case ExpressionType.MultiplyAssign:
case ExpressionType.MultiplyAssignChecked:
return AssignmentOperatorType.Multiply;
case ExpressionType.OrAssign:
return AssignmentOperatorType.BitwiseOr;
case ExpressionType.RightShiftAssign:
return AssignmentOperatorType.ShiftRight;
case ExpressionType.SubtractAssign:
case ExpressionType.SubtractAssignChecked:
return AssignmentOperatorType.Subtract;
default:
return null;
}
}
}
public enum AssignmentOperatorType

5
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs

@ -117,6 +117,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -117,6 +117,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
case UnaryOperatorType.NullConditional:
return NullConditionalRole;
case UnaryOperatorType.NullConditionalRewrap:
case UnaryOperatorType.IsTrue:
return null; // no syntax
default:
throw new NotSupportedException("Invalid value for UnaryOperatorType");
@ -193,5 +194,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -193,5 +194,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// This has no syntax in C#, but the node is used to ensure parentheses are inserted where necessary.
/// </summary>
NullConditionalRewrap,
/// <summary>
/// Implicit call of "operator true".
/// </summary>
IsTrue,
}
}

14
ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs

@ -37,6 +37,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -37,6 +37,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </remarks>
class PrettifyAssignments : DepthFirstAstVisitor, IAstTransform
{
TransformContext context;
public override void VisitAssignmentExpression(AssignmentExpression assignment)
{
base.VisitAssignmentExpression(assignment);
@ -52,13 +54,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -52,13 +54,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
}
// TODO: context.Settings.IntroduceIncrementAndDecrement
if (assignment.Operator == AssignmentOperatorType.Add || assignment.Operator == AssignmentOperatorType.Subtract) {
if (context.Settings.IntroduceIncrementAndDecrement && assignment.Operator == AssignmentOperatorType.Add || assignment.Operator == AssignmentOperatorType.Subtract) {
// detect increment/decrement
var rr = assignment.Right.GetResolveResult();
if (rr.IsCompileTimeConstant && rr.Type.IsCSharpPrimitiveIntegerType() && CSharpPrimitiveCast.Cast(rr.Type.GetTypeCode(), 1, false).Equals(rr.ConstantValue)) {
// only if it's not a custom operator
if (assignment.Annotation<IL.CallInstruction>() == null && assignment.Annotation<IL.UserDefinedCompoundAssign>() == null) {
if (assignment.Annotation<IL.CallInstruction>() == null && assignment.Annotation<IL.UserDefinedCompoundAssign>() == null && assignment.Annotation<IL.DynamicCompoundAssign>() == null) {
UnaryOperatorType type;
// When the parent is an expression statement, pre- or post-increment doesn't matter;
// so we can pick post-increment which is more commonly used (for (int i = 0; i < x; i++))
@ -121,7 +122,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -121,7 +122,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
void IAstTransform.Run(AstNode node, TransformContext context)
{
node.AcceptVisitor(this);
this.context = context;
try {
node.AcceptVisitor(this);
} finally {
this.context = null;
}
}
}
}

7
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
break;
case "System.Activator.CreateInstance":
if (method.TypeArguments.Count == 1 && arguments.Length == 0 && method.TypeArguments[0].Kind == TypeKind.TypeParameter) {
if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0])) {
invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First())));
}
break;
@ -201,6 +201,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -201,6 +201,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return;
}
bool IsInstantiableTypeParameter(IType type)
{
return type is ITypeParameter tp && tp.HasDefaultConstructorConstraint;
}
Expression WrapInParens(Expression expression)
{
if (expression is ConditionalExpression)

5
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -285,6 +285,7 @@ @@ -285,6 +285,7 @@
<Compile Include="DotNetCore\LightJson\Serialization\TextScanner.cs" />
<Compile Include="DotNetCore\UniversalAssemblyResolver.cs" />
<Compile Include="DotNetCore\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\Instructions\DynamicInstructions.cs" />
<Compile Include="IL\PointerArithmeticOffset.cs" />
<Compile Include="IL\ControlFlow\AwaitInCatchTransform.cs" />
<Compile Include="IL\ILAstWritingOptions.cs" />
@ -294,10 +295,12 @@ @@ -294,10 +295,12 @@
<Compile Include="IL\SequencePoint.cs" />
<Compile Include="IL\Instructions\CallIndirect.cs" />
<Compile Include="IL\Instructions\DefaultValue.cs" />
<Compile Include="IL\Transforms\DynamicCallSiteTransform.cs" />
<Compile Include="IL\Transforms\EarlyExpressionTransforms.cs" />
<Compile Include="IL\Transforms\ExpressionTreeCast.cs" />
<Compile Include="IL\Instructions\ExpressionTreeCast.cs" />
<Compile Include="IL\Transforms\HighLevelLoopTransform.cs" />
<Compile Include="IL\Transforms\NamedArgumentTransform.cs" />
<Compile Include="IL\Transforms\IntroduceDynamicTypeOnLocals.cs" />
<Compile Include="IL\Transforms\NullPropagationTransform.cs" />
<Compile Include="IL\Transforms\ProxyCallReplacer.cs" />
<Compile Include="IL\Instructions\StringToInt.cs" />

14
ICSharpCode.Decompiler/IL/ILReader.cs

@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.IL @@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.IL
this.compilation = typeSystem.Compilation;
}
IMethod method;
Cil.MethodBody body;
Cil.MethodDebugInformation debugInfo;
StackType methodReturnStackType;
@ -67,11 +68,12 @@ namespace ICSharpCode.Decompiler.IL @@ -67,11 +68,12 @@ namespace ICSharpCode.Decompiler.IL
List<(ILVariable, ILVariable)> stackMismatchPairs;
IEnumerable<ILVariable> stackVariables;
void Init(Cil.MethodBody body)
void Init(Cil.MethodBody body, IMethod method)
{
if (body == null)
throw new ArgumentNullException(nameof(body));
this.body = body;
this.method = method;
this.debugInfo = body.Method.DebugInformation;
this.currentInstruction = null;
this.nextInstructionIndex = 0;
@ -167,7 +169,7 @@ namespace ICSharpCode.Decompiler.IL @@ -167,7 +169,7 @@ namespace ICSharpCode.Decompiler.IL
parameterType = typeSystem.Resolve(p.ParameterType, isFromSignature: true);
}
} else {
parameterType = typeSystem.Resolve(p.ParameterType, isFromSignature: true);
parameterType = method.Parameters[p.Index].Type;
}
Debug.Assert(!parameterType.IsUnbound());
if (parameterType.IsUnbound()) {
@ -379,9 +381,9 @@ namespace ICSharpCode.Decompiler.IL @@ -379,9 +381,9 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// Debugging helper: writes the decoded instruction stream interleaved with the inferred evaluation stack layout.
/// </summary>
public void WriteTypedIL(Cil.MethodBody body, ITextOutput output, CancellationToken cancellationToken = default(CancellationToken))
public void WriteTypedIL(Cil.MethodBody body, IMethod method, ITextOutput output, CancellationToken cancellationToken = default(CancellationToken))
{
Init(body);
Init(body, method);
ReadInstructions(cancellationToken);
foreach (var inst in instructionBuilder) {
if (inst is StLoc stloc && stloc.IsStackAdjustment) {
@ -422,11 +424,11 @@ namespace ICSharpCode.Decompiler.IL @@ -422,11 +424,11 @@ namespace ICSharpCode.Decompiler.IL
public ILFunction ReadIL(Cil.MethodBody body, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
Init(body);
var method = typeSystem.Resolve(body.Method);
Init(body, method);
ReadInstructions(cancellationToken);
var blockBuilder = new BlockBuilder(body, typeSystem, variableByExceptionHandler);
blockBuilder.CreateBlocks(mainContainer, instructionBuilder, isBranchTarget, cancellationToken);
var method = typeSystem.Resolve(body.Method);
var function = new ILFunction(method, body.Method, mainContainer);
CollectionExtensions.AddRange(function.Variables, parameterVariables);
CollectionExtensions.AddRange(function.Variables, localVariables);

1400
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

34
ICSharpCode.Decompiler/IL/Instructions.tt

@ -36,6 +36,8 @@ @@ -36,6 +36,8 @@
new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" },
new OpCode("CompoundAssignmentInstruction", "Common instruction for compound assignments.",
AbstractBaseClass, CustomConstructor, CustomArguments(("target", null), ("value", null))),
new OpCode("DynamicInstruction", "Instruction representing a dynamic call site.",
AbstractBaseClass, CustomWriteTo, MayThrow, SideEffect)
};
OpCode[] opCodes = {
@ -81,6 +83,12 @@ @@ -81,6 +83,12 @@
MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"),
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
new OpCode("dynamic.compound", "Common instruction for dynamic compound assignments.",
CustomClassName("DynamicCompoundAssign"), BaseClass("CompoundAssignmentInstruction"),
MayThrow, SideEffect, CustomWriteTo, CustomConstructor, ResultType("O"),
MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"),
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
new OpCode("bit.not", "Bitwise NOT", Unary, CustomConstructor, MatchCondition("IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType")),
new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")),
new OpCode("br", "Unconditional branch. <c>goto target;</c>",
@ -271,6 +279,30 @@ @@ -271,6 +279,30 @@
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"),
MatchCondition("this.IsChecked == o.IsChecked")),
new OpCode("dynamic.binary.operator", "ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).",
CustomClassName("DynamicBinaryOperatorInstruction"), Dynamic, CustomArguments(("left", null), ("right", null)), CustomWriteTo),
new OpCode("dynamic.unary.operator", "ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation).",
CustomClassName("DynamicUnaryOperatorInstruction"), Dynamic, CustomArguments(("operand", null)), CustomWriteTo),
new OpCode("dynamic.convert", "ILAst representation of a cast inside a dynamic expression (maps to Binder.Convert).",
CustomClassName("DynamicConvertInstruction"), Dynamic, HasTypeOperand, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
new OpCode("dynamic.getmember", "ILAst representation of a property get method call inside a dynamic expression (maps to Binder.GetMember).",
CustomClassName("DynamicGetMemberInstruction"), Dynamic, CustomArguments(("target", new[] { "O" })), CustomConstructor, CustomWriteTo),
new OpCode("dynamic.setmember", "ILAst representation of a property set method call inside a dynamic expression (maps to Binder.SetMember).",
CustomClassName("DynamicSetMemberInstruction"), Dynamic, CustomArguments(("target", new[] { "O" }), ("value", null)), CustomWriteTo),
new OpCode("dynamic.getindex", "ILAst representation of an indexer get method call inside a dynamic expression (maps to Binder.GetIndex).",
CustomClassName("DynamicGetIndexInstruction"), Dynamic, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo),
new OpCode("dynamic.setindex", "ILAst representation of an indexer set method call inside a dynamic expression (maps to Binder.SetIndex).",
CustomClassName("DynamicSetIndexInstruction"), Dynamic, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo),
new OpCode("dynamic.invokemember", "ILAst representation of a method call inside a dynamic expression (maps to Binder.InvokeMember).",
CustomClassName("DynamicInvokeMemberInstruction"), Dynamic, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo),
new OpCode("dynamic.invokeconstructor", "ILAst representation of a constuctor invocation inside a dynamic expression (maps to Binder.InvokeConstructor).",
CustomClassName("DynamicInvokeConstructorInstruction"), Dynamic, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo),
new OpCode("dynamic.invoke", "ILAst representation of a delegate invocation inside a dynamic expression (maps to Binder.Invoke).",
CustomClassName("DynamicInvokeInstruction"), Dynamic, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo),
new OpCode("dynamic.isevent", "ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression.",
CustomClassName("DynamicIsEventInstruction"), Dynamic, CustomArguments(("argument", new[] { "O" })), CustomWriteTo),
new OpCode("mkrefany", "Push a typed reference of type class onto the stack.",
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")),
new OpCode("refanytype", "Push the type token stored in a typed reference.",
@ -1086,4 +1118,6 @@ protected override void Disconnected() @@ -1086,4 +1118,6 @@ protected override void Disconnected()
opCode.GenerateMatch = false;
opCode.GeneratePerformMatch = false;
};
static Action<OpCode> Dynamic = BaseClass("DynamicInstruction") + MayThrow + SideEffect + CustomConstructor;
#>

67
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Diagnostics;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
@ -212,6 +213,7 @@ namespace ICSharpCode.Decompiler.IL @@ -212,6 +213,7 @@ namespace ICSharpCode.Decompiler.IL
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
output.Write(".new");
else
@ -225,6 +227,71 @@ namespace ICSharpCode.Decompiler.IL @@ -225,6 +227,71 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')');
}
}
public partial class DynamicCompoundAssign : CompoundAssignmentInstruction
{
public ExpressionType Operation { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public CSharpArgumentInfo ValueArgumentInfo { get; }
public CSharpBinderFlags BinderFlags { get; }
public DynamicCompoundAssign(ExpressionType op, CSharpBinderFlags binderFlags, ILInstruction target, CSharpArgumentInfo targetArgumentInfo, ILInstruction value, CSharpArgumentInfo valueArgumentInfo)
: base(OpCode.DynamicCompoundAssign, CompoundAssignmentTypeFromOperation(op), target, value)
{
if (!IsExpressionTypeSupported(op))
throw new ArgumentOutOfRangeException("op");
this.BinderFlags = binderFlags;
this.Operation = op;
this.TargetArgumentInfo = targetArgumentInfo;
this.ValueArgumentInfo = valueArgumentInfo;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write("." + Operation.ToString().ToLower());
DynamicInstruction.WriteBinderFlags(BinderFlags, output, options);
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
output.Write(".new");
else
output.Write(".old");
output.Write(' ');
DynamicInstruction.WriteArgumentList(output, options, (Target, TargetArgumentInfo), (Value, ValueArgumentInfo));
}
internal static bool IsExpressionTypeSupported(ExpressionType type)
{
return type == ExpressionType.AddAssign
|| type == ExpressionType.AddAssignChecked
|| type == ExpressionType.AndAssign
|| type == ExpressionType.DivideAssign
|| type == ExpressionType.ExclusiveOrAssign
|| type == ExpressionType.LeftShiftAssign
|| type == ExpressionType.ModuloAssign
|| type == ExpressionType.MultiplyAssign
|| type == ExpressionType.MultiplyAssignChecked
|| type == ExpressionType.OrAssign
|| type == ExpressionType.PostDecrementAssign
|| type == ExpressionType.PostIncrementAssign
|| type == ExpressionType.PreDecrementAssign
|| type == ExpressionType.PreIncrementAssign
|| type == ExpressionType.RightShiftAssign
|| type == ExpressionType.SubtractAssign
|| type == ExpressionType.SubtractAssignChecked;
}
static CompoundAssignmentType CompoundAssignmentTypeFromOperation(ExpressionType op)
{
switch (op) {
case ExpressionType.PostIncrementAssign:
case ExpressionType.PostDecrementAssign:
return CompoundAssignmentType.EvaluatesToOldValue;
default:
return CompoundAssignmentType.EvaluatesToNewValue;
}
}
}
}

529
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -0,0 +1,529 @@ @@ -0,0 +1,529 @@
// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.IL.Patterns;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
[Flags]
public enum CSharpArgumentInfoFlags
{
None = 0,
UseCompileTimeType = 1,
Constant = 2,
NamedArgument = 4,
IsRef = 8,
IsOut = 0x10,
IsStaticType = 0x20
}
[Flags]
public enum CSharpBinderFlags
{
None = 0,
CheckedContext = 1,
InvokeSimpleName = 2,
InvokeSpecialName = 4,
BinaryOperationLogical = 8,
ConvertExplicit = 0x10,
ConvertArrayIndex = 0x20,
ResultIndexed = 0x40,
ValueFromCompoundAssignment = 0x80,
ResultDiscarded = 0x100
}
public struct CSharpArgumentInfo
{
public string Name { get; set; }
public CSharpArgumentInfoFlags Flags { get; set; }
public IType CompileTimeType { get; set; }
public bool HasFlag(CSharpArgumentInfoFlags flag) => (Flags & flag) != 0;
}
partial class DynamicInstruction
{
public CSharpBinderFlags BinderFlags { get; }
public IType CallingContext { get; }
protected DynamicInstruction(OpCode opCode, CSharpBinderFlags binderFlags, IType context)
: base(opCode)
{
BinderFlags = binderFlags;
CallingContext = context;
}
protected void WriteBinderFlags(ITextOutput output, ILAstWritingOptions options)
{
WriteBinderFlags(BinderFlags, output, options);
}
internal static void WriteBinderFlags(CSharpBinderFlags flags, ITextOutput output, ILAstWritingOptions options)
{
if ((flags & CSharpBinderFlags.BinaryOperationLogical) != 0)
output.Write(".logic");
if ((flags & CSharpBinderFlags.CheckedContext) != 0)
output.Write(".checked");
if ((flags & CSharpBinderFlags.ConvertArrayIndex) != 0)
output.Write(".arrayindex");
if ((flags & CSharpBinderFlags.ConvertExplicit) != 0)
output.Write(".explicit");
if ((flags & CSharpBinderFlags.InvokeSimpleName) != 0)
output.Write(".invokesimple");
if ((flags & CSharpBinderFlags.InvokeSpecialName) != 0)
output.Write(".invokespecial");
if ((flags & CSharpBinderFlags.ResultDiscarded) != 0)
output.Write(".discard");
if ((flags & CSharpBinderFlags.ResultIndexed) != 0)
output.Write(".resultindexed");
if ((flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0)
output.Write(".compound");
}
public abstract CSharpArgumentInfo GetArgumentInfoOfChild(int index);
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, params (ILInstruction, CSharpArgumentInfo)[] arguments)
{
WriteArgumentList(output, options, (IEnumerable<(ILInstruction, CSharpArgumentInfo)>)arguments);
}
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, IEnumerable<(ILInstruction, CSharpArgumentInfo)> arguments)
{
output.Write('(');
int j = 0;
foreach (var (arg, info) in arguments) {
if (j > 0)
output.Write(", ");
output.Write("[flags: ");
output.Write(info.Flags.ToString());
output.Write(", name: " + info.Name + "] ");
arg.WriteTo(output, options);
j++;
}
output.Write(')');
}
}
partial class DynamicConvertInstruction
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
type.WriteTo(output);
output.Write('(');
argument.WriteTo(output, options);
output.Write(')');
}
public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType context, ILInstruction argument)
: base(OpCode.DynamicConvertInstruction, binderFlags, context)
{
Type = type;
Argument = argument;
}
protected internal override bool PerformMatch(ref ListMatch listMatch, ref Match match)
{
return base.PerformMatch(ref listMatch, ref match);
}
public override StackType ResultType => type.GetStackType();
public bool IsChecked => (BinderFlags & CSharpBinderFlags.CheckedContext) != 0;
public bool IsExplicit => (BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
return default(CSharpArgumentInfo);
}
}
partial class DynamicInvokeMemberInstruction
{
public string Name { get; }
public IReadOnlyList<IType> TypeArguments { get; }
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeMemberInstruction(CSharpBinderFlags binderFlags, string name, IType[] typeArguments, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeMemberInstruction, binderFlags, context)
{
Name = name;
TypeArguments = typeArguments ?? Empty<IType>.Array;
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
if (TypeArguments.Count > 0) {
output.Write('<');
int i = 0;
foreach (var typeArg in TypeArguments) {
if (i > 0)
output.Write(", ");
typeArg.WriteTo(output);
i++;
}
output.Write('>');
}
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
partial class DynamicGetMemberInstruction
{
public string Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public DynamicGetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target)
: base(OpCode.DynamicGetMemberInstruction, binderFlags, context)
{
Name = name;
TargetArgumentInfo = targetArgumentInfo;
Target = target;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
WriteArgumentList(output, options, (Target, TargetArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index != 0)
throw new ArgumentOutOfRangeException(nameof(index));
return TargetArgumentInfo;
}
}
partial class DynamicSetMemberInstruction
{
public string Name { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public CSharpArgumentInfo ValueArgumentInfo { get; }
public DynamicSetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target, CSharpArgumentInfo valueArgumentInfo, ILInstruction value)
: base(OpCode.DynamicSetMemberInstruction, binderFlags, context)
{
Name = name;
TargetArgumentInfo = targetArgumentInfo;
Target = target;
ValueArgumentInfo = valueArgumentInfo;
Value = value;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Name);
WriteArgumentList(output, options, (Target, TargetArgumentInfo), (Value, ValueArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return TargetArgumentInfo;
case 1:
return ValueArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
partial class DynamicGetIndexInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicGetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicGetIndexInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("get_Item");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
partial class DynamicSetIndexInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicSetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicSetIndexInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write("set_Item");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
partial class DynamicInvokeConstructorInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeConstructorInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeConstructorInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(".ctor");
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
partial class DynamicBinaryOperatorInstruction
{
public CSharpArgumentInfo LeftArgumentInfo { get; }
public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicBinaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicBinaryOperatorInstruction, binderFlags, context)
{
Operation = operation;
LeftArgumentInfo = leftArgumentInfo;
Left = left;
RightArgumentInfo = rightArgumentInfo;
Right = right;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Left, LeftArgumentInfo), (Right, RightArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return LeftArgumentInfo;
case 1:
return RightArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
partial class DynamicUnaryOperatorInstruction
{
public CSharpArgumentInfo OperandArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicUnaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo operandArgumentInfo, ILInstruction operand)
: base(OpCode.DynamicUnaryOperatorInstruction, binderFlags, context)
{
Operation = operation;
OperandArgumentInfo = operandArgumentInfo;
Operand = operand;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Operand, OperandArgumentInfo));
}
public override StackType ResultType {
get {
switch (Operation) {
case ExpressionType.IsFalse:
case ExpressionType.IsTrue:
return StackType.I4; // bool
default:
return StackType.O;
}
}
}
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return OperandArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
partial class DynamicInvokeInstruction
{
public IReadOnlyList<CSharpArgumentInfo> ArgumentInfo { get; }
public DynamicInvokeInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments)
: base(OpCode.DynamicInvokeInstruction, binderFlags, context)
{
ArgumentInfo = argumentInfo;
Arguments = new InstructionCollection<ILInstruction>(this, 0);
Arguments.AddRange(arguments);
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
if (index < 0 || index >= ArgumentInfo.Count)
throw new ArgumentOutOfRangeException(nameof(index));
return ArgumentInfo[index];
}
}
partial class DynamicIsEventInstruction
{
public string Name { get; }
public DynamicIsEventInstruction(CSharpBinderFlags binderFlags, string name, IType context, ILInstruction argument)
: base(OpCode.DynamicIsEventInstruction, binderFlags, context)
{
Name = name;
Argument = argument;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType => StackType.I4;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
return default(CSharpArgumentInfo);
}
}
}

0
ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs → ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

2
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -378,7 +378,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -378,7 +378,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
name = "array";
} else if (type is PointerType) {
name = "ptr";
} else if (type.Kind == TypeKind.TypeParameter || type.Kind == TypeKind.Unknown) {
} else if (type.Kind == TypeKind.TypeParameter || type.Kind == TypeKind.Unknown || type.Kind == TypeKind.Dynamic) {
name = "val";
} else if (type.Kind == TypeKind.ByReference) {
name = "reference";

2
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -326,7 +326,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -326,7 +326,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
base.VisitNumericCompoundAssign(inst);
if (inst.Target.MatchLdLoc(out var v)) {
inst.ReplaceWith(new StLoc(v, new BinaryNumericInstruction(inst.Operator, inst.Target, inst.Value, inst.CheckForOverflow, inst.Sign)));
}
}
}
}
#endregion

572
ICSharpCode.Decompiler/IL/Transforms/DynamicCallSiteTransform.cs

@ -0,0 +1,572 @@ @@ -0,0 +1,572 @@
// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Transforms the "callsite initialization pattern" into DynamicInstructions.
/// </summary>
public class DynamicCallSiteTransform : IILTransform
{
ILTransformContext context;
const string CallSiteTypeName = "System.Runtime.CompilerServices.CallSite";
const string CSharpBinderTypeName = "Microsoft.CSharp.RuntimeBinder.Binder";
public void Run(ILFunction function, ILTransformContext context)
{
if (!context.Settings.Dynamic)
return;
this.context = context;
Dictionary<IField, CallSiteInfo> callsites = new Dictionary<IField, CallSiteInfo>();
HashSet<BlockContainer> modifiedContainers = new HashSet<BlockContainer>();
foreach (var block in function.Descendants.OfType<Block>()) {
if (block.Instructions.Count < 2) continue;
// Check if, we deal with a callsite cache field null check:
// if (comp(ldsfld <>p__3 == ldnull)) br IL_000c
// br IL_002b
if (!(block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst)) continue;
if (!(block.Instructions.LastOrDefault() is Branch branchAfterInit)) continue;
if (!MatchCallSiteCacheNullCheck(ifInst.Condition, out var callSiteCacheField, out var callSiteDelegate, out bool invertBranches))
continue;
if (!ifInst.TrueInst.MatchBranch(out var trueBlock))
continue;
Block callSiteInitBlock, targetBlockAfterInit;
if (invertBranches) {
callSiteInitBlock = branchAfterInit.TargetBlock;
targetBlockAfterInit = trueBlock;
} else {
callSiteInitBlock = trueBlock;
targetBlockAfterInit = branchAfterInit.TargetBlock;
}
if (!ScanCallSiteInitBlock(callSiteInitBlock, callSiteCacheField, callSiteDelegate, out var callSiteInfo, out var blockAfterInit))
continue;
if (targetBlockAfterInit != blockAfterInit)
continue;
callSiteInfo.DelegateType = callSiteDelegate;
callSiteInfo.ConditionalJumpToInit = ifInst;
callSiteInfo.Inverted = invertBranches;
callSiteInfo.BranchAfterInit = branchAfterInit;
callsites.Add(callSiteCacheField, callSiteInfo);
}
var storesToRemove = new List<StLoc>();
foreach (var invokeCall in function.Descendants.OfType<CallVirt>()) {
if (invokeCall.Method.DeclaringType.Kind != TypeKind.Delegate || invokeCall.Method.Name != "Invoke" || invokeCall.Arguments.Count == 0)
continue;
var firstArgument = invokeCall.Arguments[0];
if (firstArgument.MatchLdLoc(out var stackSlot) && stackSlot.Kind == VariableKind.StackSlot && stackSlot.IsSingleDefinition) {
firstArgument = ((StLoc)stackSlot.StoreInstructions[0]).Value;
}
if (!firstArgument.MatchLdFld(out var cacheFieldLoad, out var targetField))
continue;
if (!cacheFieldLoad.MatchLdsFld(out var cacheField))
continue;
if (!callsites.TryGetValue(cacheField, out var callsite))
continue;
context.Stepper.Step("Transform callsite for " + callsite.MemberName);
var deadArguments = new List<ILInstruction>();
ILInstruction replacement = MakeDynamicInstruction(callsite, invokeCall, deadArguments);
if (replacement == null)
continue;
invokeCall.ReplaceWith(replacement);
Debug.Assert(callsite.ConditionalJumpToInit?.Parent is Block);
var block = ((Block)callsite.ConditionalJumpToInit.Parent);
if (callsite.Inverted) {
block.Instructions.Remove(callsite.ConditionalJumpToInit);
callsite.BranchAfterInit.ReplaceWith(callsite.ConditionalJumpToInit.TrueInst);
} else {
block.Instructions.Remove(callsite.ConditionalJumpToInit);
}
foreach (var arg in deadArguments) {
if (arg.MatchLdLoc(out var temporary) && temporary.Kind == VariableKind.StackSlot && temporary.IsSingleDefinition && temporary.LoadCount == 0) {
StLoc stLoc = (StLoc)temporary.StoreInstructions[0];
if (stLoc.Parent is Block storeParentBlock) {
var value = stLoc.Value;
if (value.MatchLdsFld(out var cacheFieldCopy) && cacheFieldCopy.Equals(cacheField))
storesToRemove.Add(stLoc);
if (value.MatchLdFld(out cacheFieldLoad, out var targetFieldCopy) && cacheFieldLoad.MatchLdsFld(out cacheFieldCopy) && cacheField.Equals(cacheFieldCopy) && targetField.Equals(targetFieldCopy))
storesToRemove.Add(stLoc);
}
}
}
modifiedContainers.Add((BlockContainer)block.Parent);
}
foreach (var inst in storesToRemove) {
Block parentBlock = (Block)inst.Parent;
parentBlock.Instructions.RemoveAt(inst.ChildIndex);
}
foreach (var container in modifiedContainers)
container.SortBlocks(deleteUnreachableBlocks: true);
}
ILInstruction MakeDynamicInstruction(CallSiteInfo callsite, CallVirt targetInvokeCall, List<ILInstruction> deadArguments)
{
switch (callsite.Kind) {
case BinderMethodKind.BinaryOperation:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicBinaryOperatorInstruction(
binderFlags: callsite.Flags,
operation: callsite.Operation,
context: callsite.Context,
leftArgumentInfo: callsite.ArgumentInfos[0],
left: targetInvokeCall.Arguments[2],
rightArgumentInfo: callsite.ArgumentInfos[1],
right: targetInvokeCall.Arguments[3]
);
case BinderMethodKind.Convert:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
ILInstruction result = new DynamicConvertInstruction(
binderFlags: callsite.Flags,
context: callsite.Context,
type: callsite.ConvertTargetType,
argument: targetInvokeCall.Arguments[2]
);
if (result.ResultType == StackType.Unknown) {
// if references are missing, we need to coerce the primitive type to None.
// Otherwise we will get loads of assertions.
result = new Conv(result, PrimitiveType.None, ((DynamicConvertInstruction)result).IsChecked, Sign.None);
}
return result;
case BinderMethodKind.GetIndex:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicGetIndexInstruction(
binderFlags: callsite.Flags,
context: callsite.Context,
argumentInfo: callsite.ArgumentInfos,
arguments: targetInvokeCall.Arguments.Skip(2).ToArray()
);
case BinderMethodKind.GetMember:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicGetMemberInstruction(
binderFlags: callsite.Flags,
name: callsite.MemberName,
context: callsite.Context,
targetArgumentInfo: callsite.ArgumentInfos[0],
target: targetInvokeCall.Arguments[2]
);
case BinderMethodKind.Invoke:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicInvokeInstruction(
binderFlags: callsite.Flags,
context: callsite.Context,
argumentInfo: callsite.ArgumentInfos,
arguments: targetInvokeCall.Arguments.Skip(2).ToArray()
);
case BinderMethodKind.InvokeConstructor:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicInvokeConstructorInstruction(
binderFlags: callsite.Flags,
context: callsite.Context,
argumentInfo: callsite.ArgumentInfos,
arguments: targetInvokeCall.Arguments.Skip(2).ToArray()
);
case BinderMethodKind.InvokeMember:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicInvokeMemberInstruction(
binderFlags: callsite.Flags,
name: callsite.MemberName,
typeArguments: callsite.TypeArguments,
context: callsite.Context,
argumentInfo: callsite.ArgumentInfos,
arguments: targetInvokeCall.Arguments.Skip(2).ToArray()
);
case BinderMethodKind.IsEvent:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicIsEventInstruction(
binderFlags: callsite.Flags,
name: callsite.MemberName,
context: callsite.Context,
argument: targetInvokeCall.Arguments[2]
);
case BinderMethodKind.SetIndex:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicSetIndexInstruction(
binderFlags: callsite.Flags,
context: callsite.Context,
argumentInfo: callsite.ArgumentInfos,
arguments: targetInvokeCall.Arguments.Skip(2).ToArray()
);
case BinderMethodKind.SetMember:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicSetMemberInstruction(
binderFlags: callsite.Flags,
name: callsite.MemberName,
context: callsite.Context,
targetArgumentInfo: callsite.ArgumentInfos[0],
target: targetInvokeCall.Arguments[2],
valueArgumentInfo: callsite.ArgumentInfos[1],
value: targetInvokeCall.Arguments[3]
);
case BinderMethodKind.UnaryOperation:
deadArguments.AddRange(targetInvokeCall.Arguments.Take(2));
return new DynamicUnaryOperatorInstruction(
binderFlags: callsite.Flags,
operation: callsite.Operation,
context: callsite.Context,
operandArgumentInfo: callsite.ArgumentInfos[0],
operand: targetInvokeCall.Arguments[2]
);
default:
throw new NotSupportedException();
}
throw new NotImplementedException();
}
bool ScanCallSiteInitBlock(Block callSiteInitBlock, IField callSiteCacheField, IType callSiteDelegateType, out CallSiteInfo callSiteInfo, out Block blockAfterInit)
{
callSiteInfo = default(CallSiteInfo);
blockAfterInit = null;
int instCount = callSiteInitBlock.Instructions.Count;
if (callSiteInitBlock.IncomingEdgeCount != 1 || instCount < 2)
return false;
if (!callSiteInitBlock.Instructions[instCount - 1].MatchBranch(out blockAfterInit))
return false;
if (!callSiteInitBlock.Instructions[instCount - 2].MatchStsFld(out var field, out var value) || !field.Equals(callSiteCacheField))
return false;
if (!(value is Call createBinderCall) || createBinderCall.Method.TypeArguments.Count != 0 || createBinderCall.Arguments.Count != 1 || createBinderCall.Method.Name != "Create" || createBinderCall.Method.DeclaringType.FullName != CallSiteTypeName || createBinderCall.Method.DeclaringType.TypeArguments.Count != 1)
return false;
if (!(createBinderCall.Arguments[0] is Call binderCall) || binderCall.Method.DeclaringType.FullName != CSharpBinderTypeName || binderCall.Method.DeclaringType.TypeParameterCount != 0)
return false;
callSiteInfo.DelegateType = callSiteDelegateType;
callSiteInfo.InitBlock = callSiteInitBlock;
switch (binderCall.Method.Name) {
case "IsEvent":
callSiteInfo.Kind = BinderMethodKind.IsEvent;
// In the case of Binder.IsEvent all arguments should already be properly inlined, as there is no array initializer:
// Scan arguments: binder flags, member name, context type
if (binderCall.Arguments.Count != 3)
return false;
if (!binderCall.Arguments[0].MatchLdcI4(out int binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
if (!binderCall.Arguments[1].MatchLdStr(out string name))
return false;
callSiteInfo.MemberName = name;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[2], out var contextType))
return false;
callSiteInfo.Context = contextType;
return true;
case "Convert":
callSiteInfo.Kind = BinderMethodKind.Convert;
// In the case of Binder.Convert all arguments should already be properly inlined, as there is no array initializer:
// Scan arguments: binder flags, target type, context type
if (binderCall.Arguments.Count != 3)
return false;
if (!binderCall.Arguments[0].MatchLdcI4(out binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[1], out var targetType))
return false;
callSiteInfo.ConvertTargetType = targetType;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[2], out contextType))
return false;
callSiteInfo.Context = contextType;
return true;
case "InvokeMember":
callSiteInfo.Kind = BinderMethodKind.InvokeMember;
if (binderCall.Arguments.Count != 5)
return false;
// First argument: binder flags
// The value must be a single ldc.i4 instruction.
if (!binderCall.Arguments[0].MatchLdLoc(out var variable))
return false;
if (!callSiteInitBlock.Instructions[0].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdcI4(out binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
// Second argument: method name
// The value must be a single ldstr instruction.
if (!binderCall.Arguments[1].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[1].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdStr(out name))
return false;
callSiteInfo.MemberName = name;
// Third argument: type arguments
// The value must be either ldnull (no type arguments) or an array initializer pattern.
if (!binderCall.Arguments[2].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[2].MatchStLoc(out var variableOrTemporary, out value))
return false;
int numberOfTypeArguments = 0;
if (!value.MatchLdNull()) {
if (value is NewArr typeArgsNewArr && typeArgsNewArr.Type.IsKnownType(KnownTypeCode.Type) && typeArgsNewArr.Indices.Count == 1 && typeArgsNewArr.Indices[0].MatchLdcI4(out numberOfTypeArguments)) {
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(callSiteInitBlock, 3, variableOrTemporary, typeArgsNewArr.Type, numberOfTypeArguments, out var typeArguments, out _))
return false;
int i = 0;
callSiteInfo.TypeArguments = new IType[numberOfTypeArguments];
foreach (var typeArg in typeArguments) {
if (!TransformExpressionTrees.MatchGetTypeFromHandle(typeArg, out var type))
return false;
callSiteInfo.TypeArguments[i] = type;
i++;
}
} else {
return false;
}
}
int typeArgumentsOffset = numberOfTypeArguments;
// Special case for csc array initializers:
if (variableOrTemporary != variable) {
// store temporary from array initializer in variable
if (!callSiteInitBlock.Instructions[3 + typeArgumentsOffset].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdLoc(variableOrTemporary))
return false;
typeArgumentsOffset++;
}
// Fourth argument: context type
if (!binderCall.Arguments[3].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[3 + typeArgumentsOffset].MatchStLoc(variable, out value))
return false;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(value, out contextType))
return false;
callSiteInfo.Context = contextType;
// Fifth argument: call parameter info
if (!binderCall.Arguments[4].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[4 + typeArgumentsOffset].MatchStLoc(variable, out value))
return false;
if (!ExtractArgumentInfo(value, ref callSiteInfo, 5 + typeArgumentsOffset, variable))
return false;
return true;
case "GetMember":
case "SetMember":
callSiteInfo.Kind = binderCall.Method.Name == "GetMember" ? BinderMethodKind.GetMember : BinderMethodKind.SetMember;
if (binderCall.Arguments.Count != 4)
return false;
// First argument: binder flags
// The value must be a single ldc.i4 instruction.
if (!binderCall.Arguments[0].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[0].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdcI4(out binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
// Second argument: method name
// The value must be a single ldstr instruction.
if (!binderCall.Arguments[1].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[1].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdStr(out name))
return false;
callSiteInfo.MemberName = name;
// Third argument: context type
if (!binderCall.Arguments[2].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[2].MatchStLoc(variable, out value))
return false;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(value, out contextType))
return false;
callSiteInfo.Context = contextType;
// Fourth argument: call parameter info
if (!binderCall.Arguments[3].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[3].MatchStLoc(variable, out value))
return false;
if (!ExtractArgumentInfo(value, ref callSiteInfo, 4, variable))
return false;
return true;
case "GetIndex":
case "SetIndex":
case "InvokeConstructor":
case "Invoke":
switch (binderCall.Method.Name) {
case "GetIndex":
callSiteInfo.Kind = BinderMethodKind.GetIndex;
break;
case "SetIndex":
callSiteInfo.Kind = BinderMethodKind.SetIndex;
break;
case "InvokeConstructor":
callSiteInfo.Kind = BinderMethodKind.InvokeConstructor;
break;
case "Invoke":
callSiteInfo.Kind = BinderMethodKind.Invoke;
break;
default:
throw new NotSupportedException();
}
if (binderCall.Arguments.Count != 3)
return false;
// First argument: binder flags
// The value must be a single ldc.i4 instruction.
if (!binderCall.Arguments[0].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[0].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdcI4(out binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
// Second argument: context type
if (!binderCall.Arguments[1].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[1].MatchStLoc(variable, out value))
return false;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(value, out contextType))
return false;
callSiteInfo.Context = contextType;
// Third argument: call parameter info
if (!binderCall.Arguments[2].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[2].MatchStLoc(variable, out value))
return false;
if (!ExtractArgumentInfo(value, ref callSiteInfo, 3, variable))
return false;
return true;
case "UnaryOperation":
case "BinaryOperation":
callSiteInfo.Kind = binderCall.Method.Name == "BinaryOperation" ? BinderMethodKind.BinaryOperation : BinderMethodKind.UnaryOperation;
if (binderCall.Arguments.Count != 4)
return false;
// First argument: binder flags
// The value must be a single ldc.i4 instruction.
if (!binderCall.Arguments[0].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[0].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdcI4(out binderFlagsInteger))
return false;
callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger;
// Second argument: operation
// The value must be a single ldc.i4 instruction.
if (!binderCall.Arguments[1].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[1].MatchStLoc(variable, out value))
return false;
if (!value.MatchLdcI4(out int operation))
return false;
callSiteInfo.Operation = (ExpressionType)operation;
// Third argument: context type
if (!binderCall.Arguments[2].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[2].MatchStLoc(variable, out value))
return false;
if (!TransformExpressionTrees.MatchGetTypeFromHandle(value, out contextType))
return false;
callSiteInfo.Context = contextType;
// Fourth argument: call parameter info
if (!binderCall.Arguments[3].MatchLdLoc(out variable))
return false;
if (!callSiteInitBlock.Instructions[3].MatchStLoc(variable, out value))
return false;
if (!ExtractArgumentInfo(value, ref callSiteInfo, 4, variable))
return false;
return true;
default:
return false;
}
}
bool ExtractArgumentInfo(ILInstruction value, ref CallSiteInfo callSiteInfo, int instructionOffset, ILVariable variable)
{
if (!(value is NewArr newArr2 && newArr2.Type.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" && newArr2.Indices.Count == 1 && newArr2.Indices[0].MatchLdcI4(out var numberOfArguments)))
return false;
if (!TransformArrayInitializers.HandleSimpleArrayInitializer(callSiteInfo.InitBlock, instructionOffset, variable, newArr2.Type, numberOfArguments, out var arguments, out _))
return false;
int i = 0;
callSiteInfo.ArgumentInfos = new CSharpArgumentInfo[numberOfArguments];
var compileTimeTypes = callSiteInfo.DelegateType.GetDelegateInvokeMethod().Parameters.SelectArray(p => p.Type);
foreach (var arg in arguments) {
if (!(arg is Call createCall))
return false;
if (!(createCall.Method.Name == "Create" && createCall.Method.DeclaringType.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" && createCall.Arguments.Count == 2))
return false;
if (!createCall.Arguments[0].MatchLdcI4(out var argumentInfoFlags))
return false;
string argumentName = null;
if (!createCall.Arguments[1].MatchLdStr(out argumentName))
if (!createCall.Arguments[1].MatchLdNull())
return false;
callSiteInfo.ArgumentInfos[i] = new CSharpArgumentInfo { Flags = (CSharpArgumentInfoFlags)argumentInfoFlags, Name = argumentName, CompileTimeType = compileTimeTypes[i + 1] };
i++;
}
return true;
}
bool MatchCallSiteCacheNullCheck(ILInstruction condition, out IField callSiteCacheField, out IType callSiteDelegate, out bool invertBranches)
{
callSiteCacheField = null;
callSiteDelegate = null;
invertBranches = false;
if (!condition.MatchCompEqualsNull(out var argument)) {
if (!condition.MatchCompNotEqualsNull(out argument))
return false;
invertBranches = true;
}
if (!argument.MatchLdsFld(out callSiteCacheField) || callSiteCacheField.ReturnType.TypeArguments.Count != 1 || callSiteCacheField.ReturnType.FullName != CallSiteTypeName)
return false;
callSiteDelegate = callSiteCacheField.ReturnType.TypeArguments[0];
if (callSiteDelegate.Kind != TypeKind.Delegate)
return false;
return true;
}
struct CallSiteInfo
{
public bool Inverted;
public ILInstruction BranchAfterInit;
public IfInstruction ConditionalJumpToInit;
public Block InitBlock;
public IType DelegateType;
public BinderMethodKind Kind;
public CSharpBinderFlags Flags;
public ExpressionType Operation;
public IType Context;
public IType ConvertTargetType;
public IType[] TypeArguments;
public CSharpArgumentInfo[] ArgumentInfos;
public string MemberName;
}
enum BinderMethodKind
{
BinaryOperation,
Convert,
GetIndex,
GetMember,
Invoke,
InvokeConstructor,
InvokeMember,
IsEvent,
SetIndex,
SetMember,
UnaryOperation
}
}
}

112
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
@ -302,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -302,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
}
TransformAssignment.HandleCompoundAssign(inst, context);
}
}
protected internal override void VisitIfInstruction(IfInstruction inst)
{
@ -329,6 +330,115 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -329,6 +330,115 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (new NullableLiftingTransform(context).Run(inst))
return;
if (TransformDynamicAddAssignOrRemoveAssign(inst))
return;
}
/// <summary>
/// op is either add or remove/subtract:
/// if (dynamic.isevent (target)) {
/// dynamic.invokemember.invokespecial.discard op_Name(target, value)
/// } else {
/// dynamic.compound.op (dynamic.getmember Name(target), value)
/// }
/// =>
/// dynamic.compound.op (dynamic.getmember Name(target), value)
/// </summary>
bool TransformDynamicAddAssignOrRemoveAssign(IfInstruction inst)
{
if (!inst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst))
return false;
if (!(condition is DynamicIsEventInstruction isEvent))
return false;
trueInst = Block.Unwrap(trueInst);
falseInst = Block.Unwrap(falseInst);
if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign))
return false;
if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember))
return false;
if (!isEvent.Argument.Match(getMember.Target).Success)
return false;
if (!SemanticHelper.IsPure(isEvent.Argument.Flags))
return false;
if (!(trueInst is DynamicInvokeMemberInstruction invokeMember))
return false;
if (!(invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.InvokeSpecialName) && invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.ResultDiscarded)))
return false;
switch (dynamicCompoundAssign.Operation) {
case ExpressionType.AddAssign:
if (invokeMember.Name != "add_" + getMember.Name)
return false;
break;
case ExpressionType.SubtractAssign:
if (invokeMember.Name != "remove_" + getMember.Name)
return false;
break;
default:
return false;
}
if (!dynamicCompoundAssign.Value.Match(invokeMember.Arguments[1]).Success)
return false;
if (!invokeMember.Arguments[0].Match(getMember.Target).Success)
return false;
context.Step("+= / -= dynamic.isevent pattern -> dynamic.compound.op", inst);
inst.ReplaceWith(dynamicCompoundAssign);
return true;
}
/// <summary>
/// dynamic.setmember.compound Name(target, dynamic.binary.operator op(dynamic.getmember Name(target), value))
/// =>
/// dynamic.compound.op (dynamic.getmember Name(target), value)
/// </summary>
protected internal override void VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst)
{
base.VisitDynamicSetMemberInstruction(inst);
if (!inst.BinderFlags.HasFlag(CSharpBinderFlags.ValueFromCompoundAssignment))
return;
if (!(inst.Value is DynamicBinaryOperatorInstruction binaryOp))
return;
if (!(binaryOp.Left is DynamicGetMemberInstruction dynamicGetMember))
return;
if (!dynamicGetMember.Target.Match(inst.Target).Success)
return;
if (!SemanticHelper.IsPure(dynamicGetMember.Target.Flags))
return;
if (inst.Name != dynamicGetMember.Name || !DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation))
return;
context.Step("dynamic.setmember.compound -> dynamic.compound.op", inst);
inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.BinderFlags, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo));
}
/// <summary>
/// dynamic.setindex.compound(target, index, dynamic.binary.operator op(dynamic.getindex(target, index), value))
/// =>
/// dynamic.compound.op (dynamic.getindex(target, index), value)
/// </summary>
protected internal override void VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst)
{
base.VisitDynamicSetIndexInstruction(inst);
if (!inst.BinderFlags.HasFlag(CSharpBinderFlags.ValueFromCompoundAssignment))
return;
if (!(inst.Arguments.LastOrDefault() is DynamicBinaryOperatorInstruction binaryOp))
return;
if (!(binaryOp.Left is DynamicGetIndexInstruction dynamicGetIndex))
return;
if (inst.Arguments.Count != dynamicGetIndex.Arguments.Count + 1)
return;
// Ensure that same arguments are passed to dynamicGetIndex and inst:
for (int j = 0; j < dynamicGetIndex.Arguments.Count; j++) {
if (!SemanticHelper.IsPure(dynamicGetIndex.Arguments[j].Flags))
return;
if (!dynamicGetIndex.Arguments[j].Match(dynamicGetIndex.Arguments[j]).Success)
return;
}
if (!DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation))
return;
context.Step("dynamic.setindex.compound -> dynamic.compound.op", inst);
inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.BinderFlags, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo));
}
IfInstruction HandleConditionalOperator(IfInstruction inst)

18
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -343,11 +343,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -343,11 +343,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (parent is ILiftableInstruction liftable && liftable.IsLifted) {
return true; // inline into lifted operators
}
if (parent is NullCoalescingInstruction && NullableType.IsNullable(v.Type)) {
return true; // inline nullables into ?? operator
}
if (parent is NullableUnwrap && NullableType.IsNullable(v.Type)) {
return true; // inline nullables into ?. operator
switch (parent.OpCode) {
case OpCode.NullCoalescingInstruction:
if (NullableType.IsNullable(v.Type))
return true; // inline nullables into ?? operator
break;
case OpCode.NullableUnwrap:
return true; // inline into ?. operator
case OpCode.DynamicGetMemberInstruction:
case OpCode.DynamicGetIndexInstruction:
case OpCode.LdObj:
if (parent.Parent.OpCode == OpCode.DynamicCompoundAssign)
return true; // inline into dynamic compound assignments
break;
}
// decide based on the target into which we are inlining
switch (next.OpCode) {

51
ICSharpCode.Decompiler/IL/Transforms/IntroduceDynamicTypeOnLocals.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
class IntroduceDynamicTypeOnLocals : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
foreach (var variable in function.Variables) {
if (variable.Kind != VariableKind.Local &&
variable.Kind != VariableKind.StackSlot &&
variable.Kind != VariableKind.ForeachLocal &&
variable.Kind != VariableKind.UsingLocal) {
continue;
}
if (!variable.Type.IsKnownType(KnownTypeCode.Object) || variable.LoadCount == 0)
continue;
foreach (var load in variable.LoadInstructions) {
if (load.Parent is DynamicInstruction dynamicInstruction) {
var argumentInfo = dynamicInstruction.GetArgumentInfoOfChild(load.ChildIndex);
if (!argumentInfo.HasFlag(CSharpArgumentInfoFlags.UseCompileTimeType)) {
variable.Type = SpecialType.Dynamic;
}
}
}
}
}
}
}

28
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -208,13 +208,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -208,13 +208,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst = arg;
}
// ensure the access chain does not contain any 'nullable.unwrap' that aren't directly part of the chain
for (int i = 1; i < call.Arguments.Count; ++i) {
if (call.Arguments[i].HasFlag(InstructionFlags.MayUnwrapNull)) {
return false;
}
}
if (ArgumentsAfterFirstMayUnwrapNull(call.Arguments))
return false;
} else if (inst is NullableUnwrap unwrap) {
inst = unwrap.Argument;
} else if (inst is DynamicGetMemberInstruction dynGetMember) {
inst = dynGetMember.Target;
} else if (inst is DynamicInvokeMemberInstruction dynInvokeMember) {
inst = dynInvokeMember.Arguments[0];
if (ArgumentsAfterFirstMayUnwrapNull(dynInvokeMember.Arguments))
return false;
} else if (inst is DynamicGetIndexInstruction dynGetIndex) {
inst = dynGetIndex.Arguments[0];
if (ArgumentsAfterFirstMayUnwrapNull(dynGetIndex.Arguments))
return false;
} else {
// unknown node -> invalid chain
return false;
@ -222,6 +229,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -222,6 +229,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
chainLength++;
}
bool ArgumentsAfterFirstMayUnwrapNull(InstructionCollection<ILInstruction> arguments)
{
// ensure the access chain does not contain any 'nullable.unwrap' that aren't directly part of the chain
for (int i = 1; i < arguments.Count; ++i) {
if (arguments[i].HasFlag(InstructionFlags.MayUnwrapNull)) {
return true;
}
}
return false;
}
bool IsValidEndOfChain()
{
switch (mode) {

4
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -161,11 +161,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -161,11 +161,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return new DefaultValue(elementType);
}
}
/// <summary>
/// Handle simple case where RuntimeHelpers.InitializeArray is not used.
/// </summary>
bool HandleSimpleArrayInitializer(Block block, int pos, ILVariable store, IType elementType, int length, out ILInstruction[] values, out int instructionsToRemove)
internal static bool HandleSimpleArrayInitializer(Block block, int pos, ILVariable store, IType elementType, int length, out ILInstruction[] values, out int instructionsToRemove)
{
instructionsToRemove = 0;
values = null;

5
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -293,6 +293,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -293,6 +293,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step($"Compound assignment (user-defined binary)", compoundStore);
newInst = new UserDefinedCompoundAssign(operatorCall.Method, CompoundAssignmentType.EvaluatesToNewValue,
operatorCall.Arguments[0], rhs);
} else if (setterValue is DynamicBinaryOperatorInstruction dynamicBinaryOp) {
if (!IsMatchingCompoundLoad(dynamicBinaryOp.Left, compoundStore, forbiddenVariable: storeInSetter?.Variable))
return false;
context.Step($"Compound assignment (dynamic binary)", compoundStore);
newInst = new DynamicCompoundAssign(dynamicBinaryOp.Operation, dynamicBinaryOp.BinderFlags, dynamicBinaryOp.Left, dynamicBinaryOp.LeftArgumentInfo, dynamicBinaryOp.Right, dynamicBinaryOp.RightArgumentInfo);
} else {
return false;
}

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

@ -1034,7 +1034,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1034,7 +1034,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
bool MatchGetTypeFromHandle(ILInstruction inst, out IType type)
internal static bool MatchGetTypeFromHandle(ILInstruction inst, out IType type)
{
type = null;
return inst is CallInstruction getTypeCall

7
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -277,7 +277,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -277,7 +277,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (callVirt.Arguments.Count != 1)
return false;
return target.MatchLdLocRef(objVar) || (boxedValue && target.MatchLdLoc(objVar)) || (usingNull && callVirt.Arguments[0].MatchLdNull());
return target.MatchLdLocRef(objVar)
|| (boxedValue && target.MatchLdLoc(objVar))
|| (usingNull && callVirt.Arguments[0].MatchLdNull())
|| (isReference && checkInst is NullableRewrap
&& target.MatchIsInst(out var arg, out var type2)
&& arg.MatchLdLoc(objVar) && type2.IsKnownType(KnownTypeCode.IDisposable));
}
}
}

3
ILSpy/Languages/CSharpHighlightingTokenWriter.cs

@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy @@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy
case "foreach":
case "lock":
case "global":
case "dynamic":
case "await":
color = structureKeywordsColor;
break;
@ -291,6 +290,8 @@ namespace ICSharpCode.ILSpy @@ -291,6 +290,8 @@ namespace ICSharpCode.ILSpy
HighlightingColor color = null;
if (identifier.Name == "value" && identifier.Ancestors.OfType<Accessor>().FirstOrDefault() is Accessor accessor && accessor.Role != PropertyDeclaration.GetterRole)
color = valueKeywordColor;
if ((identifier.Name == "dynamic" || identifier.Name == "var") && identifier.Parent is AstType)
color = queryKeywordsColor;
switch (GetCurrentDefinition()) {
case ITypeDefinition t:
switch (t.Kind) {

2
ILSpy/Languages/ILAstLanguage.cs

@ -94,7 +94,7 @@ namespace ICSharpCode.ILSpy @@ -94,7 +94,7 @@ namespace ICSharpCode.ILSpy
return;
var typeSystem = new DecompilerTypeSystem(method.Module);
ILReader reader = new ILReader(typeSystem);
reader.WriteTypedIL(method.Body, output, options.CancellationToken);
reader.WriteTypedIL(method.Body, typeSystem.Resolve(method), output, options.CancellationToken);
}
}

Loading…
Cancel
Save