diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 604b32919..6eb934819 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -84,6 +84,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index 0e8c4ca29..279010c1c 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -109,6 +109,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
+ [Test]
+ public void Lock([ValueSource("defaultOptions")] CompilerOptions cscOptions)
+ {
+ Run(cscOptions: cscOptions);
+ }
+
[Test, Ignore("Not implemented")]
public void LiftedOperators([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
diff --git a/ICSharpCode.Decompiler.Tests/Lock.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.cs
similarity index 83%
rename from ICSharpCode.Decompiler.Tests/Lock.cs
rename to ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.cs
index da5a59c74..dd475ceb6 100644
--- a/ICSharpCode.Decompiler.Tests/Lock.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.cs
@@ -18,21 +18,22 @@
using System;
-public class Lock
+namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
- public void LockThis()
+ public class Lock
{
- lock (this)
+ public void LockThis()
{
- Console.WriteLine();
+ lock (this) {
+ Console.WriteLine();
+ }
}
- }
- public void LockOnType()
- {
- lock (typeof(Lock))
+ public void LockOnType()
{
- Console.WriteLine();
+ lock (typeof(Lock)) {
+ Console.WriteLine();
+ }
}
}
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.il
new file mode 100644
index 000000000..77d86c654
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.il
@@ -0,0 +1,146 @@
+
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly '1c2baaro'
+{
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
+ 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
+ .permissionset reqmin
+ = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module '1c2baaro.dll'
+// MVID: {5FC5B58D-AAD7-4436-A58F-6F3D75486C66}
+.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
+.imagebase 0x10000000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x00C60000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ extends [mscorlib]System.Object
+{
+ .method public hidebysig instance void
+ LockThis() cil managed
+ {
+ // Code size 42 (0x2a)
+ .maxstack 2
+ .locals init (bool V_0,
+ class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock V_1,
+ bool V_2)
+ IL_0000: nop
+ IL_0001: ldc.i4.0
+ IL_0002: stloc.0
+ .try
+ {
+ IL_0003: ldarg.0
+ IL_0004: dup
+ IL_0005: stloc.1
+ IL_0006: ldloca.s V_0
+ IL_0008: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_000d: nop
+ IL_000e: nop
+ IL_000f: call void [mscorlib]System.Console::WriteLine()
+ IL_0014: nop
+ IL_0015: nop
+ IL_0016: leave.s IL_0028
+
+ } // end .try
+ finally
+ {
+ IL_0018: ldloc.0
+ IL_0019: ldc.i4.0
+ IL_001a: ceq
+ IL_001c: stloc.2
+ IL_001d: ldloc.2
+ IL_001e: brtrue.s IL_0027
+
+ IL_0020: ldloc.1
+ IL_0021: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_0026: nop
+ IL_0027: endfinally
+ } // end handler
+ IL_0028: nop
+ IL_0029: ret
+ } // end of method Lock::LockThis
+
+ .method public hidebysig instance void
+ LockOnType() cil managed
+ {
+ // Code size 51 (0x33)
+ .maxstack 2
+ .locals init (bool V_0,
+ class [mscorlib]System.Type V_1,
+ bool V_2)
+ IL_0000: nop
+ IL_0001: ldc.i4.0
+ IL_0002: stloc.0
+ .try
+ {
+ IL_0003: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ IL_0008: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+ IL_000d: dup
+ IL_000e: stloc.1
+ IL_000f: ldloca.s V_0
+ IL_0011: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_0016: nop
+ IL_0017: nop
+ IL_0018: call void [mscorlib]System.Console::WriteLine()
+ IL_001d: nop
+ IL_001e: nop
+ IL_001f: leave.s IL_0031
+
+ } // end .try
+ finally
+ {
+ IL_0021: ldloc.0
+ IL_0022: ldc.i4.0
+ IL_0023: ceq
+ IL_0025: stloc.2
+ IL_0026: ldloc.2
+ IL_0027: brtrue.s IL_0030
+
+ IL_0029: ldloc.1
+ IL_002a: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_002f: nop
+ IL_0030: endfinally
+ } // end handler
+ IL_0031: nop
+ IL_0032: ret
+ } // end of method Lock::LockOnType
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method Lock::.ctor
+
+} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file ../../../TestCases/Pretty\Lock.res
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.il
new file mode 100644
index 000000000..6f30273b4
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.il
@@ -0,0 +1,122 @@
+
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly titpuxma
+{
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
+ 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
+ .permissionset reqmin
+ = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module titpuxma.dll
+// MVID: {8B90EB29-A139-4376-848E-C5D4D42952F1}
+.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
+.imagebase 0x10000000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x02AF0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ extends [mscorlib]System.Object
+{
+ .method public hidebysig instance void
+ LockThis() cil managed
+ {
+ // Code size 30 (0x1e)
+ .maxstack 2
+ .locals init (bool V_0,
+ class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock V_1)
+ IL_0000: ldc.i4.0
+ IL_0001: stloc.0
+ .try
+ {
+ IL_0002: ldarg.0
+ IL_0003: dup
+ IL_0004: stloc.1
+ IL_0005: ldloca.s V_0
+ IL_0007: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_000c: call void [mscorlib]System.Console::WriteLine()
+ IL_0011: leave.s IL_001d
+
+ } // end .try
+ finally
+ {
+ IL_0013: ldloc.0
+ IL_0014: brfalse.s IL_001c
+
+ IL_0016: ldloc.1
+ IL_0017: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_001c: endfinally
+ } // end handler
+ IL_001d: ret
+ } // end of method Lock::LockThis
+
+ .method public hidebysig instance void
+ LockOnType() cil managed
+ {
+ // Code size 39 (0x27)
+ .maxstack 2
+ .locals init (bool V_0,
+ class [mscorlib]System.Type V_1)
+ IL_0000: ldc.i4.0
+ IL_0001: stloc.0
+ .try
+ {
+ IL_0002: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ IL_0007: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+ IL_000c: dup
+ IL_000d: stloc.1
+ IL_000e: ldloca.s V_0
+ IL_0010: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_0015: call void [mscorlib]System.Console::WriteLine()
+ IL_001a: leave.s IL_0026
+
+ } // end .try
+ finally
+ {
+ IL_001c: ldloc.0
+ IL_001d: brfalse.s IL_0025
+
+ IL_001f: ldloc.1
+ IL_0020: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_0025: endfinally
+ } // end handler
+ IL_0026: ret
+ } // end of method Lock::LockOnType
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method Lock::.ctor
+
+} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file ../../../TestCases/Pretty\Lock.opt.res
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.roslyn.il
new file mode 100644
index 000000000..44b40e105
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.opt.roslyn.il
@@ -0,0 +1,125 @@
+
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly Lock
+{
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
+ 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
+
+ .permissionset reqmin
+ = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module Lock.dll
+// MVID: {5161B18E-7152-4B49-B4A8-67524BD74953}
+.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
+.imagebase 0x10000000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x00E10000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ extends [mscorlib]System.Object
+{
+ .method public hidebysig instance void
+ LockThis() cil managed
+ {
+ // Code size 30 (0x1e)
+ .maxstack 2
+ .locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock V_0,
+ bool V_1)
+ IL_0000: ldarg.0
+ IL_0001: stloc.0
+ IL_0002: ldc.i4.0
+ IL_0003: stloc.1
+ .try
+ {
+ IL_0004: ldloc.0
+ IL_0005: ldloca.s V_1
+ IL_0007: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_000c: call void [mscorlib]System.Console::WriteLine()
+ IL_0011: leave.s IL_001d
+
+ } // end .try
+ finally
+ {
+ IL_0013: ldloc.1
+ IL_0014: brfalse.s IL_001c
+
+ IL_0016: ldloc.0
+ IL_0017: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_001c: endfinally
+ } // end handler
+ IL_001d: ret
+ } // end of method Lock::LockThis
+
+ .method public hidebysig instance void
+ LockOnType() cil managed
+ {
+ // Code size 39 (0x27)
+ .maxstack 2
+ .locals init (class [mscorlib]System.Type V_0,
+ bool V_1)
+ IL_0000: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+ IL_000a: stloc.0
+ IL_000b: ldc.i4.0
+ IL_000c: stloc.1
+ .try
+ {
+ IL_000d: ldloc.0
+ IL_000e: ldloca.s V_1
+ IL_0010: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_0015: call void [mscorlib]System.Console::WriteLine()
+ IL_001a: leave.s IL_0026
+
+ } // end .try
+ finally
+ {
+ IL_001c: ldloc.1
+ IL_001d: brfalse.s IL_0025
+
+ IL_001f: ldloc.0
+ IL_0020: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_0025: endfinally
+ } // end handler
+ IL_0026: ret
+ } // end of method Lock::LockOnType
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ } // end of method Lock::.ctor
+
+} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.roslyn.il
new file mode 100644
index 000000000..8010d6325
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Lock.roslyn.il
@@ -0,0 +1,138 @@
+
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
+ .ver 4:0:0:0
+}
+.assembly Lock
+{
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
+ 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
+
+ // --- The following custom attribute is added automatically, do not uncomment -------
+ // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
+
+ .permissionset reqmin
+ = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module Lock.dll
+// MVID: {3273D43A-61AF-4B6E-B6CF-5B3C9A7E807A}
+.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
+.imagebase 0x10000000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00000001 // ILONLY
+// Image base: 0x029B0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ extends [mscorlib]System.Object
+{
+ .method public hidebysig instance void
+ LockThis() cil managed
+ {
+ // Code size 36 (0x24)
+ .maxstack 2
+ .locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock V_0,
+ bool V_1)
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: stloc.0
+ IL_0003: ldc.i4.0
+ IL_0004: stloc.1
+ .try
+ {
+ IL_0005: ldloc.0
+ IL_0006: ldloca.s V_1
+ IL_0008: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_000d: nop
+ IL_000e: nop
+ IL_000f: call void [mscorlib]System.Console::WriteLine()
+ IL_0014: nop
+ IL_0015: nop
+ IL_0016: leave.s IL_0023
+
+ } // end .try
+ finally
+ {
+ IL_0018: ldloc.1
+ IL_0019: brfalse.s IL_0022
+
+ IL_001b: ldloc.0
+ IL_001c: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_0021: nop
+ IL_0022: endfinally
+ } // end handler
+ IL_0023: ret
+ } // end of method Lock::LockThis
+
+ .method public hidebysig instance void
+ LockOnType() cil managed
+ {
+ // Code size 45 (0x2d)
+ .maxstack 2
+ .locals init (class [mscorlib]System.Type V_0,
+ bool V_1)
+ IL_0000: nop
+ IL_0001: ldtoken ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+ IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+ IL_000b: stloc.0
+ IL_000c: ldc.i4.0
+ IL_000d: stloc.1
+ .try
+ {
+ IL_000e: ldloc.0
+ IL_000f: ldloca.s V_1
+ IL_0011: call void [mscorlib]System.Threading.Monitor::Enter(object,
+ bool&)
+ IL_0016: nop
+ IL_0017: nop
+ IL_0018: call void [mscorlib]System.Console::WriteLine()
+ IL_001d: nop
+ IL_001e: nop
+ IL_001f: leave.s IL_002c
+
+ } // end .try
+ finally
+ {
+ IL_0021: ldloc.1
+ IL_0022: brfalse.s IL_002b
+
+ IL_0024: ldloc.0
+ IL_0025: call void [mscorlib]System.Threading.Monitor::Exit(object)
+ IL_002a: nop
+ IL_002b: endfinally
+ } // end handler
+ IL_002c: ret
+ } // end of method Lock::LockOnType
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 8 (0x8)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: nop
+ IL_0007: ret
+ } // end of method Lock::.ctor
+
+} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Lock
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 2778e79d4..568236cab 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -101,6 +101,7 @@ namespace ICSharpCode.Decompiler.CSharp
PostOrderTransforms = {
//new UseExitPoints(),
new ConditionDetection(),
+ new LockTransform(),
// CachedDelegateInitialization must run after ConditionDetection and before/in LoopingBlockTransform
// and must run before NullCoalescingTransform
new CachedDelegateInitialization(),
diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
index 2d7c8a224..b015d2338 100644
--- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
@@ -245,7 +245,15 @@ namespace ICSharpCode.Decompiler.CSharp
tryCatch.CatchClauses.Add(new CatchClause { Body = faultBlock });
return tryCatch;
}
-
+
+ protected internal override Statement VisitLockInstruction(LockInstruction inst)
+ {
+ return new LockStatement {
+ Expression = exprBuilder.Translate(inst.OnExpression),
+ EmbeddedStatement = ConvertAsBlock(inst.Body)
+ };
+ }
+
protected internal override Statement VisitPinnedRegion(PinnedRegion inst)
{
var fixedStmt = new FixedStatement();
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
index 9c718b350..e0c89cfcf 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
@@ -85,11 +85,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
result = TransformFor(expressionStatement);
if (result != null)
return result;
- if (context.Settings.LockStatement) {
- result = TransformLock(expressionStatement);
- if (result != null)
- return result;
- }
if (context.Settings.AutomaticProperties) {
result = ReplaceBackingFieldUsage(expressionStatement);
if (result != null)
@@ -677,104 +672,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
#endregion
- #region lock
- static readonly AstNode lockFlagInitPattern = new ExpressionStatement(
- new AssignmentExpression(
- new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)),
- new PrimitiveExpression(false)
- ));
-
- static readonly AstNode lockTryCatchPattern = new TryCatchStatement {
- TryBlock = new BlockStatement {
- new OptionalNode(new VariableDeclarationStatement()).ToStatement(),
- new InvocationExpression(new MemberReferenceExpression(new TypeReferenceExpression(new TypePattern(typeof(System.Threading.Monitor)).ToType()), "Enter"),
- new AnyNode("enter"),
- new DirectionExpression {
- FieldDirection = FieldDirection.Ref,
- Expression = new NamedNode("flag", new IdentifierExpression(Pattern.AnyString))
- }),
- new Repeat(new AnyNode()).ToStatement()
- },
- FinallyBlock = new BlockStatement {
- new IfElseStatement {
- Condition = new Backreference("flag"),
- TrueStatement = new BlockStatement {
- new InvocationExpression(new MemberReferenceExpression(new TypeReferenceExpression(new TypePattern(typeof(System.Threading.Monitor)).ToType()), "Exit"), new AnyNode("exit"))
- }
- }
- }};
-
- static readonly AstNode oldMonitorCallPattern = new ExpressionStatement(
- new InvocationExpression(new MemberReferenceExpression(new TypeReferenceExpression(new TypePattern(typeof(System.Threading.Monitor)).ToType()), "Enter"), new AnyNode("enter"))
- );
-
- static readonly AstNode oldLockTryCatchPattern = new TryCatchStatement
- {
- TryBlock = new BlockStatement {
- new Repeat(new AnyNode()).ToStatement()
- },
- FinallyBlock = new BlockStatement {
- new InvocationExpression(new MemberReferenceExpression(new TypeReferenceExpression(new TypePattern(typeof(System.Threading.Monitor)).ToType()), "Exit"), new AnyNode("exit"))
- }
- };
-
- bool AnalyzeLockV2(ExpressionStatement node, out Expression enter, out Expression exit)
- {
- enter = null;
- exit = null;
- Match m1 = oldMonitorCallPattern.Match(node);
- if (!m1.Success) return false;
- Match m2 = oldLockTryCatchPattern.Match(node.NextSibling);
- if (!m2.Success) return false;
- enter = m1.Get("enter").Single();
- exit = m2.Get("exit").Single();
- return true;
- }
-
- bool AnalyzeLockV4(ExpressionStatement node, out Expression enter, out Expression exit)
- {
- enter = null;
- exit = null;
- Match m1 = lockFlagInitPattern.Match(node);
- if (!m1.Success) return false;
- Match m2 = lockTryCatchPattern.Match(node.NextSibling);
- if (!m2.Success) return false;
- enter = m2.Get("enter").Single();
- exit = m2.Get("exit").Single();
- return m1.Get("variable").Single().Identifier == m2.Get("flag").Single().Identifier;
- }
-
- public LockStatement TransformLock(ExpressionStatement node)
- {
- Expression enter, exit;
- bool isV2 = AnalyzeLockV2(node, out enter, out exit);
- if (isV2 || AnalyzeLockV4(node, out enter, out exit)) {
- AstNode tryCatch = node.NextSibling;
- if (!exit.IsMatch(enter)) {
- // If exit and enter are not the same, then enter must be "exit = ..."
- AssignmentExpression assign = enter as AssignmentExpression;
- if (assign == null)
- return null;
- if (!exit.IsMatch(assign.Left))
- return null;
- enter = assign.Right;
- // TODO: verify that 'obj' variable can be removed
- }
- // TODO: verify that 'flag' variable can be removed
- // transform the code into a lock statement:
- LockStatement l = new LockStatement();
- l.Expression = enter.Detach();
- l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach();
- if (!isV2) // Remove 'Enter()' call
- ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove();
- tryCatch.ReplaceWith(l);
- node.Remove(); // remove flag variable
- return l;
- }
- return null;
- }
- #endregion
-
#region switch on strings
static readonly IfElseStatement switchOnStringPattern = new IfElseStatement {
Condition = new BinaryOperatorExpression {
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 0bd21adb5..5067537a5 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -273,12 +273,14 @@
+
+
diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs
index 7c1668c89..25a4e8f03 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions.cs
@@ -73,6 +73,8 @@ namespace ICSharpCode.Decompiler.IL
TryFinally,
/// Try-fault statement
TryFault,
+ /// Lock statement
+ LockInstruction,
/// Breakpoint instruction
DebugBreak,
/// Comparison. The inputs must be both integers; or both floats; or both object references. Object references can only be compared for equality or inequality. Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which evaluates to 1 (true).
@@ -1621,6 +1623,99 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
+{
+ /// Lock statement
+ public sealed partial class LockInstruction : ILInstruction
+ {
+ public LockInstruction(ILInstruction onExpression, ILInstruction body) : base(OpCode.LockInstruction)
+ {
+ this.OnExpression = onExpression;
+ this.Body = body;
+ }
+ public static readonly SlotInfo OnExpressionSlot = new SlotInfo("OnExpression", canInlineInto: true);
+ ILInstruction onExpression;
+ public ILInstruction OnExpression {
+ get { return this.onExpression; }
+ set {
+ ValidateChild(value);
+ SetChildInstruction(ref this.onExpression, value, 0);
+ }
+ }
+ public static readonly SlotInfo BodySlot = new SlotInfo("Body");
+ ILInstruction body;
+ public ILInstruction Body {
+ get { return this.body; }
+ set {
+ ValidateChild(value);
+ SetChildInstruction(ref this.body, value, 1);
+ }
+ }
+ protected sealed override int GetChildCount()
+ {
+ return 2;
+ }
+ protected sealed override ILInstruction GetChild(int index)
+ {
+ switch (index) {
+ case 0:
+ return this.onExpression;
+ case 1:
+ return this.body;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ protected sealed override void SetChild(int index, ILInstruction value)
+ {
+ switch (index) {
+ case 0:
+ this.OnExpression = value;
+ break;
+ case 1:
+ this.Body = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ protected sealed override SlotInfo GetChildSlot(int index)
+ {
+ switch (index) {
+ case 0:
+ return OnExpressionSlot;
+ case 1:
+ return BodySlot;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ public sealed override ILInstruction Clone()
+ {
+ var clone = (LockInstruction)ShallowClone();
+ clone.OnExpression = this.onExpression.Clone();
+ clone.Body = this.body.Clone();
+ return clone;
+ }
+ public override void AcceptVisitor(ILVisitor visitor)
+ {
+ visitor.VisitLockInstruction(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor)
+ {
+ return visitor.VisitLockInstruction(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor, C context)
+ {
+ return visitor.VisitLockInstruction(this, context);
+ }
+ protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
+ {
+ var o = other as LockInstruction;
+ return o != null && this.onExpression.PerformMatch(o.onExpression, ref match) && this.body.PerformMatch(o.body, ref match);
+ }
+ }
+}
+namespace ICSharpCode.Decompiler.IL
{
/// Breakpoint instruction
public sealed partial class DebugBreak : SimpleInstruction
@@ -4188,6 +4283,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
+ protected internal virtual void VisitLockInstruction(LockInstruction inst)
+ {
+ Default(inst);
+ }
protected internal virtual void VisitDebugBreak(DebugBreak inst)
{
Default(inst);
@@ -4462,6 +4561,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
+ protected internal virtual T VisitLockInstruction(LockInstruction inst)
+ {
+ return Default(inst);
+ }
protected internal virtual T VisitDebugBreak(DebugBreak inst)
{
return Default(inst);
@@ -4736,6 +4839,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
+ protected internal virtual T VisitLockInstruction(LockInstruction inst, C context)
+ {
+ return Default(inst, context);
+ }
protected internal virtual T VisitDebugBreak(DebugBreak inst, C context)
{
return Default(inst, context);
@@ -4939,6 +5046,7 @@ namespace ICSharpCode.Decompiler.IL
"try.catch.handler",
"try.finally",
"try.fault",
+ "lock",
"debug.break",
"comp",
"call",
@@ -5069,6 +5177,18 @@ namespace ICSharpCode.Decompiler.IL
variable = default(ILVariable);
return false;
}
+ public bool MatchLockInstruction(out ILInstruction onExpression, out ILInstruction body)
+ {
+ var inst = this as LockInstruction;
+ if (inst != null) {
+ onExpression = inst.OnExpression;
+ body = inst.Body;
+ return true;
+ }
+ onExpression = default(ILInstruction);
+ body = default(ILInstruction);
+ return false;
+ }
public bool MatchDebugBreak()
{
var inst = this as DebugBreak;
diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt
index 41efe3d84..2ff5d34df 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.tt
+++ b/ICSharpCode.Decompiler/IL/Instructions.tt
@@ -116,6 +116,11 @@
BaseClass("TryInstruction"), CustomConstructor, CustomWriteTo, CustomComputeFlags,
MatchCondition("TryBlock.PerformMatch(o.TryBlock, ref match)"),
MatchCondition("faultBlock.PerformMatch(o.faultBlock, ref match)")),
+ new OpCode("lock", "Lock statement", CustomClassName("LockInstruction"),
+ CustomChildren(new [] {
+ new ArgumentInfo("onExpression"),
+ new ChildInfo("body")
+ }), CustomWriteTo, CustomComputeFlags),
new OpCode("debug.break", "Breakpoint instruction",
NoArguments, VoidResult, SideEffect),
new OpCode("comp", "Comparison. The inputs must be both integers; or both floats; or both object references. "
diff --git a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
new file mode 100644
index 000000000..815a4393d
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ICSharpCode.Decompiler.IL
+{
+ partial class LockInstruction
+ {
+ protected override InstructionFlags ComputeFlags()
+ {
+ return Body.Flags | OnExpression.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
+ }
+
+ public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
+
+ public override StackType ResultType => StackType.Void;
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write(".lock (");
+ OnExpression.WriteTo(output);
+ output.WriteLine(") {");
+ output.Indent();
+ Body.WriteTo(output);
+ output.Unindent();
+ output.WriteLine();
+ output.Write("}");
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs
new file mode 100644
index 000000000..24961dd56
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.Decompiler.IL.Transforms
+{
+ class LockTransform : IBlockTransform
+ {
+ BlockTransformContext context;
+
+ void IBlockTransform.Run(Block block, BlockTransformContext context)
+ {
+ if (!context.Settings.LockStatement) return;
+ this.context = context;
+ for (int i = block.Instructions.Count - 1; i >= 0; i--) {
+ if (!TransformLockRoslyn(block, i))
+ if (!TransformLockV4(block, i))
+ TransformLockV2(block, i);
+ }
+ }
+
+ ///
+ /// stloc lockObj(ldloc tempVar)
+ /// call Enter(ldloc tempVar)
+ /// .try BlockContainer {
+ /// Block lockBlock(incoming: 1) {
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// } finally BlockContainer {
+ /// Block exitBlock(incoming: 1) {
+ /// call Exit(ldloc lockObj)
+ /// leave exitBlock (nop)
+ /// }
+ /// }
+ /// .lock (lockObj) BlockContainer {
+ /// Block lockBlock (incoming: 1) {
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// }
+ ///
+ bool TransformLockV2(Block block, int i)
+ {
+ if (i < 2) return false;
+ if (!(block.Instructions[i] is TryFinally body) || !(block.Instructions[i - 2] is StLoc objectStore) ||
+ !objectStore.Value.MatchLdLoc(out var tempVar) || !MatchCall(block.Instructions[i - 1] as Call, "Enter", tempVar))
+ return false;
+ if (!objectStore.Variable.IsSingleDefinition)
+ return false;
+ if (!(body.TryBlock is BlockContainer tryContainer) || tryContainer.EntryPoint.Instructions.Count == 0 || tryContainer.EntryPoint.IncomingEdgeCount != 1)
+ return false;
+ if (!(body.FinallyBlock is BlockContainer finallyContainer) || !MatchExitBlock(finallyContainer.EntryPoint, null, objectStore.Variable))
+ return false;
+ context.Step("LockTransformV2", block);
+ block.Instructions.RemoveAt(i - 1);
+ block.Instructions.RemoveAt(i - 2);
+ body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock));
+ return true;
+ }
+
+ ///
+ /// stloc flag(ldc.i4 0)
+ /// .try BlockContainer {
+ /// Block lockBlock (incoming: 1) {
+ /// call Enter(stloc obj(lockObj), ldloca flag)
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// } finally BlockContainer {
+ /// Block (incoming: 1) {
+ /// if (ldloc flag) Block {
+ /// call Exit(ldloc obj)
+ /// }
+ /// leave lockBlock (nop)
+ /// }
+ /// }
+ /// =>
+ /// .lock (lockObj) BlockContainer {
+ /// Block lockBlock (incoming: 1) {
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// }
+ ///
+ bool TransformLockV4(Block block, int i)
+ {
+ if (i < 1) return false;
+ if (!(block.Instructions[i] is TryFinally body) || !(block.Instructions[i - 1] is StLoc flagStore))
+ return false;
+ if (!flagStore.Variable.Type.IsKnownType(KnownTypeCode.Boolean) || !flagStore.Value.MatchLdcI4(0))
+ return false;
+ if (!(body.TryBlock is BlockContainer tryContainer) || !MatchLockEntryPoint(tryContainer.EntryPoint, flagStore.Variable, out StLoc objectStore))
+ return false;
+ if (!(body.FinallyBlock is BlockContainer finallyContainer) || !MatchExitBlock(finallyContainer.EntryPoint, flagStore.Variable, objectStore.Variable))
+ return false;
+ context.Step("LockTransformV4", block);
+ block.Instructions.RemoveAt(i - 1);
+ tryContainer.EntryPoint.Instructions.RemoveAt(0);
+ body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock));
+ return true;
+ }
+
+ ///
+ /// stloc obj(lockObj)
+ /// stloc flag(ldc.i4 0)
+ /// .try BlockContainer {
+ /// Block lockBlock (incoming: 1) {
+ /// call Enter(ldloc obj, ldloca flag)
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// } finally BlockContainer {
+ /// Block (incoming: 1) {
+ /// if (ldloc flag) Block {
+ /// call Exit(ldloc obj)
+ /// }
+ /// leave lockBlock (nop)
+ /// }
+ /// }
+ /// =>
+ /// .lock (lockObj) BlockContainer {
+ /// Block lockBlock (incoming: 1) {
+ /// call WriteLine()
+ /// leave lockBlock (nop)
+ /// }
+ /// }
+ ///
+ bool TransformLockRoslyn(Block block, int i)
+ {
+ if (i < 2) return false;
+ if (!(block.Instructions[i] is TryFinally body) || !(block.Instructions[i - 1] is StLoc flagStore) || !(block.Instructions[i - 2] is StLoc objectStore))
+ return false;
+ if (!objectStore.Variable.IsSingleDefinition || !flagStore.Variable.Type.IsKnownType(KnownTypeCode.Boolean) || !flagStore.Value.MatchLdcI4(0))
+ return false;
+ if (!(body.TryBlock is BlockContainer tryContainer) || !MatchLockEntryPoint(tryContainer.EntryPoint, flagStore.Variable, objectStore.Variable))
+ return false;
+ if (!(body.FinallyBlock is BlockContainer finallyContainer) || !MatchExitBlock(finallyContainer.EntryPoint, flagStore.Variable, objectStore.Variable))
+ return false;
+ context.Step("LockTransformRoslyn", block);
+ block.Instructions.RemoveAt(i - 1);
+ block.Instructions.RemoveAt(i - 2);
+ tryContainer.EntryPoint.Instructions.RemoveAt(0);
+ body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock));
+ return true;
+ }
+
+ bool MatchExitBlock(Block entryPoint, ILVariable flag, ILVariable obj)
+ {
+ if (entryPoint.Instructions.Count != 2 || entryPoint.IncomingEdgeCount != 1)
+ return false;
+ if (flag != null) {
+ if (!entryPoint.Instructions[0].MatchIfInstruction(out var cond, out var trueInst) || !(trueInst is Block trueBlock))
+ return false;
+ if (!(cond.MatchLdLoc(flag) || (cond.MatchCompNotEquals(out var left, out var right) && left.MatchLdLoc(flag) && right.MatchLdcI4(0))) || !MatchExitBlock(trueBlock, obj))
+ return false;
+ } else {
+ if (!MatchCall(entryPoint.Instructions[0] as Call, "Exit", obj))
+ return false;
+ }
+ if (!entryPoint.Instructions[1].MatchLeave((BlockContainer)entryPoint.Parent, out var retVal) || !retVal.MatchNop())
+ return false;
+ return true;
+ }
+
+ bool MatchExitBlock(Block exitBlock, ILVariable obj)
+ {
+ if (exitBlock.Instructions.Count != 1)
+ return false;
+ if (!MatchCall(exitBlock.Instructions[0] as Call, "Exit", obj))
+ return false;
+ return true;
+ }
+
+ bool MatchLockEntryPoint(Block entryPoint, ILVariable flag, ILVariable obj)
+ {
+ if (entryPoint.Instructions.Count == 0 || entryPoint.IncomingEdgeCount != 1)
+ return false;
+ if (!MatchCall(entryPoint.Instructions[0] as Call, "Enter", obj, flag))
+ return false;
+ return true;
+ }
+
+ bool MatchLockEntryPoint(Block entryPoint, ILVariable flag, out StLoc obj)
+ {
+ obj = null;
+ if (entryPoint.Instructions.Count == 0 || entryPoint.IncomingEdgeCount != 1)
+ return false;
+ if (!MatchCall(entryPoint.Instructions[0] as Call, "Enter", flag, out obj))
+ return false;
+ return true;
+ }
+
+ bool MatchCall(Call call, string methodName, ILVariable flag, out StLoc obj)
+ {
+ obj = null;
+ const string ThreadingMonitor = "System.Threading.Monitor";
+ if (call == null || call.Method.Name != methodName || call.Method.DeclaringType.FullName != ThreadingMonitor ||
+ call.Method.TypeArguments.Count != 0 || call.Arguments.Count != 2)
+ return false;
+ if (!call.Arguments[1].MatchLdLoca(flag) || !(call.Arguments[0] is StLoc val))
+ return false;
+ obj = val;
+ return true;
+ }
+
+ bool MatchCall(Call call, string methodName, params ILVariable[] variables)
+ {
+ const string ThreadingMonitor = "System.Threading.Monitor";
+ if (call == null || call.Method.Name != methodName || call.Method.DeclaringType.FullName != ThreadingMonitor ||
+ call.Method.TypeArguments.Count != 0 || call.Arguments.Count != variables.Length)
+ return false;
+ if (!call.Arguments[0].MatchLdLoc(variables[0]))
+ return false;
+ if (variables.Length == 2) {
+ if (!call.Arguments[1].MatchLdLoca(variables[1]))
+ return false;
+ }
+ return true;
+ }
+ }
+}