diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index e74d0d3b7..b38581f86 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -62,6 +62,8 @@
+
+
diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
index d7b6ebefb..37203d3e1 100644
--- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
@@ -54,6 +54,12 @@ namespace ICSharpCode.Decompiler.Tests
Run();
}
+ [Test]
+ public void Issue1038()
+ {
+ Run();
+ }
+
[Test]
public void Issue1047()
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.cs
new file mode 100644
index 000000000..bc89e56f4
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
+{
+ public class Issue1038 where TR : class, new()
+ {
+ public event Action TestEvent = delegate {
+ };
+ }
+}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.il
new file mode 100644
index 000000000..2cfc108f0
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1038.il
@@ -0,0 +1,125 @@
+// 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 extern System
+{
+ .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 ConsoleApp11
+{
+ .ver 1:0:0:0
+}
+.module ConsoleApp11.exe
+// MVID: {B973FCD6-A9C4-48A9-8291-26DDC248E208}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003 // WINDOWS_CUI
+.corflags 0x00020003 // ILONLY 32BITPREFERRED
+// Image base: 0x000001C4B6C90000
+
+.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2
+{
+ // Fields
+ .field private class [System.Core]System.Action`2 TestEvent
+ .field private static class [System.Core]System.Action`2 '<>f__am$cache0'
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
+
+ // Methods
+ .method public hidebysig specialname rtspecialname instance void .ctor () cil managed
+ {
+ .maxstack 8
+
+ ldarg.0
+ ldsfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::'<>f__am$cache0'
+ brtrue.s IL_0019
+
+ ldnull
+ ldftn void class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::'m__0'(!0, !1)
+ newobj instance void class [System.Core]System.Action`2::.ctor(object, native int)
+ stsfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::'<>f__am$cache0'
+
+ IL_0019: ldsfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::'<>f__am$cache0'
+ stfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::TestEvent
+ ret
+ }
+
+ .method public hidebysig specialname instance void add_TestEvent (class [System.Core]System.Action`2 'value') cil managed
+ {
+ .maxstack 3
+ .locals init (
+ [0] class [System.Core]System.Action`2,
+ [1] class [System.Core]System.Action`2
+ )
+
+ ldarg.0
+ ldfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::TestEvent
+ stloc.0
+ IL_0007: ldloc.0
+ stloc.1
+ ldarg.0
+ ldflda class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::TestEvent
+ ldloc.1
+ ldarg.1
+ call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
+ castclass class [System.Core]System.Action`2
+ ldloc.0
+ call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange>(!!0&, !!0, !!0)
+ stloc.0
+ ldloc.0
+ ldloc.1
+ bne.un IL_0007
+ ret
+ }
+
+ .method public hidebysig specialname instance void remove_TestEvent (class [System.Core]System.Action`2 'value') cil managed
+ {
+ .maxstack 3
+ .locals init (
+ [0] class [System.Core]System.Action`2,
+ [1] class [System.Core]System.Action`2
+ )
+
+ ldarg.0
+ ldfld class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::TestEvent
+ stloc.0
+ IL_0007: ldloc.0
+ stloc.1
+ ldarg.0
+ ldflda class [System.Core]System.Action`2 class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::TestEvent
+ ldloc.1
+ ldarg.1
+ call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
+ castclass class [System.Core]System.Action`2
+ ldloc.0
+ call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange>(!!0&, !!0, !!0)
+ stloc.0
+ ldloc.0
+ ldloc.1
+ bne.un IL_0007
+ ret
+ }
+
+ .method private hidebysig static void 'm__0' (!TK '', !TR '') cil managed
+ {
+ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
+ .maxstack 8
+ ret
+ }
+
+ // Events
+ .event class [System.Core]System.Action`2 TestEvent
+ {
+ .addon instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::add_TestEvent(class [System.Core]System.Action`2)
+ .removeon instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1038`2::remove_TestEvent(class [System.Core]System.Action`2)
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
index baa74e9ed..e8a19c3e7 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
@@ -633,7 +633,46 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
};
-
+
+ static readonly Accessor automaticEventPatternV4MCS = new Accessor {
+ Attributes = { new Repeat(new AnyNode()) },
+ Body = new BlockStatement {
+ new AssignmentExpression {
+ Left = new NamedNode("var1", new IdentifierExpression(Pattern.AnyString)),
+ Operator = AssignmentOperatorType.Assign,
+ Right = new NamedNode(
+ "field",
+ new MemberReferenceExpression {
+ Target = new Choice { new ThisReferenceExpression(), new TypeReferenceExpression { Type = new AnyNode() } },
+ MemberName = Pattern.AnyString
+ }
+ )
+ },
+ new DoWhileStatement {
+ EmbeddedStatement = new BlockStatement {
+ new AssignmentExpression(new NamedNode("var2", new IdentifierExpression(Pattern.AnyString)), new IdentifierExpressionBackreference("var1")),
+ new AssignmentExpression {
+ Left = new IdentifierExpressionBackreference("var1"),
+ Right = new InvocationExpression(new MemberReferenceExpression(new TypeReferenceExpression(new TypePattern(typeof(System.Threading.Interlocked)).ToType()),
+ "CompareExchange",
+ new AstType[] { new AnyNode("type") }), // type argument+
+ new Expression[] { // arguments
+ new DirectionExpression { FieldDirection = FieldDirection.Ref, Expression = new Backreference("field") },
+ new CastExpression(new Backreference("type"), new InvocationExpression(new AnyNode("delegateCombine").ToExpression(), new IdentifierExpressionBackreference("var2"), new IdentifierExpression("value"))),
+ new IdentifierExpressionBackreference("var1")
+ }
+ )
+ }
+ },
+ Condition = new BinaryOperatorExpression {
+ Left = new CastExpression(new TypePattern(typeof(object)), new IdentifierExpressionBackreference("var1")),
+ Operator = BinaryOperatorType.InEquality,
+ Right = new IdentifierExpressionBackreference("var2")
+ },
+ }
+ }
+ };
+
bool CheckAutomaticEventMatch(Match m, CustomEventDeclaration ev, bool isAddAccessor)
{
if (!m.Success)
@@ -678,10 +717,22 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
+ bool CheckAutomaticEventV4MCS(CustomEventDeclaration ev, out Match addMatch, out Match removeMatch)
+ {
+ addMatch = removeMatch = default(Match);
+ addMatch = automaticEventPatternV4MCS.Match(ev.AddAccessor);
+ if (!CheckAutomaticEventMatch(addMatch, ev, true))
+ return false;
+ removeMatch = automaticEventPatternV4MCS.Match(ev.RemoveAccessor);
+ if (!CheckAutomaticEventMatch(removeMatch, ev, false))
+ return false;
+ return true;
+ }
+
EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev)
{
Match m1, m2;
- if (!CheckAutomaticEventV4(ev, out m1, out m2) && !CheckAutomaticEventV2(ev, out m1, out m2))
+ if (!CheckAutomaticEventV4(ev, out m1, out m2) && !CheckAutomaticEventV2(ev, out m1, out m2) && !CheckAutomaticEventV4MCS(ev, out m1, out m2))
return null;
RemoveCompilerGeneratedAttribute(ev.AddAccessor.Attributes, attributeTypesToRemoveFromAutoEvents);
EventDeclaration ed = new EventDeclaration();