Skip to content

Commit 557a9f9

Browse files
committed
fix generating 'virtual' modifier of properties with non-public accessor
1 parent 998b82c commit 557a9f9

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection.ReverseGenerating/Generator.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,13 @@ static void AppendMethodModifiers(StringBuilder sb, MethodBase? m)
11801180
else if (m.IsVirtual && !m.IsFinal) {
11811181
sb.Append("virtual ");
11821182
}
1183+
else if (
1184+
m is MethodInfo methodMayBeAccessor &&
1185+
methodMayBeAccessor.TryGetPropertyFromAccessorMethod(out var p) &&
1186+
p.GetAccessors(nonPublic: true).Any(static a => a.IsVirtual && !a.IsFinal)
1187+
) {
1188+
sb.Append("virtual ");
1189+
}
11831190
}
11841191

11851192
var isAsyncStateMachine = m.GetCustomAttributesData().Any(

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection/MethodInfoAccessorMethodExtensions.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,41 @@
11
// SPDX-FileCopyrightText: 2022 smdn <smdn@smdn.jp>
22
// SPDX-License-Identifier: MIT
33
using System;
4+
#if NULL_STATE_STATIC_ANALYSIS_ATTRIBUTES
5+
using System.Diagnostics.CodeAnalysis;
6+
#endif
47
using System.Linq;
58
using System.Reflection;
69

710
namespace Smdn.Reflection;
811

912
internal static class MethodInfoAccessorMethodExtensions {
1013
public static bool IsPropertyAccessorMethod(this MethodInfo m)
11-
=> m is null
12-
? throw new ArgumentNullException(nameof(m))
13-
: m.DeclaringType?.GetProperties()?.FirstOrDefault(p =>
14-
m == p.GetMethod || m == p.SetMethod
15-
) != null;
14+
=> TryGetPropertyFromAccessorMethod(m, out _);
15+
16+
public static bool TryGetPropertyFromAccessorMethod(
17+
this MethodInfo accessor,
18+
#if NULL_STATE_STATIC_ANALYSIS_ATTRIBUTES
19+
[NotNullWhen(true)]
20+
#endif
21+
out PropertyInfo? property
22+
)
23+
{
24+
if (accessor is null)
25+
throw new ArgumentNullException(nameof(accessor));
26+
27+
const BindingFlags bindingFlags =
28+
BindingFlags.Instance |
29+
BindingFlags.Static |
30+
BindingFlags.Public |
31+
BindingFlags.NonPublic;
32+
33+
property = accessor.DeclaringType?.GetProperties(bindingFlags)?.FirstOrDefault(p =>
34+
accessor == p.GetMethod || accessor == p.SetMethod
35+
);
36+
37+
return property is not null;
38+
}
1639

1740
public static bool IsEventAccessorMethod(this MethodInfo m)
1841
=> m is null

tests/Smdn.Reflection.ReverseGenerating/Smdn.Reflection.ReverseGenerating/Generator.MemberDeclaration.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,33 @@ public abstract class Modifiers_NewVirtual : Modifiers_Abstract {
524524
[MemberDeclarationTestCase("new protected virtual int PProtectedVirtual { private get; set; }")] new protected virtual int PProtectedVirtual { private get; set; }
525525
}
526526

527+
public class Modifiers_Virtual_WithAccessorAccessiblity {
528+
[MemberDeclarationTestCase("public virtual int PVirtualWithPrivateGetter { private get; set; }")] public virtual int PVirtualWithPrivateGetter { private get; set; }
529+
[MemberDeclarationTestCase("public virtual int PVirtualWithPrivateSetter { get; private set; }")] public virtual int PVirtualWithPrivateSetter { get; private set; }
530+
531+
[MemberDeclarationTestCase("public virtual int PVirtual { get; }")] public virtual int PVirtual { get; }
532+
[MemberDeclarationTestCase("public virtual int PVirtualWithProtectedGetter { protected get; set; }")] public virtual int PVirtualWithProtectedGetter { protected get; set; }
533+
[MemberDeclarationTestCase("public virtual int PVirtualWithProtectedSetter { get; protected set; }")] public virtual int PVirtualWithProtectedSetter { get; protected set; }
534+
}
535+
536+
public class Modifiers_Override_WithAccessorAccessiblity : Modifiers_Virtual_WithAccessorAccessiblity {
537+
[MemberDeclarationTestCase("public override int PVirtual { get; }")] public override int PVirtual { get => throw null; }
538+
[MemberDeclarationTestCase("public override int PVirtualWithProtectedGetter { set; }")] public override int PVirtualWithProtectedGetter { set => throw null; }
539+
[MemberDeclarationTestCase("public override int PVirtualWithProtectedSetter { get; }")] public override int PVirtualWithProtectedSetter { get => throw null; }
540+
}
541+
542+
public class Modifiers_SealedOverride_WithAccessorAccessiblity : Modifiers_Virtual_WithAccessorAccessiblity {
543+
[MemberDeclarationTestCase("public sealed override int PVirtual { get; }")] public sealed override int PVirtual { get => throw null; }
544+
[MemberDeclarationTestCase("public sealed override int PVirtualWithProtectedGetter { protected get; set; }")] public sealed override int PVirtualWithProtectedGetter { protected get => throw null; set => throw null; }
545+
[MemberDeclarationTestCase("public sealed override int PVirtualWithProtectedSetter { get; protected set; }")] public sealed override int PVirtualWithProtectedSetter { get => throw null; protected set => throw null; }
546+
}
547+
548+
public class Modifiers_NewVirtual_WithAccessorAccessiblity : Modifiers_Virtual_WithAccessorAccessiblity {
549+
[MemberDeclarationTestCase("new public virtual int PVirtual { get; }")] public new virtual int PVirtual { get; }
550+
[MemberDeclarationTestCase("new public virtual int PVirtualWithProtectedGetter { private get; set; }")] new public virtual int PVirtualWithProtectedGetter { /* changes accessibility */ private get; set; }
551+
[MemberDeclarationTestCase("new public virtual int PVirtualWithProtectedSetter { get; private set; }")] public new virtual int PVirtualWithProtectedSetter { get; /* changes accessibility */ private set; }
552+
}
553+
527554
public class Indexers1 {
528555
[IndexerName("Indexer")]
529556
[MemberDeclarationTestCase("public int this[int x] { get; set; }")]

0 commit comments

Comments
 (0)