From 0b7d13421de224bdc1dc4007d98a33157fe1ea25 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 23 Nov 2022 14:24:06 +0200 Subject: [PATCH] Support ForEachVariableStatement in stackalloc analyzer --- .../CSharpDoNotUseStackallocInLoops.cs | 7 ++++--- .../Runtime/DoNotUseStackallocInLoopsTests.cs | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpDoNotUseStackallocInLoops.cs b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpDoNotUseStackallocInLoops.cs index 22a2a694f2..e5eeac01f4 100644 --- a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpDoNotUseStackallocInLoops.cs +++ b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpDoNotUseStackallocInLoops.cs @@ -38,7 +38,8 @@ public sealed override void Initialize(AnalysisContext context) // foreach loops are special, in that as with other loops we don't want stackallocs // in the body of the loop, but in the expression of a foreach is ok. case SyntaxKind.ForEachStatement: - ForEachStatementSyntax foreachStatement = (ForEachStatementSyntax)node; + case SyntaxKind.ForEachVariableStatement: + var foreachStatement = (CommonForEachStatementSyntax)node; if (foreachStatement.Expression.Contains(ctx.Node)) { continue; @@ -71,7 +72,7 @@ static bool ShouldWarn(IOperation? op, SyntaxNode node) foreach (IOperation child in block.Operations) { if (child.Syntax.SpanStart > node.SpanStart && - (child is IReturnOperation || (child is IBranchOperation branch && branch.BranchKind == BranchKind.Break))) + (child is IReturnOperation or IBranchOperation { BranchKind: BranchKind.Break })) { // Err on the side of false negatives / caution and say this stackalloc is ok. // Note, too, it's possible we're breaking out of a nested loop, and the outer loop @@ -88,7 +89,7 @@ static bool ShouldWarn(IOperation? op, SyntaxNode node) } // Warn as needed. - if (ShouldWarn(ctx.SemanticModel.GetOperationWalkingUpParentChain(ctx.Node, default), ctx.Node)) + if (ShouldWarn(ctx.SemanticModel.GetOperationWalkingUpParentChain(ctx.Node, ctx.CancellationToken), ctx.Node)) { ctx.ReportDiagnostic(ctx.Node.CreateDiagnostic(Rule)); } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotUseStackallocInLoopsTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotUseStackallocInLoopsTests.cs index b4ad3cbeb0..94a375f9c7 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotUseStackallocInLoopsTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotUseStackallocInLoopsTests.cs @@ -285,5 +285,26 @@ private static void SourceOfForeachLoopInAnotherLoop() { }" }.RunAsync(); } + + [Fact] + public async Task Diagnostics_StackallocAsSourceOfForeachVariableLoop() + { + await new VerifyCS.Test + { + LanguageVersion = LanguageVersion.CSharp8, + TestCode = @" + using System; + public class C + { + public static void Foo() + { + foreach (var (x, y) in stackalloc (double, double)[] { (0, 0) }) + { + Span span = {|CA2014:stackalloc byte[1024]|}; + } + } + }" + }.RunAsync(); + } } }