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

            if (context.Node is AccessorDeclarationSyntax setter &&
                setter.Body == null &&
                context.ContainingSymbol is IMethodSymbol setMethod &&
                setMethod.DeclaredAccessibility == Accessibility.Private &&
                setMethod.AssociatedSymbol is IPropertySymbol property &&
                !property.IsIndexer)
            {
                using (var walker = MutationWalker.For(property, context.SemanticModel, context.CancellationToken))
                {
                    foreach (var value in walker.All())
                    {
                        if (MeansPropertyIsMutable(value))
                        {
                            return;
                        }
                    }
                }

                context.ReportDiagnostic(Diagnostic.Create(Descriptor, setter.GetLocation()));
            }
        }
Exemple #2
0
        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 walker = MutationWalker.Borrow(propertySymbol, context.SemanticModel, context.CancellationToken))
            {
                foreach (var value in walker)
                {
                    if (MeansPropertyIsMutable(value))
                    {
                        return;
                    }
                }
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, setter.GetLocation()));
        }
        private static bool IsInjected(ISymbol member, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (member is IFieldSymbol field)
            {
                using (var walker = MutationWalker.Borrow(field, semanticModel, cancellationToken))
                {
                    foreach (var assignedValue in walker)
                    {
                        if (assignedValue.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() == null)
                        {
                            continue;
                        }

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

            if (member is IPropertySymbol property)
            {
                using (var walker = MutationWalker.Borrow(property, semanticModel, cancellationToken))
                {
                    foreach (var assignedValue in walker)
                    {
                        if (assignedValue.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() == null)
                        {
                            continue;
                        }

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

            return(false);
        }
        private static bool ShouldUseParameter(SyntaxNodeAnalysisContext context, ISymbol left, ExpressionSyntax expression)
        {
            if (expression.FirstAncestor <AnonymousFunctionExpressionSyntax>() != null)
            {
                if (left is IFieldSymbol field &&
                    !field.IsReadOnly)
                {
                    return(false);
                }

                if (left is IPropertySymbol property &&
                    !property.IsGetOnly())
                {
                    return(false);
                }
            }

            return(TryGetIdentifier(expression, out var identifierName) &&
                   identifierName.IsSymbol(left, context.SemanticModel, context.CancellationToken) &&
                   IsMutatedOnceBefore());

            bool IsMutatedOnceBefore()
            {
                if (expression.TryFirstAncestor(out StatementSyntax statement))
                {
                    using (var walker = MutationWalker.For(left, context.SemanticModel, context.CancellationToken))
                    {
                        return(walker.TrySingle(out var single) &&
                               single.TryFirstAncestor(out StatementSyntax singleStatement) &&
                               singleStatement.IsExecutedBefore(statement) == ExecutedBefore.Yes);
                    }
                }

                return(false);
            }
        }
Exemple #5
0
 public MemberWalker(MutationWalker inner)
 {
     this.inner = inner;
 }
        private void AddReturnValue(ExpressionSyntax value)
        {
            if (this.awaits)
            {
                if (AsyncAwait.TryAwaitTaskRun(value, this.semanticModel, this.cancellationToken, out ExpressionSyntax 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 = MutationWalker.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);
            }
        }