Skip to content

Commit

Permalink
fix: reconstruct full nullable types with shorthand syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
jolexxa committed Oct 19, 2024
1 parent bc9f9ae commit 00b3e18
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: true,
Getter: static (object obj) => ((MyModel)obj).Age,
Setter: static (object obj, object? value) => ((MyModel)obj).Age = (int)value,
Setter: static (object obj, object? value) => ((MyModel)obj).Age = (int?)value,
GenericType: new GenericType(
OpenType: typeof(int),
ClosedType: typeof(int),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<int>(),
GenericTypeGetter: static receiver => receiver.Receive<int?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: true,
Getter: static (object obj) => ((MyType)obj).OptionalFloat,
Setter: static (object obj, object? value) => ((MyType)obj).OptionalFloat = (Nullable<float>)value,
Setter: static (object obj, object? value) => ((MyType)obj).OptionalFloat = (float?)value,
GenericType: new GenericType(
OpenType: typeof(Nullable<>),
ClosedType: typeof(Nullable<float>),
OpenType: typeof(float),
ClosedType: typeof(float),
IsNullable: true,
Arguments: new GenericType[] {
new GenericType(
OpenType: typeof(float),
ClosedType: typeof(float),
IsNullable: false,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<float>(),
GenericTypeGetter2: default
)
},
GenericTypeGetter: static receiver => receiver.Receive<Nullable<float>>(),
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<float?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand All @@ -103,13 +94,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: true,
Getter: static (object obj) => ((MyType)obj).OptionalInt,
Setter: static (object obj, object? value) => ((MyType)obj).OptionalInt = (int)value,
Setter: static (object obj, object? value) => ((MyType)obj).OptionalInt = (int?)value,
GenericType: new GenericType(
OpenType: typeof(int),
ClosedType: typeof(int),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<int>(),
GenericTypeGetter: static receiver => receiver.Receive<int?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: false,
Getter: static (object obj) => ((InitArgsModel)obj).Address,
Setter: static (object obj, object? value) => ((InitArgsModel)obj).Address = (string)value,
Setter: static (object obj, object? value) => ((InitArgsModel)obj).Address = (string?)value,
GenericType: new GenericType(
OpenType: typeof(string),
ClosedType: typeof(string),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<string>(),
GenericTypeGetter: static receiver => receiver.Receive<string?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down Expand Up @@ -74,7 +74,7 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
ClosedType: typeof(string),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<string>(),
GenericTypeGetter: static receiver => receiver.Receive<string?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down Expand Up @@ -172,7 +172,7 @@ public object Construct(System.Collections.Generic.IReadOnlyDictionary<string, o
args = args ?? throw new System.ArgumentNullException(nameof(args), "Constructing InitArgsModel requires init args.");
return new InitArgsModel() {
Age = args.ContainsKey("Age") ? (int)args["Age"] : default(int)!,
Description = args.ContainsKey("Description") ? (string)args["Description"] : default(string)!,
Description = args.ContainsKey("Description") ? (string?)args["Description"] : default(string?),
HasAttended = args.ContainsKey("HasAttended") ? (InitArgsEnum)args["HasAttended"] : InitArgsEnum.No,
Name = args.ContainsKey("Name") ? (string)args["Name"] : default(string)!
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: false,
Getter: static (object obj) => ((NullablePropertyTypes)obj).Age,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Age = (int)value,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Age = (int?)value,
GenericType: new GenericType(
OpenType: typeof(int),
ClosedType: typeof(int),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<int>(),
GenericTypeGetter: static receiver => receiver.Receive<int?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand All @@ -48,10 +48,10 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: false,
Getter: static (object obj) => ((NullablePropertyTypes)obj).Map,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Map = (Dictionary<int, Dictionary<string, List<object>>>)value,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Map = (Dictionary<int, Dictionary<string, List<object?>?>?>?)value,
GenericType: new GenericType(
OpenType: typeof(Dictionary<,>),
ClosedType: typeof(Dictionary<int, Dictionary<string, List<object>>>),
ClosedType: typeof(Dictionary<int, Dictionary<string, List<object?>?>?>),
IsNullable: true,
Arguments: new GenericType[] {
new GenericType(
Expand All @@ -64,7 +64,7 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
),
new GenericType(
OpenType: typeof(Dictionary<,>),
ClosedType: typeof(Dictionary<string, List<object>>),
ClosedType: typeof(Dictionary<string, List<object?>?>),
IsNullable: true,
Arguments: new GenericType[] {
new GenericType(
Expand All @@ -77,28 +77,28 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
),
new GenericType(
OpenType: typeof(List<>),
ClosedType: typeof(List<object>),
ClosedType: typeof(List<object?>),
IsNullable: true,
Arguments: new GenericType[] {
new GenericType(
OpenType: typeof(object),
ClosedType: typeof(object),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<object>(),
GenericTypeGetter: static receiver => receiver.Receive<object?>(),
GenericTypeGetter2: default
)
},
GenericTypeGetter: static receiver => receiver.Receive<List<object>>(),
GenericTypeGetter: static receiver => receiver.Receive<List<object?>?>(),
GenericTypeGetter2: default
)
},
GenericTypeGetter: static receiver => receiver.Receive<Dictionary<string, List<object>>>(),
GenericTypeGetter2: static receiver => receiver.Receive<string, List<object>>()
GenericTypeGetter: static receiver => receiver.Receive<Dictionary<string, List<object?>?>?>(),
GenericTypeGetter2: static receiver => receiver.Receive<string, List<object?>?>()
)
},
GenericTypeGetter: static receiver => receiver.Receive<Dictionary<int, Dictionary<string, List<object>>>>(),
GenericTypeGetter2: static receiver => receiver.Receive<int, Dictionary<string, List<object>>>()
GenericTypeGetter: static receiver => receiver.Receive<Dictionary<int, Dictionary<string, List<object?>?>?>?>(),
GenericTypeGetter2: static receiver => receiver.Receive<int, Dictionary<string, List<object?>?>?>()
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
[typeof(TagAttribute)] = new System.Attribute[] {
Expand All @@ -112,13 +112,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: false,
Getter: static (object obj) => ((NullablePropertyTypes)obj).Name,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Name = (string)value,
Setter: static (object obj, object? value) => ((NullablePropertyTypes)obj).Name = (string?)value,
GenericType: new GenericType(
OpenType: typeof(string),
ClosedType: typeof(string),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<string>(),
GenericTypeGetter: static receiver => receiver.Receive<string?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: true,
Getter: static (object obj) => ((NestedType)obj).OptionalFloat,
Setter: static (object obj, object? value) => ((NestedType)obj).OptionalFloat = (float)value,
Setter: static (object obj, object? value) => ((NestedType)obj).OptionalFloat = (float?)value,
GenericType: new GenericType(
OpenType: typeof(float),
ClosedType: typeof(float),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<float>(),
GenericTypeGetter: static receiver => receiver.Receive<float?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand All @@ -80,13 +80,13 @@ public class MetatypeMetadata : Chickensoft.Introspection.IMetatype {
IsRequired: false,
HasDefaultValue: true,
Getter: static (object obj) => ((NestedType)obj).OptionalInt,
Setter: static (object obj, object? value) => ((NestedType)obj).OptionalInt = (int)value,
Setter: static (object obj, object? value) => ((NestedType)obj).OptionalInt = (int?)value,
GenericType: new GenericType(
OpenType: typeof(int),
ClosedType: typeof(int),
IsNullable: true,
Arguments: System.Array.Empty<GenericType>(),
GenericTypeGetter: static receiver => receiver.Receive<int>(),
GenericTypeGetter: static receiver => receiver.Receive<int?>(),
GenericTypeGetter2: default
),
Attributes: new System.Collections.Generic.Dictionary<System.Type, System.Attribute[]>() {
Expand Down
19 changes: 5 additions & 14 deletions Chickensoft.Introspection.Generator/src/TypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -531,24 +531,15 @@ TypeDeclarationSyntax type

hasSetter = hasSetter || isInit;

var isNullable = property.Type.IsNullable();
var propType = property.Type;

var isNullable = propType.IsNullable();
propType = property.Type.UnwrapNullable();

var defaultValueExpression =
property.Initializer?.Value.NormalizeWhitespace().ToString();

var propType = property.Type;

if (property.Type is NullableTypeSyntax nullableType) {
propType = nullableType.ElementType;
}

var genericType = propType is GenericNameSyntax genericSyntax
? GenericTypeNode.Create(genericSyntax, isNullable)
: new GenericTypeNode(
Type: propType.NormalizeWhitespace().ToString(),
IsNullable: isNullable,
Children: ImmutableArray<GenericTypeNode>.Empty
);
var genericType = GenericTypeNode.Create(propType, isNullable);

properties.Add(
new DeclaredProperty(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ public void Write(IndentedTextWriter writer, string typeSimpleNameClosed) {
? $"static (object obj) => (({typeSimpleNameClosed})obj).{Name}"
: "null";

var type = GenericType.ClosedType;

var setter = HasSetter
? (
IsInit
? "null"
: $"static (object obj, object? value) => " +
$"(({typeSimpleNameClosed})obj)" +
$".{Name} = ({GenericType.ClosedType}){propertyValue}"
$".{Name} = ({type}){propertyValue}"
)
: "null";

Expand Down
15 changes: 11 additions & 4 deletions Chickensoft.Introspection.Generator/src/models/DeclaredType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,17 @@ IEnumerable<DeclaredType> baseTypes
var propStrings = allProperties
.Where(prop => prop.IsInit || prop.IsRequired)
.Select(
(prop) =>
$"{prop.Name} = args.ContainsKey(\"{prop.Name}\") " +
$"? ({prop.GenericType.ClosedType})args[\"{prop.Name}\"] : " +
$"{(prop.DefaultValueExpression is { } value ? value : $"default({prop.GenericType.ClosedType})!")}"
(prop) => {
var bang = prop.GenericType.IsNullable ? "" : "!";
return
$"{prop.Name} = args.ContainsKey(\"{prop.Name}\") " +
$"? ({prop.GenericType.ClosedType})args[\"{prop.Name}\"] : " +
$"{(
prop.DefaultValueExpression is { } value
? value
: $"default({prop.GenericType.ClosedType}){bang}"
)}";
}
);

writer.WriteCommaSeparatedList(
Expand Down
57 changes: 28 additions & 29 deletions Chickensoft.Introspection.Generator/src/models/GenericTypeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,52 +24,51 @@ ImmutableArray<GenericTypeNode> Children
/// </summary>
public string ClosedType => Type + TypeReference.GetGenerics(
Children.Select(child => child.ClosedType).ToImmutableArray()
);
) + Q;

public string OpenType =>
Type + TypeReference.GetOpenGenerics(Children.Length) + Q;

private string Q => IsNullable ? "?" : "";

/// <summary>
/// Recursively constructs a generic type node from a generic name syntax.
/// </summary>
/// <param name="genericName">Generic name syntax.</param>
/// <param name="typeSyntax">Generic name syntax.</param>
/// <returns>Generic type node tree.</returns>
public static GenericTypeNode Create(
GenericNameSyntax genericName, bool isNullable
TypeSyntax typeSyntax, bool isNullable
) {
var type = genericName.Identifier.NormalizeWhitespace().ToString();
isNullable = isNullable || typeSyntax.IsNullable();
typeSyntax = typeSyntax.UnwrapNullable();

if (typeSyntax is not GenericNameSyntax genericNameSyntax) {
return new GenericTypeNode(
typeSyntax.NormalizeWhitespace().ToString(),
IsNullable: isNullable,
Children: ImmutableArray<GenericTypeNode>.Empty
);
}

var type = genericNameSyntax.Identifier.NormalizeWhitespace().ToString();

var children = genericName.TypeArgumentList.Arguments
var children = genericNameSyntax.TypeArgumentList.Arguments
.Select(arg => {
var isNullable = false;
while (arg is NullableTypeSyntax nullableTypeSyntax) {
isNullable = true;
arg = nullableTypeSyntax.ElementType;
}
isNullable = isNullable || arg.IsNullable();
return arg switch {
GenericNameSyntax genericNameSyntax => Create(
genericNameSyntax, isNullable
),
_ => new GenericTypeNode(
arg.NormalizeWhitespace().ToString(),
IsNullable: isNullable,
ImmutableArray<GenericTypeNode>.Empty
)
};
typeSyntax = typeSyntax.UnwrapNullable();
isNullable = arg.IsNullable();
return Create(arg, isNullable);
})
.ToImmutableArray();

return new GenericTypeNode(type, isNullable, children);
}

public void Write(IndentedTextWriter writer) {
var openType = Type + TypeReference.GetOpenGenerics(Children.Length);
var closedType = Type + TypeReference.GetGenerics(
Children.Select(child => child.ClosedType).ToImmutableArray()
);

writer.WriteLine("new GenericType(");
writer.Indent++;
writer.WriteLine($"OpenType: typeof({openType.TrimEnd('?')}),");
writer.WriteLine($"ClosedType: typeof({closedType.TrimEnd('?')}),");
writer.WriteLine($"OpenType: typeof({OpenType.TrimEnd('?')}),");
writer.WriteLine($"ClosedType: typeof({ClosedType.TrimEnd('?')}),");
writer.WriteLine($"IsNullable: {(IsNullable ? "true" : "false")},");

if (Children.Length > 0) {
Expand All @@ -91,7 +90,7 @@ public void Write(IndentedTextWriter writer) {

writer.WriteLine(
"GenericTypeGetter: static receiver => " +
$"receiver.Receive<{closedType}>(),"
$"receiver.Receive<{ClosedType}>(),"
);
if (Children.Length >= 2) {
writer.WriteLine(
Expand Down
10 changes: 10 additions & 0 deletions Chickensoft.Introspection.Generator/src/utils/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ type is GenericNameSyntax generic &&
generic.Identifier.ValueText == "Nullable"
);
}

public static TypeSyntax UnwrapNullable(this TypeSyntax type) {
return type switch {
NullableTypeSyntax nullable => nullable.ElementType,
GenericNameSyntax generic
when generic.Identifier.ValueText == "Nullable" =>
generic.TypeArgumentList.Arguments.First(),
_ => type
};
}
}
Loading

0 comments on commit 00b3e18

Please sign in to comment.