internal static bool TryGetDisposedRootMember(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken, out IdentifierNameSyntax disposedMember) { if (MemberPath.TryFindRoot(disposeCall, out disposedMember)) { var property = semanticModel.GetSymbolSafe(disposedMember, cancellationToken) as IPropertySymbol; if (property == null || property.IsAutoProperty()) { return(true); } if (property.GetMethod == null) { return(false); } foreach (var reference in property.GetMethod.DeclaringSyntaxReferences) { var node = reference.GetSyntax(cancellationToken); using (var pooled = ReturnValueWalker.Borrow(node, ReturnValueSearch.TopLevel, semanticModel, cancellationToken)) { if (pooled.Count == 0) { return(true); } return(pooled.TrySingle(out var expression) && MemberPath.TryFindRoot(expression, out disposedMember)); } } } return(false); }
internal static bool IsIgnored(ExpressionSyntax node, SemanticModel semanticModel, CancellationToken cancellationToken) { if (node.Parent is AnonymousFunctionExpressionSyntax || node.Parent is UsingStatementSyntax || node.Parent is EqualsValueClauseSyntax || node.Parent is ReturnStatementSyntax || node.Parent is ArrowExpressionClauseSyntax) { return(false); } if (node.Parent is StatementSyntax) { return(true); } if (node.Parent is AssignmentExpressionSyntax assignment && assignment.Left is IdentifierNameSyntax left && left.Identifier.ValueText == "_") { return(true); } if (node.Parent is ArgumentSyntax argument) { if (argument.Parent is ArgumentListSyntax argumentList && argumentList.Parent is InvocationExpressionSyntax invocation && semanticModel.TryGetSymbol(invocation, cancellationToken, out var method) && method.Name == "Add" && method.ContainingType.IsAssignableTo(KnownSymbol.IEnumerable, semanticModel.Compilation)) { if (method.ContainingType == KnownSymbol.CompositeDisposable) { return(false); } if (!method.ContainingType.TypeArguments.Any(x => x.IsAssignableTo(KnownSymbol.IDisposable, semanticModel.Compilation))) { if (MemberPath.TryFindRoot(invocation, out var identifierName) && semanticModel.TryGetSymbol(identifierName, cancellationToken, out ISymbol symbol) && FieldOrProperty.TryCreate(symbol, out var fieldOrProperty) && argument.TryFirstAncestor(out TypeDeclarationSyntax typeDeclaration) && DisposableMember.IsDisposed(fieldOrProperty, typeDeclaration, semanticModel, cancellationToken) != Result.No) { return(false); } return(true); } return(false); } return(IsArgumentDisposedByReturnValue(argument, semanticModel, cancellationToken).IsEither(Result.No, Result.AssumeNo) && IsArgumentAssignedToDisposable(argument, semanticModel, cancellationToken).IsEither(Result.No, Result.AssumeNo)); } if (node.Parent is MemberAccessExpressionSyntax memberAccess) { if (memberAccess.Parent is InvocationExpressionSyntax invocation && DisposeCall.IsIDisposableDispose(invocation, semanticModel, cancellationToken)) { return(false); } return(IsArgumentDisposedByInvocationReturnValue(memberAccess, semanticModel, cancellationToken).IsEither(Result.No, Result.AssumeNo)); } return(false); }
internal static bool TryGetDisposedRootMember(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out IdentifierNameSyntax?disposedMember) { if (MemberPath.TryFindRoot(disposeCall, out var rootIdentifier) && (disposedMember = rootIdentifier.Parent as IdentifierNameSyntax) is { })