diff --git a/samples/ConsoleApp/ConsoleApp.csproj b/samples/ConsoleApp/ConsoleApp.csproj
index 5de1fbdff..e9ab58119 100644
--- a/samples/ConsoleApp/ConsoleApp.csproj
+++ b/samples/ConsoleApp/ConsoleApp.csproj
@@ -20,6 +20,7 @@
+
diff --git a/samples/ConsoleAppMinimal/ConsoleAppMinimal.csproj b/samples/ConsoleAppMinimal/ConsoleAppMinimal.csproj
index 5de1fbdff..e9ab58119 100644
--- a/samples/ConsoleAppMinimal/ConsoleAppMinimal.csproj
+++ b/samples/ConsoleAppMinimal/ConsoleAppMinimal.csproj
@@ -20,6 +20,7 @@
+
diff --git a/samples/ExceptionPropertiesSample/ExceptionPropertiesSample.csproj b/samples/ExceptionPropertiesSample/ExceptionPropertiesSample.csproj
index d24b2f473..ebc0466f2 100644
--- a/samples/ExceptionPropertiesSample/ExceptionPropertiesSample.csproj
+++ b/samples/ExceptionPropertiesSample/ExceptionPropertiesSample.csproj
@@ -22,7 +22,7 @@
+
-
diff --git a/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj b/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj
index c7ac5d2ed..e1f3e5414 100644
--- a/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj
+++ b/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj
@@ -17,8 +17,7 @@
+
-
-
diff --git a/samples/ScheduleConsoleApp/Orchestrators/StockPriceOrchestrator.cs b/samples/ScheduleConsoleApp/Orchestrators/StockPriceOrchestrator.cs
index 3cc04a60f..18fb75322 100644
--- a/samples/ScheduleConsoleApp/Orchestrators/StockPriceOrchestrator.cs
+++ b/samples/ScheduleConsoleApp/Orchestrators/StockPriceOrchestrator.cs
@@ -18,7 +18,7 @@ public override async Task RunAsync(TaskOrchestrationContext context, st
logger.LogInformation("Current price for {symbol} is ${price:F2}", symbol, currentPrice);
- return $"Stock {symbol} price: ${currentPrice:F2} at {DateTime.UtcNow}";
+ return $"Stock {symbol} price: ${currentPrice:F2} at {context.CurrentUtcDateTime}";
}
catch (Exception ex)
{
diff --git a/samples/ScheduleConsoleApp/ScheduleConsoleApp.csproj b/samples/ScheduleConsoleApp/ScheduleConsoleApp.csproj
index 5c356d93b..227ee159d 100644
--- a/samples/ScheduleConsoleApp/ScheduleConsoleApp.csproj
+++ b/samples/ScheduleConsoleApp/ScheduleConsoleApp.csproj
@@ -17,5 +17,6 @@
+
diff --git a/samples/ScheduleWebApp/ScheduleWebApp.csproj b/samples/ScheduleWebApp/ScheduleWebApp.csproj
index a505e3df4..3d426a2f7 100644
--- a/samples/ScheduleWebApp/ScheduleWebApp.csproj
+++ b/samples/ScheduleWebApp/ScheduleWebApp.csproj
@@ -18,5 +18,6 @@
+
diff --git a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs
index a299d5777..bfffb57a2 100644
--- a/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs
+++ b/src/Analyzers/Orchestration/OrchestrationAnalyzer.cs
@@ -27,11 +27,14 @@ public override void Initialize(AnalysisContext context)
{
KnownTypeSymbols knownSymbols = new(context.Compilation);
- if (knownSymbols.FunctionOrchestrationAttribute == null || knownSymbols.FunctionNameAttribute == null ||
- knownSymbols.TaskOrchestratorInterface == null ||
- knownSymbols.DurableTaskRegistry == null)
+ // Check if at least one orchestration type can be detected
+ bool canAnalyzeDurableFunctions = knownSymbols.FunctionOrchestrationAttribute != null && knownSymbols.FunctionNameAttribute != null;
+ bool canAnalyzeTaskOrchestrator = knownSymbols.TaskOrchestratorInterface != null && knownSymbols.TaskOrchestrationContext != null;
+ bool canAnalyzeFuncOrchestrator = knownSymbols.DurableTaskRegistry != null;
+
+ if (!canAnalyzeDurableFunctions && !canAnalyzeTaskOrchestrator && !canAnalyzeFuncOrchestrator)
{
- // symbols not available in this compilation, skip analysis
+ // no symbols available in this compilation, skip analysis
return;
}
@@ -42,124 +45,133 @@ public override void Initialize(AnalysisContext context)
}
// look for Durable Functions Orchestrations
- context.RegisterSyntaxNodeAction(
- ctx =>
+ if (canAnalyzeDurableFunctions)
{
- ctx.CancellationToken.ThrowIfCancellationRequested();
-
- if (ctx.ContainingSymbol is not IMethodSymbol methodSymbol)
+ context.RegisterSyntaxNodeAction(
+ ctx =>
{
- return;
- }
+ ctx.CancellationToken.ThrowIfCancellationRequested();
- if (!methodSymbol.ContainsAttributeInAnyMethodArguments(knownSymbols.FunctionOrchestrationAttribute))
- {
- return;
- }
+ if (ctx.ContainingSymbol is not IMethodSymbol methodSymbol)
+ {
+ return;
+ }
- if (!methodSymbol.TryGetSingleValueFromAttribute(knownSymbols.FunctionNameAttribute, out string functionName))
- {
- return;
- }
+ if (!methodSymbol.ContainsAttributeInAnyMethodArguments(knownSymbols.FunctionOrchestrationAttribute!))
+ {
+ return;
+ }
+
+ if (!methodSymbol.TryGetSingleValueFromAttribute(knownSymbols.FunctionNameAttribute!, out string functionName))
+ {
+ return;
+ }
- var rootMethodSyntax = (MethodDeclarationSyntax)ctx.Node;
+ var rootMethodSyntax = (MethodDeclarationSyntax)ctx.Node;
- visitor.VisitDurableFunction(ctx.SemanticModel, rootMethodSyntax, methodSymbol, functionName, ctx.ReportDiagnostic);
- },
- SyntaxKind.MethodDeclaration);
+ visitor.VisitDurableFunction(ctx.SemanticModel, rootMethodSyntax, methodSymbol, functionName, ctx.ReportDiagnostic);
+ },
+ SyntaxKind.MethodDeclaration);
+ }
// look for ITaskOrchestrator/TaskOrchestrator`2 Orchestrations
- context.RegisterSyntaxNodeAction(
- ctx =>
+ if (canAnalyzeTaskOrchestrator)
{
- ctx.CancellationToken.ThrowIfCancellationRequested();
-
- if (ctx.ContainingSymbol is not INamedTypeSymbol classSymbol)
+ context.RegisterSyntaxNodeAction(
+ ctx =>
{
- return;
- }
+ ctx.CancellationToken.ThrowIfCancellationRequested();
- bool implementsITaskOrchestrator = classSymbol.AllInterfaces.Any(i => i.Equals(knownSymbols.TaskOrchestratorInterface, SymbolEqualityComparer.Default));
- if (!implementsITaskOrchestrator)
- {
- return;
- }
+ if (ctx.ContainingSymbol is not INamedTypeSymbol classSymbol)
+ {
+ return;
+ }
- IEnumerable orchestrationMethods = classSymbol.GetMembers().OfType()
- .Where(m => m.Parameters.Any(p => p.Type.Equals(knownSymbols.TaskOrchestrationContext, SymbolEqualityComparer.Default)));
+ bool implementsITaskOrchestrator = classSymbol.AllInterfaces.Any(i => i.Equals(knownSymbols.TaskOrchestratorInterface, SymbolEqualityComparer.Default));
+ if (!implementsITaskOrchestrator)
+ {
+ return;
+ }
- string functionName = classSymbol.Name;
+ IEnumerable orchestrationMethods = classSymbol.GetMembers().OfType()
+ .Where(m => m.Parameters.Any(p => p.Type.Equals(knownSymbols.TaskOrchestrationContext, SymbolEqualityComparer.Default)));
- foreach (IMethodSymbol? methodSymbol in orchestrationMethods)
- {
- IEnumerable methodSyntaxes = methodSymbol.GetSyntaxNodes();
- foreach (MethodDeclarationSyntax rootMethodSyntax in methodSyntaxes)
+ string functionName = classSymbol.Name;
+
+ foreach (IMethodSymbol? methodSymbol in orchestrationMethods)
{
- visitor.VisitTaskOrchestrator(ctx.SemanticModel, rootMethodSyntax, methodSymbol, functionName, ctx.ReportDiagnostic);
+ IEnumerable methodSyntaxes = methodSymbol.GetSyntaxNodes();
+ foreach (MethodDeclarationSyntax rootMethodSyntax in methodSyntaxes)
+ {
+ visitor.VisitTaskOrchestrator(ctx.SemanticModel, rootMethodSyntax, methodSymbol, functionName, ctx.ReportDiagnostic);
+ }
}
- }
- },
- SyntaxKind.ClassDeclaration);
+ },
+ SyntaxKind.ClassDeclaration);
+ }
// look for OrchestratorFunc Orchestrations
- context.RegisterOperationAction(
- ctx =>
+ if (canAnalyzeFuncOrchestrator)
{
- if (ctx.Operation is not IInvocationOperation invocation)
+ context.RegisterOperationAction(
+ ctx =>
{
- return;
- }
+ if (ctx.Operation is not IInvocationOperation invocation)
+ {
+ return;
+ }
- if (!SymbolEqualityComparer.Default.Equals(invocation.Type, knownSymbols.DurableTaskRegistry))
- {
- return;
- }
+ if (!SymbolEqualityComparer.Default.Equals(invocation.Type, knownSymbols.DurableTaskRegistry))
+ {
+ return;
+ }
- // there are 8 AddOrchestratorFunc overloads
- if (invocation.TargetMethod.Name != "AddOrchestratorFunc")
- {
- return;
- }
+ // there are 8 AddOrchestratorFunc overloads
+ if (invocation.TargetMethod.Name != "AddOrchestratorFunc")
+ {
+ return;
+ }
- // all overloads have the parameter 'orchestrator', either as an Action or a Func
- IArgumentOperation orchestratorArgument = invocation.Arguments.First(a => a.Parameter!.Name == "orchestrator");
- if (orchestratorArgument.Value is not IDelegateCreationOperation delegateCreationOperation)
- {
- return;
- }
+ // all overloads have the parameter 'orchestrator', either as an Action or a Func
+ IArgumentOperation orchestratorArgument = invocation.Arguments.First(a => a.Parameter!.Name == "orchestrator");
+ if (orchestratorArgument.Value is not IDelegateCreationOperation delegateCreationOperation)
+ {
+ return;
+ }
- // obtains the method symbol from the delegate creation operation
- IMethodSymbol? methodSymbol = null;
- SyntaxNode? methodSyntax = null;
- switch (delegateCreationOperation.Target)
- {
- case IAnonymousFunctionOperation lambdaOperation:
- // use the containing symbol of the lambda (e.g. the class declaring it) as the method symbol
- methodSymbol = ctx.ContainingSymbol as IMethodSymbol;
- methodSyntax = delegateCreationOperation.Syntax;
- break;
- case IMethodReferenceOperation methodReferenceOperation:
- // use the method reference as the method symbol
- methodSymbol = methodReferenceOperation.Method;
- methodSyntax = methodReferenceOperation.Method.DeclaringSyntaxReferences.First().GetSyntax();
- break;
- default:
- break;
- }
-
- if (methodSymbol == null || methodSyntax == null)
- {
- return;
- }
+ // obtains the method symbol from the delegate creation operation
+ IMethodSymbol? methodSymbol = null;
+ SyntaxNode? methodSyntax = null;
+ switch (delegateCreationOperation.Target)
+ {
+ case IAnonymousFunctionOperation _:
+ // use the containing symbol of the lambda (e.g. the class declaring it) as the method symbol
+ methodSymbol = ctx.ContainingSymbol as IMethodSymbol;
+ methodSyntax = delegateCreationOperation.Syntax;
+ break;
+ case IMethodReferenceOperation methodReferenceOperation:
+ // use the method reference as the method symbol
+ methodSymbol = methodReferenceOperation.Method;
+ methodSyntax = methodReferenceOperation.Method.DeclaringSyntaxReferences.First().GetSyntax();
+ break;
+ default:
+ break;
+ }
- // try to get the name of the orchestration from the method call, otherwise use the containing type name
- IArgumentOperation nameArgument = invocation.Arguments.First(a => a.Parameter!.Name == "name");
- Optional