Exemplo n.º 1
0
        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 HandleDeclaration(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            var variableDeclaration = (VariableDeclarationSyntax)context.Node;

            foreach (var declarator in variableDeclaration.Variables)
            {
                var value = declarator.Initializer?.Value;
                if (value == null ||
                    !Disposable.IsPotentiallyAssignableTo(value, context.SemanticModel, context.CancellationToken))
                {
                    continue;
                }

                if (Disposable.IsCreation(value, context.SemanticModel, context.CancellationToken)
                    .IsEither(Result.Yes, Result.Maybe))
                {
                    if (variableDeclaration.Parent is UsingStatementSyntax ||
                        variableDeclaration.Parent is AnonymousFunctionExpressionSyntax)
                    {
                        return;
                    }

                    var block = declarator.FirstAncestorOrSelf <BlockSyntax>();
                    if (block == null)
                    {
                        return;
                    }

                    if (context.SemanticModel.GetDeclaredSymbolSafe(declarator, context.CancellationToken) is ILocalSymbol local)
                    {
                        if (IsReturned(local, block, context.SemanticModel, context.CancellationToken))
                        {
                            return;
                        }

                        if (IsAssignedToFieldOrProperty(local, block, context.SemanticModel, context.CancellationToken))
                        {
                            return;
                        }

                        if (IsAddedToFieldOrProperty(local, block, context.SemanticModel, context.CancellationToken))
                        {
                            return;
                        }

                        if (IsDisposedAfter(local, value, context.SemanticModel, context.CancellationToken))
                        {
                            return;
                        }
                    }

                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, variableDeclaration.GetLocation()));
                }
            }
        }
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (context.ContainingSymbol is IMethodSymbol method &&
                context.Node is MethodDeclarationSyntax methodDeclaration &&
                Disposable.IsAssignableFrom(method.ReturnType, context.Compilation))
            {
                using var walker = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.RecursiveInside, context.SemanticModel, context.CancellationToken);
                if (walker.TryFirst(x => IsCreated(x), out _) &&
                    walker.TryFirst(x => IsCachedOrInjected(x) && !IsNop(x), out _))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP015DoNotReturnCachedAndCreated, methodDeclaration.Identifier.GetLocation()));
                }
            }

            bool IsCreated(ExpressionSyntax expression)
            {
                return(Disposable.IsCreation(expression, context.SemanticModel, context.CancellationToken) == Result.Yes);
            }

            bool IsCachedOrInjected(ExpressionSyntax expression)
            {
                return(Disposable.IsCachedOrInjected(expression, expression, context.SemanticModel, context.CancellationToken));
            }

            bool IsNop(ExpressionSyntax expression)
            {
                return(Disposable.IsNop(expression, context.SemanticModel, context.CancellationToken));
            }
        }
Exemplo n.º 4
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is AssignmentExpressionSyntax {
                Left : { } left, Right : { } right
            } assignment&&
                !left.IsKind(SyntaxKind.ElementAccessExpression) &&
                context.SemanticModel.TryGetSymbol(left, context.CancellationToken, out var assignedSymbol))
            {
                if (LocalOrParameter.TryCreate(assignedSymbol, out var localOrParameter) &&
                    Disposable.IsCreation(right, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) &&
                    Disposable.ShouldDispose(localOrParameter, context.SemanticModel, context.CancellationToken))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP001DisposeCreated, assignment.GetLocation()));
                }

                if (IsReassignedWithCreated(assignment, context))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP003DisposeBeforeReassigning, assignment.GetLocation()));
                }

                if (assignedSymbol is IParameterSymbol {
                    RefKind : RefKind.Ref
                } refParameter&&
                    refParameter.ContainingSymbol.DeclaredAccessibility != Accessibility.Private &&
                    context.SemanticModel.TryGetType(right, context.CancellationToken, out var type) &&
                    Disposable.IsAssignableFrom(type, context.Compilation))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP008DoNotMixInjectedAndCreatedForMember, 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()));
                    }
                }
            }
        }
Exemplo n.º 6
0
        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 Handle(SyntaxNodeAnalysisContext context)
 {
     if (!context.IsExcludedFromAnalysis() &&
         context.Node is LocalDeclarationStatementSyntax localDeclaration)
     {
         foreach (var declarator in localDeclaration.Declaration.Variables)
         {
             if (declarator.Initializer is EqualsValueClauseSyntax initializer &&
                 initializer.Value is ExpressionSyntax value &&
                 Disposable.IsCreation(value, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) &&
                 context.SemanticModel.GetDeclaredSymbolSafe(declarator, context.CancellationToken) is ILocalSymbol local &&
                 Disposable.ShouldDispose(local, value, context.SemanticModel, context.CancellationToken))
             {
                 context.ReportDiagnostic(Diagnostic.Create(Descriptor, localDeclaration.GetLocation()));
             }
         }
     }
 }
        private static bool IsPreferUsing(ILocalSymbol local, InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context)
        {
            return(local.TrySingleDeclaration(context.CancellationToken, out var declaration) &&
                   declaration is VariableDeclaratorSyntax declarator &&
                   declaration.TryFirstAncestor(out LocalDeclarationStatementSyntax localDeclarationStatement) &&
                   invocation.TryFirstAncestor(out ExpressionStatementSyntax expressionStatement) &&
                   (DeclarationIsAssignment() || IsTrivialTryFinally()) &&
                   !IsMutated());

            bool DeclarationIsAssignment()
            {
                return(localDeclarationStatement.Parent == expressionStatement.Parent &&
                       Disposable.IsCreation(declarator.Initializer?.Value, context.SemanticModel, context.CancellationToken) == Result.Yes);
            }

            bool IsTrivialTryFinally()
            {
                return(expressionStatement.Parent is BlockSyntax block &&
                       block.Statements.Count == 1 &&
                       block.Parent is FinallyClauseSyntax finallyClause &&
                       finallyClause.Parent is TryStatementSyntax tryStatement &&
                       !tryStatement.Catches.Any());
            }

            bool IsMutated()
            {
                using (var walker = MutationWalker.For(local, context.SemanticModel, context.CancellationToken))
                {
                    if (declarator.Initializer?.Value.IsKind(SyntaxKind.NullLiteralExpression) == true &&
                        walker.TrySingle(out var mutation) &&
                        mutation.TryFirstAncestor(out ExpressionStatementSyntax statement) &&
                        statement.Parent is BlockSyntax block &&
                        block.Statements[0] == statement &&
                        block.Parent is TryStatementSyntax)
                    {
                        return(false);
                    }

                    return(walker.All().Any());
                }
            }
        }
