Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/PatternKit.Generators/ComposerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ private bool ValidateStepSignature(StepInfo step, SourceProductionContext contex

// Validate it's actually System.Func by checking namespace and name
var fullName = nextType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (!fullName.StartsWith("global::System.Func<"))
if (!fullName.StartsWith("global::System.Func<", StringComparison.Ordinal))
{
context.ReportDiagnostic(Diagnostic.Create(
InvalidStepSignatureDescriptor,
Expand Down Expand Up @@ -743,9 +743,9 @@ private bool IsAsyncMethod(IMethodSymbol method)

var fullName = namedType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
return fullName == "global::System.Threading.Tasks.Task" ||
fullName.StartsWith("global::System.Threading.Tasks.Task<") ||
fullName.StartsWith("global::System.Threading.Tasks.Task<", StringComparison.Ordinal) ||
fullName == "global::System.Threading.Tasks.ValueTask" ||
fullName.StartsWith("global::System.Threading.Tasks.ValueTask<");
fullName.StartsWith("global::System.Threading.Tasks.ValueTask<", StringComparison.Ordinal);
}

private bool IsPartial(SyntaxNode node)
Expand Down
6 changes: 3 additions & 3 deletions src/PatternKit.Generators/DecoratorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private DecoratorConfig ParseDecoratorConfig(AttributeData attribute, INamedType

// Determine default base type name
var baseName = contractSymbol.Name;
if (baseName.StartsWith("I") && baseName.Length > 1 && char.IsUpper(baseName[1]))
if (baseName.StartsWith("I", StringComparison.Ordinal) && baseName.Length > 1 && char.IsUpper(baseName[1]))
{
// Interface with I prefix: IStorage -> StorageDecoratorBase
baseName = baseName.Substring(1);
Expand Down Expand Up @@ -596,8 +596,8 @@ private static bool IsAsyncMethod(IMethodSymbol method)
var returnType = method.ReturnType;
var typeName = returnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

return typeName.StartsWith("global::System.Threading.Tasks.Task") ||
typeName.StartsWith("global::System.Threading.Tasks.ValueTask");
return typeName.StartsWith("global::System.Threading.Tasks.Task", StringComparison.Ordinal) ||
typeName.StartsWith("global::System.Threading.Tasks.ValueTask", StringComparison.Ordinal);
}

private static bool CanTypeAcceptNull(ITypeSymbol type)
Expand Down
18 changes: 9 additions & 9 deletions src/PatternKit.Generators/FacadeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ private static ImmutableArray<MethodInfo> CollectContractFirstMethods(
: contractType.ContainingNamespace.ToDisplayString();

var defaultFacadeTypeName = contractType.TypeKind == TypeKind.Interface
? (contractType.Name.StartsWith("I") ? contractType.Name.Substring(1) + "Impl" : contractType.Name + "Impl")
? (contractType.Name.StartsWith("I", StringComparison.Ordinal) ? contractType.Name.Substring(1) + "Impl" : contractType.Name + "Impl")
: contractType.Name + "Impl";

return new FacadeInfo(
Expand Down Expand Up @@ -453,15 +453,15 @@ private static bool ReturnTypesCompatible(ITypeSymbol type1, ITypeSymbol type2)
private static bool IsAsyncMethod(IMethodSymbol method)
{
var returnType = method.ReturnType.ToDisplayString();
return returnType.StartsWith("System.Threading.Tasks.Task") ||
returnType.StartsWith("System.Threading.Tasks.ValueTask");
return returnType.StartsWith("System.Threading.Tasks.Task", StringComparison.Ordinal) ||
returnType.StartsWith("System.Threading.Tasks.ValueTask", StringComparison.Ordinal);
}

private static bool IsTaskLike(ITypeSymbol type)
{
var name = type.ToDisplayString();
return name.StartsWith("System.Threading.Tasks.Task") ||
name.StartsWith("System.Threading.Tasks.ValueTask");
return name.StartsWith("System.Threading.Tasks.Task", StringComparison.Ordinal) ||
name.StartsWith("System.Threading.Tasks.ValueTask", StringComparison.Ordinal);
}

private static ITypeSymbol UnwrapTaskType(ITypeSymbol type)
Expand Down Expand Up @@ -756,11 +756,11 @@ private static void GenerateContractMethod(
{
// Handle async return types
var returnTypeStr = methodSymbol.ReturnType.ToDisplayString();
if (returnTypeStr.StartsWith("System.Threading.Tasks.ValueTask<"))
if (returnTypeStr.StartsWith("System.Threading.Tasks.ValueTask<", StringComparison.Ordinal))
{
sb.AppendLine($" return System.Threading.Tasks.ValueTask.FromResult<{GetAsyncReturnType(methodSymbol)}>(default!);");
}
else if (returnTypeStr.StartsWith("System.Threading.Tasks.Task<"))
else if (returnTypeStr.StartsWith("System.Threading.Tasks.Task<", StringComparison.Ordinal))
{
sb.AppendLine($" return System.Threading.Tasks.Task.FromResult<{GetAsyncReturnType(methodSymbol)}>(default!);");
}
Expand Down Expand Up @@ -1013,7 +1013,7 @@ private static string GenerateAutoFacade(SourceProductionContext context, Facade
var fieldName = g.Key;
// Generate parameter name: if field starts with underscore, remove it; otherwise, use field name as-is
// The parameter will be different from the field if underscore is present
var paramName = fieldName.StartsWith("_") ? fieldName.Substring(1) : fieldName;
var paramName = fieldName.StartsWith("_", StringComparison.Ordinal) ? fieldName.Substring(1) : fieldName;
var externalType = g.First().MappingMethod!.ContainingType;
var typeFullName = externalType.ToDisplayString(FullyQualifiedFormat);
return $"{typeFullName} {paramName}";
Expand All @@ -1025,7 +1025,7 @@ private static string GenerateAutoFacade(SourceProductionContext context, Facade
// Generate constructor body with null checks
// For fields without underscore, the parameter name matches the field name, requiring `this.` qualifier for disambiguation
foreach (var (fieldName, paramName) in groupedByField.Select(g =>
(g.Key, g.Key.StartsWith("_") ? g.Key.Substring(1) : g.Key)))
(g.Key, g.Key.StartsWith("_", StringComparison.Ordinal) ? g.Key.Substring(1) : g.Key)))
{
sb.AppendLine($" this.{fieldName} = {paramName} ?? throw new System.ArgumentNullException(nameof({paramName}));");
}
Expand Down
2 changes: 1 addition & 1 deletion src/PatternKit.Generators/PrototypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ private bool IsImmutableReferenceType(ITypeSymbol type)

// Check for known immutable collections (basic check)
var typeName = type.ToDisplayString();
if (typeName.StartsWith("System.Collections.Immutable."))
if (typeName.StartsWith("System.Collections.Immutable.", StringComparison.Ordinal))
return true;

// Conservative: assume mutable
Expand Down
12 changes: 6 additions & 6 deletions src/PatternKit.Generators/ProxyGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ private ProxyConfig ParseProxyConfig(AttributeData attribute, INamedTypeSymbol c

// Determine default proxy type name
var baseName = contractSymbol.Name;
if (baseName.StartsWith("I") && baseName.Length > 1 && char.IsUpper(baseName[1]))
if (baseName.StartsWith("I", StringComparison.Ordinal) && baseName.Length > 1 && char.IsUpper(baseName[1]))
{
// Interface with I prefix: IUserService -> UserServiceProxy
baseName = baseName.Substring(1);
Expand Down Expand Up @@ -592,8 +592,8 @@ private static bool IsAsyncMethod(IMethodSymbol method)
var returnType = method.ReturnType;
var typeName = returnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

return typeName.StartsWith("global::System.Threading.Tasks.Task") ||
typeName.StartsWith("global::System.Threading.Tasks.ValueTask");
return typeName.StartsWith("global::System.Threading.Tasks.Task", StringComparison.Ordinal) ||
typeName.StartsWith("global::System.Threading.Tasks.ValueTask", StringComparison.Ordinal);
}

private static bool IsGenericAsyncReturnType(IMethodSymbol method)
Expand All @@ -615,8 +615,8 @@ private static bool IsGenericAsyncReturnType(IMethodSymbol method)

return (fullName == "global::System.Threading.Tasks.Task<T>" ||
fullName == "global::System.Threading.Tasks.ValueTask<T>") ||
(namedType.Arity > 0 && (originalTypeName.StartsWith("global::System.Threading.Tasks.Task<") ||
originalTypeName.StartsWith("global::System.Threading.Tasks.ValueTask<")));
(namedType.Arity > 0 && (originalTypeName.StartsWith("global::System.Threading.Tasks.Task<", StringComparison.Ordinal) ||
originalTypeName.StartsWith("global::System.Threading.Tasks.ValueTask<", StringComparison.Ordinal)));
}

private static bool IsCancellationToken(ITypeSymbol type)
Expand Down Expand Up @@ -1490,7 +1490,7 @@ private List<string> DetermineParameterPropertyNames(List<ParameterInfo> paramet
}
else
{
propName = char.ToUpper(param.Name[0]) + (param.Name.Length > 1 ? param.Name.Substring(1) : "");
propName = char.ToUpperInvariant(param.Name[0]) + (param.Name.Length > 1 ? param.Name.Substring(1) : "");

// Avoid conflicts with reserved property names
if (usedPropNames.Contains(propName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ private static SingletonConfig ParseSingletonConfig(AttributeData attribute)
private static bool HasNameConflict(INamedTypeSymbol typeSymbol, string propertyName)
{
// Normalize verbatim identifiers by stripping leading @
var normalizedName = propertyName.StartsWith("@") ? propertyName.Substring(1) : propertyName;
var normalizedName = propertyName.StartsWith("@", StringComparison.Ordinal) ? propertyName.Substring(1) : propertyName;

// Check for existing members with the same name in declared members
if (typeSymbol.GetMembers(normalizedName).Length > 0)
Expand Down
4 changes: 2 additions & 2 deletions src/PatternKit.Generators/StateMachineGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ private ImmutableArray<HookModel> CollectExitHooks(
ulong targetValue;
try
{
targetValue = Convert.ToUInt64(constant.Value);
targetValue = Convert.ToUInt64(constant.Value, global::System.Globalization.CultureInfo.InvariantCulture);
}
catch
{
Expand All @@ -505,7 +505,7 @@ private ImmutableArray<HookModel> CollectExitHooks(

try
{
var fieldValue = Convert.ToUInt64(field.ConstantValue);
var fieldValue = Convert.ToUInt64(field.ConstantValue, global::System.Globalization.CultureInfo.InvariantCulture);
if (fieldValue == targetValue)
return field.Name;
}
Expand Down
2 changes: 1 addition & 1 deletion src/PatternKit.Generators/VisitorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static string GetDefaultVisitorInterfaceName(INamedTypeSymbol baseType)

// If base is an interface with I-prefix (Hungarian notation), don't add another I
if (baseType.TypeKind == TypeKind.Interface &&
baseName.StartsWith("I") &&
baseName.StartsWith("I", StringComparison.Ordinal) &&
baseName.Length > 1 &&
char.IsUpper(baseName[1]))
{
Expand Down
8 changes: 4 additions & 4 deletions test/PatternKit.Generators.Tests/DecoratorGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ public interface IStorage
.First(gs => gs.HintName == "TestNamespace_IStorage.Decorator.g.cs")
.SourceText.ToString();

var appleIndex = generatedSource.IndexOf("void Apple");
var bananaIndex = generatedSource.IndexOf("void Banana");
var mangoIndex = generatedSource.IndexOf("void Mango");
var zebraIndex = generatedSource.IndexOf("void Zebra");
var appleIndex = generatedSource.IndexOf("void Apple", StringComparison.Ordinal);
var bananaIndex = generatedSource.IndexOf("void Banana", StringComparison.Ordinal);
var mangoIndex = generatedSource.IndexOf("void Mango", StringComparison.Ordinal);
var zebraIndex = generatedSource.IndexOf("void Zebra", StringComparison.Ordinal);

ScenarioExpect.True(appleIndex < bananaIndex);
ScenarioExpect.True(bananaIndex < mangoIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1214,7 +1214,7 @@ public static async Task<string> Run()
var result = task.Result;

// Should either be the expected result or an error message
if (result.StartsWith("ERROR:"))
if (result.StartsWith("ERROR:", StringComparison.Ordinal))
{
ScenarioExpect.Fail($"Test threw exception: {result}");
}
Expand Down
8 changes: 4 additions & 4 deletions test/PatternKit.Generators.Tests/FacadeGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -924,10 +924,10 @@ public static void C() { }
var generatedSource = generatedSources.First().SourceText.ToString();

// Methods should appear in alphabetical order: Alpha, Charlie, Mike, Zebra
var alphaIndex = generatedSource.IndexOf("void Alpha()");
var charlieIndex = generatedSource.IndexOf("void Charlie()");
var mikeIndex = generatedSource.IndexOf("void Mike()");
var zebraIndex = generatedSource.IndexOf("void Zebra()");
var alphaIndex = generatedSource.IndexOf("void Alpha()", StringComparison.Ordinal);
var charlieIndex = generatedSource.IndexOf("void Charlie()", StringComparison.Ordinal);
var mikeIndex = generatedSource.IndexOf("void Mike()", StringComparison.Ordinal);
var zebraIndex = generatedSource.IndexOf("void Zebra()", StringComparison.Ordinal);

ScenarioExpect.True(alphaIndex < charlieIndex);
ScenarioExpect.True(charlieIndex < mikeIndex);
Expand Down
14 changes: 7 additions & 7 deletions test/PatternKit.Generators.Tests/StateMachineGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ private void OnEnterPaid() { }
ScenarioExpect.Contains("OnEnterPaid()", generatedSource);

// Verify State is updated before entry hooks
var submitIndex = generatedSource.IndexOf("State = global::PatternKit.Examples.OrderState.Submitted");
var entrySubmittedIndex = generatedSource.IndexOf("OnEnterSubmitted()");
var submitIndex = generatedSource.IndexOf("State = global::PatternKit.Examples.OrderState.Submitted", StringComparison.Ordinal);
var entrySubmittedIndex = generatedSource.IndexOf("OnEnterSubmitted()", StringComparison.Ordinal);
ScenarioExpect.True(submitIndex < entrySubmittedIndex, "State should be updated before entry hook is called");

// And the updated compilation actually compiles
Expand Down Expand Up @@ -403,8 +403,8 @@ private void OnPay() { }
ScenarioExpect.Contains("OnExitSubmitted()", generatedSource);

// Verify exit hooks are called before transition action
var exitIndex = generatedSource.IndexOf("OnExitDraft()");
var transitionIndex = generatedSource.IndexOf("OnSubmit()");
var exitIndex = generatedSource.IndexOf("OnExitDraft()", StringComparison.Ordinal);
var transitionIndex = generatedSource.IndexOf("OnSubmit()", StringComparison.Ordinal);
ScenarioExpect.True(exitIndex < transitionIndex, "Exit hook should be called before transition action");

// And the updated compilation actually compiles
Expand Down Expand Up @@ -532,8 +532,8 @@ private void OnTransition() { }

// Verify no exception is thrown for guard failures
var generatedSource = result.Results[0].GeneratedSources[0].SourceText.ToString();
var guardFailureIndex = generatedSource.IndexOf("if (!CanTransition())");
var throwIndex = generatedSource.IndexOf("throw new global::System.InvalidOperationException($\"Guard failed", guardFailureIndex);
var guardFailureIndex = generatedSource.IndexOf("if (!CanTransition())", StringComparison.Ordinal);
var throwIndex = generatedSource.IndexOf("throw new global::System.InvalidOperationException($\"Guard failed", guardFailureIndex, StringComparison.Ordinal);
ScenarioExpect.True(throwIndex == -1, "Should not throw exception on guard failure with Ignore policy");

// And the updated compilation actually compiles
Expand Down Expand Up @@ -899,7 +899,7 @@ private async ValueTask OnTransitionAsync(CancellationToken ct)
ScenarioExpect.True(hasGeneratedCode, "No code was generated");

// Check compilation diagnostics
var compDiags = updated.GetDiagnostics().Where(d => d.Id.StartsWith("PKST")).ToArray();
var compDiags = updated.GetDiagnostics().Where(d => d.Id.StartsWith("PKST", StringComparison.Ordinal)).ToArray();
ScenarioExpect.True(compDiags.Length > 0, $"No PKST diagnostics found. Generated code: {result.Results[0].GeneratedSources.Length} files");
}

Expand Down
8 changes: 4 additions & 4 deletions test/PatternKit.Generators.Tests/TemplateGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ private void Transform(ImportContext ctx)
.First(gs => gs.HintName.Contains("ImportWorkflow"))
.SourceText.ToString();

var onStartIndex = generatedSource.IndexOf("OnStart(ctx);");
var validateIndex = generatedSource.IndexOf("Validate(ctx);");
var onStartIndex = generatedSource.IndexOf("OnStart(ctx);", StringComparison.Ordinal);
var validateIndex = generatedSource.IndexOf("Validate(ctx);", StringComparison.Ordinal);
ScenarioExpect.True(onStartIndex < validateIndex, "BeforeAll hook should be called before steps");
}

Expand Down Expand Up @@ -243,8 +243,8 @@ private void OnComplete(ImportContext ctx)
.First(gs => gs.HintName.Contains("ImportWorkflow"))
.SourceText.ToString();

var transformIndex = generatedSource.LastIndexOf("Transform(ctx);");
var onCompleteIndex = generatedSource.IndexOf("OnComplete(ctx);");
var transformIndex = generatedSource.LastIndexOf("Transform(ctx);", StringComparison.Ordinal);
var onCompleteIndex = generatedSource.IndexOf("OnComplete(ctx);", StringComparison.Ordinal);
ScenarioExpect.True(transformIndex < onCompleteIndex, "AfterAll hook should be called after steps");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ public partial class ValidDerived : ValidBase { }

// Should have no generator diagnostics
var diagnostics = run.Results.SelectMany(r => r.Diagnostics)
.Where(d => d.Id.StartsWith("PKVIS"))
.Where(d => d.Id.StartsWith("PKVIS", StringComparison.Ordinal))
.ToArray();
ScenarioExpect.Empty(diagnostics);
}
Expand Down
Loading