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()); }
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)); }
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); }
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); }
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)); }
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()); }
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()); }