Exemplo n.º 9
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is ObjectCreationExpressionSyntax objectCreation)
            {
                if (context.SemanticModel.TryGetType(objectCreation, context.CancellationToken, out var type) &&
                    type.IsAssignableTo(KnownSymbol.HttpClient, context.Compilation) &&
                    !IsStaticFieldInitializer(objectCreation) &&
                    !IsStaticPropertyInitializer(objectCreation) &&
                    !IsStaticCtor(context.ContainingSymbol))
                {
                    context.ReportDiagnostic(Diagnostic.Create(IDISP014UseSingleInstanceOfHttpClient.Descriptor, objectCreation.GetLocation()));
                }

                if (Disposable.IsCreation(objectCreation, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) &&
                    Disposable.IsIgnored(objectCreation, context.SemanticModel, context.CancellationToken))
                {
                    context.ReportDiagnostic(Diagnostic.Create(IDISP004DontIgnoreCreated.Descriptor, context.Node.GetLocation()));
                }
            }
        }
Exemplo n.º 10
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            if (context.Node is InvocationExpressionSyntax invocation &&
                Disposable.IsCreation(invocation, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) &&
                Disposable.IsIgnored(invocation, context.SemanticModel, context.CancellationToken))
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation()));
            }

            if (context.Node is MemberAccessExpressionSyntax memberAccess &&
                context.SemanticModel.TryGetSymbol(memberAccess.Expression, context.CancellationToken, out IPropertySymbol property) &&
                Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation) &&
                Disposable.IsCreation(memberAccess.Expression, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) &&
                Disposable.IsIgnored(memberAccess.Expression, context.SemanticModel, context.CancellationToken))
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation()));
            }
        }
        private static void HandleReturnValue(SyntaxNodeAnalysisContext context, ExpressionSyntax returnValue)
        {
            if (Disposable.IsCreation(returnValue, context.SemanticModel, context.CancellationToken)
                .IsEither(Result.Yes, Result.Maybe))
            {
                var symbol = context.SemanticModel.GetSymbolSafe(returnValue, context.CancellationToken);
                if (symbol == null)
                {
                    return;
                }

                foreach (var reference in symbol.DeclaringSyntaxReferences)
                {
                    var node = reference.GetSyntax(context.CancellationToken);
                    if (node?.Parent?.Parent is UsingStatementSyntax)
                    {
                        return;
                    }
                }

                context.ReportDiagnostic(Diagnostic.Create(Descriptor, returnValue.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()));
            }
        }
Exemplo n.º 13
0
        private static bool MustBeHandled(
            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 (Disposable.IsCreation(node, semanticModel, cancellationToken)
                .IsEither(Result.No, Result.Unknown))
            {
                return(false);
            }

            if (node.Parent is StatementSyntax)
            {
                return(true);
            }

            if (node.Parent is ArgumentSyntax argument)
            {
                if (argument.Parent.Parent is InvocationExpressionSyntax invocation)
                {
                    using (var returnWalker = ReturnValueWalker.Create(invocation, Search.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var returnValue in returnWalker.Item)
                        {
                            if (MustBeHandled(returnValue, semanticModel, cancellationToken))
                            {
                                return(true);
                            }
                        }
                    }

                    return(false);
                }

                if (argument.Parent.Parent is ObjectCreationExpressionSyntax)
                {
                    if (TryGetAssignedFieldOrProperty(argument, semanticModel, cancellationToken, out ISymbol member, out IMethodSymbol ctor) &&
                        member != null)
                    {
                        var initializer = argument.FirstAncestorOrSelf <ConstructorInitializerSyntax>();
                        if (initializer != null)
                        {
                            if (semanticModel.GetDeclaredSymbolSafe(initializer.Parent, cancellationToken) is IMethodSymbol chainedCtor &&
                                chainedCtor.ContainingType != member.ContainingType)
                            {
                                if (Disposable.TryGetDisposeMethod(chainedCtor.ContainingType, Search.TopLevel, out IMethodSymbol disposeMethod))
                                {
                                    return(!Disposable.IsMemberDisposed(member, disposeMethod, semanticModel, cancellationToken));
                                }
                            }
                        }

                        if (Disposable.IsMemberDisposed(member, ctor.ContainingType, semanticModel, cancellationToken)
                            .IsEither(Result.Yes, Result.Maybe))
                        {
                            return(false);
                        }

                        return(true);
                    }

                    return(ctor?.ContainingType != KnownSymbol.StreamReader &&
                           ctor?.ContainingType != KnownSymbol.CompositeDisposable);
                }
            }

            return(false);
        }