internal static bool SingleForSymbol(ISymbol symbol, SyntaxNode scope, Search search, SemanticModel semanticModel, CancellationToken cancellationToken, out AssignmentExpressionSyntax assignment) { assignment = null; if (symbol == null || scope == null) { return(false); } using (var pooledAssignments = Borrow(scope, search, semanticModel, cancellationToken)) { foreach (var candidate in pooledAssignments.Assignments) { var assignedSymbol = semanticModel.GetSymbolSafe(candidate.Left, cancellationToken); if (SymbolComparer.Equals(symbol, assignedSymbol)) { if (assignment != null) { assignment = null; return(false); } assignment = candidate; } } } return(assignment != null); }
public override void VisitInvocationExpression(InvocationExpressionSyntax node) { if (this.visitedLocations.Add(node)) { base.VisitInvocationExpression(node); var method = this.semanticModel.GetSymbolSafe(node, this.cancellationToken); if (this.Context is ElementAccessExpressionSyntax && SymbolComparer.Equals(this.CurrentSymbol, this.semanticModel.GetSymbolSafe((node.Expression as MemberAccessExpressionSyntax)?.Expression, this.cancellationToken))) { if (method.Name == "Add") { if (method.ContainingType.Is(KnownSymbol.IDictionary) && node.ArgumentList?.Arguments.Count == 2) { this.values.Add(node.ArgumentList.Arguments[1].Expression); } else if (node.ArgumentList?.Arguments.Count == 1) { this.values.Add(node.ArgumentList.Arguments[0].Expression); } } } this.HandleInvoke(method, node.ArgumentList); } }
internal Result IsMemberDisposed(ISymbol member) { foreach (var invocation in this.invocations) { if (invocation.TryGetInvokedMethodName(out var name) && name != "Dispose") { continue; } if (TryGetDisposedRootMember(invocation, this.SemanticModel, this.CancellationToken, out var disposed) && SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(disposed, this.CancellationToken))) { return(Result.Yes); } } foreach (var name in this.identifiers) { if (SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(name, this.CancellationToken))) { return(Result.AssumeYes); } } return(Result.No); }
public override void VisitConstructorInitializer(ConstructorInitializerSyntax node) { if (this.method.MethodKind == MethodKind.Constructor) { var calledCtor = this.semanticModel.GetSymbolSafe(node, this.cancellationToken); if (this.IsValidCtor(calledCtor)) { var callingCtor = this.semanticModel.GetDeclaredSymbolSafe(node.Parent, this.cancellationToken) as IMethodSymbol; if (SymbolComparer.Equals(calledCtor.ContainingType, callingCtor?.ContainingType)) { this.initializers.Add(node); } else if (this.ctors.Contains(callingCtor)) { this.initializers.Add(node); } } } else { this.initializers.Add(node); } base.VisitConstructorInitializer(node); }
private static void HandleDisposeMethod(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } if (context.ContainingSymbol is IMethodSymbol method && method.IsOverride && method.Name == "Dispose") { var overridden = method.OverriddenMethod; if (overridden == null) { return; } using (var invocations = InvocationWalker.Create(context.Node)) { foreach (var invocation in invocations.Item) { if ( SymbolComparer.Equals( context.SemanticModel.GetSymbolSafe(invocation, context.CancellationToken), overridden)) { return; } } } if (overridden.DeclaringSyntaxReferences.Length == 0) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); return; } using ( var disposeWalker = Disposable.DisposeWalker.Create(overridden, context.SemanticModel, context.CancellationToken)) { foreach (var disposeCall in disposeWalker.Item) { if (Disposable.TryGetDisposedRootMember(disposeCall, context.SemanticModel, context.CancellationToken, out ExpressionSyntax disposed)) { var member = context.SemanticModel.GetSymbolSafe(disposed, context.CancellationToken); if ( !Disposable.IsMemberDisposed(member, method, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); return; } } } } } }
public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { if (node.Type is SimpleNameSyntax typeName && typeName.Identifier.ValueText == this.context.Identifier.ValueText) { if (this.semanticModel.GetSymbolSafe(node, this.cancellationToken) is IMethodSymbol ctor && SymbolComparer.Equals(this.Type, ctor.ContainingType)) { this.objectCreations.Add(node); } }
public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { var ctor = this.semanticModel.GetSymbolSafe(node, this.cancellationToken) as IMethodSymbol; if (SymbolComparer.Equals(this.type, ctor?.ContainingType)) { this.objectCreations.Add(node); } base.VisitObjectCreationExpression(node); }
public override void VisitInvocationExpression(InvocationExpressionSyntax node) { var invokedMethod = this.semanticModel.GetSymbolSafe(node, this.cancellationToken) as IMethodSymbol; if (SymbolComparer.Equals(this.method, invokedMethod)) { this.invocations.Add(node); } base.VisitInvocationExpression(node); }
public override void VisitElementAccessExpression(ElementAccessExpressionSyntax node) { if (node.Parent is AssignmentExpressionSyntax assignment && this.visitedLocations.Add(node) && this.Context is ElementAccessExpressionSyntax && SymbolComparer.Equals(this.CurrentSymbol, this.semanticModel.GetSymbolSafe(node.Expression, this.cancellationToken))) { this.values.Add(assignment.Right); base.VisitElementAccessExpression(node); } }
internal static bool Creates(this ObjectCreationExpressionSyntax creation, ConstructorDeclarationSyntax ctor, Search search, SemanticModel semanticModel, CancellationToken cancellationToken) { var created = semanticModel.GetSymbolSafe(creation, cancellationToken) as IMethodSymbol; var ctorSymbol = semanticModel.GetDeclaredSymbolSafe(ctor, cancellationToken); if (SymbolComparer.Equals(ctorSymbol, created)) { return(true); } return(search == Search.Recursive && IsRunBefore(created, ctorSymbol, semanticModel, cancellationToken)); }
private static bool IsRunBefore(IMethodSymbol first, IMethodSymbol other, SemanticModel semanticModel, CancellationToken cancellationToken) { if (first == null || other == null) { return(false); } if (TryGetInitializer(other, cancellationToken, out ConstructorInitializerSyntax initializer)) { if (SymbolComparer.Equals(first.ContainingType, other.ContainingType) && !initializer.ThisOrBaseKeyword.IsKind(SyntaxKind.ThisKeyword)) { return(false); } if (!other.ContainingType.Is(first.ContainingType) && initializer.ThisOrBaseKeyword.IsKind(SyntaxKind.BaseKeyword)) { return(false); } } else { if (SymbolComparer.Equals(first.ContainingType, other.ContainingType) || !other.ContainingType.Is(first.ContainingType)) { return(false); } } var next = semanticModel.GetSymbolSafe(initializer, cancellationToken); if (SymbolComparer.Equals(first, next)) { return(true); } if (next == null) { if (TryGetDefault(other.ContainingType?.BaseType, out next)) { return(SymbolComparer.Equals(first, next)); } return(false); } return(IsRunBefore(first, next, semanticModel, cancellationToken)); }
private bool IsValidCtor(IMethodSymbol ctor) { if (!SymbolComparer.Equals(this.method, ctor)) { return(false); } if (SymbolComparer.Equals(this.contextType, ctor?.ContainingType)) { return(true); } return(this.ctors.Contains(ctor)); }
public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) { var ctor = this.semanticModel.GetDeclaredSymbolSafe(node, this.cancellationToken); if (SymbolComparer.Equals(this.type, ctor.ContainingType)) { if (ctor.DeclaredAccessibility != Accessibility.Private) { this.nonPrivateCtors.Add(node); } if (ctor.Parameters.Length == 0) { this.Default = node; } } base.VisitConstructorDeclaration(node); }
internal static bool FirstWith(ISymbol symbol, SyntaxNode scope, Search search, SemanticModel semanticModel, CancellationToken cancellationToken, out AssignmentExpressionSyntax assignment) { assignment = null; if (symbol == null || scope == null) { return(false); } using (var pooledAssignments = Borrow(scope, search, semanticModel, cancellationToken)) { foreach (var candidate in pooledAssignments.Assignments) { if (candidate.Right is ConditionalExpressionSyntax conditional) { if (SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(conditional.WhenTrue, cancellationToken)) || SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(conditional.WhenFalse, cancellationToken))) { assignment = candidate; return(true); } } var assignedSymbol = semanticModel.GetSymbolSafe(candidate.Right, cancellationToken); if (SymbolComparer.Equals(symbol, assignedSymbol)) { assignment = candidate; return(true); } if (candidate.Right is ObjectCreationExpressionSyntax objectCreation && objectCreation.ArgumentList != null && objectCreation.ArgumentList.Arguments.TryGetFirst(x => SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(x.Expression, cancellationToken)), out ArgumentSyntax _)) { assignment = candidate; return(true); } } } return(false); }
public override void VisitArgument(ArgumentSyntax node) { if (this.visitedLocations.Add(node) && (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword) || node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword))) { var invocation = node.FirstAncestorOrSelf <InvocationExpressionSyntax>(); var argSymbol = this.semanticModel.GetSymbolSafe(node.Expression, this.cancellationToken); if (invocation != null && (SymbolComparer.Equals(this.CurrentSymbol, argSymbol) || this.refParameters.Contains(argSymbol as IParameterSymbol))) { var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (method != null && method.DeclaringSyntaxReferences.Length > 0) { foreach (var reference in method.DeclaringSyntaxReferences) { var methodDeclaration = reference.GetSyntax(this.cancellationToken) as MethodDeclarationSyntax; if (methodDeclaration.TryGetMatchingParameter(node, out ParameterSyntax parameterSyntax)) { var parameterSymbol = this.semanticModel.GetDeclaredSymbolSafe(parameterSyntax, this.cancellationToken); if (parameterSymbol != null) { if (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword)) { this.refParameters.Add(parameterSymbol).IgnoreReturnValue(); } if (node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword)) { this.values.Add(node.Expression); } } } } } } } base.VisitArgument(node); }
internal static bool IsDisposing(InvocationExpressionSyntax invocation, ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken) { var method = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol; if (method == null || method.Parameters.Length != 0 || method != KnownSymbol.IDisposable.Dispose) { return(false); } if (TryGetDisposedRootMember(invocation, semanticModel, cancellationToken, out ExpressionSyntax disposed)) { if (SymbolComparer.Equals(member, semanticModel.GetSymbolSafe(disposed, cancellationToken))) { return(true); } } return(false); }
internal Result IsMemberDisposed(ISymbol member) { foreach (var invocation in this.invocations) { if (TryGetDisposedRootMember(invocation, this.SemanticModel, this.CancellationToken, out ExpressionSyntax disposed) && SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(disposed, this.CancellationToken))) { return(Result.Yes); } } foreach (var name in this.identifiers) { if (SymbolComparer.Equals(member, this.SemanticModel.GetSymbolSafe(name, this.CancellationToken))) { return(Result.Maybe); } } return(Result.No); }
private bool TryHandleInvocation(MemberAccessExpressionSyntax invocation) { if (invocation == null) { return(false); } var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (method == null || method.DeclaringSyntaxReferences.Length == 0) { return(true); } foreach (var reference in method.DeclaringSyntaxReferences) { base.Visit(reference.GetSyntax(this.cancellationToken)); } for (var i = this.values.Count - 1; i >= 0; i--) { var symbol = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken); if (this.search == Search.Recursive && SymbolComparer.Equals(symbol, method)) { this.values.RemoveAt(i); continue; } if (symbol is IParameterSymbol parameter && parameter.IsThis) { this.values[i] = invocation.Expression; } } this.values.PurgeDuplicates(); return(true); }
internal static bool IsDisposing(InvocationExpressionSyntax invocation, ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken) { if (invocation.Expression is MemberAccessExpressionSyntax memberAccess && memberAccess.Name is IdentifierNameSyntax methodName && methodName.Identifier.ValueText != "Dispose") { return(false); } if (semanticModel.GetSymbolSafe(invocation, cancellationToken) is IMethodSymbol method && method.Parameters.Length == 0 && method == KnownSymbol.RefCounter.Dispose && TryGetDisposedRootMember(invocation, semanticModel, cancellationToken, out var disposed)) { if (SymbolComparer.Equals(member, semanticModel.GetSymbolSafe(disposed, cancellationToken))) { return(true); } } return(false); }
private bool TryHandlePropertyGet(ExpressionSyntax propertyGet) { if (propertyGet == null) { return(false); } var property = this.semanticModel.GetSymbolSafe(propertyGet, this.cancellationToken) as IPropertySymbol; var getter = property?.GetMethod; if (getter == null) { return(false); } if (getter.DeclaringSyntaxReferences.Length == 0) { return(true); } foreach (var reference in getter.DeclaringSyntaxReferences) { base.Visit(reference.GetSyntax(this.cancellationToken)); } for (var i = this.values.Count - 1; i >= 0; i--) { var symbol = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken); if (this.search == Search.Recursive && SymbolComparer.Equals(symbol, property)) { this.values.RemoveAt(i); } } this.values.PurgeDuplicates(); return(true); }
internal static void AllWith(ISymbol symbol, SyntaxNode scope, Search search, SemanticModel semanticModel, CancellationToken cancellationToken, List <AssignmentExpressionSyntax> assignments) { if (symbol == null || scope == null) { return; } using (var walker = Borrow(scope, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var candidate in walker.Assignments) { if (candidate.Right is ConditionalExpressionSyntax conditional) { if (SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(conditional.WhenTrue, cancellationToken)) || SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(conditional.WhenFalse, cancellationToken))) { assignments.Add(candidate); } } if (candidate.Right is BinaryExpressionSyntax binary && binary.IsKind(SyntaxKind.CoalesceExpression)) { if (SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(binary.Left, cancellationToken)) || SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(binary.Right, cancellationToken))) { assignments.Add(candidate); } } var assignedSymbol = semanticModel.GetSymbolSafe(candidate.Right, cancellationToken); if (SymbolComparer.Equals(symbol, assignedSymbol)) { assignments.Add(candidate); } if (candidate.Right is ObjectCreationExpressionSyntax objectCreation && objectCreation.ArgumentList != null && objectCreation.ArgumentList.Arguments.TryFirst(x => SymbolComparer.Equals(symbol, semanticModel.GetSymbolSafe(x.Expression, cancellationToken)), out ArgumentSyntax _)) { assignments.Add(candidate); } } if (search == Search.Recursive) { foreach (var argument in walker.arguments) { if (argument.Expression is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == symbol.Name && semanticModel.GetSymbolSafe(argument.Parent?.Parent, cancellationToken) is IMethodSymbol method && method.TrySingleDeclaration(cancellationToken, out BaseMethodDeclarationSyntax methodDeclaration) && methodDeclaration.TryGetMatchingParameter(argument, out var parameter)) { AllWith(semanticModel.GetDeclaredSymbolSafe(parameter, cancellationToken), methodDeclaration, search, semanticModel, cancellationToken, assignments); } } } } }
private void HandleAssignedValue(SyntaxNode assignee, ExpressionSyntax value) { if (value == null) { return; } var assignedSymbol = this.semanticModel.GetSymbolSafe(assignee, this.cancellationToken) ?? this.semanticModel.GetDeclaredSymbolSafe(assignee, this.cancellationToken); if (assignedSymbol == null) { return; } if (this.Context is ElementAccessExpressionSyntax) { switch (value) { case ArrayCreationExpressionSyntax arrayCreation: { if (arrayCreation.Initializer == null) { return; } foreach (var item in arrayCreation.Initializer.Expressions) { this.values.Add(item); } } break; case ObjectCreationExpressionSyntax objectCreation: { if (objectCreation.Initializer == null) { return; } foreach (var item in objectCreation.Initializer.Expressions) { if (item is InitializerExpressionSyntax kvp) { if (kvp.Expressions.Count == 2) { this.values.Add(kvp.Expressions[1]); } } else if (item is AssignmentExpressionSyntax assignment) { this.values.Add(assignment.Right); } else { this.values.Add(item); } } } break; case InitializerExpressionSyntax initializer: { foreach (var item in initializer.Expressions) { this.values.Add(item); } } break; default: return; } return; } var property = assignedSymbol as IPropertySymbol; if (!SymbolComparer.Equals(this.CurrentSymbol, property) && (this.CurrentSymbol is IFieldSymbol || this.CurrentSymbol is IPropertySymbol) && property != null && Property.AssignsSymbolInSetter( property, this.CurrentSymbol, this.semanticModel, this.cancellationToken)) { var before = this.values.Count; foreach (var reference in property.DeclaringSyntaxReferences) { var declaration = (PropertyDeclarationSyntax)reference.GetSyntax(this.cancellationToken); if (declaration.TryGetSetAccessorDeclaration(out AccessorDeclarationSyntax setter)) { this.Visit(setter); } } for (var i = before; i < this.values.Count; i++) { var parameter = this.semanticModel.GetSymbolSafe(this.values[i], this.cancellationToken) as IParameterSymbol; if (Equals(parameter?.ContainingSymbol, property.SetMethod)) { this.values[i] = value; } } } else { if (SymbolComparer.Equals(this.CurrentSymbol, assignedSymbol) || this.refParameters.Contains(assignedSymbol as IParameterSymbol)) { this.values.Add(value); } } }
private static bool IsReturned(ILocalSymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var walker = ReturnValueWalker.Borrow(block, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var value in walker) { var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (SymbolComparer.Equals(symbol, returnedSymbol)) { return(true); } if (value is ObjectCreationExpressionSyntax objectCreation) { if (objectCreation.ArgumentList != null) { foreach (var argument in objectCreation.ArgumentList.Arguments) { var arg = semanticModel.GetSymbolSafe(argument.Expression, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } if (objectCreation.Initializer != null) { foreach (var argument in objectCreation.Initializer.Expressions) { var arg = semanticModel.GetSymbolSafe(argument, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } } if (value is InvocationExpressionSyntax invocation) { if (returnedSymbol == KnownSymbol.RxDisposable.Create && invocation.ArgumentList != null && invocation.ArgumentList.Arguments.TryGetSingle(out ArgumentSyntax argument) && argument.Expression is ParenthesizedLambdaExpressionSyntax lambda) { var body = lambda.Body; using (var pooledInvocations = InvocationWalker.Borrow(body)) { foreach (var candidate in pooledInvocations.Invocations) { if (Disposable.IsDisposing(candidate, symbol, semanticModel, cancellationToken)) { return(true); } } } } } } } return(false); }
internal static bool IsDisposedBefore(ISymbol symbol, ExpressionSyntax assignment, SemanticModel semanticModel, CancellationToken cancellationToken) { bool IsDisposing(InvocationExpressionSyntax invocation, ISymbol current) { if (invocation.TryGetInvokedMethodName(out var name) && name != "Dispose") { return(false); } var invokedSymbol = semanticModel.GetSymbolSafe(invocation, cancellationToken); if (invokedSymbol?.Name != "Dispose") { return(false); } var statement = invocation.FirstAncestorOrSelf <StatementSyntax>(); if (statement != null) { using (var names = IdentifierNameWalker.Borrow(statement)) { foreach (var identifierName in names.IdentifierNames) { if (identifierName.Identifier.ValueText == current.Name && SymbolComparer.Equals(current, semanticModel.GetSymbolSafe(identifierName, cancellationToken))) { 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); } if (TryGetScope(assignment, out var block)) { using (var walker = InvocationWalker.Borrow(block)) { foreach (var invocation in walker.Invocations) { if (invocation.IsBeforeInScope(assignment) != Result.Yes) { continue; } if (IsDisposing(invocation, symbol)) { return(true); } } } } if (assignment 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 (IsDisposing(invocation, symbol) || IsDisposing(invocation, property)) { return(true); } } } } return(false); }