From 6e4a2160daae0f31d3908f34bbc5481d04b05a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Luthi?= Date: Thu, 21 Dec 2023 16:46:13 +0100 Subject: [PATCH] =?UTF-8?q?Unconditionally=20generate=20C#=C2=A0classes=20?= =?UTF-8?q?with=20nullable=20reference=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3944 --- .../Writers/CSharp/CSharpConventionService.cs | 19 +------------- .../CSharp/CodeClassDeclarationWriter.cs | 2 ++ .../Writers/CSharp/CodeMethodWriter.cs | 15 ++++------- .../Writers/CSharp/CodePropertyWriter.cs | 12 +-------- .../Writers/CSharp/CodeMethodWriterTests.cs | 26 +++++++++---------- .../Writers/CSharp/CodePropertyWriterTests.cs | 4 +-- 6 files changed, 24 insertions(+), 54 deletions(-) diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index 5a5c1309e8..03ee7febb9 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -21,23 +21,6 @@ public class CSharpConventionService : CommonLanguageConventionService public const string NullableEnableDirective = "#nullable enable"; public const string NullableRestoreDirective = "#nullable restore"; - public static void WriteNullableOpening(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER", false); - writer.WriteLine(NullableEnableDirective, false); - } - public static void WriteNullableMiddle(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine(NullableRestoreDirective, false); - writer.WriteLine("#else", false); - } - public static void WriteNullableClosing(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine("#endif", false); - } private const string ReferenceTypePrefix = ""; #pragma warning disable S1006 // Method overrides should not change parameter defaults diff --git a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs index f3431da66f..5a7728715c 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs @@ -7,6 +7,7 @@ namespace Kiota.Builder.Writers.CSharp; public class CodeClassDeclarationWriter : BaseElementWriter { public static string AutoGenerationHeader => "// "; + public static string NullableHeader => "#nullable enable"; public CodeClassDeclarationWriter(CSharpConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { @@ -17,6 +18,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent?.Parent is CodeNamespace) { writer.WriteLine(AutoGenerationHeader); + writer.WriteLine(NullableHeader); codeElement.Usings .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder .Select(static x => x.Declaration?.IsExternal ?? false ? diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs index 66d29a759f..67840faa3b 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; @@ -629,18 +629,13 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua GetParameterSignatureWithNullableRefType(p, code) : conventions.GetParameterSignature(p, code)) .ToList()); - CSharpConventionService.WriteNullableOpening(writer); writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}"); - writer.WriteLine("{"); - CSharpConventionService.WriteNullableMiddle(writer); } - - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}"); + else + { + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}"); + } writer.WriteLine("{"); - - if (includeNullableReferenceType) - CSharpConventionService.WriteNullableClosing(writer); - } private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) diff --git a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs index 07d2272db5..e1d79f7509 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs @@ -18,17 +18,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w CodePropertyKind.QueryParameter);// Other property types are appropriately constructor initialized conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); - if (isNullableReferenceType) - { - CSharpConventionService.WriteNullableOpening(writer); - WritePropertyInternal(codeElement, writer, $"{propertyType}?"); - CSharpConventionService.WriteNullableMiddle(writer); - } - - WritePropertyInternal(codeElement, writer, propertyType);// Always write the normal way - - if (isNullableReferenceType) - CSharpConventionService.WriteNullableClosing(writer); + WritePropertyInternal(codeElement, writer, isNullableReferenceType ? $"{propertyType}?" : propertyType); } private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType) diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs index ae87bd46ba..4044b2cd8f 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs @@ -479,7 +479,7 @@ public void WritesRequestExecutorBody() Assert.Contains(AsyncKeyword, result); Assert.Contains("await", result); Assert.Contains("cancellationToken", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestExecutorBodyWithUntypedReturnValue() @@ -505,7 +505,7 @@ public void WritesRequestExecutorBodyWithUntypedReturnValue() Assert.Contains(AsyncKeyword, result); Assert.Contains("await", result); Assert.Contains("cancellationToken", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyForMultipart() @@ -519,7 +519,7 @@ public void WritesRequestGeneratorBodyForMultipart() writer.Write(method); var result = tw.ToString(); Assert.Contains("SetContentFromParsable", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestExecutorBodyForCollection() @@ -544,7 +544,7 @@ public void WritesRequestExecutorBodyForCollection() Assert.Contains("SendCollectionAsync", result); Assert.Contains("return collectionResult?.ToList()", result); Assert.Contains($"{ReturnTypeName}.CreateFromDiscriminatorValue", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void DoesntCreateDictionaryOnEmptyErrorMapping() @@ -557,7 +557,7 @@ public void DoesntCreateDictionaryOnEmptyErrorMapping() var result = tw.ToString(); Assert.DoesNotContain("var errorMapping = new Dictionary>", result); Assert.Contains("default", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesModelFactoryBodyForUnionModels() @@ -943,7 +943,7 @@ public void WritesRequestExecutorBodyForCollections() var result = tw.ToString(); Assert.Contains("SendCollectionAsync", result); Assert.Contains("cancellationToken", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyForNullableScalar() @@ -961,7 +961,7 @@ public void WritesRequestGeneratorBodyForNullableScalar() Assert.Contains("requestInfo.Configure(config)", result); Assert.Contains("SetContentFromScalar", result); Assert.Contains("return requestInfo;", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyForScalar() @@ -982,7 +982,7 @@ public void WritesRequestGeneratorBodyForScalar() Assert.Contains("return requestInfo;", result); Assert.Contains("async Task", result);//verify we only have one nullable marker Assert.DoesNotContain("async Task", result);//verify we only have one nullable marker - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyForParsable() @@ -1000,7 +1000,7 @@ public void WritesRequestGeneratorBodyForParsable() Assert.Contains("requestInfo.Configure(config)", result); Assert.Contains("SetContentFromParsable", result); Assert.Contains("return requestInfo;", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyWhenUrlTemplateIsOverrode() @@ -1015,7 +1015,7 @@ public void WritesRequestGeneratorBodyWhenUrlTemplateIsOverrode() writer.Write(method); var result = tw.ToString(); Assert.Contains("var requestInfo = new RequestInformation(Method.GET, \"{baseurl+}/foo/bar\", PathParameters)", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyForScalarCollection() @@ -1036,7 +1036,7 @@ public void WritesRequestGeneratorBodyForScalarCollection() writer.Write(method); var result = tw.ToString(); Assert.Contains("SetContentFromScalarCollection", result); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyKnownRequestBodyType() @@ -1056,7 +1056,7 @@ public void WritesRequestGeneratorBodyKnownRequestBodyType() var result = tw.ToString(); Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase); Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesRequestGeneratorBodyUnknownRequestBodyType() @@ -1086,7 +1086,7 @@ public void WritesRequestGeneratorBodyUnknownRequestBodyType() Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase); Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase); - AssertExtensions.CurlyBracesAreClosed(result, 1); + AssertExtensions.CurlyBracesAreClosed(result); } [Fact] public void WritesInheritedDeSerializerBody() diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs index a12cd43520..681136e375 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs @@ -84,7 +84,7 @@ public void WritesCustomProperty() property.Kind = CodePropertyKind.Custom; writer.Write(property); var result = tw.ToString(); - Assert.Contains($"{TypeName} {PropertyName}", result); + Assert.Contains($"{TypeName}? {PropertyName}", result); Assert.Contains("get; set;", result); } [Fact] @@ -103,7 +103,7 @@ public void MapsCustomPropertiesToBackingStore() property.Kind = CodePropertyKind.Custom; writer.Write(property); var result = tw.ToString(); - Assert.Contains("get { return BackingStore?.Get(\"propertyName\"); }", result); + Assert.Contains("get { return BackingStore?.Get(\"propertyName\"); }", result); Assert.Contains("set { BackingStore?.Set(\"propertyName\", value);", result); } [Fact]