public void Single(string mutation) { var testCode = @" namespace RoslynSandbox { public class Foo { public Foo() { this.Value = 1; } public int Value { get; } } }"; 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 property = semanticModel.GetDeclaredSymbol(syntaxTree.FindPropertyDeclaration("Value")); using (var walker = MutationWalker.For(property, semanticModel, CancellationToken.None)) { Assert.AreEqual(mutation, walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual(mutation, single.ToString()); } }
public static void One(string mutation) { var code = @" namespace N { public class C { public C() { var value = 0; value = 1; } } }"; code = code.AssertReplace("value = 1", mutation); var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var symbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(syntaxTree.Find <VariableDeclaratorSyntax>("value")); using var walker = MutationWalker.For(symbol, semanticModel, CancellationToken.None); Assert.AreEqual(mutation, walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual(mutation, single.ToString()); }
public static void Out() { var code = @" namespace N { public class C { private int value; public C() { Update(out this.value); } private static void Update(out int field) { field = 1; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, Settings.Default.MetadataReferences); var semanticModel = compilation.GetSemanticModel(syntaxTree); var field = (IFieldSymbol)semanticModel.GetDeclaredSymbol(syntaxTree.Find <VariableDeclaratorSyntax>("value")); using var walker = MutationWalker.For(field, semanticModel, CancellationToken.None); Assert.AreEqual("out this.value", walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual("out this.value", single.ToString()); }
public void Ref() { var testCode = @" namespace RoslynSandbox { public class Foo { private int value; public Foo() { Update(ref this.value); } private static void Update(ref int field) { field++; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var field = (IFieldSymbol)semanticModel.GetDeclaredSymbol(syntaxTree.Find <VariableDeclaratorSyntax>("value")); using (var walker = MutationWalker.For(field, semanticModel, CancellationToken.None)) { Assert.AreEqual("ref this.value", walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual("ref this.value", single.ToString()); } }
public static void One(string mutation) { var code = @" namespace N { public class C { public C() { this.Value = 1; } public int Value { get; } } }"; 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 property = semanticModel.GetDeclaredSymbol(syntaxTree.FindPropertyDeclaration("Value")); using var walker = MutationWalker.For(property, semanticModel, CancellationToken.None); Assert.AreEqual(mutation, walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual(mutation, single.ToString()); }
internal static bool TryGetSingle(ILocalSymbol local, SemanticModel semanticModel, CancellationToken cancellationToken, out ExpressionSyntax expression) { expression = null; if (local.TrySingleDeclaration(cancellationToken, out VariableDeclarationSyntax declaration) && declaration.Variables.TrySingle(out var variable)) { using (var walker = MutationWalker.For(local, semanticModel, cancellationToken)) { if (walker.IsEmpty) { expression = variable.Initializer?.Value; return(expression != null); } if (variable.Initializer == null && walker.TrySingle(out var node) && node.Parent is AssignmentExpressionSyntax assignment) { expression = assignment.Right; return(expression != null); } return(false); } } return(false); }
internal static bool TryGetSingle(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken, out ExpressionSyntax expression) { expression = null; if (property.IsGetOnly() && property.TrySingleDeclaration(cancellationToken, out PropertyDeclarationSyntax declaration)) { using (var walker = MutationWalker.For(property, semanticModel, cancellationToken)) { if (walker.IsEmpty) { expression = declaration.Initializer?.Value; return(expression != null); } if (declaration.Initializer == null && walker.TrySingle(out var node) && node.Parent is AssignmentExpressionSyntax assignment) { expression = assignment.Right; return(expression != null); } return(false); } } return(false); }
private static bool IsPreferUsing(ILocalSymbol local, InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context) { return(local.TrySingleDeclaration(context.CancellationToken, out var declaration) && declaration is VariableDeclaratorSyntax declarator && declaration.TryFirstAncestor(out LocalDeclarationStatementSyntax localDeclarationStatement) && invocation.TryFirstAncestor(out ExpressionStatementSyntax expressionStatement) && (DeclarationIsAssignment() || IsTrivialTryFinally()) && !IsMutated()); bool DeclarationIsAssignment() { return(localDeclarationStatement.Parent == expressionStatement.Parent && Disposable.IsCreation(declarator.Initializer?.Value, context.SemanticModel, context.CancellationToken) == Result.Yes); } bool IsTrivialTryFinally() { return(expressionStatement.Parent is BlockSyntax block && block.Statements.Count == 1 && block.Parent is FinallyClauseSyntax finallyClause && finallyClause.Parent is TryStatementSyntax tryStatement && !tryStatement.Catches.Any()); } bool IsMutated() { using (var walker = MutationWalker.For(local, context.SemanticModel, context.CancellationToken)) { if (declarator.Initializer?.Value.IsKind(SyntaxKind.NullLiteralExpression) == true && walker.TrySingle(out var mutation) && mutation.TryFirstAncestor(out ExpressionStatementSyntax statement) && statement.Parent is BlockSyntax block && block.Statements[0] == statement && block.Parent is TryStatementSyntax) { return(false); } return(walker.All().Any()); } } }
public static void ObjectInitializer() { var code = @" namespace N { public class C { public int Value { get; private set; } public static C Create() => new C { Value = 1 }; } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var property = semanticModel.GetDeclaredSymbol(syntaxTree.FindPropertyDeclaration("Value")); using var walker = MutationWalker.For(property, semanticModel, CancellationToken.None); Assert.AreEqual("Value = 1", walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual("Value = 1", single.ToString()); }
public static void IgnoresBang() { var code = @" namespace N { public class C { public C() { string? value = null; var x = value!; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, Settings.Default.MetadataReferences); var semanticModel = compilation.GetSemanticModel(syntaxTree); var symbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(syntaxTree.Find <VariableDeclaratorSyntax>("value")); using var walker = MutationWalker.For(symbol, semanticModel, CancellationToken.None); Assert.AreEqual(true, walker.IsEmpty); }
public static void ObjectInitializer() { var code = @" namespace N { public class C { private int value; public static C Create() => new C { value = 1 }; } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var field = (IFieldSymbol)semanticModel.GetDeclaredSymbol(syntaxTree.Find <VariableDeclaratorSyntax>("value")); using (var walker = MutationWalker.For(field, semanticModel, CancellationToken.None)) { Assert.AreEqual("value = 1", walker.All().Single().ToString()); Assert.AreEqual(true, walker.TrySingle(out var single)); Assert.AreEqual("value = 1", single.ToString()); } }
private static bool IsUsedAfter(ILocalSymbol local, InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context, out IReadOnlyList <Location> locations) { if (local.TrySingleDeclaration(context.CancellationToken, out var declaration) && declaration.TryFirstAncestor(out BlockSyntax block)) { List <Location> temp = null; using (var walker = IdentifierNameWalker.Borrow(block)) { foreach (var identifierName in walker.IdentifierNames) { if (identifierName.Identifier.ValueText == local.Name && invocation.IsExecutedBefore(identifierName) == ExecutedBefore.Yes && context.SemanticModel.TryGetSymbol(identifierName, context.CancellationToken, out ILocalSymbol candidate) && local.Equals(candidate) && !IsAssigned(identifierName) && !IsReassigned(identifierName)) { if (temp == null) { temp = new List <Location>(); } temp.Add(identifierName.GetLocation()); } } locations = temp; return(locations != null); } } locations = null; return(false); bool IsAssigned(IdentifierNameSyntax identifier) { switch (identifier.Parent) { case AssignmentExpressionSyntax assignment: return(assignment.Left == identifier); case ArgumentSyntax argument when argument.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword): return(true); } return(false); } bool IsReassigned(ExpressionSyntax location) { using (var walker = MutationWalker.For(local, context.SemanticModel, context.CancellationToken)) { foreach (var mutation in walker.All()) { if (mutation.TryFirstAncestorOrSelf(out ExpressionSyntax expression) && invocation.IsExecutedBefore(expression) != ExecutedBefore.No && expression.IsExecutedBefore(location) != ExecutedBefore.No) { return(true); } } } return(false); } }