private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is ArgumentSyntax { Parent : ArgumentListSyntax { Parent : InvocationExpressionSyntax invocation } } argument&& argument.RefOrOutKeyword.IsEither(SyntaxKind.RefKeyword, SyntaxKind.OutKeyword) && IsCreation(argument, context.SemanticModel, context.CancellationToken) && context.SemanticModel.TryGetSymbol(argument.Expression, context.CancellationToken, out var symbol)) { if (symbol.Kind == SymbolKind.Discard || (LocalOrParameter.TryCreate(symbol, out var localOrParameter) && Disposable.ShouldDispose(localOrParameter, context.SemanticModel, context.CancellationToken))) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP001DisposeCreated, argument.GetLocation())); } if (Disposable.IsAssignedWithCreated(symbol, invocation, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) && !Disposable.IsDisposedBefore(symbol, invocation, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP003DisposeBeforeReassigning, argument.GetLocation())); } } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is ArgumentSyntax argument && argument.Parent is ArgumentListSyntax argumentList && argumentList.Parent is InvocationExpressionSyntax invocation && argument.RefOrOutKeyword.IsEither(SyntaxKind.RefKeyword, SyntaxKind.OutKeyword) && context.SemanticModel.TryGetSymbol(invocation, context.CancellationToken, out var method) && method.TrySingleDeclaration(context.CancellationToken, out BaseMethodDeclarationSyntax declaration) && method.TryFindParameter(argument, out var parameter) && Disposable.IsPotentiallyAssignableFrom(parameter.Type, context.Compilation)) { if (Disposable.IsCreation(argument, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) && !Disposable.IsAddedToFieldOrProperty(parameter, declaration, context.SemanticModel, context.CancellationToken) && context.SemanticModel.TryGetSymbol(argument.Expression, context.CancellationToken, out ISymbol symbol)) { if (LocalOrParameter.TryCreate(symbol, out var localOrParameter) && Disposable.ShouldDispose(localOrParameter, argument.Expression, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(IDISP001DisposeCreated.Descriptor, argument.GetLocation())); } if (Disposable.IsAssignedWithCreated(symbol, invocation, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) && !Disposable.IsDisposedBefore(symbol, invocation, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(IDISP003DisposeBeforeReassigning.Descriptor, argument.GetLocation())); } } } }
private static void HandleReturnValue(SyntaxNodeAnalysisContext context, ExpressionSyntax returnValue) { if (Disposable.IsCreation(returnValue, context.SemanticModel, context.CancellationToken) == Result.Yes && context.SemanticModel.TryGetSymbol(returnValue, context.CancellationToken, out ISymbol returnedSymbol)) { if (IsInUsing(returnedSymbol, context.CancellationToken) || Disposable.IsDisposedBefore(returnedSymbol, returnValue, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(IDISP011DontReturnDisposed.Descriptor, returnValue.GetLocation())); } else { if (returnValue.FirstAncestor <AccessorDeclarationSyntax>() is AccessorDeclarationSyntax accessor && accessor.IsKind(SyntaxKind.GetAccessorDeclaration)) { context.ReportDiagnostic(Diagnostic.Create(IDISP012PropertyShouldNotReturnCreated.Descriptor, returnValue.GetLocation())); } if (returnValue.FirstAncestor <ArrowExpressionClauseSyntax>() is ArrowExpressionClauseSyntax arrow && arrow.Parent is PropertyDeclarationSyntax) { context.ReportDiagnostic(Diagnostic.Create(IDISP012PropertyShouldNotReturnCreated.Descriptor, returnValue.GetLocation())); } if (!IsDisposableReturnTypeOrIgnored(ReturnType(context), context.Compilation)) { context.ReportDiagnostic(Diagnostic.Create(IDISP005ReturntypeShouldBeIDisposable.Descriptor, returnValue.GetLocation())); } } } else if (returnValue is InvocationExpressionSyntax invocation && invocation.ArgumentList is ArgumentListSyntax argumentList) { foreach (var argument in argumentList.Arguments) { if (Disposable.IsCreation(argument.Expression, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) && context.SemanticModel.TryGetSymbol(argument.Expression, context.CancellationToken, out ISymbol argumentSymbol)) { if (IsInUsing(argumentSymbol, context.CancellationToken) || Disposable.IsDisposedBefore(argumentSymbol, argument.Expression, context.SemanticModel, context.CancellationToken)) { if (IsLazyEnumerable(invocation, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(IDISP011DontReturnDisposed.Descriptor, argument.GetLocation())); } } } } } if (ReturnType(context).IsAwaitable() && returnValue.TryFirstAncestor <UsingStatementSyntax>(out var usingStatement) && usingStatement.Statement.Contains(returnValue) && !returnValue.TryFirstAncestorOrSelf <AwaitExpressionSyntax>(out _) && context.SemanticModel.TryGetType(returnValue, context.CancellationToken, out var returnValueType) && returnValueType.IsAwaitable() && ShouldAwait(context, returnValue)) { context.ReportDiagnostic(Diagnostic.Create(IDISP013AwaitInUsing.Descriptor, returnValue.GetLocation())); } }
private static bool IsReassignedWithCreated(AssignmentExpressionSyntax assignment, SyntaxNodeAnalysisContext context) { if (assignment.FirstAncestor <AccessorDeclarationSyntax>() is AccessorDeclarationSyntax accessor && accessor.IsKind(SyntaxKind.SetAccessorDeclaration) && assignment.Right is IdentifierNameSyntax assignedIdentifier && assignedIdentifier.Identifier.ValueText == "value") { return(false); } if (Disposable.IsAlreadyAssignedWithCreated(assignment.Left, context.SemanticModel, context.CancellationToken, out var assignedSymbol) .IsEither(Result.No, Result.AssumeNo, Result.Unknown)) { return(false); } if (assignedSymbol == KnownSymbol.SerialDisposable.Disposable || assignedSymbol == KnownSymbol.SingleAssignmentDisposable.Disposable) { return(false); } if (Disposable.IsDisposedBefore(assignedSymbol, assignment, context.SemanticModel, context.CancellationToken)) { return(false); } if (FieldOrProperty.TryCreate(assignedSymbol, out var fieldOrProperty) && TestFixture.IsAssignedAndDisposedInSetupAndTearDown(fieldOrProperty, context.Node.FirstAncestor <TypeDeclarationSyntax>(), context.SemanticModel, context.CancellationToken)) { return(false); } if (IsNullChecked(assignedSymbol, assignment, context.SemanticModel, context.CancellationToken)) { return(false); } if (TryGetAssignedLocal(out var local) && Disposable.IsDisposedAfter(local, assignment, context.SemanticModel, context.CancellationToken)) { return(false); } return(true); bool TryGetAssignedLocal(out ILocalSymbol result) { result = null; if (assignment.TryFirstAncestor(out MemberDeclarationSyntax memberDeclaration)) { using (var walker = VariableDeclaratorWalker.Borrow(memberDeclaration)) { return(walker.VariableDeclarators.TrySingle( x => context.SemanticModel.TryGetSymbol( x.Initializer?.Value, context.CancellationToken, out ISymbol symbol) && symbol.Equals(assignedSymbol), out var match) && match.Initializer.Value.IsExecutedBefore(assignment) == ExecutedBefore.Yes && context.SemanticModel.TryGetSymbol(match, context.CancellationToken, out result)); } } return(false); } }