Пример #1
0
        public static void ArgumentOverloaded()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public class C1
    {
        public int P => M(1);

        public virtual int M(int n) => n;
    }

    public class C2
    {
        public override int M(int x) => x;
    }
}");
            var compilation   = CSharpCompilation.Create("test", new[] { tree });
            var semanticModel = compilation.GetSemanticModel(tree);

            Assert.AreEqual(true, semanticModel.TryGetNamedType(tree.FindClassDeclaration("C2"), 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;

            Assert.AreEqual(node, target.Source);
            Assert.AreEqual("int x", target.Symbol.ToDisplayString(Format));
            Assert.AreEqual("public override int M(int x) => x;", target.Declaration.ToString());
        }
Пример #2
0
        public static void LocalFunction()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public static class C
    {
        public static int P
        {
            get
            {
                return M();

                int M() => 1;
            }
        }
    }
}");
            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.FindInvocation("M()");
            var target = recursion.Target(node).Value;

            Assert.AreEqual("M()", target.Source.ToString());
            Assert.AreEqual("M()", target.Symbol.ToDisplayString(Format));
            Assert.AreEqual("int M() => 1;", target.Declaration.ToString());
        }
        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));
        }
Пример #5
0
        internal static bool IsValueValidForRegisteredType(ExpressionSyntax value, ITypeSymbol registeredType, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (value.FirstAncestor <TypeDeclarationSyntax>() is { } containingTypeDeclaration&&
                semanticModel.TryGetNamedType(containingTypeDeclaration, cancellationToken, out var containingType))
            {
                using var recursion = Recursion.Borrow(containingType, semanticModel, cancellationToken);
                return(IsValueValidForRegisteredType(value, registeredType, recursion));
            }

            return(true);
        internal static bool Ignores(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (candidate.TryFirstAncestor(out TypeDeclarationSyntax? containingTypeDeclaration) &&
                semanticModel.TryGetNamedType(containingTypeDeclaration, cancellationToken, out var containingType))
            {
                using var recursion = Recursion.Borrow(containingType, semanticModel, cancellationToken);
                return(Ignores(candidate, recursion));
            }

            return(false);
        }
Пример #7
0
        internal static bool TryGet(ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ITypeSymbol?result, [NotNullWhen(true)] out ExpressionSyntax?source)
        {
            if (expression.TryFirstAncestor(out TypeDeclarationSyntax? containingType) &&
                semanticModel.TryGetNamedType(containingType, cancellationToken, out var type))
            {
                using var recursion = Recursion.Borrow(type, semanticModel, cancellationToken);
                return(TryGet(expression, recursion, out result, out source));
            }

            result = null;
            source = null;
            return(false);
        }
        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 DisposedByReturnValue(ArgumentSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax?creation)
        {
            if (candidate.TryFirstAncestor(out TypeDeclarationSyntax? containingTypeDeclaration) &&
                semanticModel.TryGetNamedType(containingTypeDeclaration, cancellationToken, out var containingType))
            {
                using var recursion = Recursion.Borrow(containingType, semanticModel, cancellationToken);
                if (recursion.Target(candidate) is { } target)
                {
                    return(DisposedByReturnValue(target, recursion, out creation));
                }
            }

            creation = null;
            return(false);
        }
        private static bool Ignores(ExpressionSyntax candidate, Recursion recursion)
        {
            using (var temp = Recursion.Borrow(recursion.ContainingType, recursion.SemanticModel, recursion.CancellationToken))
            {
                if (Disposes(candidate, temp))
                {
                    return(false);
                }
            }

            using (var temp = Recursion.Borrow(recursion.ContainingType, recursion.SemanticModel, recursion.CancellationToken))
            {
                if (Assigns(candidate, temp, out _))
                {
                    return(false);
                }
            }

            using (var temp = Recursion.Borrow(recursion.ContainingType, recursion.SemanticModel, recursion.CancellationToken))
            {
                if (Stores(candidate, temp, out _))
                {
                    return(false);
                }
            }

            using (var temp = Recursion.Borrow(recursion.ContainingType, recursion.SemanticModel, recursion.CancellationToken))
            {
                if (Returns(candidate, temp))
                {
                    return(false);
                }
            }

            return(candidate switch
            {
                { Parent : AssignmentExpressionSyntax {
                      Left : IdentifierNameSyntax {
                          Identifier : { ValueText : "_" }
                      }
                  } }
        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);
        }
Пример #13
0
        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));
        }
Пример #14
0
        public static void ArgumentGeneric()
        {
            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;

            Assert.AreEqual(node, target.Source);
            Assert.AreEqual("T n", target.Symbol.ToDisplayString(Format));
            Assert.AreEqual("public T M<T>(T n) => n;", target.Declaration.ToString());
        }
Пример #15
0
        public static void ExtensionMethodConditional()
        {
            var tree          = CSharpSyntaxTree.ParseText(@"
namespace N
{
    public static class C
    {
        public static int M1(int? i) => i?.M2() ?? 0;

        public static int M2(this int 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.FindInvocation("i?.M2()");
            var target = recursion.Target(node).Value;

            Assert.AreEqual("i", target.Source.ToString());
            Assert.AreEqual("int n", target.Symbol.ToDisplayString(Format));
            Assert.AreEqual("public static int M2(this int n) => n;", target.Declaration.ToString());
        }