private static bool IsLazyEnumerable(InvocationExpressionSyntax invocation, SemanticModel semanticModel, CancellationToken cancellationToken, PooledSet <SyntaxNode> visited = null)
        {
            if (semanticModel.GetSymbolSafe(invocation, cancellationToken) is IMethodSymbol method &&
                method.ReturnType.IsAssignableTo(KnownSymbol.IEnumerable, semanticModel.Compilation) &&
                method.TrySingleDeclaration(cancellationToken, out MethodDeclarationSyntax methodDeclaration))
            {
                if (YieldStatementWalker.Any(methodDeclaration))
                {
                    return(true);
                }

                using (var walker = ReturnValueWalker.Borrow(methodDeclaration, ReturnValueSearch.TopLevel, semanticModel, cancellationToken))
                {
                    using (visited = visited.IncrementUsage())
                    {
                        foreach (var returnValue in walker)
                        {
                            if (returnValue is InvocationExpressionSyntax nestedInvocation &&
                                visited.Add(returnValue) &&
                                IsLazyEnumerable(nestedInvocation, semanticModel, cancellationToken, visited))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 2
0
        internal static bool TryGetDisposedRootMember(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken, out ExpressionSyntax disposedMember)
        {
            if (MemberPath.TryFindRootMember(disposeCall, out disposedMember))
            {
                var property = semanticModel.GetSymbolSafe(disposedMember, cancellationToken) as IPropertySymbol;
                if (property == null ||
                    property.IsAutoProperty(cancellationToken))
                {
                    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, Search.TopLevel, semanticModel, cancellationToken))
                    {
                        if (pooled.Count == 0)
                        {
                            return(false);
                        }

                        return(MemberPath.TryFindRootMember(pooled[0], out disposedMember));
                    }
                }
            }

            return(false);
        }
        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));
            }
        }
        private static bool IsPotentiallyCachedOrInjectedCore(ExpressionSyntax value, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var symbol = semanticModel.GetSymbolSafe(value, cancellationToken);

            if (IsInjectedCore(symbol) == Result.Yes)
            {
                return(true);
            }

            if (symbol is IPropertySymbol property &&
                !property.IsAutoProperty(cancellationToken))
            {
                using (var returnValues = ReturnValueWalker.Borrow(value, Search.TopLevel, semanticModel, cancellationToken))
                {
                    using (var recursive = RecursiveValues.Create(returnValues, semanticModel, cancellationToken))
                    {
                        return(IsInjectedCore(recursive, semanticModel, cancellationToken)
                               .IsEither(Result.Yes, Result.Maybe));
                    }
                }
            }

            using (var assignedValues = AssignedValueWalker.Borrow(value, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Check if any path returns a created IDisposable
        /// </summary>
        internal static Result IsCreation(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!IsPotentiallyAssignableTo(candidate, semanticModel, cancellationToken) ||
                candidate is ThisExpressionSyntax ||
                candidate is BaseExpressionSyntax)
            {
                return(Result.No);
            }

            if (candidate is IdentifierNameSyntax identifierName &&
                identifierName.Identifier.ValueText == "value" &&
                candidate.FirstAncestor <AccessorDeclarationSyntax>() is AccessorDeclarationSyntax accessor &&
                accessor.IsKind(SyntaxKind.SetAccessorDeclaration))
            {
                return(Result.No);
            }

            if (candidate is ObjectCreationExpressionSyntax)
            {
                return(Result.Yes);
            }

            using (var walker = ReturnValueWalker.Borrow(candidate, Search.Recursive, semanticModel, cancellationToken))
            {
                if (walker.Count == 0)
                {
                    var symbol = semanticModel.GetSymbolSafe(candidate, cancellationToken);
                    if (symbol != null &&
                        symbol.DeclaringSyntaxReferences.Length == 0)
                    {
                        return(IsCreationCore(symbol));
                    }

                    using (var recursive = RecursiveValues.Create(new[] { candidate }, semanticModel, cancellationToken))
                    {
                        return(IsCreationCore(recursive, semanticModel, cancellationToken));
                    }
                }

                using (var recursive = RecursiveValues.Create(walker, semanticModel, cancellationToken))
                {
                    return(IsCreationCore(recursive, semanticModel, cancellationToken));
                }
            }
        }
Exemplo n.º 6
0
        internal static bool IsNop(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (semanticModel.TryGetSymbol(candidate, cancellationToken, out ISymbol symbol) &&
                FieldOrProperty.TryCreate(symbol, out var fieldOrProperty) &&
                fieldOrProperty.IsStatic &&
                IsAssignableFrom(fieldOrProperty.Type, semanticModel.Compilation))
            {
                if (fieldOrProperty.Type == KnownSymbol.Task ||
                    symbol == KnownSymbol.RxDisposable.Empty)
                {
                    return(true);
                }

                using (var walker = ReturnValueWalker.Borrow(candidate, ReturnValueSearch.Recursive, semanticModel, cancellationToken))
                {
                    if (walker.Count > 0)
                    {
                        return(walker.TrySingle(out var value) &&
                               semanticModel.TryGetType(value, cancellationToken, out var type) &&
                               IsNop(type));
                    }
                }

                using (var walker = AssignedValueWalker.Borrow(symbol, semanticModel, cancellationToken))
                {
                    return(walker.TrySingle(out var value) &&
                           semanticModel.TryGetType(value, cancellationToken, out var type) &&
                           IsNop(type));
                }
            }

            return(false);

            bool IsNop(ITypeSymbol type)
            {
                return(type.IsSealed &&
                       type.BaseType == KnownSymbol.Object &&
                       type.TryFindSingleMethod("Dispose", out var disposeMethod) &&
                       disposeMethod.Parameters.Length == 0 &&
                       disposeMethod.TrySingleDeclaration(cancellationToken, out MethodDeclarationSyntax declaration) &&
                       declaration.Body is BlockSyntax body &&
                       body.Statements.Count == 0);
            }
        }
        internal static bool IsCachedOrInjected(ExpressionSyntax value, ExpressionSyntax location, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var symbol = semanticModel.GetSymbolSafe(value, cancellationToken);

            if (IsInjectedCore(symbol).IsEither(Result.Yes, Result.AssumeYes))
            {
                return(true);
            }

            if (symbol is IPropertySymbol property &&
                !property.IsAutoProperty())
            {
                using (var returnValues = ReturnValueWalker.Borrow(value, ReturnValueSearch.TopLevel, semanticModel, cancellationToken))
                {
                    using (var recursive = RecursiveValues.Borrow(returnValues, semanticModel, cancellationToken))
                    {
                        return(IsAnyCachedOrInjected(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.AssumeYes));
                    }
                }
            }

            return(IsAssignedWithInjected(symbol, location, semanticModel, cancellationToken));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Check if any path returns a created IDisposable
        /// </summary>
        internal static Result IsCreation(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!IsPotentiallyAssignableTo(candidate, semanticModel, cancellationToken) ||
                candidate is ThisExpressionSyntax ||
                candidate is BaseExpressionSyntax)
            {
                return(Result.No);
            }

            if (candidate is ObjectCreationExpressionSyntax)
            {
                return(Result.Yes);
            }

            using (var walker = ReturnValueWalker.Borrow(candidate, Search.Recursive, semanticModel, cancellationToken))
            {
                if (walker.Count == 0)
                {
                    var symbol = semanticModel.GetSymbolSafe(candidate, cancellationToken);
                    if (symbol != null && symbol.DeclaringSyntaxReferences.Length == 0)
                    {
                        return(IsCreationCore(candidate, semanticModel, cancellationToken));
                    }

                    using (var recursive = RecursiveValues.Create(new[] { candidate }, semanticModel, cancellationToken))
                    {
                        return(IsCreationCore(recursive, semanticModel, cancellationToken));
                    }
                }

                using (var recursive = RecursiveValues.Create(walker, semanticModel, cancellationToken))
                {
                    return(IsCreationCore(recursive, semanticModel, cancellationToken));
                }
            }
        }
Exemplo n.º 9
0
        internal static bool IsDisposing(InvocationExpressionSyntax disposeCall, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (TryGetDisposed(disposeCall, semanticModel, cancellationToken, out var disposed))
            {
                if (disposed.Equals(symbol))
                {
                    return(true);
                }

                if (disposed is IPropertySymbol property &&
                    property.TrySingleDeclaration(cancellationToken, out var declaration))
                {
                    using (var walker = ReturnValueWalker.Borrow(declaration, ReturnValueSearch.TopLevel, semanticModel, cancellationToken))
                    {
                        return(walker.TrySingle(out var returnValue) &&
                               MemberPath.TrySingle(returnValue, out var expression) &&
                               semanticModel.TryGetSymbol(expression, cancellationToken, out ISymbol nested) &&
                               nested.Equals(symbol));
                    }
                }
            }

            return(false);
        }
        private static bool IsReturned(ILocalSymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            using (var walker = ReturnValueWalker.Borrow(block, Search.TopLevel, semanticModel, cancellationToken))
            {
                foreach (var value in walker)
                {
                    var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken);
                    if (SymbolComparer.Equals(symbol, returnedSymbol))
                    {
                        return(true);
                    }

                    if (value is ObjectCreationExpressionSyntax objectCreation)
                    {
                        if (objectCreation.ArgumentList != null)
                        {
                            foreach (var argument in objectCreation.ArgumentList.Arguments)
                            {
                                var arg = semanticModel.GetSymbolSafe(argument.Expression, cancellationToken);
                                if (SymbolComparer.Equals(symbol, arg))
                                {
                                    return(true);
                                }
                            }
                        }

                        if (objectCreation.Initializer != null)
                        {
                            foreach (var argument in objectCreation.Initializer.Expressions)
                            {
                                var arg = semanticModel.GetSymbolSafe(argument, cancellationToken);
                                if (SymbolComparer.Equals(symbol, arg))
                                {
                                    return(true);
                                }
                            }
                        }
                    }

                    if (value is InvocationExpressionSyntax invocation)
                    {
                        if (returnedSymbol == KnownSymbol.RxDisposable.Create &&
                            invocation.ArgumentList != null &&
                            invocation.ArgumentList.Arguments.TryGetSingle(out ArgumentSyntax argument) &&
                            argument.Expression is ParenthesizedLambdaExpressionSyntax lambda)
                        {
                            var body = lambda.Body;
                            using (var pooledInvocations = InvocationWalker.Borrow(body))
                            {
                                foreach (var candidate in pooledInvocations.Invocations)
                                {
                                    if (Disposable.IsDisposing(candidate, symbol, semanticModel, cancellationToken))
                                    {
                                        return(true);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 11
0
        private static Result CheckReturnValues(IParameterSymbol parameter, SyntaxNode memberAccess, SemanticModel semanticModel, CancellationToken cancellationToken, PooledHashSet <SyntaxNode> visited)
        {
            Result CheckReturnValue(ExpressionSyntax returnValue)
            {
                if (returnValue is ObjectCreationExpressionSyntax nestedObjectCreation)
                {
                    if (nestedObjectCreation.TryGetMatchingArgument(parameter, out var nestedArgument))
                    {
                        return(IsArgumentDisposedByReturnValue(nestedArgument, semanticModel, cancellationToken, visited));
                    }

                    return(Result.No);
                }

                if (returnValue is InvocationExpressionSyntax nestedInvocation)
                {
                    if (nestedInvocation.TryGetMatchingArgument(parameter, out var nestedArgument))
                    {
                        return(IsArgumentDisposedByReturnValue(nestedArgument, semanticModel, cancellationToken, visited));
                    }

                    return(Result.No);
                }

                if (returnValue is MemberAccessExpressionSyntax nestedMemberAccess)
                {
                    return(IsArgumentDisposedByInvocationReturnValue(nestedMemberAccess, semanticModel, cancellationToken, visited));
                }

                return(Result.Unknown);
            }

            var result = Result.No;

            using (var returnWalker = ReturnValueWalker.Borrow(memberAccess, Search.Recursive, semanticModel, cancellationToken))
            {
                using (visited = PooledHashSet <SyntaxNode> .BorrowOrIncrementUsage(visited))
                {
                    if (!visited.Add(memberAccess))
                    {
                        return(Result.Unknown);
                    }

                    foreach (var returnValue in returnWalker)
                    {
                        switch (CheckReturnValue(returnValue))
                        {
                        case Result.Unknown:
                            return(Result.Unknown);

                        case Result.Yes:
                            if (result == Result.No)
                            {
                                result = Result.Yes;
                            }

                            break;

                        case Result.AssumeYes:
                            result = Result.AssumeYes;
                            break;

                        case Result.No:
                            return(Result.No);

                        case Result.AssumeNo:
                            return(Result.AssumeNo);

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }
            }

            return(result);
        }
Exemplo n.º 12
0
        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);
        }
Exemplo n.º 13
0
        private bool AddRecursiveValues(ExpressionSyntax assignedValue)
        {
            if (assignedValue == null ||
                assignedValue.IsMissing ||
                !this.checkedLocations.Add(assignedValue))
            {
                return(false);
            }

            if (assignedValue is LiteralExpressionSyntax ||
                assignedValue is DefaultExpressionSyntax ||
                assignedValue is TypeOfExpressionSyntax ||
                assignedValue is ObjectCreationExpressionSyntax ||
                assignedValue is ArrayCreationExpressionSyntax ||
                assignedValue is ImplicitArrayCreationExpressionSyntax ||
                assignedValue is InitializerExpressionSyntax)
            {
                this.values.Add(assignedValue);
                return(true);
            }

            var argument = assignedValue.Parent as ArgumentSyntax;

            if (argument?.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword) == true)
            {
                var invocation    = assignedValue.FirstAncestor <InvocationExpressionSyntax>();
                var invokedMethod = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken);
                if (invokedMethod == null ||
                    invokedMethod.DeclaringSyntaxReferences.Length == 0)
                {
                    this.values.Add(invocation);
                    return(true);
                }

                var before = this.values.Count;
                foreach (var reference in invokedMethod.DeclaringSyntaxReferences)
                {
                    var methodDeclaration = reference.GetSyntax(this.cancellationToken) as MethodDeclarationSyntax;
                    if (methodDeclaration.TryGetMatchingParameter(argument, out ParameterSyntax parameter))
                    {
                        using (var assignedValues = AssignedValueWalker.Borrow(this.semanticModel.GetDeclaredSymbolSafe(parameter, this.cancellationToken), this.semanticModel, this.cancellationToken))
                        {
                            assignedValues.HandleInvoke(invokedMethod, invocation.ArgumentList);
                            return(this.AddManyRecursively(assignedValues));
                        }
                    }
                }

                return(before != this.values.Count);
            }

            if (assignedValue is BinaryExpressionSyntax binaryExpression)
            {
                switch (binaryExpression.Kind())
                {
                case SyntaxKind.CoalesceExpression:
                    var left  = this.AddRecursiveValues(binaryExpression.Left);
                    var right = this.AddRecursiveValues(binaryExpression.Right);
                    return(left || right);

                case SyntaxKind.AsExpression:
                    return(this.AddRecursiveValues(binaryExpression.Left));

                default:
                    return(false);
                }
            }

            if (assignedValue is CastExpressionSyntax cast)
            {
                return(this.AddRecursiveValues(cast.Expression));
            }

            if (assignedValue is ConditionalExpressionSyntax conditional)
            {
                var whenTrue  = this.AddRecursiveValues(conditional.WhenTrue);
                var whenFalse = this.AddRecursiveValues(conditional.WhenFalse);
                return(whenTrue || whenFalse);
            }

            if (assignedValue is AwaitExpressionSyntax @await)
            {
                using (var walker = ReturnValueWalker.Borrow(@await, Search.Recursive, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(walker));
                }
            }

            if (assignedValue is ElementAccessExpressionSyntax)
            {
                this.values.Add(assignedValue);
                return(true);
            }

            var symbol = this.semanticModel.GetSymbolSafe(assignedValue, this.cancellationToken);

            if (symbol == null)
            {
                return(false);
            }

            if (symbol is IFieldSymbol)
            {
                this.values.Add(assignedValue);
                return(true);
            }

            if (symbol is IParameterSymbol)
            {
                this.values.Add(assignedValue);
                using (var assignedValues = AssignedValueWalker.Borrow(assignedValue, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(assignedValues));
                }
            }

            if (symbol is ILocalSymbol)
            {
                using (var assignedValues = AssignedValueWalker.Borrow(assignedValue, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(assignedValues));
                }
            }

            if (symbol is IPropertySymbol property)
            {
                if (property.DeclaringSyntaxReferences.Length == 0)
                {
                    this.values.Add(assignedValue);
                    return(true);
                }

                using (var returnValues = ReturnValueWalker.Borrow(assignedValue, Search.Recursive, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(returnValues));
                }
            }

            if (symbol is IMethodSymbol method)
            {
                if (method.DeclaringSyntaxReferences.Length == 0)
                {
                    this.values.Add(assignedValue);
                    return(true);
                }

                using (var walker = ReturnValueWalker.Borrow(assignedValue, Search.Recursive, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(walker));
                }
            }

            return(false);
        }
Exemplo n.º 14
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.Borrow(invocation, Search.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var returnValue in returnWalker)
                        {
                            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);
        }
Exemplo n.º 15
0
        private bool AddRecursiveValues(ExpressionSyntax assignedValue)
        {
            if (assignedValue == null ||
                assignedValue.IsMissing ||
                !this.checkedLocations.Add(assignedValue))
            {
                return(false);
            }

            if (assignedValue.Parent is ArgumentSyntax argument &&
                argument.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword))
            {
                if (assignedValue.TryFirstAncestor(out InvocationExpressionSyntax invocation) &&
                    this.semanticModel.TryGetSymbol(invocation, this.cancellationToken, out var target) &&
                    target.TrySingleMethodDeclaration(this.cancellationToken, out var targetDeclaration))
                {
                    if (targetDeclaration.TryFindParameter(argument, out var parameter) &&
                        this.semanticModel.TryGetSymbol(parameter, this.cancellationToken, out var parameterSymbol))
                    {
                        using (var assignedValues = AssignedValueWalker.Borrow(parameterSymbol, this.semanticModel, this.cancellationToken))
                        {
                            assignedValues.HandleInvoke(target, invocation.ArgumentList);
                            return(this.AddManyRecursively(assignedValues));
                        }
                    }

                    return(false);
                }

                this.values.Add(invocation);
                return(true);
            }

            switch (assignedValue)
            {
            case ArrayCreationExpressionSyntax _:
            case DefaultExpressionSyntax _:
            case ElementAccessExpressionSyntax _:
            case ImplicitArrayCreationExpressionSyntax _:
            case InitializerExpressionSyntax _:
            case LiteralExpressionSyntax _:
            case ObjectCreationExpressionSyntax _:
            case TypeOfExpressionSyntax _:
                this.values.Add(assignedValue);
                return(true);

            case BinaryExpressionSyntax binaryExpression:
                switch (binaryExpression.Kind())
                {
                case SyntaxKind.CoalesceExpression:
                    var left  = this.AddRecursiveValues(binaryExpression.Left);
                    var right = this.AddRecursiveValues(binaryExpression.Right);
                    return(left || right);

                case SyntaxKind.AsExpression:
                    return(this.AddRecursiveValues(binaryExpression.Left));

                default:
                    return(false);
                }

            case CastExpressionSyntax cast:
                return(this.AddRecursiveValues(cast.Expression));

            case ConditionalExpressionSyntax conditional:
                var whenTrue  = this.AddRecursiveValues(conditional.WhenTrue);
                var whenFalse = this.AddRecursiveValues(conditional.WhenFalse);
                return(whenTrue || whenFalse);

            case AwaitExpressionSyntax awaitExpression:
                using (var walker = ReturnValueWalker.Borrow(awaitExpression, ReturnValueSearch.RecursiveInside, this.semanticModel, this.cancellationToken))
                {
                    return(this.AddManyRecursively(walker));
                }
            }

            if (this.semanticModel.TryGetSymbol(assignedValue, this.cancellationToken, out ISymbol symbol))
            {
                switch (symbol)
                {
                case ILocalSymbol _:
                    using (var assignedValues = AssignedValueWalker.Borrow(assignedValue, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(assignedValues));
                    }

                case IParameterSymbol _:
                    this.values.Add(assignedValue);
                    using (var assignedValues = AssignedValueWalker.Borrow(assignedValue, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(assignedValues));
                    }

                case IFieldSymbol _:
                    this.values.Add(assignedValue);
                    return(true);

                case IPropertySymbol _:
                case IMethodSymbol _:
                    if (symbol.DeclaringSyntaxReferences.Length == 0)
                    {
                        this.values.Add(assignedValue);
                        return(true);
                    }

                    using (var returnValues = ReturnValueWalker.Borrow(assignedValue, ReturnValueSearch.RecursiveInside, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(returnValues));
                    }
                }
            }

            return(false);
        }