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);
                }
            }
示例#3
0
        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);
                }
            }
示例#10
0
        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());
        }
示例#13
0
        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);
            }
        }
示例#14
0
        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);
                }
            }
示例#23
0
        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);
                }
            }
示例#26
0
        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()));
            }
        }
示例#27
0
        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);
            }
        }