internal static bool IsDisposedAfter(ISymbol local, ExpressionSyntax location, SemanticModel semanticModel, CancellationToken cancellationToken) { if (location.FirstAncestorOrSelf <MemberDeclarationSyntax>() is MemberDeclarationSyntax scope) { using (var walker = InvocationWalker.Borrow(scope)) { foreach (var invocation in walker.Invocations) { if (location.IsExecutedBefore(invocation).IsEither(ExecutedBefore.Maybe, ExecutedBefore.Yes) && DisposeCall.IsDisposing(invocation, local, semanticModel, cancellationToken)) { return(true); } } } using (var walker = UsingStatementWalker.Borrow(scope)) { foreach (var usingStatement in walker.UsingStatements) { if (location.IsExecutedBefore(usingStatement) == ExecutedBefore.Yes && usingStatement.Expression is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == local.Name) { return(true); } } } } return(false); }
internal Result IsMemberDisposed(ISymbol member) { foreach (var invocation in this.invocations) { if (DisposeCall.IsDisposing(invocation, member, this.SemanticModel, this.CancellationToken)) { return(Result.Yes); } } if (member is IPropertySymbol property && property.OverriddenProperty is IPropertySymbol overridden) { return(this.IsMemberDisposed(overridden)); } foreach (var name in this.identifiers) { if (member.Name == name.Identifier.ValueText && this.SemanticModel.TryGetSymbol(name, this.CancellationToken, out ISymbol candidate) && member.Equals(candidate)) { return(Result.AssumeYes); } } return(Result.No); }
internal static bool IsDisposed(FieldOrProperty member, MethodDeclarationSyntax disposeMethod, SemanticModel semanticModel, CancellationToken cancellationToken) { using var walker = DisposeWalker.Borrow(disposeMethod, semanticModel, cancellationToken); if (Disposable.IsAssignableFrom(member.Type, semanticModel.Compilation)) { foreach (var candidate in walker.Invocations) { if (DisposeCall.IsDisposing(candidate, member.Symbol, semanticModel, cancellationToken)) { return(true); } } } foreach (var candidate in walker.Identifiers) { if (candidate.Identifier.Text == member.Name && semanticModel.TryGetSymbol(candidate, cancellationToken, out var candidateSymbol) && candidateSymbol.OriginalDefinition.Equals(member.Symbol)) { return(true); } } return(false); }
internal static bool IsDisposed(FieldOrProperty member, IMethodSymbol disposeMethod, SemanticModel semanticModel, CancellationToken cancellationToken) { if (disposeMethod == null) { return(false); } using (var walker = DisposeWalker.Borrow(disposeMethod, semanticModel, cancellationToken)) { foreach (var invocation in walker) { if (DisposeCall.IsDisposing(invocation, member.Symbol, semanticModel, cancellationToken)) { return(true); } } } return(false); }
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 { Left : { } left } &&
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); } }
internal static bool IsReturned(ISymbol symbol, SyntaxNode scope, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var walker = ReturnValueWalker.Borrow(scope, ReturnValueSearch.TopLevel, semanticModel, cancellationToken)) { foreach (var value in walker) { var candidate = value; switch (candidate) { case CastExpressionSyntax castExpression: candidate = castExpression.Expression; break; case BinaryExpressionSyntax binary when binary.IsKind(SyntaxKind.AsExpression): candidate = binary.Left; break; } if (candidate is ObjectCreationExpressionSyntax objectCreation) { if (objectCreation.ArgumentList != null) { foreach (var argument in objectCreation.ArgumentList.Arguments) { if (semanticModel.TryGetSymbol(argument.Expression, cancellationToken, out ISymbol argumentSymbol) && symbol.Equals(argumentSymbol)) { return(true); } } } if (objectCreation.Initializer != null) { foreach (var expression in objectCreation.Initializer.Expressions) { if (semanticModel.TryGetSymbol(expression, cancellationToken, out ISymbol expressionSymbol) && symbol.Equals(expressionSymbol)) { return(true); } } } } if (semanticModel.TryGetSymbol(candidate, cancellationToken, out ISymbol returnedSymbol) && symbol.Equals(returnedSymbol)) { return(true); } if (candidate is InvocationExpressionSyntax invocation) { if (returnedSymbol == KnownSymbol.RxDisposable.Create && invocation.ArgumentList != null && invocation.ArgumentList.Arguments.TrySingle(out var argument) && argument.Expression is ParenthesizedLambdaExpressionSyntax lambda) { var body = lambda.Body; using (var pooledInvocations = InvocationWalker.Borrow(body)) { foreach (var disposeCandidate in pooledInvocations.Invocations) { if (DisposeCall.IsDisposing(disposeCandidate, symbol, semanticModel, cancellationToken)) { return(true); } } } } } } } return(false); }