Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 488176f

Browse files
Nullable fixes
1 parent 0ecb9ef commit 488176f

6 files changed

Lines changed: 60 additions & 31 deletions

File tree

ReQuesty.Builder/ReQuestyBuilder.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,17 +1200,6 @@ private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, Co
12001200
IndexParameter = parameter,
12011201
}];
12021202

1203-
if (!"string".Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && config.IncludeBackwardCompatible)
1204-
{ // adding a second indexer for the string version of the parameter so we keep backward compatibility
1205-
//TODO remove for v2
1206-
CodeIndexer backCompatibleValue = (CodeIndexer)result[0].Clone();
1207-
backCompatibleValue.Name += "-string";
1208-
backCompatibleValue.IndexParameter.Type = DefaultIndexerParameterType;
1209-
backCompatibleValue.Deprecation = new DeprecationInformation("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.");
1210-
backCompatibleValue.IsLegacyIndexer = true;
1211-
result.Add(backCompatibleValue);
1212-
}
1213-
12141203
return [.. result];
12151204
}
12161205
private static readonly StructuralPropertiesReservedNameProvider structuralPropertiesReservedNameProvider = new();

ReQuesty.Builder/Writers/CSharp/CSharpConventionService.cs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,36 @@ public class CSharpConventionService : CommonLanguageConventionService
1616
public const char NullableMarker = '?';
1717
public static string NullableMarkerAsString => "?";
1818
public override string ParseNodeInterfaceName => "IParseNode";
19+
public const string NullableEnableDirective = "#nullable enable";
20+
public const string NullableRestoreDirective = "#nullable restore";
1921

2022
public const string CS0618 = "CS0618";
2123
public const string CS1591 = "CS1591";
2224

23-
public void WritePragmaDisable(LanguageWriter writer, string code)
25+
public static void WriteNullableOpening(LanguageWriter writer)
26+
{
27+
ArgumentNullException.ThrowIfNull(writer);
28+
writer.WriteLine(NullableEnableDirective, false);
29+
}
30+
31+
public static void WriteNullableMiddle(LanguageWriter writer)
32+
{
33+
ArgumentNullException.ThrowIfNull(writer);
34+
writer.WriteLine(NullableRestoreDirective, false);
35+
}
36+
37+
public static void WritePragmaDisable(LanguageWriter writer, string code)
2438
{
2539
ArgumentNullException.ThrowIfNull(writer);
2640
writer.WriteLine($"#pragma warning disable {code}");
2741
}
28-
public void WritePragmaRestore(LanguageWriter writer, string code)
42+
43+
public static void WritePragmaRestore(LanguageWriter writer, string code)
2944
{
3045
ArgumentNullException.ThrowIfNull(writer);
3146
writer.WriteLine($"#pragma warning restore {code}");
3247
}
48+
3349
private const string ReferenceTypePrefix = "<see cref=\"";
3450
private const string ReferenceTypeSuffix = "\"/>";
3551
public override bool WriteShortDescription(IDocumentedElement element, LanguageWriter writer, string prefix = "<summary>", string suffix = "</summary>")
@@ -209,19 +225,24 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i
209225
{
210226
string typeName = TranslateType(currentType);
211227
string nullableSuffix = ShouldTypeHaveNullableMarker(code) ? NullableMarkerAsString : string.Empty;
212-
string collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "List<" : string.Empty;
228+
229+
string collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation
230+
? "List<"
231+
: string.Empty;
213232
string collectionSuffix = currentType.CollectionKind switch
214233
{
215234
CodeTypeCollectionKind.Complex when includeCollectionInformation => ">",
216235
CodeTypeCollectionKind.Array when includeCollectionInformation => "[]",
217236
_ => string.Empty,
218237
};
238+
219239
string genericParameters = currentType.GenericTypeParameterValues.Any() ?
220240
$"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" :
221241
string.Empty;
242+
222243
if (currentType.ActionOf && includeActionInformation)
223244
{
224-
return $"Action<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>";
245+
return $"Action<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>?";
225246
}
226247

227248
return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}";

ReQuesty.Builder/Writers/CSharp/CodeBlockEndWriter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter write
1010
if (codeElement?.Parent is CodeClass codeClass && codeClass.Parent is CodeNamespace)
1111
{
1212
writer.CloseBlock();
13-
conventions.WritePragmaRestore(writer, CSharpConventionService.CS0618);
13+
CSharpConventionService.WriteNullableMiddle(writer);
14+
CSharpConventionService.WritePragmaRestore(writer, CSharpConventionService.CS0618);
1415
}
1516
}
1617
}

