Skip to content

Add AZC0020 analyzer to enforce CancellationToken propagation via RequestContext#56230

Open
Copilot wants to merge 5 commits intomainfrom
copilot/add-analyzer-rule-requestcontext
Open

Add AZC0020 analyzer to enforce CancellationToken propagation via RequestContext#56230
Copilot wants to merge 5 commits intomainfrom
copilot/add-analyzer-rule-requestcontext

Conversation

Copy link
Contributor

Copilot AI commented Feb 12, 2026

Description

Azure SDK protocol APIs accept RequestContext instead of direct CancellationToken parameters. Existing analyzers (CA2016) only detect missing token propagation when the callee explicitly accepts CancellationToken, allowing cancellation to be silently dropped in RequestContext scenarios.

Changes

New Analyzer (AZC0020)

  • Detects when methods with CancellationToken parameters call Azure SDK APIs without propagating the token to RequestContext
  • Scoped to Azure SDK APIs (methods in Azure namespace) to avoid false positives
  • Handles lambda expressions, anonymous functions, and object initializer syntax
  • Uses general data flow analysis to detect CancellationToken usage in any expression (extension methods, helper methods, inline expressions, etc.)
  • Conservative: skips pre-existing RequestContext objects from parameters/locals where token state is indeterminate

Implementation

  • RequestContextCancellationTokenAnalyzer.cs: Operation-based analyzer using IInvocationOperation with recursive operation tree traversal
  • Descriptors.cs: AZC0020 diagnostic descriptor (warning severity)
  • AZC0020Tests.cs: 13 test cases covering positive/negative scenarios, including extension methods and custom helper patterns
  • Documentation: AZC0020.md, updated README.md and list-of-diagnostics.md

Example

Violation detected:

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    await client.UpdateAsync(content, new RequestContext());
    // ⚠️ AZC0020: CancellationToken not propagated
}

Fixed (object initializer):

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    await client.UpdateAsync(content, new RequestContext 
    { 
        CancellationToken = cancellationToken 
    });
}

Fixed (extension method):

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    await client.UpdateAsync(content, cancellationToken.ToRequestContext());
}

Fixed (helper method):

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    await client.UpdateAsync(content, CreateContext(cancellationToken));
}

private RequestContext CreateContext(CancellationToken token)
{
    return new RequestContext { CancellationToken = token };
}

This checklist is used to make sure that common guidelines for a pull request are followed.

General Guidelines

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, see this page.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

SDK Generation Guidelines

  • If an SDK is being regenerated based on a new swagger spec, a link to the pull request containing these swagger spec changes has been included above.
  • The generate.cmd file for the SDK has been updated with the version of AutoRest, as well as the commitid of your swagger spec or link to the swagger spec, used to generate the code.
  • The *.csproj and AssemblyInfo.cs files have been updated with the new version of the SDK.
Original prompt

This section details on the original issue you should resolve

<issue_title>Add analyzer rule to enforce CancellationToken propagation via RequestContext</issue_title>
<issue_description>In Azure SDK for .NET, many protocol‑layer APIs accept a RequestContext parameter instead of a direct CancellationToken. Since RequestContext contains a CancellationToken, callers are expected to propagate any incoming token into the RequestContext passed to the SDK.

However, existing analyzers (e.g., CA2016 – CancellationToken must be passed to method) only enforce propagation when the callee explicitly accepts a CancellationToken. They do not detect cases where:

  • A calling method accepts a CancellationToken
  • The call is made to an Azure SDK API that takes RequestContext
  • The RequestContext is created without flowing the incoming CancellationToken

This allows cancellation to be silently dropped, especially in application or service code (e.g., MCP server), without any static analysis warning.

Why This Matters

  • RequestContext is the standard mechanism for cancellation in many Azure SDK protocol APIs.
  • Missing cancellation propagation can lead to:
    • Hung requests
    • Poor responsiveness under shutdown or timeout conditions
    • Inconsistent cancellation behavior across SDK calls
  • This gap is easy to miss during reviews and is not caught by existing analyzers.

Proposed Solution

Introduce a new analyzer rule (or extend an existing Azure SDK analyzer) that:

  • Detects methods that accept a CancellationToken
  • Identifies calls to Azure SDK APIs where:
    • The API accepts a RequestContext
    • The provided RequestContext does not carry the caller’s CancellationToken
  • Reports a diagnostic when the token is not propagated into RequestContext

This rule should be usable by application code, not just the SDK itself, so that customers and internal services can enforce correct cancellation behavior.

Example

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    // ❌ CancellationToken is accepted but not propagated
    await client.UpdateAsync(
        content,
        new RequestContext()); // cancellationToken is dropped
}

Expected fix:

public async Task UpdateAsync(CancellationToken cancellationToken)
{
    await client.UpdateAsync(
        content,
        new RequestContext
        {
            CancellationToken = cancellationToken
        });
}

