File: EditAndContinue\BreakpointSpansTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.EditAndContinue;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.Debugging;
 
[Trait(Traits.Feature, Traits.Features.DebuggingBreakpoints)]
public class BreakpointSpansTests
{
    #region Helpers 
 
    private static void TestSpan(string markup, ParseOptions options = null)
        => Test(markup, isMissing: false, isLine: false, options: options);
 
    private static void TestMissing(string markup)
        => Test(markup, isMissing: true, isLine: false);
 
    private static void TestLine(string markup)
        => Test(markup, isMissing: false, isLine: true);
 
    private static void Test(string markup, bool isMissing, bool isLine, ParseOptions options = null)
    {
        MarkupTestFile.GetPositionAndSpan(
            markup, out var source, out var position, out TextSpan? expectedSpan);
        var tree = SyntaxFactory.ParseSyntaxTree(source, options);
 
        var hasBreakpoint = BreakpointSpans.TryGetBreakpointSpan(
            tree, position.Value, CancellationToken.None, out var breakpointSpan);
 
        if (isLine)
        {
            Assert.True(hasBreakpoint);
            Assert.True(breakpointSpan.Length == 0);
        }
        else if (isMissing)
        {
            Assert.False(hasBreakpoint);
        }
        else
        {
            Assert.True(hasBreakpoint);
            AssertEx.AreEqual(
                expectedSpan.Value,
                breakpointSpan,
                message: $"Expected: [|{source.Substring(expectedSpan.Value.Start, expectedSpan.Value.Length)}|], Actual: [|{source.Substring(breakpointSpan.Start, breakpointSpan.Length)}|]");
        }
    }
 
    /// <summary>
    /// Verifies all breakpoint spans of the declaration node marked by $$ in <paramref name="markup"/>
    /// and it's breakpoint span envelope (span that contains all breakpoint span of the declaration).
    /// 
    /// Only test declarations that have a single possible body (e.g. <see cref="VariableDeclaratorSyntax"/>,
    /// not <see cref="FieldDeclarationSyntax"/> or <see cref="VariableDeclarationSyntax"/>).
    /// </summary>
    private static void VerifyAllSpansInDeclaration<TDeclaration>(string markup)
        where TDeclaration : SyntaxNode
    {
        MarkupTestFile.GetPositionAndSpans(markup, out var source, out var position, out var expectedSpans);
 
        var tree = SyntaxFactory.ParseSyntaxTree(source);
        var root = tree.GetRoot();
        var declarationNode = root.FindToken(position).Parent.FirstAncestorOrSelf<TDeclaration>();
 
        var actualSpans = GetBreakpointSequence(declarationNode, position).ToArray();
 
        AssertEx.Equal(expectedSpans, actualSpans,
            itemSeparator: "\r\n",
            itemInspector: span => "[|" + source.Substring(span.Start, span.Length) + "|]");
 
        var expectedEnvelope = expectedSpans.IsEmpty ? default : TextSpan.FromBounds(expectedSpans[0].Start, expectedSpans[^1].End);
        Assert.NotNull(declarationNode);
 
        var actualEnvelope = SyntaxUtilities.TryGetDeclarationBody(declarationNode, symbol: null)?.Envelope ?? default;
        Assert.Equal(expectedEnvelope, actualEnvelope);
    }
 
    public static IEnumerable<TextSpan> GetBreakpointSequence(SyntaxNode root, int position)
    {
        TextSpan lastSpan = default;
        var endPosition = root.Span.End;
        for (var p = position; p < endPosition; p++)
        {
            if (BreakpointSpans.TryGetClosestBreakpointSpan(root, p, minLength: 0, out var span) && span.Start > lastSpan.Start)
            {
                lastSpan = span;
                yield return span;
            }
        }
    }
 
    #endregion
 
