public void Lambda(string code, Search search, string expected) { var testCode = @" namespace RoslynSandbox { using System; internal class Foo { internal Foo() { Func<int> temp = () => 1; } internal static int StaticCreateIntStatementBody() { return 1; } } }"; testCode = testCode.AssertReplace("Func<int> temp = () => 1", code); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public static void ReturnNullCoalesce() { var code = @" namespace N { public class C { public C() { var temp = ReturnNullCoalesce(null); } private static string ReturnNullCoalesce(string text) { return text ?? string.Empty; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var methodDeclaration = syntaxTree.FindEqualsValueClause("var temp = ReturnNullCoalesce(null)").Value; using var returnValues = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.Recursive, semanticModel, CancellationToken.None); Assert.AreEqual("null, string.Empty", string.Join(", ", returnValues)); }
public static void AwaitSyntaxError(ReturnValueSearch search, string expected) { var code = @" using System.Threading.Tasks; internal class C { internal static async Task M() { var text = await CreateAsync().ConfigureAwait(false); } internal static async Task<string> CreateAsync() { await Task.Delay(0); return await Task.SyntaxError(() => new string(' ', 1)).ConfigureAwait(false); } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindExpression("await CreateAsync().ConfigureAwait(false)"); using var pooled = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); }
public static void Lambda(string expression, ReturnValueSearch search, string expected) { var code = @" namespace N { using System; internal class C { internal C() { Func<int> temp = () => 1; } internal static int StaticCreateIntStatementBody() { return 1; } } }".AssertReplace("Func<int> temp = () => 1", expression); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(expression).Value; using var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); var actual = string.Join(", ", returnValues); Assert.AreEqual(expected, actual); }
public static void ReturnTernary() { var code = @" namespace N { public class C { public C() { var temp = ReturnTernary(true); } private static int ReturnTernary(bool b) { return b ? 1 : 2; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var methodDeclaration = syntaxTree.FindEqualsValueClause("var temp = ReturnTernary(true)").Value; using var walker = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.Recursive, semanticModel, CancellationToken.None); Assert.AreEqual("1, 2", string.Join(", ", walker.ReturnValues)); }
public static void RecursiveWithOptionalParameter() { var code = @" namespace N { using System; using System.Collections.Generic; public abstract class C { public C(IDisposable disposable) { var local = disposable; local = WithOptionalParameter(local); } private static IDisposable WithOptionalParameter(IDisposable parameter, IEnumerable<IDisposable> values = null) { if (values == null) { return WithOptionalParameter(parameter, new[] { parameter }); } return parameter; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindInvocation("WithOptionalParameter(local)"); using var walker = ReturnValueWalker.Borrow(value, ReturnValueSearch.Recursive, semanticModel, CancellationToken.None); Assert.AreEqual("disposable", string.Join(", ", walker.ReturnValues)); }
public static void ProcessReturnStatement(ISymbol local, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken, RefCounterStatus status) { using (var walker = ReturnValueWalker.Borrow(block, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var value in walker) { var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (SymbolComparer.Equals(local, returnedSymbol)) { var method = block.FirstAncestor <MethodDeclarationSyntax>(); var access = block.FirstAncestor <AccessorDeclarationSyntax>(); bool isGet = false; if (method != null) { isGet = KnownSymbol.IsGetMethodName(method.Identifier.ToString()); } else if (access != null) { isGet = true; } if (isGet) { status.RemainRef("return value from get method", value.GetLocation()); } else { status.ReleaseReference("return value from non get", value.GetLocation()); } } } } }
public void AsyncAwaitRecursive(string code, ReturnValueSearch search, string expected) { var testCode = @" namespace RoslynSandbox { using System; using System.Threading.Tasks; public class Disposable : IDisposable { public void Dispose() { } } internal class Foo { internal async Task Bar() { var value = await RecursiveAsync(); } internal static Task<int> RecursiveAsync() => RecursiveAsync(); internal static Task<int> RecursiveAsync(int arg) => RecursiveAsync(arg); private static async Task<int> RecursiveAsync1(int value) { return await RecursiveAsync2(value); } private static async Task<int> RecursiveAsync2(int value) { return await RecursiveAsync1(value); } private static Task<int> RecursiveAsync3(int value) { return RecursiveAsync4(value); } private static async Task<int> RecursiveAsync4(int value) { return await RecursiveAsync3(value); } } }".AssertReplace("var value = await RecursiveAsync()", $"var value = {code}"); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None)) { Assert.AreEqual(expected, string.Join(", ", returnValues)); } }
public void ValidationErrorToStringConverter() { var testCode = @" namespace RoslynSandbox { using System; using System.Globalization; using System.Windows.Controls; using System.Windows.Data; public class ValidationErrorToStringConverter : IValueConverter { /// <summary> Gets the default instance </summary> public static readonly ValidationErrorToStringConverter Default = new ValidationErrorToStringConverter(); /// <inheritdoc /> public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is string text) { return text; } if (value is ValidationResult result) { return this.Convert(result.ErrorContent, targetType, parameter, culture); } if (value is ValidationError error) { return this.Convert(error.ErrorContent, targetType, parameter, culture); } return value; } /// <inheritdoc /> object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException($""{this.GetType().Name} only supports one-way conversion.""); } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var methodDeclaration = syntaxTree.FindMethodDeclaration("Convert"); using (var returnValues = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.Recursive, semanticModel, CancellationToken.None)) { Assert.AreEqual("error.ErrorContent, result.ErrorContent, value", string.Join(", ", returnValues)); } }
public void Property(string code, ReturnValueSearch search, string expected) { var testCode = @" namespace RoslynSandbox { internal class Foo { private readonly int value = 1; internal Foo() { var temp = CalculatedExpressionBody; } public int CalculatedExpressionBody => 1; public int CalculatedStatementBody { get { return 1; } } public Foo ThisExpressionBody => this; public int CalculatedReturningFieldExpressionBody => this.value; public int CalculatedReturningFieldStatementBody { get { return this.value; } } } }".AssertReplace("var temp = CalculatedExpressionBody", $"var temp = {code}"); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", returnValues); Assert.AreEqual(expected, actual); } }
public void ChainedExtensionMethod() { var testCode = @" namespace RoslynSandbox { using System; public class Foo { public void Bar(int i) { var value = i.AsDisposable().AsDisposable(); } } public static class Ext { public static IDisposable AsDisposable(this int i) => new Disposable(); public static IDisposable AsDisposable(this IDisposable d) => new WrappingDisposable(d); } public sealed class WrappingDisposable : IDisposable { private readonly IDisposable inner; public WrappingDisposable(IDisposable inner) { this.inner = inner; } public void Dispose() { this.inner.Dispose(); } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var methodDeclaration = syntaxTree.FindEqualsValueClause("var value = i.AsDisposable().AsDisposable()").Value; using (var returnValues = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.Recursive, semanticModel, CancellationToken.None)) { Assert.AreEqual("new WrappingDisposable(d)", returnValues.Single().ToString()); } }
public static void PropertyRecursive(string expression, ReturnValueSearch search, string expected) { var code = @" namespace N { internal class C { internal C() { var temp = StaticRecursiveExpressionBody; } public static int StaticRecursiveExpressionBody => StaticRecursiveExpressionBody; public static int StaticRecursiveStatementBody { get { return StaticRecursiveStatementBody; } } public int RecursiveExpressionBody => this.RecursiveExpressionBody; public int RecursiveStatementBody { get { return this.RecursiveStatementBody; } } } }".AssertReplace("var temp = StaticRecursiveExpressionBody", $"var temp = {expression}"); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(expression).Value; using var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); var actual = string.Join(", ", returnValues); Assert.AreEqual(expected, actual); }
public static void AsyncAwait(string expression, ReturnValueSearch search, string expected) { var code = @" namespace N { using System; using System.Threading.Tasks; public class Disposable : IDisposable { public void Dispose() { } } internal class C { internal async Task M() { var value = await CreateStringAsync(); } internal static int CreateInt() => 1; internal static async Task<string> CreateStringAsync() { await Task.Delay(0); return new string(' ', 1); } internal static async Task<int> CreateIntAsync() { await Task.Delay(0); return 1; } internal static Task<int> ReturnTaskFromResultAsync() => Task.FromResult(1); internal static Task<int> ReturnTaskFromResultAsync(int arg) => Task.FromResult(arg); internal static async Task<string> ReturnAwaitTaskRunAsync() => await Task.Run(() => new string(' ', 1)); internal static async Task<string> ReturnAwaitTaskRunConfigureAwaitAsync() => await Task.Run(() => new string(' ', 1)).ConfigureAwait(false); internal static Task<int> CreateAsync(int arg) { switch (arg) { case 0: return Task.FromResult(1); case 1: return Task.FromResult(arg); case 2: return Task.Run(() => 2); case 3: return Task.Run(() => arg); case 4: return Task.Run(() => { return 3; }); default: return Task.Run(() => { return arg; }); } } } }".AssertReplace("var value = await CreateStringAsync()", $"var value = {expression}"); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(expression).Value; using var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); Assert.AreEqual(expected, string.Join(", ", returnValues)); }
public static void CallRecursive(string expression, ReturnValueSearch search, string expected) { var code = @" namespace N { using System; using System.Collections.Generic; using System.IO; internal class C { internal C() { var temp = Recursive(); } public static int Recursive() => Recursive(); public static int Recursive(int arg) => Recursive(arg); public static bool Recursive(bool flag) { if (flag) { return Recursive(!flag); } return flag; } private static int RecursiveWithOptional(int arg, IEnumerable<int> args = null) { if (arg == null) { return RecursiveWithOptional(arg, new[] { arg }); } return arg; } private static int Recursive1(int value) { return Recursive2(value); } private static int Recursive2(int value) { return Recursive1(value); } private static IReadOnlyList<IDisposable> Flatten(IReadOnlyList<IDisposable> source, List<IDisposable> result = null) { result = result ?? new List<IDisposable>(); result.AddRange(source); foreach (var condition in source) { Flatten(new[] { condition }, result); } return result; } } }".AssertReplace("var temp = Recursive()", $"var temp = {expression}"); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(expression).Value; using var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); var actual = string.Join(", ", returnValues); Assert.AreEqual(expected, actual); }
public static void Call(string expression, ReturnValueSearch search, string expected) { var code = @" namespace N { using System; using System.Collections.Generic; using System.IO; internal class C { internal C() { var temp = StaticCreateIntStatementBody(); } internal static int StaticCreateIntStatementBody() { return 1; } internal static int StaticCreateIntExpressionBody() => 2; internal static int IdStatementBody(int arg) { return arg; } internal static int IdExpressionBody(int arg) => arg; internal static int OptionalIdExpressionBody(int arg = 1) => arg; internal static int CallingIdExpressionBody(int arg1) => IdExpressionBody(arg1); public static int AssigningToParameter(int arg) { if (true) { return arg; } else { if (true) { arg = 2; } else { arg = 3; } return arg; } return 4; } public static int ConditionalId(int arg) { if (true) { return arg; } return arg; } public static int ReturnLocal() { var local = 1; return local; } public static int ReturnLocalAssignedTwice(bool flag) { var local = 1; local = 2; if (flag) { return local; } local = 5; return 3; } public C ThisExpressionBody() => this; public static Stream ReturningFileOpenRead() { return System.IO.File.OpenRead(string.Empty); } public static Stream ReturningLocalFileOpenRead() { var stream = System.IO.File.OpenRead(string.Empty); return stream; } } }".AssertReplace("var temp = StaticCreateIntStatementBody()", $"var temp = {expression}"); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(expression).Value; using var returnValues = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None); var actual = string.Join(", ", returnValues); Assert.AreEqual(expected, actual); }
public void AsyncAwait(string code, Search search, string expected) { var testCode = @" namespace RoslynSandbox { using System; using System.Threading.Tasks; public class Disposable : IDisposable { public void Dispose() { } } internal class Foo { internal async Task Bar() { var value = // Meh(); } internal static async Task<int> RecursiveAsync() => RecursiveAsync(); internal static async Task<int> RecursiveAsync(int arg) => RecursiveAsync(arg); internal static async Task<string> CreateStringAsync() { await Task.Delay(0); return new string(' ', 1); } internal static async Task<string> ReturnAwaitTaskRunAsync() { await Task.Delay(0); return await Task.Run(() => new string(' ', 1)).ConfigureAwait(false); } internal static Task<int> CreateAsync(int arg) { switch (arg) { case 0: return Task.FromResult(1); case 1: return Task.FromResult(arg); case 2: return Task.Run(() => 2); case 3: return Task.Run(() => arg); case 4: return Task.Run(() => { return 3; }); default: return Task.Run(() => { return arg; }); } } internal static async int CreateInt() => 1; private static async Task<int> RecursiveAsync1(int value) { return await RecursiveAsync2(value); } private static async Task<int> RecursiveAsync2(int value) { return await RecursiveAsync1(value); } private static async Task<int> RecursiveAsync3(int value) { return RecursiveAsync4(value); } private static async Task<int> RecursiveAsync4(int value) { return await RecursiveAsync3(value); } } }"; testCode = testCode.AssertReplace("// Meh()", code); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None)) { Assert.AreEqual(expected, string.Join(", ", pooled)); } }
public void Call(string code, Search search, string expected) { var testCode = @" namespace RoslynSandbox { using System; using System.Collections.Generic; internal class Foo { internal Foo() { var temp = // Meh(); } internal static int StaticCreateIntStatementBody() { return 1; } internal static int StaticCreateIntExpressionBody() => 2; internal static int IdStatementBody(int arg) { return arg; } internal static int IdExpressionBody(int arg) => arg; internal static int OptionalIdExpressionBody(int arg = 1) => arg; internal static int CallingIdExpressionBody(int arg1) => IdExpressionBody(arg1); public static int AssigningToParameter(int arg) { if (true) { return arg; } else { if (true) { arg = 2; } else { arg = 3; } return arg; } return 4; } public static int ConditionalId(int arg) { if (true) { return arg; } return arg; } public static int ReturnLocal() { var local = 1; return local; } public static int ReturnLocalAssignedTwice(bool flag) { var local = 1; local = 2; if (flag) { return local; } local = 5; return 3; } public static int Recursive() => Recursive(); public static int Recursive(int arg) => Recursive(arg); public static bool Recursive(bool flag) { if (flag) { return Recursive(!flag); } return flag; } public Foo ThisExpressionBody() => this; private static int RecursiveWithOptional(int arg, IEnumerable<int> args = null) { if (arg == null) { return RecursiveWithOptional(arg, new[] { arg }); } return arg; } private static int Recursive1(int value) { return Recursive2(value); } private static int Recursive2(int value) { return Recursive1(value); } } }"; testCode = testCode.AssertReplace("// Meh()", code); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = ReturnValueWalker.Borrow(value, search, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }