From a05ebad7fcfb2cc9dff6ab8760d72c647f779149 Mon Sep 17 00:00:00 2001 From: Mathias Beaulieu-Duncan Date: Mon, 20 Apr 2026 19:42:17 -0400 Subject: [PATCH] =?UTF-8?q?Fix=20CS8601=20in=20generated=20proto=E2=86=92c?= =?UTF-8?q?ommand=20list=20mappings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated CommandServiceImpl.g.cs had warnings like: Slug = request.Slug?.ToList(), // CS8601 if Slug is non-nullable List The ?. was over-defensive: proto3 repeated fields are emitted as RepeatedField in C# and are NEVER null. The conditional access made the result List? which then triggered CS8601 when assigned to a non-nullable target on the command POCO. Dropped ?. in 4 emission sites in GrpcGenerator.cs covering: - Top-level primitive list mapping (line 872) - Top-level Guid list mapping (line 861) - Nested primitive list mapping in NestedPropertyAssignment (line 1083) - Complex list .Select chain in GenerateComplexListMapping (line 974, conditional: kept ?. for value-type collections where source.Items is read off a possibly-null wrapper message) Real fix in the generator instead of CS8601 NoWarn suppression in consumer csprojs. Consumers can drop the suppression after bumping. Co-Authored-By: Claude Opus 4.7 (1M context) --- Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs b/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs index d1fd41e..49731eb 100644 --- a/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs +++ b/Svrnty.CQRS.Grpc.Generators/GrpcGenerator.cs @@ -858,7 +858,8 @@ public class GrpcGenerator : IIncrementalGenerator var constructorType = prop.FullyQualifiedType.TrimEnd('?'); return $"{indent}{prop.Name} = new {constructorType}({source}?.Items?.Select(x => System.Guid.Parse(x)).ToArray() ?? System.Array.Empty()),"; } - return $"{indent}{prop.Name} = {source}?.Select(x => System.Guid.Parse(x)).ToList(),"; + // proto repeated fields are never null — drop ?. to avoid CS8601 on assignment to non-nullable target + return $"{indent}{prop.Name} = {source}.Select(x => System.Guid.Parse(x)).ToList(),"; } else if (prop.IsValueTypeCollection) { @@ -869,7 +870,8 @@ public class GrpcGenerator : IIncrementalGenerator else { // Primitive list: just ToList() - return $"{indent}{prop.Name} = {source}?.ToList(),"; + // proto repeated fields are never null — drop ?. to avoid CS8601 on assignment to non-nullable target + return $"{indent}{prop.Name} = {source}.ToList(),"; } } @@ -969,7 +971,9 @@ public class GrpcGenerator : IIncrementalGenerator var sb = new StringBuilder(); // For value type collections, the proto message has an Items field containing the repeated elements var itemsSource = prop.IsValueTypeCollection ? $"{source}?.Items" : source; - sb.AppendLine($"{indent}{prop.Name} = {itemsSource}?.Select(x => new {prop.ElementType}"); + // Value-type wrapper messages can be null (?.Items needs ?.). Plain proto repeated is never null. + var selectAccess = prop.IsValueTypeCollection ? "?." : "."; + sb.AppendLine($"{indent}{prop.Name} = {itemsSource}{selectAccess}Select(x => new {prop.ElementType}"); sb.AppendLine($"{indent}{{"); foreach (var nestedProp in prop.ElementNestedProperties!) @@ -1078,7 +1082,8 @@ public class GrpcGenerator : IIncrementalGenerator var constructorType = prop.FullyQualifiedType.TrimEnd('?'); return $"{indent}{prop.Name} = new {constructorType}({source}?.ToArray() ?? System.Array.Empty<{prop.ElementType ?? "object"}>()),"; } - return $"{indent}{prop.Name} = {source}?.ToList(),"; + // proto repeated fields are never null — drop ?. to avoid CS8601 + return $"{indent}{prop.Name} = {source}.ToList(),"; } // Handle complex types