public static void RecursionTargetExtensionMethodArgumentsStaticInvocation()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public static class C
    {
        public static int P => M(1, 2);

        public static int M(this int m, int n) => m + n;
    }
}");
            var compilation   = CSharpCompilation.Create("test", new[] { tree });
            var semanticModel = compilation.GetSemanticModel(tree);

            Assert.AreEqual(true, semanticModel.TryGetNamedType(tree.FindClassDeclaration("C"), CancellationToken.None, out var type));
            using var recursion = Recursion.Borrow(type, semanticModel, CancellationToken.None);
            var argument = tree.FindArgument("1");
            var target   = recursion.Target(argument).Value;

            using var walker1 = UsagesWalker.Borrow(target.Symbol, target.Declaration, semanticModel, CancellationToken.None);
            Assert.AreEqual("m", string.Join(", ", walker1.Usages));

            argument          = tree.FindArgument("2");
            target            = recursion.Target(argument).Value;
            using var walker2 = UsagesWalker.Borrow(target.Symbol, target.Declaration, semanticModel, CancellationToken.None);
            Assert.AreEqual("n", string.Join(", ", walker2.Usages));
        }
        public static void RecursionTargetExtensionMethodArgumentsGeneric()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public static class C
    {
        public static bool P => 1.M<int>(2);

        public static bool M<T>(this T m, T n) => Equals(m, n);
    }
}");
            var compilation   = CSharpCompilation.Create("test", new[] { tree });
            var semanticModel = compilation.GetSemanticModel(tree);

            Assert.AreEqual(true, semanticModel.TryGetNamedType(tree.FindClassDeclaration("C"), CancellationToken.None, out var type));
            using var recursion = Recursion.Borrow(type, semanticModel, CancellationToken.None);
            var invocation       = tree.FindInvocation("1.M<int>(2");
            var invocationTarget = recursion.Target(invocation).Value;

            using var invocationWalker = UsagesWalker.Borrow(invocationTarget.Symbol, invocationTarget.Declaration, semanticModel, CancellationToken.None);
            Assert.AreEqual("m", string.Join(", ", invocationWalker.Usages));

            var argument       = tree.FindArgument("2");
            var argumentTarget = recursion.Target(argument).Value;

            using var argumentWalker = UsagesWalker.Borrow(argumentTarget.Symbol, argumentTarget.Declaration, semanticModel, CancellationToken.None);
            Assert.AreEqual("n", string.Join(", ", argumentWalker.Usages));
        }
        internal static bool Returns(LocalOrParameter localOrParameter, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            using var recursion = Recursion.Borrow(localOrParameter.Symbol.ContainingType, semanticModel, cancellationToken);
            using var walker    = UsagesWalker.Borrow(localOrParameter, recursion.SemanticModel, recursion.CancellationToken);
            foreach (var usage in walker.Usages)
            {
                if (Returns(usage, recursion))
                {
                    return(true);
                }
            }

            return(false);
        }
        internal static bool Stores(LocalOrParameter localOrParameter, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ISymbol?container)
        {
            using var recursion = Recursion.Borrow(localOrParameter.Symbol.ContainingType, semanticModel, cancellationToken);
            using var walker    = UsagesWalker.Borrow(localOrParameter, semanticModel, cancellationToken);
            foreach (var usage in walker.Usages)
            {
                if (Stores(usage, recursion, out container))
                {
                    return(true);
                }
            }

            container = null;
            return(false);
        }
        internal static bool ShouldDispose(LocalOrParameter localOrParameter, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (localOrParameter.Symbol is IParameterSymbol parameter &&
                parameter.RefKind != RefKind.None)
            {
                return(false);
            }

            using var recursion = Recursion.Borrow(localOrParameter.Symbol.ContainingType, semanticModel, cancellationToken);
            using var walker    = UsagesWalker.Borrow(localOrParameter, semanticModel, cancellationToken);
            foreach (var usage in walker.Usages)
            {
                if (Returns(usage, recursion))
                {
                    return(false);
                }

                if (Assigns(usage, recursion, out _))
                {
                    return(false);
                }

                if (Stores(usage, recursion, out _))
                {
                    return(false);
                }

                if (Disposes(usage, recursion))
                {
                    return(false);
                }

                if (DisposedByReturnValue(usage, recursion, out _))
                {
                    return(false);
                }
            }

            return(true);
        }
        public static void RecursionTargetArgumentGeneric()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public class C
    {
        public int P => this.M<int>(1);

        public T M<T>(T n) => n;
    }
}");
            var compilation   = CSharpCompilation.Create("test", new[] { tree });
            var semanticModel = compilation.GetSemanticModel(tree);

            Assert.AreEqual(true, semanticModel.TryGetNamedType(tree.FindClassDeclaration("C"), CancellationToken.None, out var type));
            using var recursion = Recursion.Borrow(type, semanticModel, CancellationToken.None);
            var node   = tree.FindArgument("1");
            var target = recursion.Target(node).Value;

            using var walker = UsagesWalker.Borrow(target.Symbol, target.Declaration, semanticModel, CancellationToken.None);
            Assert.AreEqual("n", string.Join(", ", walker.Usages));
        }