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));
                }
            }
        }
        private static void HandleFieldOrProperty(SyntaxNodeAnalysisContext context, FieldOrProperty fieldOrProperty)
        {
            using (var assignedValues = AssignedValueWalker.Borrow(fieldOrProperty.Symbol, context.SemanticModel, context.CancellationToken))
            {
                using (var recursive = RecursiveValues.Borrow(assignedValues, context.SemanticModel, context.CancellationToken))
                {
                    if (Disposable.IsAnyCreation(recursive, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes))
                    {
                        if (Disposable.IsAnyCachedOrInjected(recursive, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) ||
                            IsMutableFromOutside(fieldOrProperty))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(IDISP008DontMixInjectedAndCreatedForMember.Descriptor, context.Node.GetLocation()));
                        }
                        else if (context.Node.TryFirstAncestorOrSelf <TypeDeclarationSyntax>(out var typeDeclaration) &&
                                 DisposableMember.IsDisposed(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken).IsEither(Result.No, Result.AssumeNo) &&
                                 !TestFixture.IsAssignedAndDisposedInSetupAndTearDown(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(IDISP002DisposeMember.Descriptor, context.Node.GetLocation()));

                            if (!DisposeMethod.TryFindFirst(fieldOrProperty.ContainingType, context.Compilation, Search.TopLevel, out _) &&
                                !TestFixture.IsAssignedInSetUp(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken, out _))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(IDISP006ImplementIDisposable.Descriptor, context.Node.GetLocation()));
                            }
                        }
                    }
                }
            }
        }
        private static Result IsCreationCore(RecursiveValues values, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            values.Reset();
            var result = Result.No;

            while (values.MoveNext())
            {
                switch (IsCreationCore(values.Current, semanticModel, cancellationToken))
                {
                case Result.Unknown:
                    if (result == Result.No)
                    {
                        result = Result.Unknown;
                    }

                    break;

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

                case Result.No:
                    break;

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

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            return(result);
        }
        private static Result IsAssignedWithCreated(RecursiveValues walker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (walker.Count == 0)
            {
                return(Result.No);
            }

            return(IsCreationCore(walker, semanticModel, cancellationToken));
        }
Exemplo n.º 5
0
        internal static Result IsAnyCreation(RecursiveValues walker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (walker.Count == 0)
            {
                return(Result.No);
            }

            return(IsCreationCore(walker, semanticModel, cancellationToken));
        }
Exemplo n.º 6
0
 internal static Result IsAssignedWithCreated(ISymbol symbol, ExpressionSyntax location, SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     using (var assignedValues = AssignedValueWalker.Borrow(symbol, location, semanticModel, cancellationToken))
     {
         using (var recursive = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken))
         {
             return(IsAnyCreation(recursive, semanticModel, cancellationToken));
         }
     }
 }
 private static bool IsAssignedWithInjected(ISymbol symbol, ExpressionSyntax location, SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     using (var assignedValues = AssignedValueWalker.Borrow(symbol, location, semanticModel, cancellationToken))
     {
         using (var recursive = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken))
         {
             return(IsAnyCachedOrInjected(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.AssumeYes));
         }
     }
 }
 internal static Result IsAssignedWithCreated(ISymbol symbol, SyntaxNode context, SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     using (var pooled = AssignedValueWalker.Create(symbol, context, semanticModel, cancellationToken))
     {
         using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken))
         {
             return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken));
         }
     }
 }
Exemplo n.º 9
0
        internal static bool IsCachedOrInjectedOnly(ExpressionSyntax value, ExpressionSyntax location, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (semanticModel.TryGetSymbol(value, cancellationToken, out var symbol))
            {
                using var assignedValues = AssignedValueWalker.Borrow(symbol, location, semanticModel, cancellationToken);
                using var recursive      = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken);
                return((IsAnyCachedOrInjected(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.AssumeYes) ||
                        IsInjectedCore(symbol).IsEither(Result.Yes, Result.AssumeYes)) &&
                       !IsAnyCreation(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.AssumeYes));
            }

            return(false);
        }
        internal static Result IsAssignedWithCreated(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!IsPotentiallyAssignableTo(field?.Type))
            {
                return(Result.No);
            }

            using (var pooled = AssignedValueWalker.Create(field, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken));
                }
            }
        }
Exemplo n.º 11
0
        internal static Result IsAssignedWithCreated(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!IsPotentiallyAssignableTo(property?.Type))
            {
                return(Result.No);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(property, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken));
                }
            }
        }
