-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CancellationToken roslyn analyzer (#303)
Currently, CancellationToken binding is not supported (ignored) during [input conversion](https://github.com/Azure/azure-functions-durable-extension/blob/dev/src/Worker.Extensions.DurableTask/OrchestrationInputConverter.cs#L79). This analyzer will prevent users from using it inside Azure Functions Orchestrators.
- Loading branch information
1 parent
aa810cc
commit c4fac92
Showing
5 changed files
with
113 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
src/Analyzers/Functions/Orchestration/CancellationTokenOrchestrationAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.DurableTask.Analyzers.Orchestration; | ||
using static Microsoft.DurableTask.Analyzers.Functions.Orchestration.CancellationTokenOrchestrationAnalyzer; | ||
|
||
namespace Microsoft.DurableTask.Analyzers.Functions.Orchestration; | ||
|
||
/// <summary> | ||
/// Analyzer that reports a warning when CancellationToken is used in a Durable Functions Orchestration. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class CancellationTokenOrchestrationAnalyzer : OrchestrationAnalyzer<CancellationTokenOrchestrationVisitor> | ||
{ | ||
/// <summary> | ||
/// Diagnostic ID supported for the analyzer. | ||
/// </summary> | ||
public const string DiagnosticId = "DURABLE0007"; | ||
|
||
static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.CancellationTokenOrchestrationAnalyzerTitle), Resources.ResourceManager, typeof(Resources)); | ||
static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.CancellationTokenOrchestrationAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources)); | ||
|
||
static readonly DiagnosticDescriptor Rule = new( | ||
DiagnosticId, | ||
Title, | ||
MessageFormat, | ||
AnalyzersCategories.Orchestration, | ||
DiagnosticSeverity.Warning, | ||
isEnabledByDefault: true); | ||
|
||
/// <inheritdoc/> | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule]; | ||
|
||
/// <summary> | ||
/// Visitor that inspects Durable Functions's method signatures for CancellationToken parameters. | ||
/// </summary> | ||
public sealed class CancellationTokenOrchestrationVisitor : OrchestrationVisitor | ||
{ | ||
/// <inheritdoc/> | ||
public override bool Initialize() | ||
{ | ||
return this.KnownTypeSymbols.CancellationToken is not null; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override void VisitDurableFunction(SemanticModel semanticModel, MethodDeclarationSyntax methodSyntax, IMethodSymbol methodSymbol, string orchestrationName, Action<Diagnostic> reportDiagnostic) | ||
{ | ||
foreach (IParameterSymbol parameter in methodSymbol.Parameters) | ||
{ | ||
if (parameter.Type.Equals(this.KnownTypeSymbols.CancellationToken, SymbolEqualityComparer.Default)) | ||
{ | ||
reportDiagnostic(RoslynExtensions.BuildDiagnostic(Rule, parameter, orchestrationName)); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
test/Analyzers.Tests/Functions/Orchestration/CancellationTokenOrchestrationAnalyzerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.CodeAnalysis.Testing; | ||
using Microsoft.DurableTask.Analyzers.Functions.Orchestration; | ||
using VerifyCS = Microsoft.DurableTask.Analyzers.Tests.Verifiers.CSharpAnalyzerVerifier<Microsoft.DurableTask.Analyzers.Functions.Orchestration.CancellationTokenOrchestrationAnalyzer>; | ||
|
||
namespace Microsoft.DurableTask.Analyzers.Tests.Functions.Orchestration; | ||
|
||
public class CancellationTokenOrchestrationAnalyzerTests | ||
{ | ||
[Fact] | ||
public async Task EmptyCodeHasNoDiag() | ||
{ | ||
string code = @""; | ||
|
||
await VerifyCS.VerifyDurableTaskAnalyzerAsync(code); | ||
} | ||
|
||
[Fact] | ||
public async Task DurableFunctionOrchestrationUsingCancellationTokenAsParameterHasDiag() | ||
{ | ||
string code = Wrapper.WrapDurableFunctionOrchestration(@" | ||
[Function(""Run"")] | ||
void Method([OrchestrationTrigger] TaskOrchestrationContext context, {|#0:CancellationToken token|}) | ||
{ | ||
} | ||
"); | ||
|
||
DiagnosticResult expected = BuildDiagnostic().WithLocation(0).WithArguments("Run"); | ||
|
||
await VerifyCS.VerifyDurableTaskAnalyzerAsync(code, expected); | ||
} | ||
|
||
static DiagnosticResult BuildDiagnostic() | ||
{ | ||
return VerifyCS.Diagnostic(CancellationTokenOrchestrationAnalyzer.DiagnosticId); | ||
} | ||
} |