private static void HandleProperty(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            AccessorDeclarationSyntax setter = (AccessorDeclarationSyntax)context.Node;

            if (setter.Body != null)
            {
                return;
            }

            var propertySymbol = context.ContainingProperty();

            if (propertySymbol.SetMethod?.DeclaredAccessibility != Accessibility.Private ||
                propertySymbol.IsIndexer)
            {
                return;
            }

            using (var pooled = AssignedValueWalker.Create(propertySymbol, context.SemanticModel, context.CancellationToken))
            {
                foreach (var value in pooled.Item)
                {
                    if (MeansPropertyIsMutable(value))
                    {
                        return;
                    }
                }
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, setter.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.Create(value, Search.TopLevel, semanticModel, cancellationToken))
                {
                    using (var recursive = RecursiveValues.Create(returnValues.Item, semanticModel, cancellationToken))
                    {
                        return(IsInjectedCore(recursive, semanticModel, cancellationToken)
                               .IsEither(Result.Yes, Result.Maybe));
                    }
                }
            }

            using (var sources = AssignedValueWalker.Create(value, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken))
                {
                    return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
Exemplo n.º 3
0
 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.º 4
0
        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));
                }
            }
        }
        internal static bool IsAssignedWithCreatedAndNotCachedOrInjected(IFieldSymbol field, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (field == null ||
                !IsPotentiallyAssignableTo(field.Type))
            {
                return(false);
            }

            using (var sources = AssignedValueWalker.Create(field, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(sources.Item, 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 sources = AssignedValueWalker.Create(property, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken))
                {
                    return(IsAssignedWithCreated(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe) &&
                           IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
Exemplo n.º 7
0
        private static bool IsInjected(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (member is IFieldSymbol field)
            {
                using (var pooled = AssignedValueWalker.Create(field, semanticModel, cancellationToken))
                {
                    foreach (var assignedValue in pooled.Item)
                    {
                        if (assignedValue.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() == null)
                        {
                            continue;
                        }

                        if (semanticModel.GetSymbolSafe(assignedValue, cancellationToken) is IParameterSymbol)
                        {
                            return(true);
                        }
                    }
                }
            }

            if (member is IPropertySymbol property)
            {
                using (var pooled = AssignedValueWalker.Create(property, semanticModel, cancellationToken))
                {
                    foreach (var assignedValue in pooled.Item)
                    {
                        if (assignedValue.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() == null)
                        {
                            continue;
                        }

                        if (semanticModel.GetSymbolSafe(assignedValue, cancellationToken) is IParameterSymbol)
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 8
0
        private static bool IsNeverNull(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (!(member is IFieldSymbol || member is IPropertySymbol))
            {
                return(false);
            }

            using (var sources = AssignedValueWalker.Create(member, semanticModel, cancellationToken))
            {
                foreach (var value in sources.Item)
                {
                    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 sources = AssignedValueWalker.Create(symbol, disposeCall, semanticModel, cancellationToken))
            {
                using (var recursive = RecursiveValues.Create(sources.Item, semanticModel, cancellationToken))
                {
                    return(IsInjectedCore(recursive, semanticModel, cancellationToken).IsEither(Result.Yes, Result.Maybe));
                }
            }
        }
        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 sources = AssignedValueWalker.Create(values.Current, semanticModel, cancellationToken))
                    {
                        using (var recursive = RecursiveValues.Create(sources.Item, 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);
        }
            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 pooled = AssignedValueWalker.Create(this.semanticModel.GetDeclaredSymbolSafe(parameter, this.cancellationToken), this.semanticModel, this.cancellationToken))
                            {
                                pooled.Item.HandleInvoke(invokedMethod, invocation.ArgumentList);
                                return(this.AddManyRecursively(pooled.Item));
                            }
                        }
                    }

                    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 pooled = ReturnValueWalker.Create(@await, Search.Recursive, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(pooled.Item));
                    }
                }

                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 pooled = AssignedValueWalker.Create(assignedValue, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(pooled.Item));
                    }
                }

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

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

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

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

                    using (var pooled = ReturnValueWalker.Create(assignedValue, Search.Recursive, this.semanticModel, this.cancellationToken))
                    {
                        return(this.AddManyRecursively(pooled.Item));
                    }
                }

                return(false);
            }
Exemplo n.º 12
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 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));
                }
            }
        }
Exemplo n.º 13
0
        private void AddReturnValue(ExpressionSyntax value)
        {
            if (this.awaits)
            {
                if (AsyncAwait.TryAwaitTaskRun(value, this.semanticModel, this.cancellationToken, out ExpressionSyntax awaited))
                {
                    using (var pooled = this.GetRecursive(awaited))
                    {
                        if (pooled.Item.values.Count == 0)
                        {
                            this.values.Add(awaited);
                        }
                        else
                        {
                            foreach (var returnValue in pooled.Item.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 pooled = this.GetRecursive(value))
                        {
                            foreach (var returnValue in pooled.Item.values)
                            {
                                this.AddReturnValue(returnValue);
                            }
                        }
                    }
                }
                else if (this.recursionLoop.Add(value) &&
                         this.semanticModel.IsEither <IParameterSymbol, ILocalSymbol>(value, this.cancellationToken))
                {
                    using (var pooled = AssignedValueWalker.Create(value, this.semanticModel, this.cancellationToken))
                    {
                        if (pooled.Item.Count == 0)
                        {
                            this.values.Add(value);
                        }
                        else
                        {
                            foreach (var assignment in pooled.Item)
                            {
                                this.AddReturnValue(assignment);
                            }
                        }
                    }
                }
                else
                {
                    this.values.Add(value);
                }
            }
            else
            {
                this.values.Add(value);
            }
        }