File: Microsoft.NetCore.Analyzers\Runtime\DoNotUseStackallocInLoopsTests.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpSecurityCodeFixVerifier<
    Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDoNotUseStackallocInLoopsAnalyzer,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
    public class DoNotUseStackallocInLoopsTests
    {
        [Fact]
        public async Task NoDiagnostics_StackallocNotInLoopAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void NoLoop() {
                        byte* ptr1 = stackalloc byte[1];
                        Span<char> ptr2 = stackalloc char[2];
 
                        Label1:
                        Span<byte> ptr3 = stackalloc byte[3];
                        goto Label1; // false negative, but too difficult to track well with few false positives
                    }
                }");
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocAsSourceOfForeachLoop()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
                using System;
                unsafe class TestClass {
                    private static void SourceOfForeachLoop() {
                        foreach (char c in stackalloc char[] { 'a', 'b', 'c' }) { }
                    }
                }"
            }.RunAsync();
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocInLoopWithBreakAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void ForLoop() {
                        for (int i = 0; i < 10; i++)
                        {
                            if (i == 5)
                            {
                                byte* ptr = stackalloc byte[1024];
                            }
                            break;
                        }
                    }
 
                    private static void WhileLoop() {
                        while (true)
                        {
                            byte* ptr = stackalloc byte[1024];
                            break;
                        }
                    }
 
                    private static void DoWhile() {
                        do
                        {
                            byte* ptr = stackalloc byte[1024];
                            return;
                        }
                        while (true);
                    }
                }");
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocInLoopButInsideALocalFunctionAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
using System;
class TestClass {
    private static void StackAllocInLoopButInsideLocalFunction() {
        while (true) {
            XX();
 
            static void XX()
            {
                Span<int> tmp = stackalloc int[10];
                Console.WriteLine(tmp[0]);
            }
        }
    }
}"
            }.RunAsync();
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocInLoopButInsideALambdaAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
using System;
class TestClass {
    private static void StackallocInLoopButInsideALambda() {
        while (true) {
            Action a = () => {
                Span<int> tmp = stackalloc int[10];
                Console.WriteLine(tmp[0]);
            };
            a();
        }
    }
}"
            }.RunAsync();
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocInLoopButInsideALambda2Async()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
using System;
class TestClass {
    private static void StackallocInLoopButInsideALambda2() {
        while (true) {
            Action<int> a = _ => Console.Write((stackalloc int[10]).Length);
        }
    }
}"
            }.RunAsync();
        }
 
        [Fact]
        public async Task NoDiagnostics_StackallocInLoopButInsideFuncAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
using System;
class TestClass {
    private static void StackallocInLoopButInsideAction() {
        while (true) {
            Func<int> a = delegate()
            {
                Span<int> tmp = stackalloc int[10];
                return 0;
            };
            a();
        }
    }
}"
            }.RunAsync();
        }
 
        [Fact]
        public async Task Diagnostics_LoopsWithStackallocPtrAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void ForLoop() {
                        for (int i = 0; i < 10; i++)
                        {
                            byte* ptr = {|CA2014:stackalloc byte[1024]|};
                        }
                    }
 
                    private static void WhileLoop() {
                        while (true)
                        {
                            byte* ptr = {|CA2014:stackalloc byte[1024]|};
                        }
                    }
 
                    private static void DoWhile() {
                        do
                        {
                            byte* ptr = {|CA2014:stackalloc byte[1024]|};
                        }
                        while (true);
                    }
                }");
        }
 
        [Fact]
        public async Task Diagnostics_LoopsWithStackallocSpanAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void ForLoop() {
                        for (int i = 0; i < 10; i++)
                        {
                            Span<byte> span = {|CA2014:stackalloc byte[1024]|};
                        }
                    }
 
                    private static void WhileLoop() {
                        while (true)
                        {
                            Span<char> span = {|CA2014:stackalloc char[1024]|};
                        }
                    }
 
                    private static void DoWhile() {
                        do
                        {
                            Span<int> span = {|CA2014:stackalloc int[1024]|};
                        }
                        while (true);
                    }
                }");
        }
 
        [Fact]
        public async Task Diagnostics_LoopInLoopWithOuterBreakAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void LoopInLoopWithOuterBreak() {
                        while (true)
                        {
                            for (int i = 0; i < 10; i++)
                            {
                                Span<byte> span = {|CA2014:stackalloc byte[1024]|};
                            }
                            break;
                        }
                    }
                }");
        }
 
        [Fact]
        public async Task Diagnostics_LoopWithBreakInConditionalAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                unsafe class TestClass {
                    private static void LoopWithBreakInConditional() {
                        for (int i = 0; i < 10; i++)
                        {
                            Span<byte> span1 = {|CA2014:stackalloc byte[1024]|};
                            if (i == 5)
                                break;
 
                            Span<char> span2 = {|CA2014:stackalloc char[1024]|};
                            if (i == 3)
                                break;
                        }
                    }
                }");
        }
 
        [Fact]
        public async Task Diagnostics_StackallocAsSourceOfForeachLoopButInAnotherLoop()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
                using System;
                unsafe class TestClass {
                    private static void SourceOfForeachLoopInAnotherLoop() {
                        for (int i = 0; i < 10; i++)
                        {
                            foreach (char c in {|CA2014:stackalloc char[] { 'a', 'b', 'c' }|}) { }
                        }
                    }
                }"
            }.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<byte> span = {|CA2014:stackalloc byte[1024]|};
                        }
                    }
                }"
            }.RunAsync();
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task NoDiagnostics_StackallocInLoopInitializer()
        {
            return VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for (Span<int> sp1 = stackalloc int[2]; false;) { }
                    }
                }");
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task NoDiagnostics_StackallocInNonFirstVariableOfLoopInitializer()
        {
            return VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for (Span<int> span1 = GetSpan(), span2 = stackalloc int[2]; false;) { }
                    }
 
                    public static Span<int> GetSpan() => throw null;
                }");
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task NoDiagnostics_WrappedStackallocInLoopInitializer()
        {
            return new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for (Span<int> span = Helper(stackalloc int[2]) ;;) { }
                    }
 
                    public static Span<int> Helper(Span<int> span) => throw null;
                }"
            }.RunAsync();
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task Diagnostics_NestedStackallocInLoopInitializer()
        {
            return VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for(;;) {
                            for (Span<int> sp1 = [|stackalloc int[2]|]; false;) { }
                        }
                    }
                }");
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task Diagnostics_NestedStackallocInNonFirstVariableOfLoopInitializer()
        {
            return VerifyCS.VerifyAnalyzerAsync(@"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for(;;) {
                            for (Span<int> span1 = GetSpan(), span2 = [|stackalloc int[2]|]; false;) { }
                        }
                    }
 
                    public static Span<int> GetSpan() => throw null;
                }");
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task Diagnostics_StackallocInConditionExpression()
        {
            return new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        for (; [|stackalloc int[2]|].Length == 2;) { }
                    }
                }"
            }.RunAsync();
        }
 
        [Fact, WorkItem(6723, "https://github.com/dotnet/roslyn-analyzers/issues/6723")]
        public Task Diagnostics_StackallocInUpdateExpression()
        {
            return new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp8,
                TestCode = @"
                using System;
                public class C
                {
                    public static void Foo()
                    {
                        Span<int> span = default;
		                for (;; [|stackalloc int[2]|].CopyTo(span)) { }
                    }
                }"
            }.RunAsync();
        }
    }
}