Browse Source

Add support for VB.NET automatic events

pull/2845/head
ElektroKill 3 years ago
parent
commit
a5febb3e4f
No known key found for this signature in database
GPG Key ID: 7E3C5C084E40E3EC
  1. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 14
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.cs
  3. 9
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAutomaticEvents.vb
  4. 8
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs
  5. 28
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  6. 23
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -110,6 +110,8 @@
<Compile Include="Output\InsertParenthesesVisitorTests.cs" /> <Compile Include="Output\InsertParenthesesVisitorTests.cs" />
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" /> <Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="TestAssemblyResolver.cs" /> <Compile Include="TestAssemblyResolver.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />
<Compile Include="TestCases\VBPretty\VBAutomaticEvents.cs" />
<Compile Include="TypeSystem\ReflectionHelperTests.cs" /> <Compile Include="TypeSystem\ReflectionHelperTests.cs" />
<None Include="TestCases\Pretty\MetadataAttributes.cs" /> <None Include="TestCases\Pretty\MetadataAttributes.cs" />
<None Include="TestCases\Correctness\ComInterop.cs" /> <None Include="TestCases\Correctness\ComInterop.cs" />

14
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();
}
}

9
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

8
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 // 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 // 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); 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) async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null)
{ {
var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var vbFile = Path.Combine(TestCasePath, testName + ".vb");

28
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 // 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 // software and associated documentation files (the "Software"), to deal in the Software
@ -367,8 +367,16 @@ namespace ICSharpCode.Decompiler.CSharp
return true; return true;
} }
// event-fields are not [CompilerGenerated] // event-fields are not [CompilerGenerated]
if (settings.AutomaticEvents && metadata.GetTypeDefinition(field.GetDeclaringType()).GetEvents().Any(ev => metadata.GetEventDefinition(ev).Name == field.Name)) if (settings.AutomaticEvents)
return true; {
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("<PrivateImplementationDetails>", StringComparison.Ordinal)) if (settings.ArrayInitializers && metadata.GetString(metadata.GetTypeDefinition(field.GetDeclaringType()).Name).StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
{ {
// only hide fields starting with '__StaticArrayInit' // only hide fields starting with '__StaticArrayInit'
@ -412,6 +420,20 @@ namespace ICSharpCode.Decompiler.CSharp
return false; 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) static bool IsAnonymousMethodCacheField(SRM.FieldDefinition field, MetadataReader metadata)
{ {
var name = metadata.GetString(field.Name); var name = metadata.GetString(field.Name);

23
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 // 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 // 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; var field = mrr?.Member as IField;
if (field == null) if (field == null)
return null; return null;
var @event = field.DeclaringType.GetEvents(ev => ev.Name == field.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault(); foreach (var ev in field.DeclaringType.GetEvents(null, GetMemberOptions.IgnoreInheritedMembers))
if (@event != null && currentMethod.AccessorOwner != @event)
{ {
parent.RemoveAnnotations<MemberResolveResult>(); if (CSharpDecompiler.IsEventBackingFieldName(field.Name, ev.Name, out int suffixLength) &&
parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, @event)); currentMethod.AccessorOwner != ev)
return identifier; {
parent.RemoveAnnotations<MemberResolveResult>();
parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, ev));
if (suffixLength != 0)
identifier.Name = identifier.Name.Substring(0, identifier.Name.Length - suffixLength);
return identifier;
}
} }
return null; return null;
} }
@ -911,11 +916,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
switch (fieldExpression) switch (fieldExpression)
{ {
case IdentifierExpression identifier: case IdentifierExpression identifier:
if (identifier.Identifier != ev.Name) if (!CSharpDecompiler.IsEventBackingFieldName(identifier.Identifier, ev.Name, out _))
return false; return false;
break; break;
case MemberReferenceExpression memberRef: case MemberReferenceExpression memberRef:
if (memberRef.MemberName != ev.Name) if (!CSharpDecompiler.IsEventBackingFieldName(memberRef.MemberName, ev.Name, out _))
return false; return false;
break; break;
default: default:
@ -1013,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
ed.CopyAnnotationsFrom(ev); ed.CopyAnnotationsFrom(ev);
var fieldDecl = ev.Parent?.Children.OfType<FieldDeclaration>() var fieldDecl = ev.Parent?.Children.OfType<FieldDeclaration>()
.FirstOrDefault(fd => fd.Variables.Single().Name == ev.Name); .FirstOrDefault(fd => CSharpDecompiler.IsEventBackingFieldName(fd.Variables.Single().Name, ev.Name, out _));
if (fieldDecl != null) if (fieldDecl != null)
{ {
fieldDecl.Remove(); fieldDecl.Remove();

Loading…
Cancel
Save