Skip to content

Commit 7eb9f52

Browse files
committed
refactor
1 parent 5ae4166 commit 7eb9f52

File tree

2 files changed

+44
-35
lines changed

2 files changed

+44
-35
lines changed

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

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,26 @@ GeneratorOptions options
184184
if (options is null)
185185
throw new ArgumentNullException(nameof(options));
186186

187-
static bool HasUnmanagedConstraint(Type genericParameter)
188-
=> genericParameter.CustomAttributes.Any(
189-
static attr => attr.AttributeType.FullName.Equals("System.Runtime.CompilerServices.IsUnmanagedAttribute", StringComparison.Ordinal)
187+
static bool ConstraintTypesContainsValueType(Type genericParameter, out IEnumerable<Type> constraintTypesExceptForValueType)
188+
{
189+
var constraintTypes = genericParameter.GetGenericParameterConstraints();
190+
191+
var indexOfValueType = Array.FindIndex(
192+
constraintTypes,
193+
static t => string.Equals(t.FullName, typeof(ValueType).FullName, StringComparison.Ordinal)
190194
);
191195

192-
static bool IsValueType(Type t) => string.Equals(t.FullName, typeof(ValueType).FullName, StringComparison.Ordinal);
193-
static bool IsNotValueType(Type t) => !string.Equals(t.FullName, typeof(ValueType).FullName, StringComparison.Ordinal);
196+
if (indexOfValueType < 0) {
197+
constraintTypesExceptForValueType = constraintTypes;
198+
return false;
199+
}
200+
201+
constraintTypesExceptForValueType = constraintTypes
202+
.Take(indexOfValueType)
203+
.Concat(constraintTypes.Skip(indexOfValueType + 1));
204+
205+
return true;
206+
}
194207

195208
static IEnumerable<string> GetGenericParameterConstraintsOf(
196209
Type genericParameter,
@@ -199,53 +212,40 @@ bool typeWithNamespace
199212
)
200213
{
201214
var constraintAttrs = genericParameter.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
202-
IEnumerable<Type> constraintTypes = genericParameter.GetGenericParameterConstraints();
203-
IEnumerable<Type> constraintTypesExceptValueType = constraintTypes;
204-
205-
referencingNns?.UnionWith(constraintTypes.Where(IsNotValueType).SelectMany(CSharpFormatter.ToNamespaceList));
215+
var hasDefaultConstructorConstraint = constraintAttrs.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint);
216+
IEnumerable<Type>? constraintTypes = null;
206217

207-
if (
208-
constraintAttrs == GenericParameterAttributes.None &&
209-
genericParameter.HasGenericParameterNotNullConstraint()
210-
) {
211-
yield return "notnull";
218+
if (constraintAttrs == GenericParameterAttributes.None) {
219+
if (genericParameter.HasGenericParameterNotNullConstraint())
220+
yield return "notnull";
212221
}
222+
else if (constraintAttrs.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint)) {
223+
yield return genericParameter.HasGenericParameterUnmanagedConstraint()
224+
? "unmanaged"
225+
: "struct";
213226

214-
if (
215-
constraintAttrs.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint) &&
216-
constraintAttrs.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint) &&
217-
constraintTypes.Any(IsValueType)
218-
) {
219-
constraintAttrs &= ~GenericParameterAttributes.NotNullableValueTypeConstraint;
220-
constraintAttrs &= ~GenericParameterAttributes.DefaultConstructorConstraint;
221-
constraintTypesExceptValueType = constraintTypes.Where(IsNotValueType);
222-
223-
if (HasUnmanagedConstraint(genericParameter))
224-
yield return "unmanaged";
225-
else
226-
yield return "struct";
227+
if (hasDefaultConstructorConstraint && ConstraintTypesContainsValueType(genericParameter, out constraintTypes))
228+
hasDefaultConstructorConstraint = false; // contraint type of System.ValueType implies `new()`
227229
}
228230
else if (constraintAttrs.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint)) {
229231
yield return genericParameter.GetNullableAttributeMetadataValue() == NullableMetadataValue.Annotated
230232
? "class?"
231233
: "class";
232234
}
233-
else if (constraintAttrs.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint)) {
234-
if (HasUnmanagedConstraint(genericParameter))
235-
yield return "unmanaged";
236-
else
237-
yield return "struct";
238-
}
239235

240-
var orderedConstraintTypeNames = constraintTypesExceptValueType
236+
constraintTypes ??= genericParameter.GetGenericParameterConstraints();
237+
238+
var orderedConstraintTypeNames = constraintTypes
241239
.Select(constraintType => constraintType.FormatTypeName(typeWithNamespace: typeWithNamespace))
242240
.OrderBy(static name => name, StringComparer.Ordinal);
243241

244242
foreach (var ctn in orderedConstraintTypeNames)
245243
yield return ctn;
246244

247-
if (constraintAttrs.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
245+
if (hasDefaultConstructorConstraint)
248246
yield return "new()";
247+
248+
referencingNns?.UnionWith(constraintTypes.SelectMany(CSharpFormatter.ToNamespaceList));
249249
}
250250

251251
var constraints = string.Join(

src/Smdn.Reflection.ReverseGenerating/Smdn.Reflection/TypeGenericParameterExtensions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ private static void ValidateGenericParameterArgument(Type param, string paramNam
1818
throw new InvalidOperationException($"{paramName} must be a generic parameter or generic argument");
1919
}
2020

21+
public static bool HasGenericParameterUnmanagedConstraint(this Type genericParameter)
22+
{
23+
ValidateGenericParameterArgument(genericParameter, nameof(genericParameter));
24+
25+
return genericParameter.CustomAttributes.Any(
26+
static attr => string.Equals("System.Runtime.CompilerServices.IsUnmanagedAttribute", attr.AttributeType.FullName, StringComparison.Ordinal)
27+
);
28+
}
29+
2130
// ref: https://github.com/dotnet/roslyn/blob/main/docs/features/nullable-metadata.md#type-parameters
2231
public static bool HasGenericParameterNotNullConstraint(this Type genericParameter)
2332
{

0 commit comments

Comments
 (0)