Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 18, 2025

Summary

What changed?

  • Added validation for C# identifiers in [DurableTask] and [DurableEvent] attributes
  • Source generator now reports diagnostic errors (DURABLE3001/DURABLE3002) when invalid identifiers are detected (e.g., containing dots, hyphens, or spaces)
  • Code generation is skipped for tasks/events with invalid names to prevent compilation errors
  • Added analyzer release tracking files to resolve RS2008 warnings
  • Merged latest changes from main branch including new DetermineIsDurableFunctions method

Why is this change needed?

When invalid C# identifiers are used in [DurableTask(name)] attributes (e.g., "Foo.Bar"), the source generator would generate invalid code like CallFoo.BarAsync(), causing compilation errors. This change prevents that by validating names and reporting clear diagnostic errors to users.

Issues / work items


Project checklist

  • Release notes are not required for the next release
  • Backport is not required
  • All required tests have been added/updated (unit tests, E2E tests)
    • Added 18 comprehensive tests for invalid/valid identifier scenarios
  • Breaking change?
    • No - This adds validation that prevents invalid code generation. Existing valid code continues to work.

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • No
  • Yes, AI helped write parts of this PR (e.g., GitHub Copilot)
  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s): GitHub Copilot Coding Agent
  • AI-assisted areas/files:
    • src/Generators/DurableTaskSourceGenerator.cs - Added validation logic, diagnostic descriptors, resolved merge conflicts
    • test/Generators.Tests/InvalidIdentifierTests.cs - Comprehensive test coverage
    • src/Generators/AnalyzerReleases.Shipped.md and AnalyzerReleases.Unshipped.md - Documentation
  • What you changed after AI output:
    • Simplified validation logic based on code review feedback to use simple if statements
    • Changed diagnostic IDs from DURABLE1001/1002 to DURABLE3001/3002 to avoid conflicts
    • Resolved merge conflict with main branch by adopting new DetermineIsDurableFunctions method

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

Testing

Automated tests

  • Result: Passed - All 71 tests passing ✅ (61 original + 10 new from main merge)

Manual validation (only if runtime/behavior changed)

  • Environment: .NET 10.0, Windows/Linux
  • Steps + observed results:
    1. Created test project with [DurableTask("Foo.Bar")] attribute
    2. Built the project
    3. Observed diagnostic error: error DURABLE3001: The task name 'Foo.Bar' is not a valid C# identifier. Task names must start with a letter or underscore and contain only letters, digits, and underscores.
    4. No invalid code was generated
  • Evidence: See screenshot in comment

Notes for reviewers

  • Followed the restrictive approach discussed in the issue (report errors instead of attempting name sanitization)
  • Diagnostic IDs DURABLE3001/3002 were chosen to avoid conflicts with existing analyzer IDs
  • Code review feedback addressed: simplified validation logic to use straightforward if statements
  • Successfully merged with main branch, adopting new DetermineIsDurableFunctions method while preserving validation logic
Original prompt

This section details on the original issue you should resolve

<issue_title>Source generator should sanitize method names</issue_title>
<issue_description>If the "name" value of the [DurableTask(name)] attribute isn't a valid C# identifier, the source generator will still generate a method using this invalid name.

For example, defining an activity like this:

[DurableTask("Foo.Bar")]
class FooBarActivity : TaskActivityBase<object, object>
{
    // ...
}

Results in generated output like this, which doesn't compile:

public static Task<object> CallFoo.BarAsync(this TaskOrchestrationContext ctx, object input, TaskOptions? options = null)
{
    return ctx.CallActivityAsync<object>("Foo.Bar", input, options);
}

Instead, the method name should be normalized into something valid, like this:

public static Task<object> CallFooBarAsync(this TaskOrchestrationContext ctx, object input, TaskOptions? options = null)
{
    return ctx.CallActivityAsync<object>("Foo.Bar", input, options);
}
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@jviau</author><body>
How do you propose this behaves with a conflict of `[DurableTask("Foo.Bar")]` and `[DurableTask("FooBar")]`?</body></comment_new>
<comment_new><author>@cgillum</author><body>
Maybe use an underscore instead of stripping out the dot?

Or, perhaps what we should be doing is issuing an error saying that the value needs to meet the rules for valid C# identifiers rather than trying to normalize?</body></comment_new>
<comment_new><author>@jviau</author><body>
I don't have much experience with name sanitization like this. But an underscore could work. What do we do for `"Foo_Bar"` then? Double underscore?