    [Fact]
    public void GetBreakpointSequence1()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$void Goo()
    [|{|]
        [|int d = 5;|]
        [|int a = 1|], [|b = 2|], [|c = 3|];
        for ([|int i = 0|], [|j = 1|], [|k = 2|]; [|i < 10|]; [|i++|], [|j++|], [|k--|])
            [|while (b > 0)|]
            [|{|]
                [|if (c < b)|]
                    try
                    [|{|]
                        [|System.Console.WriteLine(a);|]
                    [|}|]
                    [|catch (Exception e)|]
                    [|{|]
                        [|System.Console.WriteLine(e);|]   
                    [|}|]
                    finally
                    [|{|]
                    [|}|]
                else [|if (b < 10)|]
                    [|System.Console.WriteLine(b);|]
                else
                    [|System.Console.WriteLine(c);|]
            [|}|]
    [|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence2()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$void Goo()
    [|{|]
        do
        [|{|]
            label:
               [|i++;|]
            [|var l = new List<int>()
            {
               F(),
               F(),
            };|]
            [|break;|]
            [|continue;|]
        [|}|]
        [|while (a);|]
        [|goto label;|]
    [|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence3()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$int Goo()
    [|{|]
        [|switch(a)|]
        {
            case 1:
            case 2:
                [|break;|]
            
            case 3:
                [|goto case 4;|]
        
            case 4: 
                [|throw new Exception();|]
                [|goto default;|]
            
            default:
                [|return 1;|]
        }
        [|return 2;|]
    [|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence4()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$IEnumerable<int> Goo()
    [|{|]
        [|yield return 1;|]
        [|foreach|] ([|var f|] [|in|] [|Goo()|])
        [|{|]
            [|using (z)|]
            using ([|var q = null|])
            using ([|var u = null|], [|v = null|])
            [|{|]
                [|while (a)|] [|yield return 2;|]
            [|}|]
        [|}|]
        fixed([|int* a = new int[1]|], [|b = new int[1]|], [|c = new int[1]|]) [|{|][|}|]
        [|yield break;|]
    [|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence5()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$IEnumerable<int> Goo()
    [|{|][|while(t)|][|{|][|}|][|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence6()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$IEnumerable<int> Goo()
    [|{|]
        checked 
        [|{|]
            const int a = 1;
            const int b = 2;
            unchecked 
            [|{|]
                unsafe
                [|{|]
                    [|lock(l)|]
                    [|{|]
                        [|;|]
                    [|}|]    
                [|}|]    
            [|}|]    
        [|}|]
    [|}|]
}");
    }
 
    [Fact]
    public void GetBreakpointSequence_StaticContructor_NoBody()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(@"
class Class
{
    static Clas$$s()
}");
    }
 
    [Fact]
    public void GetBreakpointSequence_Method_NoBody()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class Class
{
    int F$$unction()
}");
    }
 
    #region Switch Expression
 
    [Fact]
    public void SwitchExpression_All()
    {
        VerifyAllSpansInDeclaration<MethodDeclarationSyntax>(@"
class C
{
    $$IEnumerable<int> Goo()
    [|{|]
        [|_ = M2(
            c
            switch
            {
                (1) _ [|when f|] => [|M(0)|],
                (3) _ [|when f|] => [|M(1)|],
                (1, 2) _ [|when f|] => [|M(0)|],
                (3, 4) _ [|when f|] => [|M(2)|],
                _ => [|M(4)|],
            },
            M(5));|]
    [|}|]
}");
    }
 
    [Fact]
    public void SwitchExpression01()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
$$        [|_ = e switch
        {
            1 when f => 2,
            3 when g => 4,
            _ => 5,
        };|]
    }
}");
    }
 
    [Fact]
    public void SwitchExpression02()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        [|_ = e switch
        $${
            1 when f => 2,
            3 when g => 4,
            _ => 5,
        };|]
    }
}");
    }
 
    [Fact]
    public void SwitchExpression03()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {$$
            1 [|when f|] => 2,
            3 when g => 4,
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression04()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 [|when f|] $$=> 2,
            3 when g => 4,
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression05()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f =$$> [|2|],
            3 when g => 4,
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression06()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => [|2|],$$
            3 when g => 4,
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression07()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => 2,
$$            3 [|when g|] => 4,
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression08()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => 2,
            3 when g => [|4|],$$
            _ => 5,
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression09()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => 2,
            3 when g => 4,
$$            _ => [|5|],
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression10()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => 2,
            3 when g => 4,
            _ => [|5|],$$
        };
    }
}");
    }
 
    [Fact]
    public void SwitchExpression11()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        _ = e switch
        {
            1 when f => 2,
            3 when g => 4,
            _ => [|5|],
        $$};
    }
}");
    }
 
    [Fact]
    public void SwitchExpression12()
    {
        TestSpan(
@"class C
{
    void Goo()
    {
        [|_ = e switch
        {
            1 when f => 2,
            3 when g => 4,
            _ => 5,
        }$$;|]
    }
}");
    }
 
    #endregion
 
    #region For and ForEach
 
    [Fact]
    public void ForStatementInitializer1a()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    for ([|i = 0|], j = 0; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementInitializer1b()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or ([|i = 0|], j = 0; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementInitializer1c()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for ([|i $$= 0|], j = 0; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementInitializer1d()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for 
$$    (          
[|i = 0|], j = 0; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementInitializer2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for (i = 0, [|$$j = 0|]; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementInitializer3()
        => TestSpan("class C { void M() { for([|i = 0$$|]; ; }; }");
 
    [Fact]
    public void ForStatementCondition()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for (i = 0, j = 0; [|i < 10 && j < $$10|]; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementIncrementor1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for (i = 0, j = 0; i < 10 && j < 10; [|i+$$+|], j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForStatementIncrementor2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    for (i = 0, j = 0; i < 10 && j < 10; i++, [|$$j++|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForEachStatementExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v in [|Goo().B$$ar()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void ForEachDeconstructionStatementExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) in [|Goo().B$$ar()|])
    {
    }
  }
}");
    }
 
    #endregion
 
    #region Lambdas
 
    [Fact]
    public void SimpleLambdaBody()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    Func<string> f = s => [|G$$oo()|];
  }
}");
    }
 
    [Fact]
    public void ParenthesizedLambdaBody()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    Func<string> f = (s, i) => [|G$$oo()|];
  }
}");
    }
 
    [Fact]
    public void AnonymousMethod1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    Func<int> f = delegate [|$${|] return 1; };
  }
}");
    }
 
    [Fact]
    public void AnonymousMethod2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    Func<int> f = delegate { [|$$return 1;|] };
  }
}");
    }
 
    #endregion
 
    #region Queries
 
    [Fact]
    public void FirstFromClauseExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|var q = from x in bl$$ah()
            from y in quux().z()
            select y;|]
  }
}");
    }
 
    [Fact]
    public void SecondFromClauseExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            from y in [|quux().z$$()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void FromInQueryContinuation1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            from y in quux().z()
            group x by y into g
                from m in [|g.C$$ount()|]
                select m.Blah();
  }
}");
    }
 
    [Fact]
    public void FromInQueryContinuation2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            from y in quux().z()
            group x by y into g
     $$          from m in [|g.Count()|]
                select m.Blah();
  }
}");
    }
 
    [Fact]
    public void JoinClauseLeftExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on [|left().exp$$r()|] equals right().expr()
            select y;
  }
}");
    }
 
    [Fact]
    public void JoinClauseRightExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals [|righ$$t().expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void LetClauseExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            let a = [|expr().$$expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void WhereClauseExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            where [|expr().$$expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void WhereClauseKeyword()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            whe$$re [|expr().expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void SimpleOrdering1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby [|expr().$$expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void SimpleOrdering2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, [|expr().$$expr()|]
            select y;
  }
}");
    }
 
    [Fact]
    public void AscendingOrdering1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby [|expr().$$expr()|] ascending
            select y;
  }
}");
    }
 
    [Fact]
    public void AscendingOrdering2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, [|expr().$$expr()|] ascending
            select y;
  }
}");
    }
 
    [Fact]
    public void DescendingOrdering1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby [|expr().$$expr()|] descending
            select y;
  }
}");
    }
 
    [Fact]
    public void DescendingOrdering2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, [|expr().$$expr()|] descending
            select y;
  }
}");
    }
 
    [Fact]
    public void OrderByKeyword()
        => TestSpan("class C { void M() { from string s in null ord$$erby [|s.A|] ascending } }");
 
    [Fact]
    public void AscendingKeyword()
        => TestSpan("class C { void M() { from string s in null orderby [|s.A|] $$ascending } }");
 
    [Fact]
    public void SelectExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, expr().expr() descending
            select [|y.$$blah()|];
  }
}");
    }
 
    [Fact]
    public void AnonymousTypeAfterSelect()
    {
        TestSpan(
@"class C
{
    public void ()
    {
        var q =
            from c in categories
            join p in products on c equals p.Category into ps
            select [|new { Category = c, $$Products = ps }|];
    }
}");
    }
 
    [Fact]
    public void GroupExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, expr().expr() descending
            group [|bar()$$.goo()|] by blah().zap()
            select y.blah();
  }
}");
    }
 
    [Fact]
    public void GroupByKeyword()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, expr().expr() descending
            group [|bar().goo()|] b$$y blah().zap()
            select y.blah();
  }
}");
    }
 
    [Fact]
    public void GroupByExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q = from x in blah()
            join a in alpha on left().expr() equals right.expr()
            orderby goo, expr().expr() descending
            group bar().goo() by [|blah()$$.zap()|]
            select y.blah();
  }
}");
    }
 
    [Fact]
    public void InFrontOfFirstFromClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|var q =
    $$   from x in blah()
        from y in zap()
        let m = quux()
        join a in alpha on left().expr() equals right.expr()
        orderby goo, expr().expr() descending
        group bar().goo() by blah().zap() into g
        select y.blah();|]
  }
}");
    }
 
    [Fact]
    public void InFrontOfSecondFromClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
    $$   from y in [|zap()|]
        let m = quux()
        join a in alpha on left().expr() equals right.expr()
        orderby goo, expr().expr() descending
        group bar().goo() by blah().zap() into g
        select y.blah();
  }
}");
    }
 
    [Fact]
    public void InFrontOfLetClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
        from y in zap()
    $$   let m = [|quux()|]
        join a in alpha on left().expr() equals right.expr()
        orderby goo, expr().expr() descending
        group bar().goo() by blah().zap() into g
        select y.blah();
  }
}");
    }
 
    [Fact]
    public void InFrontOfJoinClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
        from y in zap()
        let m = quux()
    $$   join a in alpha on [|left().expr()|] equals right.expr()
        orderby goo, expr().expr() descending
        group bar().goo() by blah().zap() into g
        select y.blah();
  }
}");
    }
 
    [Fact]
    public void InFrontOfOrderByClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
        from y in zap()
        let m = quux()
        join a in alpha on left().expr() equals right.expr()
    $$   orderby [|goo|], expr().expr() descending
        group bar().goo() by blah().zap() into g
        select y.blah();
  }
}");
    }
 
    [Fact]
    public void InFrontOfGroupByClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
        from y in zap()
        let m = quux()
        join a in alpha on left().expr() equals right.expr()
        orderby goo, expr().expr() descending
    $$   group [|bar().goo()|] by blah().zap() into g
        select y.blah();
  }");
    }
 
    [Fact]
    public void InFrontOfSelectClause()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    var q =
        from x in blah()
        from y in zap()
        let m = quux()
        join a in alpha on left().expr() equals right.expr()
        orderby goo, expr().expr() descending
        group bar().goo() by blah().zap() into g
    $$   select [|y.blah()|];
  }");
    }
 
    [Fact]
    public void Select1()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => from x in new[] { 1 } select [|$$x|];
}
");
    }
 
    [Fact]
    public void Select_NoLambda1()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => [|from x in new[] { 1 } where x > 0 select $$x|];
}
");
    }
 
    [Fact]
    public void Select_NoLambda2()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => [|from x in new[] { 1 } select x into y orderby y select $$y|];
}
");
    }
 
    [Fact]
    public void GroupBy1()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => from x in new[] { 1 } group x by [|$$x|];
}
");
    }
 
    [Fact]
    public void GroupBy_NoLambda1()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => [|from x in new[] { 1 } group $$x by x|];
}
");
    }
 
    [Fact]
    public void GroupBy_NoLambda2()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => [|from x in new[] { 1 } group $$x by x + 1 into y group y by y.Key + 2|];
}
");
    }
 
    [Fact]
    public void GroupBy_NoLambda3()
    {
        TestSpan(
@"class C
{
  IEnumerable<int> Goo() => [|from x in new[] { 1 } group x by x + 1 into y group $$y by y.Key + 2|];
}
");
    }
 
    #endregion
 
    #region Field and Variable Declarators
 
    [Fact]
    public void FieldDeclarator_WithoutInitializer_All()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    int $$i, j;
}");
    }
 
    [Fact]
    public void FieldDeclarator_WithoutInitializer1()
    {
        TestMissing(
@"class C
{
    int $$i;
}");
    }
 
    [Fact]
    public void FieldDeclarator_WithoutInitializer2()
    {
        TestMissing(
@"class C
{
    pri$$vate int i;
}");
    }
 
    [Fact]
    public void FieldDeclarator_SingleVariable_Initializer_All1()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    private int $$i;
}");
    }
 
    [Fact]
    public void FieldDeclarator_SingleVariable_Initializer_All2()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    [|int $$i = 0;|]
}");
    }
    [Fact]
    public void FieldDeclarator_SingleVariable_Initializer_All3()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    [|private int $$i = 0;|]
}");
    }
 
    [Fact]
    public void FieldDeclarator_MultiVariable_Initializer_All1()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    [|private int $$i = 0|], j = 2;
}");
    }
 
    [Fact]
    public void FieldDeclarator_MultiVariable_Initializer_All2()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    [|int $$i = 0|], j = 2;
}");
    }
 
    [Fact]
    public void FieldDeclarator_MultiVariable_Initializer_All3()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    private int i = 0, [|$$j = 0|];
}");
    }
 
    [Fact]
    public void FieldDeclarator_Initializer1()
    {
        TestSpan(
@"class C
{
    [|int $$i = 1;|]
}");
    }
 
    [Fact]
    public void FieldDeclarator_Initializer2()
    {
        TestSpan(
@"class C
{
    [|private int $$i = 1;|]
}");
    }
 
    [Fact]
    public void FieldDeclarator_Initializer3()
    {
        TestSpan(
@"class C
{
    [Goo]
    [|private int $$i = 0;|]
}");
    }
 
    [Fact]
    public void FieldDeclarator_Initializer4()
    {
        TestSpan(
@"class C
{
    [|pri$$vate int i = 1;|]
}");
    }
 
    [Fact]
    public void FieldDeclarator_Initializer5()
    {
        TestSpan(
@"class C
{
$$    [|private int i = 3;|]
}");
    }
 
    [Fact]
    public void ConstVariableDeclarator0()
        => TestMissing("class C { void Goo() { const int a = $$1; } }");
 
    [Fact]
    public void ConstVariableDeclarator1()
        => TestMissing("class C { void Goo() { const $$int a = 1; } }");
 
    [Fact]
    public void ConstVariableDeclarator2()
        => TestMissing("class C { void Goo() { $$const int a = 1; } }");
 
    [Fact]
    public void ConstFieldVariableDeclarator_All()
    {
        VerifyAllSpansInDeclaration<VariableDeclaratorSyntax>(
@"class C
{
    [Goo]
    private const int i = 0, j, $$k = 0;
}");
    }
 
    [Fact]
    public void ConstFieldVariableDeclarator0()
        => TestMissing("class C { const int a = $$1; }");
 
    [Fact]
    public void ConstFieldVariableDeclarator1()
        => TestMissing("class C { const $$int a = 1; }");
 
    [Fact]
    public void ConstFieldVariableDeclarator2()
        => TestMissing("class C { $$const int a = 1; }");
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538777")]
    public void VariableDeclarator0()
        => TestMissing("class C { void Goo() { int$$ } }");
 
    [Fact]
    public void VariableDeclarator1()
    {
        TestMissing(
@"class C
{
  void Goo()
  {
    int $$i;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator2a()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|int $$i = 0;|]
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator2b()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
  $$  [|int i = 0;|]
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator2c()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|$$int i = 0;|]
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator3a()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 0, [|$$j = 3|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator3b()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|int i = 0|], $$j;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator3c()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int $$i, [|j = 0|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 0, [|j = $$1|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator5()
    {
        TestSpan(
@"class C
{
  [|int $$i = 0;|]
}");
    }
 
    [Fact]
    public void VariableDeclarator6()
    {
        TestSpan(
@"class C
{
  [|int i = 0|], $$j;
}");
    }
 
    [Fact]
    public void VariableDeclarator7()
    {
        TestSpan(
@"class C
{
  private int i = 0, [|j = $$1|];
}");
    }
 
    [Fact]
    public void VariableDeclarator8()
    {
        TestSpan(
@"class C
{
  [|priv$$ate int i = 0|], j = 1;
}");
    }
 
    [Fact]
    public void VariableDeclarator9()
    {
        TestSpan(
@"class C
{
$$  [|private int i = 0|], j = 1;
}");
    }
 
    [Fact]
    public void VariableDeclarator10()
        => TestSpan("class C { void M() { [|int i = 0$$;|] } }");
 
    [Fact]
    public void VariableDeclarator_Separators0()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    [|int i = 0|], j = 1, k = 2;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|int i = 0|]$$, j = 1, k = 2;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 0, [|j = 1|]$$, k = 2;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 0, j = 1,$$ [|k = 2|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 0, j = 1, [|k = 2|]$$;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators5()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|int i = 0|], j = 1, k = 2;$$
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators6()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i = 1, j, $$k, [|l = 2|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators7()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i$$, j, k, [|l = 2|];
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators8()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|int i = 2|], j, k, l$$;
  }
}");
    }
 
    [Fact]
    public void VariableDeclarator_Separators9()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    int i, j, [|k = 1|], m, l = 2;$$
  }
}");
    }
 
    [Fact]
    public void EventFieldDeclarator1()
    {
        TestSpan(
@"class C
{
$$    [|public event EventHandler MyEvent = delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator2()
    {
        TestSpan(
@"class C
{
    [|pub$$lic event EventHandler MyEvent = delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator3()
    {
        TestSpan(
@"class C
{
    [|public ev$$ent EventHandler MyEvent = delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator4()
    {
        TestSpan(
@"class C
{
    [|public event EventHan$$dler MyEvent = delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator5()
    {
        TestSpan(
@"class C
{
    [|public event EventHandler MyE$$vent = delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator6()
    {
        TestSpan(
@"class C
{
    [|public event EventHandler MyEvent $$= delegate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator7()
    {
        TestSpan(
@"class C
{
    [|public event EventHandler MyEvent = del$$egate { };|]
}");
    }
 
    [Fact]
    public void EventFieldDeclarator8()
    {
        TestSpan(
@"class C
{
    public event EventHandler MyEvent = delegate [|{|] $$ };
}");
    }
 
    #endregion
 
    [Fact]
    public void EventAccessorAdd()
        => TestSpan("class C { eve$$nt Action Goo { add [|{|] } remove { } } }");
 
    [Fact]
    public void EventAccessorAdd2()
        => TestSpan("class C { event Action Goo { ad$$d [|{|] } remove { } } }");
 
    [Fact]
    public void EventAccessorRemove()
        => TestSpan("class C { event Action Goo { add { } $$remove [|{|] } } }");
 
    [Fact]
    public void ElseClauseWithBlock()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    if (bar)
    {
    }
    el$$se
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void ElseClauseWithStatement()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    if (bar)
    {
    }
    el$$se
      [|Goo();|]
  }
}");
    }
 
    [Fact]
    public void ElseIf()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    if (bar)
    {
    }
    el$$se [|if (baz)|]
      Goo();
  }
}");
    }
 
    [Fact]
    public void EmptyCatch()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    [|cat$$ch|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void CatchWithType()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    [|cat$$ch(Exception)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void CatchWithTypeInType()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    [|catch(Exce$$ption)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void CatchWithTypeAndNameInType()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    [|catch(Exce$$ption e)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void CatchWithTypeAndNameInName()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    [|catch(Exception $$e)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void Filter1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    $$catch(Exception e) [|when (e.Message != null)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void Filter3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    catch(Exception e)$$ [|when (e.Message != null)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void Filter4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    catch(Exception e) [|when$$ (e.Message != null)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void Filter5()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    catch(Exception e) [|when (e.Message != null)|]      $$
    {
    }
  }
}");
    }
 
    [Fact]
    public void SimpleFinally()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    final$$ly
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void FinallyWithCatch()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
    {
    }
    catch
    {
    }
    final$$ly
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void SwitchLabelWithBlock()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        case $$1:
            [|{|]
            }
    }
  }
}");
    }
 
    [Fact]
    public void SwitchLabelWithStatement()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        cas$$e 1:
            [|goo();|]
    }
  }
}");
    }
 
    [Fact]
    public void SwitchLabelWithStatement2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        cas$$e 1:
            [|goo();|]
            bar();
    }
  }
}");
    }
 
    [Fact]
    public void SwitchLabelWithoutStatement()
        => TestSpan("class C { void M() { [|switch |]{ case 1$$: } } }");
 
    [Fact]
    public void MultipleLabelsOnFirstLabel()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        cas$$e 1:
        case 2:
            [|goo();|]
 
        case 3:
        default:
            bar();
    }
  }
}");
    }
 
    [Fact]
    public void MultipleLabelsOnSecondLabel()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        case 1:
        cas$$e 2:
            [|goo();|]
 
        case 3:
        default:
            bar();
    }
  }
}");
    }
 
    [Fact]
    public void MultipleLabelsOnLabelWithDefault()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        case 1:
        case 2:
            goo();
 
        cas$$e 3:
        default:
            [|bar();|]
    }
  }
}");
    }
 
    [Fact]
    public void MultipleLabelsOnDefault()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (goo)
    {
        case 1:
        case 2:
            goo();
 
        case 3:
        default:$$
            [|bar();|]
    }
  }
}");
    }
 
    [Fact]
    public void BlockBeforeStartToken()
    {
        TestSpan(
@"class C
{
  void Goo()
  [|$${|]
    
  }
}");
    }
 
    [Fact]
    public void BlockBeforeStartToken2()
    {
        TestSpan(
@"class C
{
  void Goo()
  $$ [|{|]
    
  }
}");
    }
 
    [Fact]
    public void BlockAfterStartToken()
    {
        TestSpan(
@"class C
{
  void Goo()
  [|{$$|]
    
  }
}");
    }
 
    [Fact]
    public void BlockAfterStartToken2()
    {
        TestSpan(
@"class C
{
  void Goo()
  [|{|] $$
    
  }
}");
    }
 
    [Fact]
    public void BlockBeforeEndToken1()
    {
        TestSpan(
@"class C
{
  void Goo()
  { 
  $$[|}|]
}");
    }
 
    [Fact]
    public void BlockBeforeEndToken2()
    {
        TestSpan(
@"class C
{
  void Goo()
  { 
  $$ [|}|]
}");
    }
 
    [Fact]
    public void BlockAfterEndToken1()
    {
        TestSpan(
@"class C
{
  void Goo()
  { 
  [|}|]$$
}");
    }
 
    [Fact]
    public void BlockAfterEndToken2()
    {
        TestSpan(
@"class C
{
  void Goo()
  { 
  [|}|] $$
}");
    }
 
    [Fact]
    public void SingleDeclarationOnType()
    {
        TestMissing(
@"class C
{
  void Goo()
  {
    i$$nt i;
  }
}");
    }
 
    [Fact]
    public void MultipleDeclarationsOnType()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|i$$nt i = 0|], j = 1;
  }
}");
    }
 
    [Fact]
    public void Label()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    go$$o:
        [|bar();|]
  }
}");
    }
 
    [Fact]
    public void WhileInWhile()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|w$$hile (expr)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void WhileInExpr()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|while (ex$$pr)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnWhileBlock()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    while (expr)
  $$ [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnDoKeyword()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    d$$o
    [|{|]
    }
    while(expr);
  }
}");
    }
 
    [Fact]
    public void OnDoBlock()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    do
  $$ [|{|]
    }
    while(expr);
  }
}");
    }
 
    [Fact]
    public void OnDoWhile()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    do
    {
    }
    [|wh$$ile(expr);|]
  }
}");
    }
 
    [Fact]
    public void OnDoWhile_MissingSemicolon()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    do
    {
    }
    [|wh$$ile(expr)|]
  }
}");
    }
 
    [Fact]
    public void OnDoExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    do
    {
    }
    [|while(ex$$pr);|]
  }
}");
    }
 
    [Fact]
    public void OnForWithDeclaration1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or ([|int i = 0|], j = 1; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForWithDeclaration2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or ([|int i = 0|]; i < 10 && j < 10; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForWithCondition()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or (; [|i < 10 && j < 10|]; i++, j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForWithIncrementor1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or (; ; [|i++|], j++)
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForWithIncrementor2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or (; ; [|i++|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnEmptyFor()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    f$$or (; ; )
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachKeyword1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    [|foreach|] (var v in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachKeyword2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|fo$$reach|] (var v in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachKeyword3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|]    $$    
(var v in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachKeyword4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|]        
$$         (var v in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachKeyword5()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|] $$(var v in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachType1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (   $$   
[|var v|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachType2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach ([|v$$ar v|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachIdentifier()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach ([|var v$$v|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachIn1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v [|i$$n|] expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachIn2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v 
$$         [|in|] expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachIn3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v 
         [|in|] $$
expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachExpr1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v in [|expr($$).blah()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachExpr2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v in [|expr().blah()|]   
     $$    )
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachExpr3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v in 
   $$ [|expr().blah()|]   
     )
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachStatement()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|](var v in expr().blah())    $$ 
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachBlock1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var v in expr().blah())
  $$ [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionKeyword1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    [|foreach|] (var (x, y) in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionKeyword2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|fo$$reach|] (var (x, y) in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionKeyword3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|]    $$    
(var (x, y) in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionKeyword4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|]        
$$         (var (x, y) in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionKeyword5()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|] $$(var (x, y) in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionType1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (   $$   
[|var (x, y)|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionType2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach ([|v$$ar (x, y)|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionIdentifier()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach ([|var (v$$v, y)|] in expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionIn1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) [|i$$n|] expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionIn2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) 
$$         [|in|] expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionIn3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) 
         [|in|] $$
expr().blah())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionExpr1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) in [|expr($$).blah()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionExpr2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) in [|expr().blah()|]   
     $$    )
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionExpr3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) in 
   $$ [|expr().blah()|]   
     )
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionStatement()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|foreach|](var (x, y) in expr().blah())    $$ 
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnForEachDeconstructionBlock1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    foreach (var (x, y) in expr().blah())
  $$ [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDecl1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    us$$ing ([|var v = goo()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDecl2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    us$$ing ([|var v = goo()|], x = bar())
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDeclType()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    using ([|v$$ar v = goo()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDeclIdentifier1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    using ([|var v$$v = goo()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDeclIdentifier2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    using ([|var vv = goo()|])     $$
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDeclIdentifier3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    using ([|var vv = goo()|])     
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithDeclExpression()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    using ([|var vv = go$$o()|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithExpression1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|usi$$ng (goo().bar())|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnUsingWithExpression2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|using (goo$$().bar())|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fi$$xed ([|int* i = &j|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fi$$xed ([|int* i = &j|], k = &m)
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fixed ([|i$$nt* i = &j|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fixed ([|int* $$i = &j|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed5()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fixed ([|int* i $$= &j|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnFixed6()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    fixed ([|int* i = &$$j|])
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnChecked1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    che$$cked
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnUnchecked1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    unche$$cked
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnUnsafe1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    uns$$afe
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnLock1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|lo$$ck (expr)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnLock2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|lock (ex$$pr)|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnIf1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|i$$f (goo().bar())|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnIf2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|if (go$$o().bar())|]
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnIfBlock()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    if (goo().bar())
   $$ [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnSwitch1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|swi$$tch (expr)|]
    {
        default:
            goo();
    }
  }
}");
    }
 
    [Fact]
    public void OnSwitch2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|switch (ex$$pr)|]
    {
        default:
            goo();
    }
  }
}");
    }
 
    [Fact]
    public void OnSwitch3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|switch (expr)|]
  $$ {
        default:
            goo();
    }
  }
}");
    }
 
    [Fact]
    public void OnSwitch4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|switch (expr)|]
    {
        default:
            goo();
  $$ }
  }
}");
    }
 
    [Fact]
    public void OnTry1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    t$$ry
    [|{|]
    }
    finally
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnTry2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    try
  $$ [|{|]
    }
    finally
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnGotoStatement1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|g$$oto goo;|]
  }
}");
    }
 
    [Fact]
    public void OnGotoStatement2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|goto go$$o;|]
  }
}");
    }
 
    [Fact]
    public void OnGotoCaseStatement1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (expr)
    {
        case 1:
            [|go$$to case 2;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnGotoCaseStatement2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (expr)
    {
        case 1:
            [|goto ca$$se 2;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnGotoCaseStatement3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (expr)
    {
        case 1:
            [|goto case $$2;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnGotoDefault1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (expr)
    {
        case 1:
            [|go$$to default;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnGotoDefault2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    switch (expr)
    {
        case 1:
            [|goto defau$$lt;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnBreak1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    while (true)
    {
        [|bre$$ak;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnContinue1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    while (true)
    {
        [|cont$$inue;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnReturn1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|retu$$rn;|]
  }
}");
    }
 
    [Fact]
    public void OnReturn2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|retu$$rn expr();|]
  }
}");
    }
 
    [Fact]
    public void OnReturn3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|return expr$$().bar();|]
  }
}");
    }
 
    [Fact]
    public void OnYieldReturn1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|yi$$eld return goo().bar();|]
  }
}");
    }
 
    [Fact]
    public void OnYieldReturn2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|yield re$$turn goo().bar();|]
  }
}");
    }
 
    [Fact]
    public void OnYieldReturn3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|yield return goo()$$.bar();|]
  }
}");
    }
 
    [Fact]
    public void OnYieldBreak1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|yi$$eld break;|]
  }
}");
    }
 
    [Fact]
    public void OnYieldBreak2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|yield brea$$k;|]
  }
}");
    }
 
    [Fact]
    public void OnThrow1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|th$$row;|]
  }
}");
    }
 
    [Fact]
    public void OnThrow2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|thr$$ow new Goo();|]
  }
}");
    }
 
    [Fact]
    public void OnThrow3()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|throw ne$$w Goo();|]
  }
}");
    }
 
    [Fact]
    public void OnThrow4()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|throw new Go$$o();|]
  }
}");
    }
 
    [Fact]
    public void OnExpressionStatement1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|goo().$$bar();|]
  }
}");
    }
 
    [Fact]
    public void OnEmptyStatement1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|$$;|]
  }
}");
    }
 
    [Fact]
    public void OnEmptyStatement2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    while (true)
    {
   $$ [|;|]
    }
  }
}");
    }
 
    [Fact]
    public void OnPropertyAccessor1()
    {
        TestSpan(
@"class C
{
  int Goo
  {
    g$$et
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnPropertyAccessor2()
    {
        TestSpan(
@"class C
{
  int Goo
  {
    [|g$$et;|]
  }
}");
    }
 
    [Fact]
    public void OnPropertyAccessor3()
    {
        TestSpan(
@"class C
{
  int Goo
  {
    get
    {
    }
 
    s$$et
    [|{|]
    }
  }
}");
    }
 
    [Fact]
    public void OnPropertyAccessor4()
    {
        TestSpan(
@"class C
{
  int Goo
  {
    [|s$$et;|]
  }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48504")]
    public void OnPropertyAccessor5()
    {
        TestSpan(
@"class C
{
  int Goo
  {
    [|in$$it;|]
  }
}");
    }
 
    [Fact]
    public void OnProperty1()
    {
        TestSpan(
@"class C
{
  int G$$oo
  {
    get
    [|{|]
    }
    
    set
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnProperty2()
    {
        TestSpan(
@"class C
{
  int G$$oo
  {
    [|get;|]
    set {} 
  }
}");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/932711")]
    public void OnPropertyWithInitializer()
    {
        TestSpan(
@"class C
{
    public int Id { get; set; } = [|int.Pa$$rse(""42"")|];
}");
 
        TestSpan(
@"class C
{
    public int$$ Id { [|get;|] set; } = int.Parse(""42"");
}");
 
        TestSpan(
@"class C
{
    public int Id { get; [|set;|] $$} = int.Parse(""42"");
}");
 
        TestSpan(
@"class C
{
    public int Id { get; [|set;|] }$$ = int.Parse(""42"");
}");
 
        TestSpan(
@"class C
{
    public int Id { get; set; } =$$ [|int.Parse(""42"")|];
}");
    }
 
    [Fact]
    public void OnPropertyExpressionBody1()
    {
        TestSpan(
@"class C
{
    public int Id => [|12$$3|];
}");
    }
 
    [Fact]
    public void OnPropertyExpressionBody2()
    {
        TestSpan(
@"class C
{
    public int Id $$=> [|123|];
}");
    }
 
    [Fact]
    public void OnPropertyExpressionBody3()
    {
        TestSpan(
@"class C
{
    $$public int Id => [|123|];
}");
    }
 
    [Fact]
    public void OnPropertyExpressionBody4()
    {
        TestSpan(
@"class C
{
    public int Id => [|123|];   $$
}");
    }
 
    [Fact]
    public void OnIndexerExpressionBody1()
    {
        TestSpan(
@"class C
{
    public int this[int a] => [|12$$3|];
}");
    }
 
    [Fact]
    public void OnIndexer1()
    {
        TestSpan(
@"class C
{
  int this[int$$ a]
  {
    get
    [|{|]
    }
    
    set
    {
    }
  }
}");
    }
 
    [Fact]
    public void OnIndexer2()
    {
        TestSpan(
@"class C
{
  int this[int$$ a]
  {
    [|get;|]
    set { }
  }
}");
    }
 
    [Fact]
    public void OnIndexerExpressionBody2()
    {
        TestSpan(
@"class C
{
    public int this[int a] $$=> [|123|];
}");
    }
 
    [Fact]
    public void OnIndexerExpressionBody3()
    {
        TestSpan(
@"class C
{
    $$public int this[int a] => [|123|];
}");
    }
 
    [Fact]
    public void OnIndexerExpressionBody4()
    {
        TestSpan(
@"class C
{
    public int this[int a] => [|123|];   $$
}");
    }
 
    [Fact]
    public void OnIndexerExpressionBody5()
    {
        TestSpan(
@"class C
{
    public int this[int $$a] => [|123|];   
}");
    }
 
    [Fact]
    public void OnMethod1()
    {
        TestSpan(
@"class C
{
    v$$oid Goo()
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnMethod2()
    {
        TestSpan(
@"class C
{
    void G$$oo()
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnMethod3()
    {
        TestSpan(
@"class C
{
    void Goo(in$$t i)
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnMethod4()
    {
        TestSpan(
@"class C
{
    void Goo(int $$i)
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnMethod5()
    {
        TestSpan(
@"class C
{
    void Goo(int i = g$$oo)
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnMethodWithExpressionBody1()
    {
        TestSpan(
@"class C
{
    v$$oid Goo() => [|123|];
}");
    }
 
    [Fact]
    public void OnMethodWithExpressionBody2()
    {
        TestSpan(
@"class C
{
    void Goo() =>$$ [|123|];
}");
    }
 
    [Fact]
    public void OnMethodWithExpressionBody3()
    {
        TestSpan(
@"class C
{
    void Goo() => [|123|]; $$
}");
    }
 
    [Fact]
    public void OnMethodWithExpressionBody4()
    {
        TestSpan(
@"class C
{
    void Goo() => [|12$$3|]; 
}");
    }
 
    [Fact]
    public void MissingOnMethod()
    {
        TestMissing(
@"class C
{
    void Goo($$);
}");
    }
 
    #region Constructors
 
    [Fact]
    public void InstanceConstructor_NoInitializer_BlockBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3][|$$public C()|] [|{|] [|}|]
}");
    }
 
    [Fact]
    public void InstanceConstructor_NoInitializer_BlockBody()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    [|pub$$lic C()|]
    {
    }
}");
    }
 
    [Fact]
    public void InstanceConstructor_NoBody()
    {
        TestSpan(
@"class Class
{
    [|Cla$$ss()|]
}");
    }
 
    [Fact]
    public void InstanceConstructor_NoInitializer_ExpressionBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3][|$$public C()|] => [|x = 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody1()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    [|pub$$lic C()|] => F();
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody2()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    [|public C()|] $$=> x = 1);
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody3()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    public C() =$$> [|x = 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody4()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    public C() => [|$$x = 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody5()
    {
        TestSpan(
@"class C
{
    public C() => [|x =$$ 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody6()
    {
        TestSpan(
@"class C
{
    public C() => [|x = 1|]$$;
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void InstanceConstructor_NoInitializer_ExpressionBody7()
    {
        TestSpan(
@"class C
{
    public C() => [|x = 1|];$$
}");
    }
 
    [Fact]
    public void InstanceConstructor_NoInitializer_Attributes()
    {
        TestSpan(
@"class C
{
    [Attribute1,$$ Attribute2]
    [Attribute3]
    [|public 
 
        C()|]
    {
    }
}");
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ImplicitBaseInitializer_OutsideOfIdentifierAndNonEmptyParameters(
        [CombinatorialValues("class", "struct", "record", "record struct")] string keyword,
        [CombinatorialValues(
            "$$[A]class [|C()|];",
            "$$class [|C()|];",
            "class$$ [|C()|];",
            "class [|C($$)|];",
            "$$class [|C(int a)|];",
            "$$class [|C(int a, int b)|];",
            "class [|C(int a, int b)|]$$;",
            "class [|C(int a, int b)|]$$ { }",
            "class [|C(int a, int b)|]$$ : B { }",
            "class [|C(int a, int b)|] : B$$ { }",
            "class [|C(int a, int b)|] : B, $$I { }",
            "class [|C<T>(int a, int b)|]$$ where T : notnull;",
            "class [|C<T>(int a, int b)|] where $$T : notnull;",
            "class [|C<T>(int a, int b)|] where T : notnull$$;",
            "class [|C<T>(int a, int b)|] where T : notnull$$ { }")] string source)
    {
        TestSpan(source.Replace("class", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ImplicitBaseInitializer_OnIdentifierOrNonEmptyParameters_NonRecord(
        [CombinatorialValues("class", "struct")] string keyword,
        [CombinatorialValues(
            "class [|$$C(int a, int b)|];",
            "class [|C$$(int a, int b)|];",
            "class [|C$$<T>(int a, int b)|];",
            "class [|C<$$T>(int a, int b)|];",
            "class [|C<$$[A]T>(int a, int b)|];",
            "class [|C<T>$$(int a, int b)|];",
            "class [|C<T>($$int a, int b)|];",
            "class [|C<T>($$[A]int a, int b)|];",
            "class [|C<T>(int a, int b$$)|];")] string source)
    {
        TestSpan(source.Replace("class", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ImplicitBaseInitializer_OnIdentifierOrNonEmptyParameters_Record(
        [CombinatorialValues("record", "record struct")] string keyword,
        [CombinatorialValues(
            "record [|$$C|](int a, int b);",          // copy-ctor
            "record [|C$$|](int a, int b);",          // copy-ctor
            "record [|C$$<T>|](int a, int b);",       // copy-ctor
            "record [|C<$$T>|](int a, int b);",       // copy-ctor
            "record [|C<$$[A]T>|](int a, int b);",    // copy-ctor
            "record [|C<T>$$|](int a, int b);",       // copy-ctor
            "record C<T>([|$$int a|], int b);",       // property getter and setter
            "record C<T>($$[A][|int a|], int b);",    // property getter and setter
            "record C<T>($$   [A][|int a|], int b);", // property getter and setter
            "record C<T>(int a, [|int b$$|]);",       // property getter and setter
            "record C<T>(int a,  $$ [|int b|]);",     // property getter and setter
            "record C<T>(int a, [|params int[] b|]  $$);",     // property getter and setter
            "record C<T>(int a, [|int b|] = default$$);")] string source) // property getter and setter
    {
        TestSpan(source.Replace("record", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ImplicitBaseInitializer_NoBreakpoint(
        [CombinatorialValues("class", "struct", "record", "record struct")] string keyword,
        [CombinatorialValues(
            "$$[A]class C;",
            "$$class C;",
            "class C$$;",
            "class C;$$",
            "class C(int a, int b);$$",
            "class C(int a, int b) : B;$$",
            "class C(int a, int b) : B { }$$")] string source)
    {
        TestMissing(source.Replace("class", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ExplicitBaseInitializer_OutsideOfIdentifierAndNonEmptyParameters(
        [CombinatorialValues("class", "struct", "record", "record struct")] string keyword,
        [CombinatorialValues(
            "$$[A]class C() : [|B()|];",
            "$$class C() : [|B()|];",
            "$$class C(int a) : [|B()|];",
            "$$class C(int a, int b) : [|B()|];",
            "class C(int a, int b)$$ : [|B()|];",
            "class C(int a, int b) :$$ [|B()|];",
            "class C(int a, int b) : [|$$B()|];",
            "class C(int a, int b) : [|B($$)|];",
            "class C(int a, int b) : [|B()$$|];",
            "class C(int a, int b) : [|B()|] $$;",
            "class C(int a, int b) : [|B()|] $$ {}",
            "class C(int a, int b) : [|B()|], $$I {}",
            "class C(int a, int b) : [|B()|], I$$ {}",
            "class C<T>(int a, int b) : [|B()|] $$ where T : notnull;",
            "class C<T>(int a, int b) : [|B()|], $$I where T : notnull { }",
            "class C<T>(int a, int b) : [|B()|], I$$ where T : notnull { }",
            "class C<T>(int a, int b) : [|B()|]  where $$T : notnull;",
            "class C<T>(int a, int b) : [|B()|]  where T : notnull$$;",
            "class C<T>(int a, int b) : [|B()|]  where T : notnull$$ { }")] string source)
    {
        TestSpan(source.Replace("class", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ExplicitBaseInitializer_OnIdentifierOrNonEmptyParameters_NonRecord(
        [CombinatorialValues("class", "struct")] string keyword,
        [CombinatorialValues(
            "class $$C(int a, int b) : [|B()|];",
            "class C$$(int a, int b) : [|B()|];",
            "class C<$$[A]T>(int a, int b) : [|B()|];",
            "class C<T>$$(int a, int b) : [|B()|];",
            "class C<T>($$int a, int b) : [|B()|];",
            "class C<T>(int a, $$int b) : [|B()|];",
            "class C<T>(int a, int b =$$ 1) : [|B()|];")] string source)
    {
        TestSpan(source.Replace("class", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ExplicitBaseInitializer_OnIdentifierOrNonEmptyParameters_Record(
        [CombinatorialValues("record", "record struct")] string keyword,
        [CombinatorialValues(
            "record [|$$C|](int a, int b) : B();",        // copy-constructor
            "record [|C$$|](int a, int b) : B();",        // copy-constructor
            "record [|C<$$[A]T>|](int a, int b) : B();",  // copy-constructor
            "record [|C<T>$$|](int a, int b) : B();",     // copy-constructor
            "record C<T>([|$$int a|], int b) : B();",     // property getter and setter
            "record C<T>(int a, [|$$int b|]) : B();",     // property getter and setter
            "record C<T>(int a, [|$$int b|] = 1) : B();")] string source) // property getter and setter
    {
        TestSpan(source.Replace("record", keyword));
    }
 
    [Theory, CombinatorialData]
    public void InstanceConstructor_Primary_ExplicitBaseInitializer_NoBreakpoint(
        [CombinatorialValues("class", "struct", "record", "record struct")] string keyword,
        [CombinatorialValues(
            "class C(int a, int b) : B() {$$ }",
            "class C(int a, int b) : B();$$",
            "class C(int a, int b) : B() { }$$",
            "class C(int a, int b) : B {$$ }",
            "class C(int a, int b) : B(), I { }$$")] string source)
    {
        TestMissing(source.Replace("class", keyword));
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_BlockBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3]$$public C() : [|base(42)|] [|{|][|}|]
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_BlockBody()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    pub$$lic C()
        : [|base(42)|]
    {
    }
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_ExpressionBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3]$$public C() : [|base(42)|] => [|x = 1|];
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_ExpressionBody1()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    pub$$lic C() : [|base(42)|] => F();
    
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_ExpressionBody2()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    public C() : [|base(42)|] $$=> F();
    
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_ExpressionBody3()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    public C() : base(42) =$$> [|F()|];
    
}");
    }
 
    [Fact]
    public void InstanceConstructor_BaseInitializer_ExpressionBody4()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class C
{
    public C() : base(42) => [|$$F()|];
    
}");
    }
 
    [Fact]
    public void InstanceConstructor_ThisInitializer()
    {
        // a sequence point for this constructor call
        TestSpan(
@"class C
{
    pub$$lic C()
        : [|this(42)|]
    {
    }
}");
    }
 
    [Fact]
    public void StaticConstructor_BlockBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3]$$static public C() [|{|] [|}|]
}");
    }
 
    [Fact]
    public void StaticConstructor_BlockBody()
    {
        TestSpan(
@"class C
{
    $$static C()
    [|{|]
    }
}");
    }
 
    [Fact]
    public void StaticConstructor_ExpressionBody_All()
    {
        VerifyAllSpansInDeclaration<ConstructorDeclarationSyntax>(
@"class C
{
    [Attribute1, Attribute2][Attribute3]$$static public C() => [|x = 1|];
}");
    }
 
    [Fact]
    public void StaticConstructor_ExpressionBody()
    {
        TestSpan(
@"class C
{
    static C() => [|$$F()|];
}");
    }
 
    [Fact]
    public void StaticConstructor_NoBody()
    {
        TestMissing(
@"class Class
{
    static Cla$$ss()
}");
    }
 
    [Fact]
    public void InstanceConstructorInitializer()
    {
        // a sequence point for this constructor call
        TestSpan(
@"class Derived : Base
{
    public Derived()
        : [|this($$42)|]
    {
    }
}");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543968")]
    public void ConstructorInitializer()
    {
        // a sequence point for base constructor call
        TestSpan(
@"class Derived : Base
{
    public Derived()
        : [|base($$42)|]
    {
    }
}
");
    }
 
    [Fact]
    public void OnStaticConstructor()
    {
        TestSpan(
@"class C
{
    st$$atic C()
    [|{|]
    }
}");
    }
 
    #endregion
 
    [Fact]
    public void OnDestructor()
    {
        TestSpan(
@"class C
{
    ~C$$()
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnOperator()
    {
        TestSpan(
@"class C
{
    public static int op$$erator+(C c1, C c2)
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnOperatorWithExpressionBody1()
    {
        TestSpan(
@"class C
{
    public static int op$$erator+(C c1, C c2) => [|c1|];
}");
    }
 
    [Fact]
    public void OnOperatorWithExpressionBody2()
    {
        TestSpan(
@"class C
{
    public static int operator+(C c1, C c2) =>$$ [|c1|];
}");
    }
 
    [Fact]
    public void OnOperatorWithExpressionBody3()
    {
        TestSpan(
@"class C
{
    public static int operator+(C c1, C c2) => [|c1|]; $$
}");
    }
 
    [Fact]
    public void OnOperatorWithExpressionBody4()
    {
        TestSpan(
@"class C
{
    public static int operator+(C c1, C c2) => [|c$$1|];
}");
    }
 
    [Fact]
    public void OnConversionOperator()
    {
        TestSpan(
@"class C
{
    public static op$$erator DateTime(C c1)
    [|{|]
    }
}");
    }
 
    [Fact]
    public void OnConversionOperatorWithExpressionBody1()
    {
        TestSpan(
@"class C
{
    public static op$$erator DateTime(C c1) => [|DataTime.Now|];
}");
    }
 
    [Fact]
    public void OnConversionOperatorWithExpressionBody2()
    {
        TestSpan(
@"class C
{
    public static operator DateTime(C c1) =>$$ [|DataTime.Now|];
}");
    }
 
    [Fact]
    public void OnConversionOperatorWithExpressionBody3()
    {
        TestSpan(
@"class C
{
    public static operator DateTime(C c1) => [|DataTime.Now|];$$
}");
    }
 
    [Fact]
    public void OnConversionOperatorWithExpressionBody4()
    {
        TestSpan(
@"class C
{
    public static operator DateTime(C c1) => [|DataTime$$.Now|];
}");
    }
 
    [Fact, WorkItem(3557, "DevDiv_Projects/Roslyn")]
    public void InFrontOfAttribute()
    {
        TestSpan(
@"class C
{
$$ [method: Obsolete]
  void Goo()
  [|{|]
  }
}");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538058")]
    public void InInactivePPRegion()
    {
        TestLine(
@"
 
#if blahblah
$$gooby
#endif");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538777")]
    public void WithIncompleteDeclaration()
    {
        TestMissing(
@"
clas C
{
    void Goo()
    {
$$        int
    }
}");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/937290")]
    public void OnGetter()
    {
        TestSpan(
@"class C
{
    public int $$Id { [|get;|] set; }
}");
 
        TestSpan(
@"class C
{
    public int Id { [|g$$et;|] set; }
}");
 
        TestSpan(
@"class C
{
    public int Id { g$$et [|{|] return 42; } set {} }
}");
 
        TestSpan(
@"class C
{
    public int$$ Id { get [|{|] return 42; } set {} }
}");
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/937290")]
    public void OnSetter()
    {
        TestSpan(
@"class C
{
    public int Id { get; [|se$$t;|] }
}");
 
        TestSpan(
@"class C
{
    public int Id { get; [|set;|] $$ }
}");
 
        TestSpan(
@"class C
{
    public int $$Id { [|set;|] get; }
}");
 
        TestSpan(
@"class C
{
    public int Id { get { return 42; } s$$et [|{|] } }
}");
 
        TestSpan(
@"class C
{
    public int Id { get { return 42; } set { [|}|] $$}
}");
    }
 
    [Fact]
    public void WhenClause_1()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
$$      case string s [|when b|]:
        break;
    }
  }
}");
    }
 
    [Fact]
    public void WhenClause_2()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
      case string s [|whe$$n b|]:
        break;
    }
  }
}");
    }
 
    [Fact]
    public void WhenClause_3()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
      case string s [|when b|]:$$
        break;
    }
  }
}");
    }
 
    [Fact]
    public void PatternSwitchCase_1()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
$$      case string s:
      default:
        [|break;|]
    }
  }
}");
    }
 
    [Fact]
    public void PatternSwitchCase_2()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
      $$case string s:
      default:
        [|break;|]
    }
  }
}");
    }
 
    [Fact]
    public void PatternSwitchCase_3()
    {
        TestSpan(
@"class C
{
  string s;
  bool b;
  void Goo()
  {
    switch (s)
    {
      case string s:$$
      default:
        [|break;|]
    }
  }
}");
    }
 
    [Fact]
    public void DeconstructionDeclarationStatement_1()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
$$    [|var (x, y) = (1, 2);|]
  }
}");
    }
 
    [Fact]
    public void DeconstructionDeclarationStatement_2()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|var (x, y) = $$(1, 2);|]
  }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody1()
    {
        TestSpan(
@"class C
{
    public int Id { get => [|12$$3|]; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody2()
    {
        TestSpan(
@"class C
{
    public int Id { get $$=> [|123|]; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody3()
    {
        TestSpan(
@"class C
{
    $$public int Id { get => [|123|]; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody4()
    {
        TestSpan(
@"class C
{
    public int Id { get => [|123|];   $$ }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody5()
    {
        TestSpan(
@"class C
{
$$    public event Action Goo { add => [|123|]; remove => 456; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody6()
    {
        TestSpan(
@"class C
{
    public event Action Goo { add => [|123|];$$ remove => 456; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody7()
    {
        TestSpan(
@"class C
{
    public event Action Goo { add => 123; $$remove => [|456|]; }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnAccessorExpressionBody8()
    {
        TestSpan(
@"class C
{
    public event Action Goo { add => 123; remove => [|456|]; }$$
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnDtorExpressionBody1()
    {
        TestSpan(
@"class C
{
$$    public ~C() => [|x = 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnDtorExpressionBody2()
    {
        TestSpan(
@"class C
{
    public ~C() => $$[|x = 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnDtorExpressionBody3()
    {
        TestSpan(
@"class C
{
    public ~C() => [|x =$$ 1|];
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnDtorExpressionBody4()
    {
        TestSpan(
@"class C
{
    public ~C() => [|x = 1|]$$;
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14438")]
    public void OnDtorExpressionBody5()
    {
        TestSpan(
@"class C
{
    public ~C() => [|x = 1|];$$
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_1()
    {
        TestSpan(
@"class C
{
    static void M()
    {
$$        int Local(object[] a)
        [|{|]
            return a.Length;
        }
    }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_2()
    {
        TestSpan(
@"class C
{
    static void M()
    {
        int Local(object[] a)$$
        [|{|]
            return a.Length;
        }
    }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_3()
    {
        TestSpan(
@"class C
{
    static void M()
    {
        int Local(object[] a)
$$        [|{|]
            return a.Length;
        }
    }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_4()
    {
        TestSpan(
@"class C
{
    static void M()
    {
$$        int Local(object[] a) => [|a.Length|];
    }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_5()
    {
        TestSpan(
@"class C
{
    static void M()
    {
        int Local(object$$[] a) => [|a.Length|];
    }
}");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/14437")]
    public void OnLocalFunctionDecl_6()
    {
        TestSpan(
@"class C
{
    static void M()
    {
        int Local(object[] a) => [|a.Length|];$$
    }
}");
    }
 
    [Fact, WorkItem("https://developercommunity.visualstudio.com/content/problem/98990/cant-set-breakpoint.html")]
    public void IncompleteExpressionStatement()
    {
        TestSpan(
@"class C
{
  void Goo()
  {
    [|$$aaa|]
  }
}");
    }
 
    #region Top Level Statements
 
    [Fact]
    public void TopLevelStatements()
    {
        VerifyAllSpansInDeclaration<CompilationUnitSyntax>(@"
$$[|int d = 5;|]
[|int a = 1|], [|b = 2|], [|c = 3|];
for ([|int i = 0|], [|j = 1|], [|k = 2|]; [|i < 10|]; [|i++|], [|j++|], [|k--|])
    [|while (b > 0)|]
    [|{|]
        [|if (c < b)|]
            try
            [|{|]
                [|System.Console.WriteLine(a);|]
            [|}|]
            [|catch (Exception e)|]
            [|{|]
                [|System.Console.WriteLine(e);|]   
            [|}|]
            finally
            [|{|]
            [|}|]
        else [|if (b < 10)|]
            [|System.Console.WriteLine(b);|]
        else
            [|System.Console.WriteLine(c);|]
    [|}|]
");
    }
 
    #endregion
}