public static void OneRefOrOut(string modifier) { var code = @" namespace N { public class C { private int value; public C() { Mutate(out this.value); } private static void Mutate(out int i) { i = 1; } } }"; code = code.AssertReplace("out", modifier); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, Settings.Default.MetadataReferences); var semanticModel = compilation.GetSemanticModel(syntaxTree); var classDeclaration = syntaxTree.FindClassDeclaration("C"); using var walker = MutationWalker.Borrow(classDeclaration, SearchScope.Type, semanticModel, CancellationToken.None); CollectionAssert.IsEmpty(walker.PrefixUnaries); CollectionAssert.IsEmpty(walker.PostfixUnaries); CollectionAssert.AreEqual(new[] { $"{modifier} this.value" }, walker.RefOrOutArguments.Select(x => x.ToString())); CollectionAssert.AreEqual(new[] { "i = 1" }, walker.Assignments.Select(x => x.ToString())); CollectionAssert.AreEqual(new[] { "i = 1", $"{modifier} this.value" }, walker.All().Select(x => x.ToString())); }
public void FieldInitializedlWithLiteralAndAssignedInCtor(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { private readonly int value = 1; private readonly int temp1 = this.value; internal Foo() { var temp1 = this.value; var temp2 = this.temp1; this.value = 2; var temp3 = this.value; var temp4 = this.temp1; } internal void Bar() { var temp5 = this.value; var temp6 = this.temp1; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void Single(string mutation) { var testCode = @" namespace RoslynSandbox { public class Foo { private int value; public Foo() { this.value = 1; } } }"; testCode = testCode.AssertReplace("this.value = 1", mutation); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var classDeclaration = syntaxTree.FindClassDeclaration("Foo"); using (var walker = MutationWalker.Borrow(classDeclaration, Scope.Instance, semanticModel, CancellationToken.None)) { Assert.AreEqual(mutation, walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual(mutation, single.ToString()); } }
public void InitializedInChainedWithLiteralGeneric(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo<T> { internal Foo() { this.Value = 2; } internal Foo(string text) : this() { this.Value = 3; var temp1 = this.Value; this.Value = 4; } public int Value { get; set; } = 1; internal void Bar() { var temp2 = this.Value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void FieldCtorArgThenIdMethod(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { private readonly int value; internal Foo(int arg) { var temp1 = this.value; this.value = Id(arg); var temp2 = this.value; } internal void Bar(int arg) { var temp3 = this.value; } private static T Id(T genericArg) => genericArg; }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void FieldPublicCtorFactory(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { public int value = 1; public Foo(int ctorArg) { var temp1 = this.value; this.value = ctorArg; var temp2 = this.value; } internal static Foo Create() { return new Foo(2); } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void LocalAssignedWithRefParameter(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { internal Foo() { int value; var temp1 = value; Assign(ref value); var temp2 = value; } internal void Assign(ref int value) { value = 1; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void LocalAssignedWithOutParameterGeneric() { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo<T> { internal Foo() { T value; Assign(out value); var temp = value; } internal void Assign(out T outValue) { outValue = default(T); } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause("var temp = value;").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); #pragma warning disable GU0006 // Use nameof. Assert.AreEqual("value", actual); #pragma warning restore GU0006 // Use nameof. } }
public void InitializedListOfIntIndexerAfterAddItem(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { using System.Collections.Generic; internal class Foo { internal Foo() { var ints = new List<int> { 1, 2 }; var temp1 = ints[0]; ints.Add(3); var temp2 = ints[0]; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code) .Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void BackingFieldPrivateSetSimple() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { public sealed class Foo { private int bar; public int Bar { get { return this.bar; } private set { this.bar = value; } } public void Meh() { var temp = this.bar; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause("var temp = this.bar").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(string.Empty, actual); } }
public void InitializedWithConstant(string code) { var testCode = @" namespace RoslynSandbox { internal class Foo { private const int Value = 2; internal Foo() { var value = 1; var temp = value; } } }"; testCode = testCode.AssertReplace("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("var temp = value;").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(code, actual); } }
public static void One(string mutation) { var code = @" namespace N { public class C { private int value; public C() { this.value = 1; } } }"; code = code.AssertReplace("this.value = 1", mutation); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, Settings.Default.MetadataReferences); var semanticModel = compilation.GetSemanticModel(syntaxTree); var classDeclaration = syntaxTree.FindClassDeclaration("C"); using var walker = MutationWalker.Borrow(classDeclaration, SearchScope.Instance, semanticModel, CancellationToken.None); Assert.AreEqual(mutation, walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual(mutation, single.ToString()); }
public void AutoPropertyGetOnlyAssignedInCtor(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" public sealed class Foo { public Foo() { var temp1 = this.Bar; this.Bar = 2; var temp2 = this.Bar; } public int Bar { get; } = 1; public void Meh() { var temp3 = this.Bar; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void BackingFieldPublicSetInitializedAndPropertyAssignedInCtorWeirdSetter(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { public sealed class Foo { private int bar = 1; public Foo() { var temp1 = this.bar; var temp2 = this.Bar; this.Bar = 2; var temp3 = this.bar; var temp4 = this.Bar; } public int Bar { get { return this.bar; } set { if (true) { this.bar = value; } else { this.bar = value; } this.bar = value / 2; this.bar = 3; } } public void Meh() { var temp5 = this.bar; var temp6 = this.Bar; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void AutoPropertyChainedCtor(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { internal Foo() { var temp1 = this.Value; this.Value = 2; var temp2 = this.Value; this.Bar(3); var temp3 = this.Value; } internal Foo(string text) : this() { var temp4 = this.Value; this.Value = 4; var temp5 = this.Value; this.Value = 5; var temp6 = this.Value; this.Bar(6); var temp7 = this.Value; this.Bar(7); var temp8 = this.Value; } public int Value { get; set; } = 1; internal void Bar(int arg) { var temp9 = this.Value; this.Value = 8; var temp10 = this.Value; this.Value = arg; var temp11 = this.Value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void AssignedInLock() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { using System; public class Foo : IDisposable { private readonly object gate; public IDisposable disposable; private bool disposed; public void Dispose() { if (this.disposed) { return; } var toDispose = (IDisposable)null; lock (this.gate) { if (this.disposed) { return; } this.disposed = true; toDispose = this.disposable; this.disposable = null; } var temp = toDispose; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause("var temp = toDispose;").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual("(IDisposable)null, this.disposable", actual); } }
public void FieldImplicitBaseWhenSubclassHasCtor(string code, object expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class FooBase { protected readonly int value = 1; internal FooBase() { var temp1 = this.value; this.value = 2; var temp2 = this.value; } } internal class Foo : FooBase { internal Foo() { var temp3 = this.value; this.value = 3; var temp4 = this.value; this.value = 4; var temp5 = this.value; } internal void Bar(int arg) { var temp6 = this.value; this.value = 5; var temp7 = this.value; this.value = arg; var temp8 = this.value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void FieldCtorCallingProtectedInitializeMethod(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { public int value = 1; internal Foo() { var temp1 = this.value; this.Initialize(2); var temp4 = this.value; this.value = 3; var temp5 = this.value; this.Initialize(4); var temp6 = this.value; } internal void Bar(int arg) { var temp7 = this.value; this.value = 5; var temp8 = this.value; this.value = arg; var temp9 = this.value; } protected void Initialize(int initArg) { var temp2 = this.value; this.value = initArg; var temp3 = this.value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void InitializedInExplicitBaseCtorWithLiteral(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class FooBase { protected readonly int value = 1; public FooBase() { this.value = -1; } public FooBase(int value) { this.value = value; } } internal class Foo : FooBase { internal Foo() :base(2) { this.value = 3; var temp1 = this.value; this.value = 4; } internal void Bar() { var temp2 = this.value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void AssignedWithArgGenericMethod() { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { internal Foo<T>(T meh) { var temp = meh; var value = temp; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause("var value = temp").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual("meh", actual); } }
public void InitializedWithDefaultGeneric() { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo<T> { internal Foo() { var value = default(T); var temp = value; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause("var temp = value;").Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual("default(T)", actual); } }
public void FieldAssignedWithRefParameterArgument(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { internal class Foo { private int value = 1; public Foo() { var temp1 = this.value; this.Assign(ref this.value, 2); var temp2 = this.value; } internal void Bar() { var temp3 = this.value; this.Assign(ref this.value, 3); var temp4 = this.value; } private void Assign(ref int refValue, int arg) { refValue = arg; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void RecursiveGetAndSet(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace RoslynSandbox { public sealed class Foo { public Foo() { var temp1 = this.Bar; this.Bar = 2; var temp2 = this.Bar; } public int Bar { get { return this.Bar; } set { this.Bar = value; } } public void Meh() { var temp3 = this.Bar; } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void MethodInjectedWithOptionalAssigningOptional(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { private string text; internal Foo() { var temp1 = this.text; this.Update(1); var temp2 = this.text; this.Update(2, ""abc""); var temp3 = this.text; } internal void Bar() { var temp4 = this.text; } internal void Update(int arg, string textArg = null) { this.text = textArg; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code).Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void InitializedTypedArrayIndexer(string code, string expected) { var syntaxTree = CSharpSyntaxTree.ParseText(@" internal class Foo { internal Foo() { int[] ints = { 1, 2 }; var temp1 = ints[0]; ints[0] = 3; var temp2 = ints[0]; } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindEqualsValueClause(code) .Value; using (var pooled = MutationWalker.Borrow(value, semanticModel, CancellationToken.None)) { var actual = string.Join(", ", pooled); Assert.AreEqual(expected, actual); } }
public void SingleRefOrOut(string modifier) { var testCode = @" namespace RoslynSandbox { public class Foo { private int value; public Foo() { Mutate(out this.value); } private static void Mutate(out int i) { i = 1; } } }"; testCode = testCode.AssertReplace("out", modifier); var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var classDeclaration = syntaxTree.FindClassDeclaration("Foo"); using (var walker = MutationWalker.Borrow(classDeclaration, Scope.Type, semanticModel, CancellationToken.None)) { CollectionAssert.IsEmpty(walker.PrefixUnaries); CollectionAssert.IsEmpty(walker.PostfixUnaries); CollectionAssert.AreEqual(new[] { $"{modifier} this.value" }, walker.RefOrOutArguments.Select(x => x.ToString())); CollectionAssert.AreEqual(new[] { "i = 1" }, walker.Assignments.Select(x => x.ToString())); CollectionAssert.AreEqual(new[] { "i = 1", $"{modifier} this.value" }, walker.All().Select(x => x.ToString())); } }
internal static bool IsDisposedBefore(ISymbol symbol, ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken) { if (TryGetScope(expression, out var block)) { using (var walker = InvocationWalker.Borrow(block)) { foreach (var invocation in walker.Invocations) { if (invocation.IsExecutedBefore(expression) == ExecutedBefore.No) { continue; } if (DisposeCall.IsDisposing(invocation, symbol, semanticModel, cancellationToken) && !IsReassignedAfter(block, invocation)) { return(true); } } } } if (expression is AssignmentExpressionSyntax assignmentExpression && semanticModel.GetSymbolSafe(assignmentExpression.Left, cancellationToken) is IPropertySymbol property && property.TryGetSetter(cancellationToken, out var setter)) { using (var pooled = InvocationWalker.Borrow(setter)) { foreach (var invocation in pooled.Invocations) { if ((DisposeCall.IsDisposing(invocation, symbol, semanticModel, cancellationToken) || DisposeCall.IsDisposing(invocation, property, semanticModel, cancellationToken)) && !IsReassignedAfter(setter, invocation)) { return(true); } } } } return(false); bool TryGetScope(SyntaxNode node, out BlockSyntax result) { result = null; if (node.FirstAncestor <AnonymousFunctionExpressionSyntax>() is AnonymousFunctionExpressionSyntax lambda) { result = lambda.Body as BlockSyntax; } else if (node.FirstAncestor <AccessorDeclarationSyntax>() is AccessorDeclarationSyntax accessor) { result = accessor.Body; } else if (node.FirstAncestor <BaseMethodDeclarationSyntax>() is BaseMethodDeclarationSyntax method) { result = method.Body; } return(result != null); } bool IsReassignedAfter(SyntaxNode scope, InvocationExpressionSyntax disposeCall) { using (var walker = MutationWalker.Borrow(scope, Scope.Member, semanticModel, cancellationToken)) { foreach (var mutation in walker.All()) { if (mutation.TryFirstAncestor(out StatementSyntax statement) && disposeCall.IsExecutedBefore(statement) == ExecutedBefore.Yes && statement.IsExecutedBefore(expression) == ExecutedBefore.Yes) { return(true); } } } return(false); } }