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 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));
                }
            }
        }
示例#3
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));
         }
     }
 }
示例#4
0
 internal static Result IsAssignedWithCreated(ISymbol symbol, SyntaxNode context, SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     using (var assignedValues = AssignedValueWalker.Borrow(symbol, context, semanticModel, cancellationToken))
     {
         using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
         {
             return(IsAssignedWithCreated(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));
         }
     }
 }
示例#6
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);
        }
示例#7
0
        internal static Result IsAssignedWithCreated(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!IsPotentiallyAssignableTo(field?.Type))
            {
                return(Result.No);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(field, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(assignedValues, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken));
                }
            }
        }
示例#8
0
        private bool AddRecursiveValues(ExpressionSyntax assignedValue)
        {
            if (assignedValue is 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(assignedValue);
                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 {
                    Left: { }, OperatorToken : { ValueText : "as" }
            } binary :
        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));
                }
            }
        }
示例#11
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);
            }
        }
示例#12
0
        private static bool IsNeverNull(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (member is IFieldSymbol field &&
                !field.IsReadOnly)
            {
                return(false);
            }

            if (member is IPropertySymbol property &&
                !property.IsReadOnly)
            {
                return(false);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(member, semanticModel, cancellationToken))
            {
                foreach (var value in assignedValues)
                {
                    if (value is ObjectCreationExpressionSyntax objectCreation)
                    {
                        if (objectCreation.Parent is EqualsValueClauseSyntax equalsValueClause &&
                            equalsValueClause.Parent is VariableDeclaratorSyntax)
                        {
                            continue;
                        }

                        if (objectCreation.Parent is AssignmentExpressionSyntax assignment &&
                            assignment.Parent is ExpressionStatementSyntax statement &&
                            statement.Parent is BlockSyntax block &&
                            block.Parent is ConstructorDeclarationSyntax)
                        {
                            continue;
                        }
                    }

                    return(false);
                }
            }

            return(true);
        }
示例#13
0
        private static bool IsNeverNull(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!(member is IFieldSymbol || member is IPropertySymbol))
            {
                return(false);
            }

            using (var assignedValues = AssignedValueWalker.Borrow(member, semanticModel, cancellationToken))
            {
                foreach (var value in assignedValues)
                {
                    if (value is ObjectCreationExpressionSyntax)
                    {
                        continue;
                    }

                    return(false);
                }
            }

            return(true);
        }
        /// <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));
                }
            }
        }
示例#15
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;
                    }
                }
示例#16
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));
                }
            }
        }
示例#17
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);
            }
        }
示例#18
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);
        }
示例#19
0
        private void AddReturnValue(ExpressionSyntax value)
        {
            if (this.search.IsEither(ReturnValueSearch.Recursive, ReturnValueSearch.RecursiveInside))
            {
                switch (value)
                {
                case InvocationExpressionSyntax invocation:
                    if (!this.TryHandleInvocation(invocation, out var method) &&
                        method != null &&
                        method.DeclaringSyntaxReferences.Length == 0)
                    {
                        this.returnValues.Add(invocation);
                    }

                    break;

                case AwaitExpressionSyntax awaitExpression:
                    this.TryHandleAwait(awaitExpression);
                    break;

                case ConditionalExpressionSyntax ternary:
                    this.AddReturnValue(ternary.WhenTrue);
                    this.AddReturnValue(ternary.WhenFalse);
                    break;

                case BinaryExpressionSyntax coalesce when coalesce.IsKind(SyntaxKind.CoalesceExpression):
                    this.AddReturnValue(coalesce.Left);

                    this.AddReturnValue(coalesce.Right);
                    break;

                case IdentifierNameSyntax identifierName when this.semanticModel.GetSymbolSafe(identifierName, this.cancellationToken).IsEither <ILocalSymbol, IParameterSymbol>():
                    if (this.assignedValueWalkers.TryGetValue(identifierName, out _))
                    {
                        this.returnValues.Add(value);
                        return;
                    }

                    var assignedValues = AssignedValueWalker.Borrow(value, this.semanticModel, this.cancellationToken);
                    this.assignedValueWalkers.Add(identifierName, assignedValues);
                    if (assignedValues.Count == 0)
                    {
                        this.returnValues.Add(value);
                    }
                    else
                    {
                        foreach (var assignment in assignedValues)
                        {
                            this.AddReturnValue(assignment);
                        }
                    }

                    break;

                case ExpressionSyntax expression when this.semanticModel.GetSymbolSafe(expression, this.cancellationToken) is IPropertySymbol:
                    if (!this.TryHandlePropertyGet(value, out var property) &&
                        property != null &&
                        property.DeclaringSyntaxReferences.Length == 0)
                    {
                        this.returnValues.Add(value);
                    }

                    break;

                default:
                    this.returnValues.Add(value);
                    break;
                }
            }
            else
            {
                this.returnValues.Add(value);
            }
        }
示例#20
0
        private void AddReturnValue(ExpressionSyntax value)
        {
            if (this.awaits)
            {
                if (AsyncAwait.TryAwaitTaskRun(value, this.semanticModel, this.cancellationToken, out var awaited))
                {
                    using (var walker = this.GetRecursive(awaited))
                    {
                        if (walker.values.Count == 0)
                        {
                            this.values.Add(awaited);
                        }
                        else
                        {
                            foreach (var returnValue in walker.values)
                            {
                                this.AddReturnValue(returnValue);
                            }
                        }
                    }

                    return;
                }

                if (AsyncAwait.TryAwaitTaskFromResult(value, this.semanticModel, this.cancellationToken, out awaited))
                {
                    this.AddReturnValue(awaited);
                    return;
                }

                if (this.search == Search.Recursive &&
                    value is AwaitExpressionSyntax @await)
                {
                    value = @await.Expression;
                }
            }

            if (this.search == Search.Recursive)
            {
                if (value is InvocationExpressionSyntax invocation)
                {
                    var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken);
                    if (method == null ||
                        method.DeclaringSyntaxReferences.Length == 0)
                    {
                        this.values.Add(value);
                    }
                    else
                    {
                        using (var walker = this.GetRecursive(value))
                        {
                            foreach (var returnValue in walker.values)
                            {
                                this.AddReturnValue(returnValue);
                            }
                        }
                    }
                }
                else if (this.recursionLoop.Add(value) &&
                         this.semanticModel.IsEither <IParameterSymbol, ILocalSymbol>(value, this.cancellationToken))
                {
                    using (var assignedValues = AssignedValueWalker.Borrow(value, this.semanticModel, this.cancellationToken))
                    {
                        if (assignedValues.Count == 0)
                        {
                            this.values.Add(value);
                        }
                        else
                        {
                            foreach (var assignment in assignedValues)
                            {
                                this.AddReturnValue(assignment);
                            }
                        }
                    }
                }
                else
                {
                    this.values.Add(value);
                }
            }
            else
            {
                this.values.Add(value);
            }
        }
        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);
        }
示例#22
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);
        }