public static void FieldPrivateCtorCalledByInitializer(SearchScope scope) { var code = @" namespace N { internal class C { public static readonly C Default = new C(); private readonly int value; private C() { this.value = 1; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var field = semanticModel.GetDeclaredSymbolSafe(syntaxTree.FindFieldDeclaration("private readonly int value"), CancellationToken.None); var bar = syntaxTree.FindTypeDeclaration("C"); Assert.AreEqual(true, AssignmentExecutionWalker.FirstFor(field, bar, scope, semanticModel, CancellationToken.None, out var result)); Assert.AreEqual("this.value = 1", result.ToString()); Assert.AreEqual(true, AssignmentExecutionWalker.SingleFor(field, bar, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.value = 1", result.ToString()); using (var walker = AssignmentExecutionWalker.For(field, bar, scope, semanticModel, CancellationToken.None)) { Assert.AreEqual("this.value = 1", walker.Assignments.Single().ToString()); } }
internal static bool IsAssignedAndDisposedInSetupAndTearDown(FieldOrProperty fieldOrProperty, TypeDeclarationSyntax scope, SemanticModel semanticModel, CancellationToken cancellationToken) { if (AssignmentExecutionWalker.SingleFor(fieldOrProperty.Symbol, scope, Scope.Member, semanticModel, cancellationToken, out var assignment) && assignment.FirstAncestor <MethodDeclarationSyntax>() is MethodDeclarationSyntax methodDeclaration) { if (Attribute.TryFind(methodDeclaration, KnownSymbol.NUnitSetUpAttribute, semanticModel, cancellationToken, out _)) { if (fieldOrProperty.ContainingType.TryFindFirstMethodRecursive(x => x.GetAttributes().Any(a => a.AttributeClass == KnownSymbol.NUnitTearDownAttribute), out var tearDown)) { return(DisposableMember.IsDisposed(fieldOrProperty, tearDown, semanticModel, cancellationToken)); } } if (Attribute.TryFind(methodDeclaration, KnownSymbol.NUnitOneTimeSetUpAttribute, semanticModel, cancellationToken, out _)) { if (fieldOrProperty.ContainingType.TryFindFirstMethodRecursive( x => x.GetAttributes().Any(a => a.AttributeClass == KnownSymbol.NUnitOneTimeTearDownAttribute), out var tearDown)) { return(DisposableMember.IsDisposed(fieldOrProperty, tearDown, semanticModel, cancellationToken)); } } } return(false); }
public static void FieldWithCtorArg(SearchScope scope) { var code = @" namespace N { internal class C { private readonly int value; internal C(int arg) { this.value = arg; } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindMemberAccessExpression("this.value"); var ctor = syntaxTree.FindConstructorDeclaration("C(int arg)"); var field = semanticModel.GetSymbolSafe(value, CancellationToken.None); Assert.AreEqual(true, AssignmentExecutionWalker.FirstFor(field, ctor, scope, semanticModel, CancellationToken.None, out var result)); Assert.AreEqual("this.value = arg", result.ToString()); Assert.AreEqual(true, AssignmentExecutionWalker.SingleFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.value = arg", result.ToString()); using (var walker = AssignmentExecutionWalker.For(field, ctor, scope, semanticModel, CancellationToken.None)) { Assert.AreEqual("this.value = arg", walker.Assignments.Single().ToString()); } }
internal static bool IsAssignedInInitializeAndDisposedInCleanup(FieldOrProperty fieldOrProperty, TypeDeclarationSyntax scope, SemanticModel semanticModel, CancellationToken cancellationToken) { if (AssignmentExecutionWalker.SingleFor(fieldOrProperty.Symbol, scope, SearchScope.Member, semanticModel, cancellationToken, out var assignment) && assignment.FirstAncestor <MethodDeclarationSyntax>() is { } methodDeclaration) { var cleanup = TearDown(KnownSymbol.NUnitSetUpAttribute, KnownSymbol.NUnitTearDownAttribute) ?? TearDown(KnownSymbol.NUnitOneTimeSetUpAttribute, KnownSymbol.NUnitOneTimeTearDownAttribute) ?? TearDown(KnownSymbol.TestInitializeAttribute, KnownSymbol.TestCleanupAttribute) ?? TearDown(KnownSymbol.ClassInitializeAttribute, KnownSymbol.ClassCleanupAttribute); return(cleanup is { } &&
internal static bool IsAssignedInSetUp(FieldOrProperty fieldOrProperty, TypeDeclarationSyntax scope, SemanticModel semanticModel, CancellationToken cancellationToken, out AttributeSyntax attribute) { if (AssignmentExecutionWalker.SingleFor(fieldOrProperty.Symbol, scope, Scope.Member, semanticModel, cancellationToken, out var assignment) && assignment.FirstAncestor <MethodDeclarationSyntax>() is MethodDeclarationSyntax methodDeclaration) { return(Attribute.TryFind(methodDeclaration, KnownSymbol.NUnitSetUpAttribute, semanticModel, cancellationToken, out attribute) || Attribute.TryFind(methodDeclaration, KnownSymbol.NUnitOneTimeSetUpAttribute, semanticModel, cancellationToken, out attribute)); } attribute = null; return(false); }
public void FieldWithCtorArgViaProperty(Scope scope) { var testCode = @" namespace RoslynSandbox { internal class Foo { private int number; internal Foo(int arg) { this.Number = arg; } public int Number { get { return this.number; } set { this.number = value; } } } }"; var syntaxTree = CSharpSyntaxTree.ParseText(testCode); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindMemberAccessExpression("this.number"); var ctor = syntaxTree.FindConstructorDeclaration("Foo(int arg)"); AssignmentExpressionSyntax result; var field = semanticModel.GetSymbolSafe(value, CancellationToken.None); if (scope != Scope.Member) { Assert.AreEqual(true, AssignmentExecutionWalker.FirstFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.number = value", result.ToString()); Assert.AreEqual(true, AssignmentExecutionWalker.SingleFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.number = value", result.ToString()); using (var walker = AssignmentExecutionWalker.For(field, ctor, scope, semanticModel, CancellationToken.None)) { Assert.AreEqual("this.number = value", walker.Assignments.Single().ToString()); } } else { Assert.AreEqual(false, AssignmentExecutionWalker.FirstFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); } }
public static void FieldInPropertyExpressionBody(SearchScope scope) { var code = @" namespace N { internal class C { private int number; internal C() { var i = this.Number; } public int Number => this.number = 3; } }"; var syntaxTree = CSharpSyntaxTree.ParseText(code); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var value = syntaxTree.FindMemberAccessExpression("this.number"); var ctor = syntaxTree.FindConstructorDeclaration("C()"); AssignmentExpressionSyntax result; var field = semanticModel.GetSymbolSafe(value, CancellationToken.None); if (scope != SearchScope.Member) { Assert.AreEqual(true, AssignmentExecutionWalker.FirstFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.number = 3", result.ToString()); Assert.AreEqual(true, AssignmentExecutionWalker.SingleFor(field, ctor, scope, semanticModel, CancellationToken.None, out result)); Assert.AreEqual("this.number = 3", result.ToString()); using (var walker = AssignmentExecutionWalker.For(field, ctor, scope, semanticModel, CancellationToken.None)) { Assert.AreEqual("this.number = 3", walker.Assignments.Single().ToString()); } } else { Assert.AreEqual(false, AssignmentExecutionWalker.FirstFor(field, ctor, scope, semanticModel, CancellationToken.None, out _)); } }
private static bool IsDefaultValueOfRegisteredType(ExpressionSyntax defaultValue, ITypeSymbol registeredType, SyntaxNodeAnalysisContext context, PooledSet <SyntaxNode> visited = null) { switch (defaultValue) { case ConditionalExpressionSyntax conditional: #pragma warning disable IDISP003 // Dispose previous before re-assigning. using (visited = visited.IncrementUsage()) #pragma warning restore IDISP003 // Dispose previous before re-assigning. { return(visited.Add(defaultValue) && IsDefaultValueOfRegisteredType(conditional.WhenTrue, registeredType, context, visited) && IsDefaultValueOfRegisteredType(conditional.WhenFalse, registeredType, context, visited)); } case BinaryExpressionSyntax binary when binary.IsKind(SyntaxKind.CoalesceExpression): #pragma warning disable IDISP003 // Dispose previous before re-assigning. using (visited = visited.IncrementUsage()) #pragma warning restore IDISP003 // Dispose previous before re-assigning. { return(visited.Add(defaultValue) && IsDefaultValueOfRegisteredType(binary.Left, registeredType, context, visited) && IsDefaultValueOfRegisteredType(binary.Right, registeredType, context, visited)); } } if (context.SemanticModel.IsRepresentationPreservingConversion(defaultValue, registeredType, context.CancellationToken)) { return(true); } if (context.SemanticModel.TryGetSymbol(defaultValue, context.CancellationToken, out ISymbol symbol)) { if (symbol is IFieldSymbol field) { if (field.TrySingleDeclaration(context.CancellationToken, out var fieldDeclaration)) { #pragma warning disable IDISP003 // Dispose previous before re-assigning. using (visited = visited.IncrementUsage()) #pragma warning restore IDISP003 // Dispose previous before re-assigning. { if (fieldDeclaration.Declaration is VariableDeclarationSyntax variableDeclaration && variableDeclaration.Variables.TryLast(out var variable) && variable.Initializer is EqualsValueClauseSyntax initializer) { return(visited.Add(initializer.Value) && IsDefaultValueOfRegisteredType(initializer.Value, registeredType, context, visited)); } return(fieldDeclaration.TryFirstAncestor <TypeDeclarationSyntax>(out var typeDeclaration) && AssignmentExecutionWalker.SingleFor(symbol, typeDeclaration, Scope.Instance, context.SemanticModel, context.CancellationToken, out var assignedValue) && visited.Add(assignedValue) && IsDefaultValueOfRegisteredType(assignedValue, registeredType, context, visited)); } } return(field.Type == KnownSymbol.Object); } if (symbol is IPropertySymbol property) { if (property.TrySingleDeclaration(context.CancellationToken, out PropertyDeclarationSyntax propertyDeclaration)) { #pragma warning disable IDISP003 // Dispose previous before re-assigning. using (visited = visited.IncrementUsage()) #pragma warning restore IDISP003 // Dispose previous before re-assigning. { if (propertyDeclaration.Initializer is EqualsValueClauseSyntax initializer) { return(visited.Add(initializer.Value) && IsDefaultValueOfRegisteredType(initializer.Value, registeredType, context, visited)); } if (property.SetMethod == null && property.GetMethod is IMethodSymbol getMethod) { return(IsReturnValueOfRegisteredType(getMethod, visited)); } return(propertyDeclaration.TryFirstAncestor <TypeDeclarationSyntax>(out var typeDeclaration) && AssignmentExecutionWalker.SingleFor(symbol, typeDeclaration, Scope.Instance, context.SemanticModel, context.CancellationToken, out var assignedValue) && visited.Add(assignedValue) && IsDefaultValueOfRegisteredType(assignedValue, registeredType, context, visited)); } } return(property.Type == KnownSymbol.Object); } if (symbol is IMethodSymbol method) { return(IsReturnValueOfRegisteredType(method, visited)); } } return(false); bool IsReturnValueOfRegisteredType(IMethodSymbol method, PooledSet <SyntaxNode> v) { if (method.TrySingleMethodDeclaration(context.CancellationToken, out var target)) { using (var walker = ReturnValueWalker.Borrow(target)) { foreach (var returnValue in walker.ReturnValues) { if (!IsDefaultValueOfRegisteredType(returnValue, registeredType, context, v)) { return(false); } } return(true); } } return(method.ReturnType == KnownSymbol.Object); } }