I am also fine with being more restrictive. It may be a safer route anyways for any unforeseen issues in the future.</body></comment_new>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

- Add DiagnosticDescriptors for invalid task and event names
- Add IsValidCSharpIdentifier helper using SyntaxFacts.IsValidIdentifier
- Update DurableTaskTypeInfo and DurableEventTypeInfo to track name locations
- Report diagnostics for invalid identifiers and skip code generation
- Add comprehensive tests for various invalid identifier scenarios
- All 59 tests passing

Co-authored-by: YunchuWang <[email protected]>
Copilot AI changed the title [WIP] Fix source generator to sanitize method names Validate C# identifiers in DurableTask source generator Dec 18, 2025
Copilot AI requested a review from YunchuWang December 18, 2025 23:40
@YunchuWang
Copy link
Member

@copilot address comments

- Change diagnostic IDs from DURABLE1001/1002 to DURABLE3001/3002 to avoid conflicts with existing analyzer IDs
- Add AnalyzerReleases.Shipped.md and AnalyzerReleases.Unshipped.md for source generator diagnostics
- Update tests to use new diagnostic IDs
- Resolves RS2008 warnings about analyzer release tracking
- All 61 tests passing

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Jan 1, 2026

@copilot address comments

Addressed the issues:

  1. Fixed diagnostic ID conflicts: Changed DURABLE1001/1002 to DURABLE3001/3002 to avoid conflicts with existing analyzer diagnostic IDs in the Analyzers project
  2. Added analyzer release tracking: Created AnalyzerReleases.Shipped.md and AnalyzerReleases.Unshipped.md files to resolve RS2008 warnings
  3. Updated tests: All tests updated to use new diagnostic IDs

All 61 tests passing ✅ (commit 59e8011)

@YunchuWang YunchuWang marked this pull request as ready for review January 1, 2026 01:32
Copilot AI review requested due to automatic review settings January 1, 2026 01:32
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds validation for C# identifiers used in [DurableTask] and [DurableEvent] attribute names, preventing the source generator from producing invalid code. When an invalid identifier is detected (e.g., containing dots, hyphens, or spaces), the generator reports a diagnostic error and skips code generation for that item.

Key Changes:

  • Added identifier validation using Roslyn's SyntaxFacts.IsValidIdentifier()
  • Introduced diagnostic rules DURABLE3001 (invalid task names) and DURABLE3002 (invalid event names)
  • Extended type tracking to capture attribute name locations for precise error reporting

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/Generators/DurableTaskSourceGenerator.cs Added validation logic, diagnostic descriptors, and filtering to prevent code generation for invalid identifiers
test/Generators.Tests/InvalidIdentifierTests.cs Comprehensive test coverage for invalid/valid identifiers across tasks, orchestrators, and events
src/Generators/AnalyzerReleases.Shipped.md Added placeholder for tracking shipped analyzer releases
src/Generators/AnalyzerReleases.Unshipped.md Documented new diagnostic rules DURABLE3001 and DURABLE3002

YunchuWang and others added 2 commits December 31, 2025 17:37
- Changed foreach loops to use simple if statements instead of extracting .Where() filters
- This makes the code more straightforward and easier to read
- All 61 tests passing

Co-authored-by: YunchuWang <[email protected]>
@YunchuWang
Copy link
Member

image LGTM

@YunchuWang
Copy link
Member

@copilot update pr description to follow .github/PULL_REQUEST_TEMPLATE.md

Copy link
Contributor Author

Copilot AI commented Jan 1, 2026

@copilot update pr description to follow .github/PULL_REQUEST_TEMPLATE.md

Updated PR description to follow the template in .github/PULL_REQUEST_TEMPLATE.md.

@YunchuWang
Copy link
Member

@copilot resolve the conflict

- Resolved merge conflict in DurableTaskSourceGenerator.cs
- Kept validation logic for invalid identifiers
- Adopted new DetermineIsDurableFunctions method from main
- All 71 tests passing (61 original + 10 new from main)

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Jan 6, 2026

@copilot resolve the conflict

Resolved the merge conflict with main branch (commit 62d3af4). The conflict was in DurableTaskSourceGenerator.cs where main introduced a new DetermineIsDurableFunctions method. The merge:

  • Kept the validation logic for invalid identifiers
  • Adopted the new DetermineIsDurableFunctions method from main
  • All 71 tests passing ✅

@torosent torosent merged commit b2d9174 into main Jan 7, 2026
8 checks passed
@torosent torosent deleted the copilot/sanitize-method-names branch January 7, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Source generator should sanitize method names

3 participants