Scope / Notes

  • This is not fully covered by CA2016 today.
  • Azure SDK for .NET already has custom analyzer infrastructure; this would fit naturally there.
  • Rule should be specific to Azure SDK APIs that rely on RequestContext for cancellation.
    </issue_description>

<agent_instructions>Implement this new rule and add tests for it.</agent_instructions>

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


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 12, 2026 21:02
…text

- Added new analyzer to detect when CancellationToken is not propagated to RequestContext
- Added diagnostic descriptor AZC0020 with warning severity
- Implemented RequestContextCancellationTokenAnalyzer with support for:
  - Method invocations with RequestContext parameters
  - Object initializer syntax for RequestContext
  - Lambda expressions and anonymous functions
  - Proper handling of pre-existing RequestContext objects
- Added comprehensive test suite with 11 test cases covering various scenarios
- All tests passing successfully

Co-authored-by: christothes <1279263+christothes@users.noreply.github.com>
- Created AZC0020.md with detailed description and examples
- Updated list-of-diagnostics.md to include AZC0020
- Updated README.md to reference the new analyzer rule
- All tests passing in Debug and Release configurations

Co-authored-by: christothes <1279263+christothes@users.noreply.github.com>
Copilot AI changed the title [WIP] Add analyzer rule for CancellationToken propagation via RequestContext Add AZC0020 analyzer to enforce CancellationToken propagation via RequestContext Feb 12, 2026
Copilot AI requested a review from christothes February 12, 2026 21:06
- Updated analyzer to recognize extension method calls on CancellationToken
- Added detection for ToRequestContext() and ToRequestOptions() methods
- Added test case AZC0020NotProducedWhenUsingToRequestContextExtension
- All 12 AZC0020 tests passing

Co-authored-by: christothes <1279263+christothes@users.noreply.github.com>
- Replaced specific extension method name checking with general approach
- Added ContainsCancellationTokenReference method that recursively checks operation tree
- Now detects any method/expression that uses the CancellationToken parameter
- Works with extension methods, helper methods, and any custom patterns
- Added test case for custom helper method pattern
- All 13 AZC0020 tests passing

Co-authored-by: christothes <1279263+christothes@users.noreply.github.com>
@christothes christothes marked this pull request as ready for review February 13, 2026 18:27
Copilot AI review requested due to automatic review settings February 13, 2026 18:28
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 a new Roslyn analyzer (AZC0020) to enforce proper CancellationToken propagation to RequestContext parameters in Azure SDK protocol API calls. The analyzer addresses a gap in existing analyzers (like CA2016) which only detect missing token propagation when the callee explicitly accepts a CancellationToken parameter, but not when the cancellation is conveyed through RequestContext objects.

Changes:

  • Implements a new diagnostic analyzer (AZC0020) using operation-based analysis with recursive operation tree traversal to detect when methods with CancellationToken parameters call Azure SDK APIs without propagating the token to RequestContext
  • Adds comprehensive test coverage with 13 test cases covering various scenarios including extension methods, helper methods, lambda expressions, and edge cases
  • Provides complete documentation including diagnostic descriptor, rule documentation (AZC0020.md), and updates to README and list-of-diagnostics

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
RequestContextCancellationTokenAnalyzer.cs Core analyzer implementation using IInvocationOperation with recursive operation tree traversal to detect missing CancellationToken propagation; handles object initializers, extension methods, helper methods, and conservatively skips pre-existing RequestContext references
Descriptors.cs Adds AZC0020 diagnostic descriptor with warning severity and clear messaging about CancellationToken propagation requirement
AZC0020Tests.cs Comprehensive test suite with 13 test cases covering positive/negative scenarios, edge cases (lambdas, extension methods, helper methods), and boundary conditions
AZC0020.md Detailed documentation explaining the rule, rationale, fix guidance, and examples
list-of-diagnostics.md Adds AZC0020 to the diagnostics list with description, violation examples, fix examples, and notes about analyzer behavior
README.md Updates the implemented rules list to include AZC0020

Copy link
Member

@jsquire jsquire left a comment

Choose a reason for hiding this comment

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

@m-nash: Are there any implications for API View here that we'd need to account for?

Comment on lines +76 to +79
var containingNamespace = method.ContainingNamespace;
while (containingNamespace != null && !containingNamespace.IsGlobalNamespace)
{
if (containingNamespace.Name == "Azure")
Copy link
Member

Choose a reason for hiding this comment

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

Should we also check for Microsoft.Azure since that's our bridge package, extensions package, and some other conventions?

I wouldn't expect that we'd encounter any RequestContext use in the T1 packages, so checking them shouldn't produce violations, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add analyzer rule to enforce CancellationToken propagation via RequestContext

3 participants