ReQuesty.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace ReQuesty.Builder.Writers.CSharp;
55
public class CodeClassDeclarationWriter(CSharpConventionService conventionService) : BaseElementWriter<ClassDeclaration, CSharpConventionService>(conventionService)
66
{
77
public static string AutoGenerationHeader => "// <auto-generated/>";
8-
public static string GeneratedCodeAttribute { get; } = $"[global::System.CodeDom.Compiler.GeneratedCode(\"ReQuesty\", \"{ReQuesty.Generated.ReQuestyVersion.CurrentMajor()}\")]";
8+
public static string GeneratedCodeAttribute { get; } = $"[global::System.CodeDom.Compiler.GeneratedCode(\"ReQuesty\", \"{ReQuesty.Generated.ReQuestyVersion.Current()}\")]";
99

1010
public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer)
1111
{
@@ -19,7 +19,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
1919
if (codeElement.Parent?.Parent is CodeNamespace)
2020
{
2121
writer.WriteLine(AutoGenerationHeader);
22-
conventions.WritePragmaDisable(writer, CSharpConventionService.CS0618);
22+
CSharpConventionService.WritePragmaDisable(writer, CSharpConventionService.CS0618);
23+
CSharpConventionService.WriteNullableOpening(writer);
2324
codeElement.Usings
2425
.Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder
2526
.Select(static x => x.Declaration?.IsExternal ?? false ?
@@ -43,13 +44,13 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
4344
writer.WriteLine(GeneratedCodeAttribute);
4445
if (!hasDescription)
4546
{
46-
conventions.WritePragmaDisable(writer, CSharpConventionService.CS1591);
47+
CSharpConventionService.WritePragmaDisable(writer, CSharpConventionService.CS1591);
4748
}
4849

4950
writer.WriteLine($"{conventions.GetAccessModifier(parentClass.Access)} partial class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}");
5051
if (!hasDescription)
5152
{
52-
conventions.WritePragmaRestore(writer, CSharpConventionService.CS1591);
53+
CSharpConventionService.WritePragmaRestore(writer, CSharpConventionService.CS1591);
5354
}
5455

5556
writer.StartBlock();

ReQuesty.Builder/Writers/CSharp/CodeMethodWriter.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,12 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod
394394
.Where(static x => !x.ExistsInBaseType)
395395
.OrderBy(static x => x.Name, StringComparer.Ordinal))
396396
{
397-
writer.WriteLine($"{{ \"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},");
397+
string propName = otherProp.Name.ToFirstCharacterUpperCase();
398+
string throwIfNotNullable = otherProp.Type.IsNullable
399+
? string.Empty
400+
: $" ?? throw new NullReferenceException(\"Unexpected null value for non-nullable property: '{propName}'\")";
401+
402+
writer.WriteLine($"{{ \"{otherProp.WireName}\", n => {{ {propName} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}{throwIfNotNullable}; }} }},");
398403
}
399404
writer.CloseBlock("};");
400405
}
@@ -646,7 +651,7 @@ protected virtual void WriteCommandBuilderBody(CodeMethod codeElement, CodeClass
646651
protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElement, CodeTypeBase returnType)
647652
{
648653
ArgumentNullException.ThrowIfNull(returnType);
649-
string returnTypeName = conventions.GetTypeString(returnType, currentElement);
654+
string returnTypeName = conventions.GetTypeString(returnType, currentElement, false);
650655
bool isStream = conventions.StreamTypeName.Equals(returnTypeName, StringComparison.OrdinalIgnoreCase);
651656
bool isEnum = returnType is CodeType codeType && codeType.TypeDefinition is CodeEnum;
652657
if (isVoid)
@@ -764,10 +769,17 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua
764769
{
765770
voidCorrectedTaskReturnType = $"IEnumerable<{voidCorrectedTaskReturnType.StripArraySuffix()}>";
766771
}
772+
773+
string nullableReturnTypeSuffix = string.Empty;
774+
if (code.IsOfKind(CodeMethodKind.RequestExecutor))
775+
{
776+
nullableReturnTypeSuffix = CSharpConventionService.NullableMarkerAsString;
777+
}
778+
767779
// TODO: Task type should be moved into the refiner
768-
string completeReturnType = isConstructor ?
780+
string completeReturnType = isConstructor ?
769781
string.Empty :
770-
$"{asyncPrefix}{voidCorrectedTaskReturnType}{genericTypeSuffix} ";
782+
$"{asyncPrefix}{voidCorrectedTaskReturnType}{nullableReturnTypeSuffix}{genericTypeSuffix} ";
771783
string baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code);
772784
string parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList());
773785
string methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterUpperCase();
@@ -776,11 +788,6 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua
776788
writer.WriteLine("{");
777789
}
778790

779-
private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement)
780-
{
781-
string[] signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries);
782-
return $"{signatureSegments[0]}? {string.Join(" ", signatureSegments[1..])}";
783-
}
784791
private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod method, bool includeNullableRef = false)
785792
{
786793
bool isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None;

ReQuesty.Builder/Writers/CSharp/CodePropertyWriter.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,20 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
2121
propertyType += "?";
2222
}
2323

24-
conventions.WriteShortDescription(codeElement, writer);
24+
bool hasDescription = conventions.WriteShortDescription(codeElement, writer);
2525
conventions.WriteDeprecationAttribute(codeElement, writer);
2626

27+
if (!hasDescription)
28+
{
29+
CSharpConventionService.WritePragmaDisable(writer, CSharpConventionService.CS1591);
30+
}
31+
2732
WritePropertyInternal(codeElement, writer, propertyType);
33+
34+
if (!hasDescription)
35+
{
36+
CSharpConventionService.WritePragmaRestore(writer, CSharpConventionService.CS1591);
37+
}
2838
}
2939

3040
private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType)
@@ -37,7 +47,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ
3747
CodeProperty? backingStoreProperty = parentClass.GetBackingStoreProperty();
3848
string setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "private " : string.Empty;
3949
string simpleBody = $"get; {setterAccessModifier}set;";
40-
string defaultValue = string.Empty;
50+
string defaultValue = " = default!;";
4151
switch (codeElement.Kind)
4252
{
4353
case CodePropertyKind.RequestBuilder:

0 commit comments

Comments
 (0)