Skip to content

Commit 72bad98

Browse files
committed
make the workaround for nullability of by-ref types configurable with DefineConstants
1 parent 00ed3c9 commit 72bad98

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection.ReverseGenerating.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ SPDX-License-Identifier: MIT
1818
$(TargetFramework.StartsWith('netstandard2'))
1919
)
2020
">$(DefineConstants);CAN_OVERRIDE_CUSTOMATTRIBUTEDATA_ATTRIBUTETYPE</DefineConstants>
21+
<DefineConstants Condition="
22+
$(TargetFramework.StartsWith('net6.0'))
23+
">$(DefineConstants);WORKAROUND_NULLABILITYINFO_BYREFTYPE</DefineConstants>
2124
</PropertyGroup>
2225

2326
<Import Project="..\Sdk.net7.0-preview.props" />

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection.ReverseGenerating/CSharpTypeFormatter.FormatTypeName.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ internal readonly record struct FormatTypeNameOptions(
1414
bool TypeWithNamespace,
1515
bool WithDeclaringTypeName,
1616
bool TranslateLanguagePrimitiveType,
17+
#if SYSTEM_REFLECTION_NULLABILITYINFOCONTEXT && WORKAROUND_NULLABILITYINFO_BYREFTYPE
18+
NullabilityInfoContext? NullabilityInfoContext = null,
19+
#endif
1720
Func<Type, string, string>? GenericParameterNameModifier = null,
1821
bool OmitAttributeSuffix = false
1922
#pragma warning restore SA1313
@@ -58,6 +61,9 @@ public static string FormatTypeName(
5861
AttributeProvider: f,
5962
TypeWithNamespace: typeWithNamespace,
6063
WithDeclaringTypeName: withDeclaringTypeName,
64+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
65+
NullabilityInfoContext: nullabilityInfoContext,
66+
#endif
6167
TranslateLanguagePrimitiveType: translateLanguagePrimitiveType
6268
)
6369
).ToString();
@@ -101,6 +107,9 @@ public static string FormatTypeName(
101107
AttributeProvider: p,
102108
TypeWithNamespace: typeWithNamespace,
103109
WithDeclaringTypeName: withDeclaringTypeName,
110+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
111+
NullabilityInfoContext: nullabilityInfoContext,
112+
#endif
104113
TranslateLanguagePrimitiveType: translateLanguagePrimitiveType
105114
)
106115
).ToString();
@@ -144,6 +153,9 @@ public static string FormatTypeName(
144153
AttributeProvider: p,
145154
TypeWithNamespace: typeWithNamespace,
146155
WithDeclaringTypeName: withDeclaringTypeName,
156+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
157+
NullabilityInfoContext: nullabilityInfoContext,
158+
#endif
147159
TranslateLanguagePrimitiveType: translateLanguagePrimitiveType
148160
)
149161
).ToString();
@@ -187,6 +199,9 @@ public static string FormatTypeName(
187199
AttributeProvider: ev,
188200
TypeWithNamespace: typeWithNamespace,
189201
WithDeclaringTypeName: withDeclaringTypeName,
202+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
203+
NullabilityInfoContext: nullabilityInfoContext,
204+
#endif
190205
TranslateLanguagePrimitiveType: translateLanguagePrimitiveType
191206
)
192207
).ToString();

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection.ReverseGenerating/CSharpTypeFormatter.FormatTypeNameWithNullabilityAnnotation.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ namespace Smdn.Reflection.ReverseGenerating;
1515
#pragma warning disable IDE0040
1616
static partial class CSharpFormatter {
1717
#pragma warning restore IDE0040
18+
19+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
1820
// Workaround: The pseudo ParameterInfo type which unwraps 'ByRef' type to its element type
1921
// See https://github.com/dotnet/runtime/issues/72320
2022
private sealed class ByRefElementTypeParameterInfo : ParameterInfo {
@@ -30,6 +32,7 @@ public ByRefElementTypeParameterInfo(ParameterInfo baseParam)
3032
public override IList<CustomAttributeData> GetCustomAttributesData()
3133
=> BaseParameter.GetCustomAttributesData();
3234
}
35+
#endif
3336

3437
private static StringBuilder FormatTypeNameWithNullabilityAnnotation(
3538
NullabilityInfo target,
@@ -45,7 +48,9 @@ static string GetNullabilityAnnotation(NullabilityInfo target)
4548
: string.Empty;
4649

4750
if (target.Type.IsByRef) {
51+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
4852
var elementTypeNullabilityInfo = target.ElementType;
53+
#endif
4954

5055
if (options.AttributeProvider is ParameterInfo p) {
5156
// retval/parameter modifiers
@@ -56,20 +61,30 @@ static string GetNullabilityAnnotation(NullabilityInfo target)
5661
else /*if (p.IsRetval)*/
5762
builder.Append("ref ");
5863

64+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
5965
// [.net6.0] Currently, NullabilityInfo.ElementType is always null if the type is ByRef.
6066
// Uses the workaround implementation instead in that case.
6167
// See https://github.com/dotnet/runtime/issues/72320
62-
if (target.ElementType is null && p.ParameterType.HasElementType)
63-
elementTypeNullabilityInfo = new NullabilityInfoContext().Create(new ByRefElementTypeParameterInfo(p)); // TODO: context
68+
if (options.NullabilityInfoContext is not null && target.ElementType is null && p.ParameterType.HasElementType)
69+
elementTypeNullabilityInfo = options.NullabilityInfoContext.Create(new ByRefElementTypeParameterInfo(p));
70+
#endif
6471
}
6572

73+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
6674
if (elementTypeNullabilityInfo is not null) {
6775
return FormatTypeNameWithNullabilityAnnotation(
6876
elementTypeNullabilityInfo,
6977
builder,
7078
options
7179
);
7280
}
81+
#else
82+
return FormatTypeNameWithNullabilityAnnotation(
83+
target.ElementType!,
84+
builder,
85+
options
86+
);
87+
#endif
7388
}
7489

7590
if (target.Type.IsArray) {
@@ -115,8 +130,12 @@ static string GetNullabilityAnnotation(NullabilityInfo target)
115130
else if (isGenericTypeClosedOrDefinition) {
116131
// other generic types
117132
if (targetType.IsByRef) {
133+
#if WORKAROUND_NULLABILITYINFO_BYREFTYPE
118134
// TODO: cannot get NullabilityInfo of generic type arguments from by-ref parameter type
119135
return builder.Append(FormatTypeNameCore(targetType, options));
136+
#else
137+
return FormatTypeNameWithNullabilityAnnotation(target.ElementType!, builder, options);
138+
#endif
120139
}
121140
else {
122141
return FormatClosedGenericTypeOrGenericTypeDefinition(target, builder, options)

0 commit comments

Comments
 (0)