private static void HandleAssignment(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; if (Disposable.IsCreation(assignment.Right, context.SemanticModel, context.CancellationToken) .IsEither(Result.No, Result.Unknown)) { return; } if (Disposable.IsAssignedWithCreated(assignment.Left, context.SemanticModel, context.CancellationToken, out ISymbol assignedSymbol) .IsEither(Result.No, Result.Unknown)) { return; } if (assignedSymbol == KnownSymbol.SerialDisposable.Disposable) { return; } if (IsDisposedBefore(assignedSymbol, assignment, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(Diagnostic.Create(Descriptor, assignment.GetLocation())); }
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 HandleField(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } var field = (IFieldSymbol)context.ContainingSymbol; if (field.IsStatic || field.IsConst) { return; } if (field.DeclaredAccessibility != Accessibility.Private && !field.IsReadOnly) { if (Disposable.IsAssignedWithCreated(field, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.Maybe)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); } } else if (Disposable.IsAssignedWithCreatedAndInjected(field, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.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 HandleArgument(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } var argument = (ArgumentSyntax)context.Node; if (argument.RefOrOutKeyword.IsKind(SyntaxKind.None)) { return; } var invocation = argument.FirstAncestor <InvocationExpressionSyntax>(); if (invocation == null) { return; } var method = context.SemanticModel.GetSymbolSafe(invocation, context.CancellationToken); if (method == null || method.DeclaringSyntaxReferences.Length == 0) { return; } if (Disposable.IsCreation(argument, context.SemanticModel, context.CancellationToken) .IsEither(Result.No, Result.Unknown)) { return; } var symbol = context.SemanticModel.GetSymbolSafe(argument.Expression, context.CancellationToken); if (Disposable.IsAssignedWithCreated(symbol, argument.FirstAncestor <InvocationExpressionSyntax>(), context.SemanticModel, context.CancellationToken) .IsEither(Result.No, Result.Unknown)) { return; } if (IsDisposedBefore(symbol, argument.Expression, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(Diagnostic.Create(Descriptor, argument.GetLocation())); }
private static void HandleProperty(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } var property = (IPropertySymbol)context.ContainingSymbol; if (property.IsStatic || property.IsIndexer) { return; } var propertyDeclaration = (PropertyDeclarationSyntax)context.Node; if (propertyDeclaration.ExpressionBody != null) { return; } if (propertyDeclaration.TryGetSetAccessorDeclaration(out AccessorDeclarationSyntax setter) && setter.Body != null) { // Handle the backing field return; } if (property.SetMethod != null && property.SetMethod.DeclaredAccessibility != Accessibility.Private) { if (Disposable.IsAssignedWithCreated(property, context.SemanticModel, context.CancellationToken) .IsEither(Result.Yes, Result.Maybe)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); } } else if (Disposable.IsAssignedWithCreatedAndInjected(property, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation())); } }
private static bool TryCreateDisposeStatement(AssignmentExpressionSyntax assignment, SemanticModel semanticModel, CancellationToken cancellationToken, out StatementSyntax result) { result = null; if (!(assignment.Parent is StatementSyntax && assignment.Parent.Parent is BlockSyntax)) { return(false); } if (Disposable.IsAssignedWithCreated(assignment.Left, semanticModel, cancellationToken, out var assignedSymbol) .IsEither(Result.No, Result.Unknown)) { return(false); } var prefix = (assignedSymbol is IPropertySymbol || assignedSymbol is IFieldSymbol) && !assignment.UsesUnderscore(semanticModel, cancellationToken) ? "this." : string.Empty; if (!Disposable.IsAssignableTo(MemberType(assignedSymbol))) { result = SyntaxFactory.ParseStatement($"({prefix}{assignment.Left} as System.IDisposable)?.Dispose();") .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker) .WithSimplifiedNames(); return(true); } if (IsAlwaysAssigned(assignedSymbol)) { result = SyntaxFactory.ParseStatement($"{prefix}{assignedSymbol.Name}.Dispose();") .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker); return(true); } result = SyntaxFactory.ParseStatement($"{prefix}{assignedSymbol.Name}?.Dispose();") .WithLeadingTrivia(SyntaxFactory.ElasticMarker) .WithTrailingTrivia(SyntaxFactory.ElasticMarker); return(true); }