Exemplo n.º 12
0
        internal static Result IsAnyCreation(RecursiveValues values, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (values.IsEmpty)
            {
                return(Result.No);
            }

            values.Reset();
            var result = Result.No;

            while (values.MoveNext())
            {
                switch (IsCreationCore(values.Current, semanticModel, cancellationToken))
                {
                case Result.Unknown:
                    if (result == Result.No)
                    {
                        result = Result.Unknown;
                    }

                    break;

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

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

                case Result.No:
                    break;

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

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            return(result);
        }
        internal static bool IsAssignedWithCreatedAndNotCachedOrInjected(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (field == null ||
                !IsPotentiallyAssignableTo(field.Type))
            {
                return(false);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(field, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe) &&
                           !IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
        internal static bool IsAssignedWithCreatedAndInjected(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (property == null ||
                !IsPotentiallyAssignableTo(property.Type))
            {
                return(false);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(property, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe) &&
                           IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
Exemplo n.º 15
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.º 16
0
        /// <summary>
        /// Check if any path returns a created IDisposable.
        /// </summary>
        internal static Result IsCreation(ExpressionSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (candidate == null)
            {
                return(Result.Unknown);
            }

            switch (candidate.Kind())
            {
            case SyntaxKind.NullLiteralExpression:
            case SyntaxKind.StringLiteralExpression:
            case SyntaxKind.NumericLiteralExpression:
            case SyntaxKind.TrueLiteralExpression:
            case SyntaxKind.FalseLiteralExpression:
            case SyntaxKind.BaseExpression:
            case SyntaxKind.ThisExpression:
                return(Result.No);
            }

            if (!IsPotentiallyAssignableFrom(candidate, semanticModel, cancellationToken))
            {
                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 recursive = RecursiveValues.Borrow(new[] { candidate }, semanticModel, cancellationToken))
            {
                return(IsAnyCreation(recursive, semanticModel, cancellationToken));
            }
        }
        /// <summary>
        /// Check if any path returns a created IDisposable
        /// </summary>
        internal static bool IsPotentiallyCachedOrInjected(InvocationExpressionSyntax disposeCall, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!TryGetDisposedRootMember(disposeCall, semanticModel, cancellationToken, out ExpressionSyntax member))
            {
                return(false);
            }

            var symbol = semanticModel.GetSymbolSafe(member, cancellationToken);

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

            using (var assignedValues = AssignedValueWalker.Borrow(symbol, disposeCall, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
Exemplo n.º 18
0
        internal static Result IsAnyCachedOrInjected(RecursiveValues values, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (values.IsEmpty)
            {
                return(Result.No);
            }

            var result = Result.No;

            values.Reset();
            while (values.MoveNext())
            {
                if (values.Current is ElementAccessExpressionSyntax elementAccess &&
                    semanticModel.TryGetSymbol(elementAccess.Expression, cancellationToken, out var symbol))
                {
                    var isInjected = IsInjectedCore(symbol);
                    if (isInjected == Result.Yes)
                    {
                        return(Result.Yes);
                    }

                    if (isInjected == Result.AssumeYes)
                    {
                        result = Result.AssumeYes;
                    }

                    using var assignedValues = AssignedValueWalker.Borrow(values.Current, semanticModel, cancellationToken);
                    using var recursive      = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken);
                    isInjected = IsAnyCachedOrInjected(recursive, semanticModel, cancellationToken);
                    if (isInjected == Result.Yes)
                    {
                        return(Result.Yes);
                    }

                    if (isInjected == Result.AssumeYes)
                    {
                        result = Result.AssumeYes;
                    }
                }
        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));
        }
        /// <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 pooled = ReturnValueWalker.Create(candidate, Search.Recursive, semanticModel, cancellationToken))
            {
                if (pooled.Item.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(pooled.Item, semanticModel, cancellationToken))
                {
                    return(IsCreationCore(recursive, semanticModel, cancellationToken));
                }
            }
        }
Exemplo n.º 21
0
        /// <summary>
        /// Check if any path returns a created IDisposable
        /// </summary>
        internal static Result IsAssignedWithCreated(ExpressionSyntax disposable, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol assignedSymbol)
        {
            if (!IsPotentiallyAssignableTo(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            if (semanticModel.GetSymbolSafe(disposable, cancellationToken) is IPropertySymbol property &&
                property.TryGetSetter(cancellationToken, out var setter))
            {
                using (var pooledSet = PooledHashSet <ISymbol> .Borrow())
                {
                    using (var pooledAssigned = AssignmentWalker.Borrow(setter, Search.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var assigned in pooledAssigned.Assignments)
                        {
                            var symbol = semanticModel.GetSymbolSafe(assigned.Left, cancellationToken);
                            if (IsPotentiallyAssignableTo(assigned.Left, semanticModel, cancellationToken) &&
                                (symbol is IFieldSymbol ||
                                 symbol is IPropertySymbol))
                            {
                                pooledSet.Add(symbol).IgnoreReturnValue();
                            }
                        }
                    }

                    assignedSymbol = null;
                    var result = Result.No;
                    foreach (var symbol in pooledSet)
                    {
                        switch (IsAssignedWithCreated(symbol, disposable, semanticModel, cancellationToken))
                        {
                        case Result.Unknown:
                            if (result == Result.No)
                            {
                                assignedSymbol = symbol;
                                result         = Result.Unknown;
                            }

                            break;

                        case Result.Yes:
                            assignedSymbol = symbol;
                            return(Result.Yes);

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

                        case Result.No:
                        case Result.AssumeNo:
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    return(result);
                }
            }

            using (var assignedValues = AssignedValueWalker.Borrow(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = assignedValues.CurrentSymbol;
                if (assignedValues.Count == 1 &&
                    disposable.Parent is AssignmentExpressionSyntax assignment &&
                    assignment.Parent is ParenthesizedExpressionSyntax parenthesizedExpression &&
                    parenthesizedExpression.Parent is BinaryExpressionSyntax binary &&
                    binary.IsKind(SyntaxKind.CoalesceExpression))
                {
                    return(Result.No);
                }

                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAnyCreation(recursive, semanticModel, cancellationToken));
                }
            }
        }
        private static Result IsInjectedCore(RecursiveValues values, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (values.Count == 0)
            {
                return(Result.No);
            }

            var result = Result.No;

            values.Reset();
            while (values.MoveNext())
            {
                if (values.Current is ElementAccessExpressionSyntax elementAccess)
                {
                    var symbol     = semanticModel.GetSymbolSafe(elementAccess.Expression, cancellationToken);
                    var isInjected = IsInjectedCore(symbol);
                    if (isInjected == Result.Yes)
                    {
                        return(Result.Yes);
                    }

                    if (isInjected == Result.Maybe)
                    {
                        result = Result.Maybe;
                    }

                    using (var assignedValues = AssignedValueWalker.Borrow(values.Current, semanticModel, cancellationToken))
                    {
                        using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                        {
                            isInjected = IsInjectedCore(recursive, semanticModel, cancellationToken);
                            if (isInjected == Result.Yes)
                            {
                                return(Result.Yes);
                            }

                            if (isInjected == Result.Maybe)
                            {
                                result = Result.Maybe;
                            }
                        }
                    }
                }
                else
                {
                    var symbol     = semanticModel.GetSymbolSafe(values.Current, cancellationToken);
                    var isInjected = IsInjectedCore(symbol);
                    if (isInjected == Result.Yes)
                    {
                        return(Result.Yes);
                    }

                    if (isInjected == Result.Maybe)
                    {
                        result = Result.Maybe;
                    }
                }
            }

            return(result);
        }
Exemplo n.º 23
0
        internal static Result IsAlreadyAssignedWithCreated(ExpressionSyntax disposable, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol assignedSymbol)
        {
            if (!IsPotentiallyAssignableFrom(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            var symbol = semanticModel.GetSymbolSafe(disposable, cancellationToken);

            if (symbol is IPropertySymbol property &&
                IsAssignableFrom(property.Type, semanticModel.Compilation) &&
                property.TryGetSetter(cancellationToken, out var setter) &&
                (setter.ExpressionBody != null || setter.Body != null))
            {
                using (var assignedSymbols = PooledSet <ISymbol> .Borrow())
                {
                    using (var pooledAssigned = AssignmentExecutionWalker.Borrow(setter, Scope.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var assigned in pooledAssigned.Assignments)
                        {
                            if (assigned.Right is IdentifierNameSyntax identifierName &&
                                identifierName.Identifier.ValueText == "value" &&
                                IsPotentiallyAssignableFrom(assigned.Left, semanticModel, cancellationToken) &&
                                semanticModel.GetSymbolSafe(assigned.Left, cancellationToken) is ISymbol candidate &&
                                candidate.IsEitherKind(SymbolKind.Field, SymbolKind.Property))
                            {
                                assignedSymbols.Add(candidate);
                            }
                        }
                    }

                    assignedSymbol = null;
                    var result = Result.No;
                    foreach (var candidate in assignedSymbols)
                    {
                        switch (IsAssignedWithCreated(candidate, disposable, semanticModel, cancellationToken))
                        {
                        case Result.Unknown:
                            if (result == Result.No)
                            {
                                assignedSymbol = candidate;
                                result         = Result.Unknown;
                            }

                            break;

                        case Result.Yes:
                            assignedSymbol = candidate;
                            return(Result.Yes);

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

                        case Result.No:
                        case Result.AssumeNo:
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    return(result);
                }
            }

            if (symbol is IParameterSymbol parameter &&
                disposable.TryFirstAncestor <ArrowExpressionClauseSyntax>(out _))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = assignedValues.CurrentSymbol;
                if (assignedValues.Count == 1 &&
                    disposable.Parent is AssignmentExpressionSyntax assignment)
                {
                    if (assignment.Parent is ParenthesizedExpressionSyntax parenthesizedExpression &&
                        parenthesizedExpression.Parent is BinaryExpressionSyntax binary &&
                        binary.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        // lazy
                        return(Result.No);
                    }
                }

                if (symbol.IsEither <IParameterSymbol, ILocalSymbol>())
                {
                    assignedValues.RemoveAll(x => IsReturnedBefore(x));
                }

                using (var recursive = RecursiveValues.Borrow(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAnyCreation(recursive, semanticModel, cancellationToken));
                }
            }

            bool IsReturnedBefore(ExpressionSyntax expression)
            {
                if (expression.TryFirstAncestor(out BlockSyntax block) &&
                    block.Statements.TryFirstOfType(out ReturnStatementSyntax _))
                {
                    if (expression.TryFirstAncestor <ForEachStatementSyntax>(out _) ||
                        expression.TryFirstAncestor <ForStatementSyntax>(out _) ||
                        expression.TryFirstAncestor <WhileStatementSyntax>(out _))
                    {
                        return(true);
                    }

                    return(!block.Contains(disposable) &&
                           block.SharesAncestor(disposable, out MemberDeclarationSyntax _));
                }

                return(false);
            }
        }
        /// <summary>
        /// Check if any path returns a created IDisposable
        /// </summary>
        internal static Result IsAssignedWithCreated(ExpressionSyntax disposable, SemanticModel semanticModel, CancellationToken cancellationToken, out ISymbol assignedSymbol)
        {
            if (!IsPotentiallyAssignableTo(disposable, semanticModel, cancellationToken))
            {
                assignedSymbol = null;
                return(Result.No);
            }

            if (semanticModel.GetSymbolSafe(disposable, cancellationToken) is IPropertySymbol property &&
                property.TryGetSetter(cancellationToken, out AccessorDeclarationSyntax setter))
            {
                using (var pooledSet = SetPool <ISymbol> .Create())
                {
                    using (var pooledAssigned = Assignment.Create(setter, Search.Recursive, semanticModel, cancellationToken))
                    {
                        foreach (var assigned in pooledAssigned.Item.Assignments)
                        {
                            var symbol = semanticModel.GetSymbolSafe(assigned.Left, cancellationToken);
                            if (IsPotentiallyAssignableTo(assigned.Left, semanticModel, cancellationToken) &&
                                (symbol is IFieldSymbol ||
                                 symbol is IPropertySymbol))
                            {
                                pooledSet.Item.Add(symbol).IgnoreReturnValue();
                            }
                        }
                    }

                    assignedSymbol = null;
                    var result = Result.No;
                    foreach (var symbol in pooledSet.Item)
                    {
                        switch (IsAssignedWithCreated(symbol, disposable, semanticModel, cancellationToken))
                        {
                        case Result.Unknown:
                            if (result == Result.No)
                            {
                                assignedSymbol = symbol;
                                result         = Result.Unknown;
                            }

                            break;

                        case Result.Yes:
                            assignedSymbol = symbol;
                            return(Result.Yes);

                        case Result.No:
                            break;

                        case Result.Maybe:
                            assignedSymbol = symbol;
                            result         = Result.Maybe;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    return(result);
                }
            }

            using (var pooled = AssignedValueWalker.Create(disposable, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(pooled.Item, semanticModel, cancellationToken))
                {
                    assignedSymbol = pooled.Item.CurrentSymbol;
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken));
                }
            }
        }