From 4be39164af19a883feaa0f3f6033f68f3af9db58 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 | 17 -------------- .../CSharp/CodeClassDeclarationWriter.cs | 2 ++ .../Writers/CSharp/CodeMethodWriter.cs | 12 ++++------ .../Writers/CSharp/CodePropertyWriter.cs | 12 +--------- .../Writers/CSharp/CodeMethodWriterTests.cs | 22 +++++++++---------- .../Writers/CSharp/CodePropertyWriterTests.cs | 4 ++-- 6 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index f7197d2894..09ecb6bcf4 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -19,23 +19,6 @@ public class CSharpConventionService : CommonLanguageConventionService public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "IParseNode"; - public static void WriteNullableOpening(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER", false); - writer.WriteLine($"#nullable enable", false); - } - public static void WriteNullableMiddle(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"#nullable restore", false); - writer.WriteLine("#else", false); - } - public static void WriteNullableClosing(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine("#endif", false); - } public override void WriteShortDescription(string description, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); diff --git a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs index cf1c4d97da..72e328f7ae 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 8ecebe7690..fb6f4e2668 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -611,16 +611,12 @@ 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} {{"); - CSharpConventionService.WriteNullableMiddle(writer); } - - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); - - if (includeNullableReferenceType) - CSharpConventionService.WriteNullableClosing(writer); - + else + { + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + } } 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 48fef8fa98..04a30f0ceb 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.Documentation.Description, 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 341ce241d3..a08c2d353a 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs @@ -478,7 +478,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 WritesRequestGeneratorBodyForMultipart() @@ -492,7 +492,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() @@ -517,7 +517,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() @@ -530,7 +530,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() @@ -916,7 +916,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() @@ -934,7 +934,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() @@ -955,7 +955,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() @@ -973,7 +973,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 WritesRequestGeneratorBodyForScalarCollection() @@ -994,7 +994,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() @@ -1014,7 +1014,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() @@ -1044,7 +1044,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 27516fbfd2..da941dfa90 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]