Skip to content

Commit 6e4a216

Browse files
committed
Unconditionally generate C# classes with nullable reference types
Fixes #3944
1 parent 399a577 commit 6e4a216

File tree

6 files changed

+24
-54
lines changed

6 files changed

+24
-54
lines changed

src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
44
using System.Linq;
@@ -21,23 +21,6 @@ public class CSharpConventionService : CommonLanguageConventionService
2121
public const string NullableEnableDirective = "#nullable enable";
2222
public const string NullableRestoreDirective = "#nullable restore";
2323

24-
public static void WriteNullableOpening(LanguageWriter writer)
25-
{
26-
ArgumentNullException.ThrowIfNull(writer);
27-
writer.WriteLine($"#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER", false);
28-
writer.WriteLine(NullableEnableDirective, false);
29-
}
30-
public static void WriteNullableMiddle(LanguageWriter writer)
31-
{
32-
ArgumentNullException.ThrowIfNull(writer);
33-
writer.WriteLine(NullableRestoreDirective, false);
34-
writer.WriteLine("#else", false);
35-
}
36-
public static void WriteNullableClosing(LanguageWriter writer)
37-
{
38-
ArgumentNullException.ThrowIfNull(writer);
39-
writer.WriteLine("#endif", false);
40-
}
4124
private const string ReferenceTypePrefix = "<see cref=\"";
4225
private const string ReferenceTypeSuffix = "\"/>";
4326
#pragma warning disable S1006 // Method overrides should not change parameter defaults

src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace Kiota.Builder.Writers.CSharp;
77
public class CodeClassDeclarationWriter : BaseElementWriter<ClassDeclaration, CSharpConventionService>
88
{
99
public static string AutoGenerationHeader => "// <auto-generated/>";
10+
public static string NullableHeader => "#nullable enable";
1011
public CodeClassDeclarationWriter(CSharpConventionService conventionService) : base(conventionService) { }
1112
public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer)
1213
{
@@ -17,6 +18,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
1718
if (codeElement.Parent?.Parent is CodeNamespace)
1819
{
1920
writer.WriteLine(AutoGenerationHeader);
21+
writer.WriteLine(NullableHeader);
2022
codeElement.Usings
2123
.Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder
2224
.Select(static x => x.Declaration?.IsExternal ?? false ?

src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using Kiota.Builder.CodeDOM;
@@ -629,18 +629,13 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua
629629
GetParameterSignatureWithNullableRefType(p, code) :
630630
conventions.GetParameterSignature(p, code))
631631
.ToList());
632-
CSharpConventionService.WriteNullableOpening(writer);
633632
writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}");
634-
writer.WriteLine("{");
635-
CSharpConventionService.WriteNullableMiddle(writer);
636633
}
637-
638-
writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}");
634+
else
635+
{
636+
writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}");
637+
}
639638
writer.WriteLine("{");
640-
641-
if (includeNullableReferenceType)
642-
CSharpConventionService.WriteNullableClosing(writer);
643-
644639
}
645640

646641
private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement)

src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
1818
CodePropertyKind.QueryParameter);// Other property types are appropriately constructor initialized
1919
conventions.WriteShortDescription(codeElement, writer);
2020
conventions.WriteDeprecationAttribute(codeElement, writer);
21-
if (isNullableReferenceType)
22-
{
23-
CSharpConventionService.WriteNullableOpening(writer);
24-
WritePropertyInternal(codeElement, writer, $"{propertyType}?");
25-
CSharpConventionService.WriteNullableMiddle(writer);
26-
}
27-
28-
WritePropertyInternal(codeElement, writer, propertyType);// Always write the normal way
29-
30-
if (isNullableReferenceType)
31-
CSharpConventionService.WriteNullableClosing(writer);
21+
WritePropertyInternal(codeElement, writer, isNullableReferenceType ? $"{propertyType}?" : propertyType);
3222
}
3323

3424
private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType)

tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ public void WritesRequestExecutorBody()
479479
Assert.Contains(AsyncKeyword, result);
480480
Assert.Contains("await", result);
481481
Assert.Contains("cancellationToken", result);
482-
AssertExtensions.CurlyBracesAreClosed(result, 1);
482+
AssertExtensions.CurlyBracesAreClosed(result);
483483
}
484484
[Fact]
485485
public void WritesRequestExecutorBodyWithUntypedReturnValue()
@@ -505,7 +505,7 @@ public void WritesRequestExecutorBodyWithUntypedReturnValue()
505505
Assert.Contains(AsyncKeyword, result);
506506
Assert.Contains("await", result);
507507
Assert.Contains("cancellationToken", result);
508-
AssertExtensions.CurlyBracesAreClosed(result, 1);
508+
AssertExtensions.CurlyBracesAreClosed(result);
509509
}
510510
[Fact]
511511
public void WritesRequestGeneratorBodyForMultipart()
@@ -519,7 +519,7 @@ public void WritesRequestGeneratorBodyForMultipart()
519519
writer.Write(method);
520520
var result = tw.ToString();
521521
Assert.Contains("SetContentFromParsable", result);
522-
AssertExtensions.CurlyBracesAreClosed(result, 1);
522+
AssertExtensions.CurlyBracesAreClosed(result);
523523
}
524524
[Fact]
525525
public void WritesRequestExecutorBodyForCollection()
@@ -544,7 +544,7 @@ public void WritesRequestExecutorBodyForCollection()
544544
Assert.Contains("SendCollectionAsync", result);
545545
Assert.Contains("return collectionResult?.ToList()", result);
546546
Assert.Contains($"{ReturnTypeName}.CreateFromDiscriminatorValue", result);
547-
AssertExtensions.CurlyBracesAreClosed(result, 1);
547+
AssertExtensions.CurlyBracesAreClosed(result);
548548
}
549549
[Fact]
550550
public void DoesntCreateDictionaryOnEmptyErrorMapping()
@@ -557,7 +557,7 @@ public void DoesntCreateDictionaryOnEmptyErrorMapping()
557557
var result = tw.ToString();
558558
Assert.DoesNotContain("var errorMapping = new Dictionary<string, Func<IParsable>>", result);
559559
Assert.Contains("default", result);
560-
AssertExtensions.CurlyBracesAreClosed(result, 1);
560+
AssertExtensions.CurlyBracesAreClosed(result);
561561
}
562562
[Fact]
563563
public void WritesModelFactoryBodyForUnionModels()
@@ -943,7 +943,7 @@ public void WritesRequestExecutorBodyForCollections()
943943
var result = tw.ToString();
944944
Assert.Contains("SendCollectionAsync", result);
945945
Assert.Contains("cancellationToken", result);
946-
AssertExtensions.CurlyBracesAreClosed(result, 1);
946+
AssertExtensions.CurlyBracesAreClosed(result);
947947
}
948948
[Fact]
949949
public void WritesRequestGeneratorBodyForNullableScalar()
@@ -961,7 +961,7 @@ public void WritesRequestGeneratorBodyForNullableScalar()
961961
Assert.Contains("requestInfo.Configure(config)", result);
962962
Assert.Contains("SetContentFromScalar", result);
963963
Assert.Contains("return requestInfo;", result);
964-
AssertExtensions.CurlyBracesAreClosed(result, 1);
964+
AssertExtensions.CurlyBracesAreClosed(result);
965965
}
966966
[Fact]
967967
public void WritesRequestGeneratorBodyForScalar()
@@ -982,7 +982,7 @@ public void WritesRequestGeneratorBodyForScalar()
982982
Assert.Contains("return requestInfo;", result);
983983
Assert.Contains("async Task<double?>", result);//verify we only have one nullable marker
984984
Assert.DoesNotContain("async Task<double??>", result);//verify we only have one nullable marker
985-
AssertExtensions.CurlyBracesAreClosed(result, 1);
985+
AssertExtensions.CurlyBracesAreClosed(result);
986986
}
987987
[Fact]
988988
public void WritesRequestGeneratorBodyForParsable()
@@ -1000,7 +1000,7 @@ public void WritesRequestGeneratorBodyForParsable()
10001000
Assert.Contains("requestInfo.Configure(config)", result);
10011001
Assert.Contains("SetContentFromParsable", result);
10021002
Assert.Contains("return requestInfo;", result);
1003-
AssertExtensions.CurlyBracesAreClosed(result, 1);
1003+
AssertExtensions.CurlyBracesAreClosed(result);
10041004
}
10051005
[Fact]
10061006
public void WritesRequestGeneratorBodyWhenUrlTemplateIsOverrode()
@@ -1015,7 +1015,7 @@ public void WritesRequestGeneratorBodyWhenUrlTemplateIsOverrode()
10151015
writer.Write(method);
10161016
var result = tw.ToString();
10171017
Assert.Contains("var requestInfo = new RequestInformation(Method.GET, \"{baseurl+}/foo/bar\", PathParameters)", result);
1018-
AssertExtensions.CurlyBracesAreClosed(result, 1);
1018+
AssertExtensions.CurlyBracesAreClosed(result);
10191019
}
10201020
[Fact]
10211021
public void WritesRequestGeneratorBodyForScalarCollection()
@@ -1036,7 +1036,7 @@ public void WritesRequestGeneratorBodyForScalarCollection()
10361036
writer.Write(method);
10371037
var result = tw.ToString();
10381038
Assert.Contains("SetContentFromScalarCollection", result);
1039-
AssertExtensions.CurlyBracesAreClosed(result, 1);
1039+
AssertExtensions.CurlyBracesAreClosed(result);
10401040
}
10411041
[Fact]
10421042
public void WritesRequestGeneratorBodyKnownRequestBodyType()
@@ -1056,7 +1056,7 @@ public void WritesRequestGeneratorBodyKnownRequestBodyType()
10561056
var result = tw.ToString();
10571057
Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase);
10581058
Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
1059-
AssertExtensions.CurlyBracesAreClosed(result, 1);
1059+
AssertExtensions.CurlyBracesAreClosed(result);
10601060
}
10611061
[Fact]
10621062
public void WritesRequestGeneratorBodyUnknownRequestBodyType()
@@ -1086,7 +1086,7 @@ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
10861086
Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase);
10871087
Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
10881088
Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase);
1089-
AssertExtensions.CurlyBracesAreClosed(result, 1);
1089+
AssertExtensions.CurlyBracesAreClosed(result);
10901090
}
10911091
[Fact]
10921092
public void WritesInheritedDeSerializerBody()

tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public void WritesCustomProperty()
8484
property.Kind = CodePropertyKind.Custom;
8585
writer.Write(property);
8686
var result = tw.ToString();
87-
Assert.Contains($"{TypeName} {PropertyName}", result);
87+
Assert.Contains($"{TypeName}? {PropertyName}", result);
8888
Assert.Contains("get; set;", result);
8989
}
9090
[Fact]
@@ -103,7 +103,7 @@ public void MapsCustomPropertiesToBackingStore()
103103
property.Kind = CodePropertyKind.Custom;
104104
writer.Write(property);
105105
var result = tw.ToString();
106-
Assert.Contains("get { return BackingStore?.Get<SomeCustomClass>(\"propertyName\"); }", result);
106+
Assert.Contains("get { return BackingStore?.Get<SomeCustomClass?>(\"propertyName\"); }", result);
107107
Assert.Contains("set { BackingStore?.Set(\"propertyName\", value);", result);
108108
}
109109
[Fact]

0 commit comments

Comments
 (0)