diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 074902fe0..27a8e277a 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -110,6 +110,8 @@ + + diff --git a/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.cs b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.cs new file mode 100644 index 000000000..29bfd5557 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.cs @@ -0,0 +1,14 @@ +public class VBAutomaticEvents +{ + public delegate void EventWithParameterEventHandler(int EventNumber); + public delegate void EventWithoutParameterEventHandler(); + + public event EventWithParameterEventHandler EventWithParameter; + public event EventWithoutParameterEventHandler EventWithoutParameter; + + public void RaiseEvents() + { + EventWithParameter?.Invoke(1); + EventWithoutParameter?.Invoke(); + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.vb b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.vb new file mode 100644 index 000000000..361cb6b17 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.vb @@ -0,0 +1,9 @@ +Public Class VBAutomaticEvents + Event EventWithParameter(ByVal EventNumber As Integer) + Event EventWithoutParameter() + + Sub RaiseEvents() + RaiseEvent EventWithParameter(1) + RaiseEvent EventWithoutParameter() + End Sub +End Class diff --git a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs index b5db5269b..b9a609cda 100644 --- a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs @@ -1,4 +1,4 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team // // 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 @@ -125,6 +125,12 @@ namespace ICSharpCode.Decompiler.Tests await Run(options: options | CompilerOptions.Library); } + [Test] + public async Task VBAutomaticEvents([ValueSource(nameof(defaultOptions))] CompilerOptions options) + { + await Run(options: options | CompilerOptions.Library); + } + async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 087b509c0..13d9c067b 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2014 Daniel Grunwald +// Copyright (c) 2014 Daniel Grunwald // // 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 @@ -367,8 +367,16 @@ namespace ICSharpCode.Decompiler.CSharp return true; } // event-fields are not [CompilerGenerated] - if (settings.AutomaticEvents && metadata.GetTypeDefinition(field.GetDeclaringType()).GetEvents().Any(ev => metadata.GetEventDefinition(ev).Name == field.Name)) - return true; + if (settings.AutomaticEvents) + { + foreach (var ev in metadata.GetTypeDefinition(field.GetDeclaringType()).GetEvents()) + { + var eventName = metadata.GetString(metadata.GetEventDefinition(ev).Name); + var fieldName = metadata.GetString(field.Name); + if (IsEventBackingFieldName(fieldName, eventName, out _)) + return true; + } + } if (settings.ArrayInitializers && metadata.GetString(metadata.GetTypeDefinition(field.GetDeclaringType()).Name).StartsWith("", StringComparison.Ordinal)) { // only hide fields starting with '__StaticArrayInit' @@ -412,6 +420,20 @@ namespace ICSharpCode.Decompiler.CSharp return false; } + internal static bool IsEventBackingFieldName(string fieldName, string eventName, out int suffixLength) + { + suffixLength = 0; + if (fieldName == eventName) + return true; + var vbSuffixLength = "Event".Length; + if (fieldName.Length == eventName.Length + vbSuffixLength && fieldName.StartsWith(eventName, StringComparison.Ordinal) && fieldName.EndsWith("Event", StringComparison.Ordinal)) + { + suffixLength = vbSuffixLength; + return true; + } + return false; + } + static bool IsAnonymousMethodCacheField(SRM.FieldDefinition field, MetadataReader metadata) { var name = metadata.GetString(field.Name); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index ca35ea946..f9a605012 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team // // 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 @@ -763,12 +763,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms var field = mrr?.Member as IField; if (field == null) return null; - var @event = field.DeclaringType.GetEvents(ev => ev.Name == field.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault(); - if (@event != null && currentMethod.AccessorOwner != @event) + foreach (var ev in field.DeclaringType.GetEvents(null, GetMemberOptions.IgnoreInheritedMembers)) { - parent.RemoveAnnotations(); - parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, @event)); - return identifier; + if (CSharpDecompiler.IsEventBackingFieldName(field.Name, ev.Name, out int suffixLength) && + currentMethod.AccessorOwner != ev) + { + parent.RemoveAnnotations(); + parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, ev)); + if (suffixLength != 0) + identifier.Name = identifier.Name.Substring(0, identifier.Name.Length - suffixLength); + return identifier; + } } return null; } @@ -911,11 +916,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms switch (fieldExpression) { case IdentifierExpression identifier: - if (identifier.Identifier != ev.Name) + if (!CSharpDecompiler.IsEventBackingFieldName(identifier.Identifier, ev.Name, out _)) return false; break; case MemberReferenceExpression memberRef: - if (memberRef.MemberName != ev.Name) + if (!CSharpDecompiler.IsEventBackingFieldName(memberRef.MemberName, ev.Name, out _)) return false; break; default: @@ -1013,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms ed.CopyAnnotationsFrom(ev); var fieldDecl = ev.Parent?.Children.OfType() - .FirstOrDefault(fd => fd.Variables.Single().Name == ev.Name); + .FirstOrDefault(fd => CSharpDecompiler.IsEventBackingFieldName(fd.Variables.Single().Name, ev.Name, out _)); if (fieldDecl != null) { fieldDecl.Remove();