diff --git a/src/Analyzers/RoslynExtensions.cs b/src/Analyzers/RoslynExtensions.cs index 10339f7a4..a7b062221 100644 --- a/src/Analyzers/RoslynExtensions.cs +++ b/src/Analyzers/RoslynExtensions.cs @@ -129,6 +129,11 @@ public static IEnumerable GetSyntaxNodes(this IMethodSy { LiteralExpressionSyntax? nameLiteralSyntax = argumentOperation.Syntax.DescendantNodes().OfType().FirstOrDefault(); + if (nameLiteralSyntax is null) + { + return default; + } + return semanticModel.GetConstantValue(nameLiteralSyntax, cancellationToken); } diff --git a/test/Analyzers.Tests/Orchestration/DateTimeOrchestrationAnalyzerTests.cs b/test/Analyzers.Tests/Orchestration/DateTimeOrchestrationAnalyzerTests.cs index e42fa379a..f418e5fc9 100644 --- a/test/Analyzers.Tests/Orchestration/DateTimeOrchestrationAnalyzerTests.cs +++ b/test/Analyzers.Tests/Orchestration/DateTimeOrchestrationAnalyzerTests.cs @@ -310,6 +310,46 @@ public async Task FuncOrchestratorWithLambdaHasDiag() await VerifyCS.VerifyDurableTaskCodeFixAsync(code, expected, fix); } + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameNoDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + async (ctx, input) => + { + return await ctx.CallActivityAsync(""Activity"", input); + }); +} +"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code); + } + + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameHasDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + context => + { + return {|#0:DateTime.Now|}; + }); +} +"); + + DiagnosticResult expected = BuildDiagnostic().WithLocation(0).WithArguments("Main", "System.DateTime.Now", "Main"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code, expected); + } + [Fact] public async Task FuncOrchestratorWithMethodReferenceHasDiag() { diff --git a/test/Analyzers.Tests/Orchestration/DelayOrchestrationAnalyzerTests.cs b/test/Analyzers.Tests/Orchestration/DelayOrchestrationAnalyzerTests.cs index 6f1b91513..5e5f2d85e 100644 --- a/test/Analyzers.Tests/Orchestration/DelayOrchestrationAnalyzerTests.cs +++ b/test/Analyzers.Tests/Orchestration/DelayOrchestrationAnalyzerTests.cs @@ -111,6 +111,46 @@ public async Task FuncOrchestratorUsingThreadSleepHasDiag() await VerifyCS.VerifyDurableTaskAnalyzerAsync(code, expected); } + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameNoDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + async (ctx, input) => + { + return await ctx.CallActivityAsync(""Activity"", input); + }); +} +"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code); + } + + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameHasDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + context => + { + {|#0:Thread.Sleep(1000)|}; + }); +} +"); + + DiagnosticResult expected = BuildDiagnostic().WithLocation(0).WithArguments("Main", "Thread.Sleep(int)", "Main"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code, expected); + } + static DiagnosticResult BuildDiagnostic() { return VerifyCS.Diagnostic(DelayOrchestrationAnalyzer.DiagnosticId); diff --git a/test/Analyzers.Tests/Orchestration/GuidOrchestrationAnalyzerTests.cs b/test/Analyzers.Tests/Orchestration/GuidOrchestrationAnalyzerTests.cs index 335f02f93..20c6a6060 100644 --- a/test/Analyzers.Tests/Orchestration/GuidOrchestrationAnalyzerTests.cs +++ b/test/Analyzers.Tests/Orchestration/GuidOrchestrationAnalyzerTests.cs @@ -92,6 +92,45 @@ public async Task FuncOrchestratorUsingNewGuidHasDiag() await VerifyCS.VerifyDurableTaskCodeFixAsync(code, expected, fix); } + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameNoDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + async (ctx, input) => + { + return await ctx.CallActivityAsync(""Activity"", input); + }); +} +"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code); + } + + [Fact] + public async Task FuncOrchestratorInForEachWithVariableNameHasDiag() + { + string code = Wrapper.WrapFuncOrchestrator(@" +string[] names = new[] { ""A"", ""B"" }; +foreach (string name in names) +{ + tasks.AddOrchestratorFunc( + name, + context => + { + return {|#0:Guid.NewGuid()|}; + }); +} +"); + + DiagnosticResult expected = BuildDiagnostic().WithLocation(0).WithArguments("Main", "Guid.NewGuid()", "Main"); + + await VerifyCS.VerifyDurableTaskAnalyzerAsync(code, expected); + } static DiagnosticResult BuildDiagnostic() { return VerifyCS.Diagnostic(GuidOrchestrationAnalyzer.DiagnosticId);