-
Notifications
You must be signed in to change notification settings - Fork 6
Better validation #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -139,10 +139,11 @@ private static bool IsWorkerInvocation(SyntaxNode node) | |||||||||||||||||||||||||||||||||||||||
| private static bool AnalyzeDelegate(GeneratorSyntaxContext context, ExpressionSyntax delegateExpression, WorkerInvocationModel model) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| var typeInfo = context.SemanticModel.GetTypeInfo(delegateExpression); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| var location = delegateExpression.GetLocation(); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Try to get the actual delegate type, not just the converted type | ||||||||||||||||||||||||||||||||||||||||
| INamedTypeSymbol? delegateType = null; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (typeInfo.Type is INamedTypeSymbol namedType && namedType.DelegateInvokeMethod != null) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| delegateType = namedType; | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -151,7 +152,7 @@ private static bool AnalyzeDelegate(GeneratorSyntaxContext context, ExpressionSy | |||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| delegateType = convertedNamedType; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (delegateType == null) | ||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -167,7 +168,7 @@ private static bool AnalyzeDelegate(GeneratorSyntaxContext context, ExpressionSy | |||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| Name = param.Name, | ||||||||||||||||||||||||||||||||||||||||
| Type = param.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), | ||||||||||||||||||||||||||||||||||||||||
| IsCancellationToken = param.Type.Name == "CancellationToken" && | ||||||||||||||||||||||||||||||||||||||||
| IsCancellationToken = param.Type.Name == "CancellationToken" && | ||||||||||||||||||||||||||||||||||||||||
| param.Type.ContainingNamespace?.ToDisplayString() == "System.Threading" | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -177,20 +178,34 @@ private static bool AnalyzeDelegate(GeneratorSyntaxContext context, ExpressionSy | |||||||||||||||||||||||||||||||||||||||
| model.Parameters.Add(paramModel); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Validate only one CancellationToken | ||||||||||||||||||||||||||||||||||||||||
| // Validate only one CancellationToken - report MW0001 | ||||||||||||||||||||||||||||||||||||||||
| if (cancellationTokenCount > 1) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| model.Diagnostics.Add(new DiagnosticInfo | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| Descriptor = Diagnostics.MultipleCancellationTokens, | ||||||||||||||||||||||||||||||||||||||||
| Location = location | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| model.HasErrors = true; | ||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Determine return type | ||||||||||||||||||||||||||||||||||||||||
| var returnType = invokeMethod.ReturnType; | ||||||||||||||||||||||||||||||||||||||||
| model.IsAsync = returnType.Name == "Task" || returnType.Name == "ValueTask"; | ||||||||||||||||||||||||||||||||||||||||
| model.ReturnType = returnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Ensure Task or void for now (simplification) | ||||||||||||||||||||||||||||||||||||||||
| // Ensure Task or void for now (simplification) - report MW0002 | ||||||||||||||||||||||||||||||||||||||||
| if (model.ReturnType != "void" && | ||||||||||||||||||||||||||||||||||||||||
| !model.ReturnType.Contains("Task") && | ||||||||||||||||||||||||||||||||||||||||
| !model.ReturnType.Contains("ValueTask")) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| model.Diagnostics.Add(new DiagnosticInfo | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| Descriptor = Diagnostics.InvalidReturnType, | ||||||||||||||||||||||||||||||||||||||||
| Location = location | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| model.HasErrors = true; | ||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -207,6 +222,21 @@ private static bool AnalyzeDelegate(GeneratorSyntaxContext context, ExpressionSy | |||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| private static void Execute(SourceProductionContext context, ImmutableArray<WorkerInvocationModel> workers) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| // Report all collected diagnostics first | ||||||||||||||||||||||||||||||||||||||||
| foreach (var worker in workers) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| if (worker?.Diagnostics != null) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| foreach (var diag in worker.Diagnostics) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| context.ReportDiagnostic(Diagnostic.Create( | ||||||||||||||||||||||||||||||||||||||||
| diag.Descriptor, | ||||||||||||||||||||||||||||||||||||||||
| diag.Location, | ||||||||||||||||||||||||||||||||||||||||
| diag.MessageArgs ?? System.Array.Empty<object>())); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+226
to
+236
|
||||||||||||||||||||||||||||||||||||||||
| foreach (var worker in workers) | |
| { | |
| if (worker?.Diagnostics != null) | |
| { | |
| foreach (var diag in worker.Diagnostics) | |
| { | |
| context.ReportDiagnostic(Diagnostic.Create( | |
| diag.Descriptor, | |
| diag.Location, | |
| diag.MessageArgs ?? System.Array.Empty<object>())); | |
| } | |
| foreach (var worker in workers.Where(w => w?.Diagnostics != null)) | |
| { | |
| foreach (var diag in worker.Diagnostics!) | |
| { | |
| context.ReportDiagnostic(Diagnostic.Create( | |
| diag.Descriptor, | |
| diag.Location, | |
| diag.MessageArgs ?? System.Array.Empty<object>())); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -290,6 +290,9 @@ public static IWorkerBuilder RunBackgroundWorker(this IHost host, Delegate actio | |||||
| /// </example> | ||||||
| public static IWorkerBuilder RunPeriodicBackgroundWorker(this IHost host, TimeSpan timespan, Delegate action) | ||||||
| { | ||||||
| if (timespan <= TimeSpan.Zero) | ||||||
| throw new ArgumentOutOfRangeException(nameof(timespan), timespan, "TimeSpan must be greater than zero."); | ||||||
|
|
||||||
| var id = System.Threading.Interlocked.Increment(ref _registrationCounter); | ||||||
| var parameters = action.Method.GetParameters(); | ||||||
| var signature = string.Join(",", parameters.Select(p => FormatTypeName(p.ParameterType))); | ||||||
|
|
@@ -343,6 +346,9 @@ public static IWorkerBuilder RunPeriodicBackgroundWorker(this IHost host, TimeSp | |||||
| /// </example> | ||||||
| public static IWorkerBuilder RunCronBackgroundWorker(this IHost host, string cronExpression, Delegate action) | ||||||
| { | ||||||
| if (string.IsNullOrWhiteSpace(cronExpression)) | ||||||
| throw new ArgumentException("Cron expression cannot be null or empty.", nameof(cronExpression)); | ||||||
|
||||||
| throw new ArgumentException("Cron expression cannot be null or empty.", nameof(cronExpression)); | |
| throw new ArgumentException("Cron expression cannot be null, empty, or whitespace.", nameof(cronExpression)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is titled "Better validation", but this change expands Claude tool permissions (ls/publish). If this is intentional, it should be called out in the PR description; otherwise consider moving it to a separate PR to keep the scope focused.