Skip to content

Commit 2051fd0

Browse files
Use StringComparer.Ordinal in source generator emission sorts (#424)
The OrderBy calls added in #413 use the default string comparer, which is culture-dependent (StringComparer.CurrentCulture). This could produce different sort orders on machines with different locale settings, breaking deterministic output. Switch to StringComparer.Ordinal for all string-based sorts in the SourceFormatter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c75c551 commit 2051fd0

3 files changed

Lines changed: 7 additions & 7 deletions

File tree

src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.Enum.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private static void FormatEnumDictionaryFactory(SourceWriter writer, string enum
5252
""");
5353

5454
writer.Indentation += 2;
55-
foreach (var member in enumTypeShape.Members.OrderBy(m => m.Key))
55+
foreach (var member in enumTypeShape.Members.OrderBy(m => m.Key, StringComparer.Ordinal))
5656
{
5757
writer.WriteLine($"""["{member.Key}"] = {member.Value},""");
5858
}

src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.TypeShapeProvider.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private static void FormatGetShapeProviderMethod(TypeShapeProviderModel provider
7171
""");
7272

7373
writer.Indentation += 2;
74-
foreach (TypeShapeModel typeModel in provider.ProvidedTypes.Values.OrderBy(t => t.SourceIdentifier))
74+
foreach (TypeShapeModel typeModel in provider.ProvidedTypes.Values.OrderBy(t => t.SourceIdentifier, StringComparer.Ordinal))
7575
{
7676
writer.WriteLine($$"""
7777
case {{FormatStringLiteral(typeModel.ReflectionName)}}:
@@ -123,7 +123,7 @@ private SourceText FormatGeneratedTypeMainFile(TypeDeclarationModel typeDeclarat
123123
writer.WriteLine($"{typeDeclaration.TypeDeclarationHeader} :");
124124
writer.WriteLine("#nullable disable annotations // Use nullable-oblivious interface implementation", disableIndentation: true);
125125
writer.Indentation++;
126-
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName))
126+
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName, StringComparer.Ordinal))
127127
{
128128
string separator = --count == 0 ? "" : ",";
129129
writer.WriteLine($"global::PolyType.IShapeable<{typeToImplement.FullyQualifiedName}>{separator}");
@@ -150,7 +150,7 @@ private SourceText FormatGeneratedTypeMainFile(TypeDeclarationModel typeDeclarat
150150

151151
if (provider.TargetSupportsIShapeableOfT)
152152
{
153-
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName))
153+
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName, StringComparer.Ordinal))
154154
{
155155
if (emittedMembers++ > 0)
156156
{
@@ -180,7 +180,7 @@ private sealed class {{LocalTypeShapeProviderName}} : global::PolyType.ITypeShap
180180

181181
writer.Indentation += 2;
182182

183-
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName))
183+
foreach (TypeId typeToImplement in typeDeclaration.ShapeableImplementations.OrderBy(t => t.FullyQualifiedName, StringComparer.Ordinal))
184184
{
185185
writer.WriteLine($$"""
186186
if (type == typeof({{typeToImplement.FullyQualifiedName}}))

src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private void AddAllSourceFiles(SourceProductionContext context, TypeShapeProvide
3434
context.CancellationToken.ThrowIfCancellationRequested();
3535
context.AddSource($"{provider.ProviderDeclaration.SourceFilenamePrefix}.g.cs", FormatTypeShapeProviderMainFile(provider));
3636

37-
foreach (TypeShapeModel type in provider.ProvidedTypes.Values.OrderBy(t => t.SourceIdentifier))
37+
foreach (TypeShapeModel type in provider.ProvidedTypes.Values.OrderBy(t => t.SourceIdentifier, StringComparer.Ordinal))
3838
{
3939
context.CancellationToken.ThrowIfCancellationRequested();
4040
context.AddSource($"{provider.ProviderDeclaration.SourceFilenamePrefix}.{type.SourceIdentifier}.g.cs", FormatProvidedType(provider, type));
@@ -289,7 +289,7 @@ private void FormatAssociatedTypesFactory(SourceWriter writer, TypeShapeModel ob
289289
""");
290290

291291
writer.Indentation += 2;
292-
foreach (AssociatedTypeId associatedType in objectShapeModel.AssociatedTypes.OrderBy(t => t.ClosedTypeReflectionName))
292+
foreach (AssociatedTypeId associatedType in objectShapeModel.AssociatedTypes.OrderBy(t => t.ClosedTypeReflectionName, StringComparer.Ordinal))
293293
{
294294
if (associatedType.OpenTypeInfo is { } openTypeInfo)
295295
{

0 commit comments

Comments
 (0)