Example #1
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (conditionalExpression.ContainsDiagnostics)
            {
                return;
            }

            ExpressionSyntax condition = conditionalExpression.Condition;

            if (condition == null)
            {
                return;
            }

            SyntaxKind kind = condition.Kind();

            if (kind == SyntaxKind.ParenthesizedExpression)
            {
                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveParenthesesFromConditionOfConditionalExpressionWhenExpressionIsSingleToken))
                {
                    var parenthesizedExpression = (ParenthesizedExpressionSyntax)condition;

                    ExpressionSyntax expression = parenthesizedExpression.Expression;

                    if (!expression.IsMissing &&
                        CSharpFacts.IsSingleTokenExpression(expression.Kind()))
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ReportOnly.RemoveParenthesesFromConditionOfConditionalExpressionWhenExpressionIsSingleToken, condition);
                    }
                }
            }
            else if (!CSharpFacts.IsSingleTokenExpression(kind) ||
                     context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveParenthesesFromConditionOfConditionalExpressionWhenExpressionIsSingleToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ParenthesizeConditionOfConditionalExpression, condition);
            }
        }
Example #2
0
        // x:
        // byte
        // ushort
        // uint
        // ulong
        // Array.Length
        // string.Length
        // ICollection<T>.Count
        // IReadOnlyCollection<T>.Count

        // x >= 0 >>> true
        // 0 >= x >>> 0 == x
        private static void AnalyzeGreaterThanOrEqualExpression(SyntaxNodeAnalysisContext context)
        {
            var greaterThanOrEqualExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(greaterThanOrEqualExpression);

            if (!info.Success)
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.ExpressionIsAlwaysEqualToTrueOrFalse) &&
                IsAlwaysEqualToTrueOrFalse(greaterThanOrEqualExpression, info.Left, info.Right, context.SemanticModel, context.CancellationToken))
            {
                ReportExpressionAlwaysEqualToTrueOrFalse(context, "true");
            }
            else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryOperator) &&
                     IsUnnecessaryRelationalOperator(info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                ReportUnnecessaryRelationalOperator(context, info.OperatorToken);
            }
        }
        private static void AnalyzeIndexerDeclaration(SyntaxNodeAnalysisContext context)
        {
            var indexerDeclaration = (IndexerDeclarationSyntax)context.Node;

            ArrowExpressionClauseSyntax expressionBody = indexerDeclaration.ExpressionBody;

            if (expressionBody?.ContainsDirectives == false)
            {
                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenDeclarationIsMultiLine) &&
                    indexerDeclaration.SyntaxTree.IsMultiLineSpan(indexerDeclaration.HeaderSpan()))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ReportOnly.ConvertExpressionBodyToBlockBodyWhenDeclarationIsMultiLine, expressionBody);
                    return;
                }

                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine) &&
                    expressionBody.Expression?.IsMultiLine() == true)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ReportOnly.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine, expressionBody);
                }
            }
        }
        internal static void ReportDiagnosticIfNotSuppressed(
            this SyntaxNodeAnalysisContext context,
            DiagnosticDescriptor descriptor,
            SyntaxNode node,
            params object[] messageArgs)
        {
            if (context.IsAnalyzerSuppressed(descriptor))
            {
                return;
            }

            ReportDiagnostic(context, descriptor, node, messageArgs);
        }
Example #5
0
        public static void ReportDiagnosticIfNotSuppressed(
            SyntaxNodeAnalysisContext context,
            DiagnosticDescriptor descriptor,
            Location location,
            params object[] messageArgs)
        {
            if (context.IsAnalyzerSuppressed(descriptor))
            {
                return;
            }

            ReportDiagnostic(context, descriptor, location, messageArgs);
        }
        private static void AnalyzeDoStatement(SyntaxNodeAnalysisContext context)
        {
            var doStatement = (DoStatementSyntax)context.Node;

            StatementSyntax statement = doStatement.Statement;

            if (!statement.IsKind(SyntaxKind.Block))
            {
                return;
            }

            SyntaxTriviaList trailingTrivia = statement.GetTrailingTrivia();

            if (!trailingTrivia.Any() ||
                trailingTrivia.SingleOrDefault(shouldThrow: false).IsWhitespaceTrivia())
            {
                if (!doStatement.WhileKeyword.LeadingTrivia.Any() &&
                    context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword))
                {
                    context.ReportDiagnostic(
                        DiagnosticDescriptors.AddNewLineBetweenClosingBraceAndWhileKeywordOrViceVersa,
                        Location.Create(doStatement.SyntaxTree, new TextSpan(statement.FullSpan.End, 0)));
                }
            }
            else if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia))
            {
                if (doStatement.WhileKeyword.LeadingTrivia.IsEmptyOrWhitespace() &&
                    !context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveNewLineBetweenClosingBraceAndWhileKeyword))
                {
                    context.ReportDiagnostic(
                        DiagnosticDescriptors.ReportOnly.RemoveNewLineBetweenClosingBraceAndWhileKeyword,
                        Location.Create(doStatement.SyntaxTree, new TextSpan(trailingTrivia.Last().SpanStart, 0)),
                        properties: DiagnosticProperties.AnalyzerOption_Invert);
                }
            }
        }
Example #7
0
        private static void AnalyzeArrowExpressionClause(SyntaxNodeAnalysisContext context)
        {
            var arrowExpressionClause = (ArrowExpressionClauseSyntax)context.Node;

            SyntaxToken arrowToken = arrowExpressionClause.ArrowToken;

            SyntaxToken previousToken = arrowToken.GetPreviousToken();

            if (SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(previousToken.TrailingTrivia))
            {
                if (!arrowToken.LeadingTrivia.Any() &&
                    SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(arrowToken.TrailingTrivia) &&
                    SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(arrowExpressionClause.Expression.GetLeadingTrivia()) &&
                    context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterExpressionBodyArrowInsteadOfBeforeIt))
                {
                    DiagnosticHelpers.ReportDiagnostic(
                        context,
                        DiagnosticDescriptors.AddNewLineBeforeExpressionBodyArrowInsteadOfAfterItOrViceVersa,
                        arrowToken.GetLocation());
                }
            }
            else if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(previousToken.TrailingTrivia))
            {
                if (SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(arrowToken.LeadingTrivia) &&
                    SyntaxTriviaAnalysis.IsEmptyOrSingleWhitespaceTrivia(arrowToken.TrailingTrivia) &&
                    !arrowExpressionClause.Expression.GetLeadingTrivia().Any() &&
                    !context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterExpressionBodyArrowInsteadOfBeforeIt))
                {
                    DiagnosticHelpers.ReportDiagnostic(
                        context,
                        DiagnosticDescriptors.ReportOnly.AddNewLineAfterExpressionBodyArrowInsteadOfBeforeIt,
                        arrowToken.GetLocation(),
                        properties: DiagnosticProperties.AnalyzerOption_Invert);
                }
            }
        }
Example #8
0
        private static void AnalyzeArrayCreationExpression(SyntaxNodeAnalysisContext context)
        {
            var arrayCreation = (ArrayCreationExpressionSyntax)context.Node;

            if (arrayCreation.ContainsDiagnostics)
            {
                return;
            }

            ArrayTypeSyntax arrayType = arrayCreation.Type;

            if (arrayType.ContainsDirectives)
            {
                return;
            }

            SeparatedSyntaxList <ExpressionSyntax> expressions = arrayCreation.Initializer?.Expressions ?? default;

            if (!expressions.Any())
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(AnalyzerOptions.UseImplicitlyTypedArrayWhenTypeIsObvious))
            {
                foreach (ExpressionSyntax expression in expressions)
                {
                    if (!CSharpTypeAnalysis.IsTypeObvious(expression, context.SemanticModel, context.CancellationToken))
                    {
                        return;
                    }
                }
            }

            TypeSyntax elementType = arrayType.ElementType;
            SyntaxList <ArrayRankSpecifierSyntax> rankSpecifiers = arrayType.RankSpecifiers;

            TextSpan textSpan = TextSpan.FromBounds(
                elementType.SpanStart,
                ((rankSpecifiers.Count > 1) ? rankSpecifiers.LastButOne() : (SyntaxNode)elementType).Span.End);

            DiagnosticHelpers.ReportDiagnostic(
                context,
                DiagnosticDescriptors.ReportOnly.UseImplicitlyTypedArray,
                Location.Create(arrayCreation.SyntaxTree, textSpan));
        }
        private static void ReportUnusedElement(
            SyntaxNodeAnalysisContext context,
            XmlNodeSyntax xmlNode,
            int index,
            SyntaxList <XmlNodeSyntax> xmlNodes)
        {
            if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnusedElementInDocumentationComment))
            {
                return;
            }

            ReportDiagnostic(context, DiagnosticDescriptors.UnusedElementInDocumentationComment, xmlNode);

            if (index > 0 &&
                xmlNodes[index - 1] is XmlTextSyntax xmlText)
            {
                SyntaxTokenList tokens = xmlText.TextTokens;

                if (tokens.Count == 1)
                {
                    if (tokens[0].IsKind(SyntaxKind.XmlTextLiteralToken))
                    {
                        SyntaxTrivia trivia = tokens[0].LeadingTrivia.SingleOrDefault(shouldThrow: false);

                        if (trivia.IsKind(SyntaxKind.DocumentationCommentExteriorTrivia))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.UnusedElementInDocumentationCommentFadeOut, trivia);
                        }
                    }
                }
                else if (tokens.Count == 2)
                {
                    if (tokens[0].IsKind(SyntaxKind.XmlTextLiteralNewLineToken) &&
                        tokens[1].IsKind(SyntaxKind.XmlTextLiteralToken))
                    {
                        SyntaxTrivia trivia = tokens[1].LeadingTrivia.SingleOrDefault(shouldThrow: false);

                        if (trivia.IsKind(SyntaxKind.DocumentationCommentExteriorTrivia))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.UnusedElementInDocumentationCommentFadeOut, trivia);
                        }
                    }
                }
            }
        }
        private static void CheckChildStatement(SyntaxNodeAnalysisContext context, StatementSyntax childStatement)
        {
            if (childStatement is BlockSyntax)
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(SA1519BracesMustNotBeOmittedFromMultiLineChildStatement.Descriptor))
            {
                // diagnostics for multi-line statements is handled by SA1519, as long as it's not suppressed
                FileLinePositionSpan lineSpan = childStatement.GetLineSpan();
                if (lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line)
                {
                    return;
                }
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, childStatement.GetLocation()));
        }
        private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax block, BlockExpressionAnalysis analysis)
        {
            if (!context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine) &&
                analysis.Expression.IsMultiLine())
            {
                return;
            }

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(block.OpenBraceToken))
            {
                return;
            }

            if (!analysis.ReturnOrThrowKeyword.LeadingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            ReportDiagnostic(context, analysis.Block, analysis.Expression);
        }
Example #12
0
        private static void HandleIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.Parent.IsKind(SyntaxKind.ElseClause))
            {
                // this will be analyzed as a clause of the outer if statement
                return;
            }

            List <StatementSyntax> clauses = new List <StatementSyntax>();

            for (IfStatementSyntax current = ifStatement; current != null; current = current.Else?.Statement as IfStatementSyntax)
            {
                clauses.Add(current.Statement);
                if (current.Else != null && !(current.Else.Statement is IfStatementSyntax))
                {
                    clauses.Add(current.Else.Statement);
                }
            }

            if (!context.IsAnalyzerSuppressed(SA1520UseBracesConsistently.DiagnosticId))
            {
                // inconsistencies will be reported as SA1520, as long as it's not suppressed
                if (clauses.OfType <BlockSyntax>().Any())
                {
                    return;
                }
            }

            foreach (StatementSyntax clause in clauses)
            {
                SyntaxNode node = clause.Parent;
                if (node.IsKind(SyntaxKind.IfStatement) && node.Parent.IsKind(SyntaxKind.ElseClause))
                {
                    node = node.Parent;
                }

                CheckChildStatement(context, node, clause);
            }
        }
        private static void CheckChildStatement(SyntaxNodeAnalysisContext context, SyntaxNode node, StatementSyntax childStatement)
        {
            if (childStatement == null || childStatement.IsMissing)
            {
                return;
            }

            if (childStatement is BlockSyntax)
            {
                // BlockSyntax child statements are handled by HandleBlock
                return;
            }

            // We are only interested in the first instance of this violation on a line.
            if (!node.GetFirstToken().IsFirstInLine())
            {
                return;
            }

            // We are only interested in the case where statement and childStatement start on the same line. Use
            // IsFirstInLine to detect this condition easily.
            SyntaxToken firstChildToken = childStatement.GetFirstToken();

            if (firstChildToken.IsMissingOrDefault() || firstChildToken.IsFirstInLine())
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(SA1519CurlyBracketsMustNotBeOmittedFromMultiLineChildStatement.DiagnosticId))
            {
                // diagnostics for multi-line statements is handled by SA1519, as long as it's not suppressed
                FileLinePositionSpan lineSpan = childStatement.GetLineSpan();
                if (lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line)
                {
                    return;
                }
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, childStatement.GetLocation()));
        }
        private static void AnalyzeAccessorDeclaration(SyntaxNodeAnalysisContext context)
        {
            var accessor = (AccessorDeclarationSyntax)context.Node;

            BlockSyntax body = accessor.Body;

            if (body != null)
            {
                AnalyzeAccessorDeclarationBlock(context, accessor, body);
            }
            else
            {
                ArrowExpressionClauseSyntax expressionBody = accessor.ExpressionBody;

                if (expressionBody?.ContainsDirectives == false &&
                    !context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine) &&
                    expressionBody.Expression?.IsMultiLine() == true)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ReportOnly.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine, expressionBody);
                }
            }
        }
        public static void ReportDiagnostic(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right)
        {
            if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantBooleanLiteral))
            {
                return;
            }

            if (binaryExpression.SpanContainsDirectives())
            {
                return;
            }

            TextSpan span = GetSpanToRemove(binaryExpression, left, right);

            context.ReportDiagnostic(
                DiagnosticDescriptors.RemoveRedundantBooleanLiteral,
                Location.Create(binaryExpression.SyntaxTree, span),
                binaryExpression.ToString(span));
        }
        private static void CheckChildStatement(SyntaxNodeAnalysisContext context, StatementSyntax childStatement)
        {
            bool reportAsHidden = false;

            if (childStatement == null || childStatement.IsMissing)
            {
                return;
            }

            if (childStatement is BlockSyntax)
            {
                // BlockSyntax child statements are handled by HandleBlock
                return;
            }

            // We are only interested in the case where statement and childStatement start on the same line. Use
            // IsFirstInLine to detect this condition easily.
            SyntaxToken firstChildToken = childStatement.GetFirstToken();

            if (firstChildToken.IsMissingOrDefault() || firstChildToken.IsFirstInLine())
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(SA1519BracesMustNotBeOmittedFromMultiLineChildStatement.Descriptor))
            {
                // diagnostics for multi-line statements is handled by SA1519, as long as it's not suppressed
                FileLinePositionSpan lineSpan = childStatement.GetLineSpan();
                if (lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line)
                {
                    reportAsHidden = true;
                }
            }

            ReportDiagnostic(context, childStatement.GetLocation(), reportAsHidden);
        }
Example #17
0
        public static void ReportDiagnostic(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right,
            bool fadeOut)
        {
            if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.SimplifyBooleanComparison))
            {
                return;
            }

            if (binaryExpression.SpanContainsDirectives())
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.SimplifyBooleanComparison, binaryExpression);

            if (!fadeOut)
            {
                return;
            }

            DiagnosticDescriptor fadeOutDescriptor = DiagnosticDescriptors.SimplifyBooleanComparisonFadeOut;

            context.ReportToken(fadeOutDescriptor, binaryExpression.OperatorToken);

            switch (binaryExpression.Kind())
            {
            case SyntaxKind.EqualsExpression:
            {
                if (left.IsKind(SyntaxKind.FalseLiteralExpression))
                {
                    context.ReportNode(fadeOutDescriptor, left);

                    if (right.IsKind(SyntaxKind.LogicalNotExpression))
                    {
                        context.ReportToken(fadeOutDescriptor, ((PrefixUnaryExpressionSyntax)right).OperatorToken);
                    }
                }
                else if (right.IsKind(SyntaxKind.FalseLiteralExpression))
                {
                    context.ReportNode(fadeOutDescriptor, right);

                    if (left.IsKind(SyntaxKind.LogicalNotExpression))
                    {
                        context.ReportToken(fadeOutDescriptor, ((PrefixUnaryExpressionSyntax)left).OperatorToken);
                    }
                }

                break;
            }

            case SyntaxKind.NotEqualsExpression:
            {
                if (left.IsKind(SyntaxKind.TrueLiteralExpression))
                {
                    context.ReportNode(fadeOutDescriptor, left);

                    if (right.IsKind(SyntaxKind.LogicalNotExpression))
                    {
                        context.ReportToken(fadeOutDescriptor, ((PrefixUnaryExpressionSyntax)right).OperatorToken);
                    }
                }
                else if (right.IsKind(SyntaxKind.TrueLiteralExpression))
                {
                    context.ReportNode(fadeOutDescriptor, right);

                    if (left.IsKind(SyntaxKind.LogicalNotExpression))
                    {
                        context.ReportToken(fadeOutDescriptor, ((PrefixUnaryExpressionSyntax)left).OperatorToken);
                    }
                }

                break;
            }
            }
        }
        private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                return;
            }

            bool skipField = context.IsAnalyzerSuppressed(DiagnosticDescriptors.MakeFieldReadOnly);

            bool skipProperty = context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseReadOnlyAutoProperty) ||
                                ((CSharpCompilation)context.Compilation).LanguageVersion < LanguageVersion.CSharp6;

            MakeMemberReadOnlyWalker walker = MakeMemberReadOnlyWalker.GetInstance();

            walker.SemanticModel     = context.SemanticModel;
            walker.CancellationToken = context.CancellationToken;

            Dictionary <string, (SyntaxNode node, ISymbol symbol)> symbols = walker.Symbols;

            foreach (MemberDeclarationSyntax memberDeclaration in typeDeclaration.Members)
            {
                switch (memberDeclaration.Kind())
                {
                case SyntaxKind.PropertyDeclaration:
                {
                    if (skipProperty)
                    {
                        break;
                    }

                    var propertyDeclaration = (PropertyDeclarationSyntax)memberDeclaration;

                    AccessorDeclarationSyntax setter = propertyDeclaration.Setter();

                    if (setter != null &&
                        setter.BodyOrExpressionBody() == null &&
                        !setter.AttributeLists.Any() &&
                        !setter.SpanContainsDirectives())
                    {
                        IPropertySymbol propertySymbol = context.SemanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken);

                        IMethodSymbol setMethod = propertySymbol.SetMethod;

                        if (setMethod?.DeclaredAccessibility == Accessibility.Private &&
                            setMethod.GetAttributes().IsEmpty &&
                            !propertySymbol.IsIndexer &&
                            !propertySymbol.IsReadOnly &&
                            ValidateType(propertySymbol.Type) &&
                            propertySymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty &&
                            !propertySymbol.HasAttribute(MetadataNames.System_Runtime_Serialization_DataMemberAttribute))
                        {
                            symbols[propertySymbol.Name] = (propertyDeclaration, propertySymbol);
                        }
                    }

                    break;
                }

                case SyntaxKind.FieldDeclaration:
                {
                    if (skipField)
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    foreach (VariableDeclaratorSyntax declarator in fieldDeclaration.Declaration.Variables)
                    {
                        if (context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken) is IFieldSymbol fieldSymbol &&
                            !fieldSymbol.IsConst &&
                            fieldSymbol.DeclaredAccessibility == Accessibility.Private &&
                            !fieldSymbol.IsReadOnly &&
                            !fieldSymbol.IsVolatile &&
                            ValidateType(fieldSymbol.Type))
                        {
                            symbols[fieldSymbol.Name] = (declarator, fieldSymbol);
                        }
                    }

                    break;
                }
                }
            }

            if (symbols.Count > 0)
            {
                foreach (MemberDeclarationSyntax memberDeclaration in typeDeclaration.Members)
                {
                    walker.Visit(memberDeclaration);

                    if (symbols.Count == 0)
                    {
                        break;
                    }
                }

                if (symbols.Count > 0)
                {
                    foreach (KeyValuePair <string, (SyntaxNode node, ISymbol symbol)> kvp in symbols)
                    {
                        if (kvp.Value.node is PropertyDeclarationSyntax propertyDeclaration)
                        {
                            AccessorDeclarationSyntax setter = propertyDeclaration.Setter();

                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReadOnlyAutoProperty, setter);
                        }
                    }

                    foreach (IGrouping <VariableDeclarationSyntax, SyntaxNode> grouping in symbols
                             .Select(f => f.Value.node)
                             .Where(f => f.IsKind(SyntaxKind.VariableDeclarator))
                             .GroupBy(f => (VariableDeclarationSyntax)f.Parent))
                    {
                        int count = grouping.Key.Variables.Count;

                        if (count == 1 ||
                            count == grouping.Count())
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.MakeFieldReadOnly, grouping.Key.Parent);
                        }
                    }
                }
            }

            MakeMemberReadOnlyWalker.Free(walker);
        }
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!conditionalExpressionInfo.Success)
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse;

            ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue;

            if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull))
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression) &&
                    semanticModel
                    .GetTypeSymbol(nullCheck.Expression, cancellationToken)?
                    .IsReferenceTypeOrNullableType() == true)
                {
                    DiagnosticHelpers.ReportDiagnostic(context,
                                                       DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression,
                                                       conditionalExpression);
                }
            }
            else if (whenNotNull.IsKind(
                         SyntaxKind.SimpleMemberAccessExpression,
                         SyntaxKind.ElementAccessExpression,
                         SyntaxKind.ConditionalAccessExpression,
                         SyntaxKind.InvocationExpression))
            {
                ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                    nullCheck.Expression,
                    whenNotNull,
                    semanticModel,
                    cancellationToken);

                if (expression == null)
                {
                    return;
                }

                ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken);

                if (typeSymbol == null)
                {
                    return;
                }

                if (typeSymbol.IsReferenceType)
                {
                    Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken);
                }
                else if (typeSymbol.IsNullableType())
                {
                    if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                    {
                        var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent;

                        if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) &&
                            (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value")
                        {
                            if (memberAccessExpression == whenNotNull)
                            {
                                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression))
                                {
                                    DiagnosticHelpers.ReportDiagnostic(
                                        context,
                                        DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression,
                                        conditionalExpression);
                                }
                            }
                            else
                            {
                                Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken);
                            }
                        }
                    }
                }
            }
            else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression) &&
                     whenNotNull.IsKind(SyntaxKind.CastExpression) &&
                     whenNull.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression))
            {
                var castExpression = (CastExpressionSyntax)whenNotNull;

                if (castExpression.Type.IsKind(SyntaxKind.NullableType) &&
                    castExpression.Expression.IsKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression))
                {
                    ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                        nullCheck.Expression,
                        castExpression.Expression,
                        isNullable: true,
                        semanticModel,
                        cancellationToken);

                    if (expression != null)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken);

                        if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                        {
                            DiagnosticHelpers.ReportDiagnostic(context,
                                                               DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression,
                                                               conditionalExpression);
                        }
                    }
                }
            }
        }
        private static void HandleIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;
            if (ifStatement.Parent.IsKind(SyntaxKind.ElseClause))
            {
                // this will be analyzed as a clause of the outer if statement
                return;
            }

            List<StatementSyntax> clauses = new List<StatementSyntax>();
            for (IfStatementSyntax current = ifStatement; current != null; current = current.Else?.Statement as IfStatementSyntax)
            {
                clauses.Add(current.Statement);
                if (current.Else != null && !(current.Else.Statement is IfStatementSyntax))
                {
                    clauses.Add(current.Else.Statement);
                }
            }

            if (!context.IsAnalyzerSuppressed(SA1520UseCurlyBracketsConsistently.DiagnosticId))
            {
                // inconsistencies will be reported as SA1520, as long as it's not suppressed
                if (clauses.OfType<BlockSyntax>().Any())
                {
                    return;
                }
            }

            foreach (StatementSyntax clause in clauses)
            {
                SyntaxNode node = clause.Parent;
                if (node.IsKind(SyntaxKind.IfStatement) && node.Parent.IsKind(SyntaxKind.ElseClause))
                {
                    node = node.Parent;
                }

                CheckChildStatement(context, node, clause);
            }
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax)context.Node;

            if (invocation.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

            if (!invocationInfo.Success)
            {
                return;
            }

            string methodName = invocationInfo.NameText;

            int argumentCount = invocationInfo.Arguments.Count;

            switch (argumentCount)
            {
            case 0:
            {
                switch (methodName)
                {
                case "Any":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCountOrLengthPropertyInsteadOfAnyMethod))
                    {
                        UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeAny(context, invocationInfo);
                    }

                    break;
                }

                case "Cast":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndCast(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantCast))
                    {
                        RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "Count":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !OptimizeLinqMethodCallAnalysis.AnalyzeSelectManyAndCount(context, invocationInfo))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeCount(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    }

                    break;
                }

                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        if (CanUseElementAccess(context, invocationInfo) &&
                            UseElementAccessAnalysis.IsFixableFirst(invocationInfo, context.SemanticModel, context.CancellationToken))
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseElementAccess, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End)));
                        }

                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirst(context, invocationInfo);
                    }

                    break;
                }

                case "Max":
                case "Min":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeSelectAndMinOrMax(context, invocationInfo);
                    }

                    break;
                }

                case "Reverse":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeOrderByAndReverse(context, invocationInfo);
                    }

                    break;
                }

                case "ToString":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantToStringCall))
                    {
                        RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseNameOfOperator) &&
                        ((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp6)
                    {
                        UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "ToLower":
                case "ToLowerInvariant":
                case "ToUpper":
                case "ToUpperInvariant":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseStringComparison))
                    {
                        UseStringComparisonAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "FirstOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    }

                    break;
                }

                case "Last":
                case "LastOrDefault":
                case "LongCount":
                case "Single":
                case "SingleOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    }

                    break;
                }

                case "OfType":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !invocation.SpanContainsDirectives())
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeOfType(context, invocationInfo);
                    }

                    break;
                }

                case "ToCharArray":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantStringToCharArrayCall))
                    {
                        RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "All":
                case "Any":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.SimplifyLogicalNegation))
                    {
                        SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !invocation.SpanContainsDirectives())
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndAny(context, invocationInfo);
                    }

                    break;
                }

                case "ContainsKey":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall))
                    {
                        OptimizeMethodCallAnalysis.OptimizeDictionaryContainsKey(context, invocationInfo);
                    }

                    break;
                }

                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        CanUseElementAccess(context, invocationInfo) &&
                        UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseElementAccess, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End)));
                    }

                    break;
                }

                case "FirstOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    }

                    break;
                }

                case "GetValueOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression) &&
                        invocationInfo.Name.IsKind(SyntaxKind.IdentifierName) &&
                        !invocation.IsParentKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) &&
                        context.SemanticModel
                        .GetMethodSymbol(invocationInfo.InvocationExpression, context.CancellationToken)?
                        .ContainingType
                        .OriginalDefinition
                        .SpecialType == SpecialType.System_Nullable_T)
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, invocationInfo.Name);
                    }

                    break;
                }

                case "Where":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CombineEnumerableWhereMethodChain))
                    {
                        CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "HasFlag":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.ConvertHasFlagCallToBitwiseOperationOrViceVersa) &&
                        context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertBitwiseOperationToHasFlagCall) &&
                        !invocation.SpanContainsDirectives() &&
                        ConvertHasFlagCallToBitwiseOperationAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        DiagnosticHelpers.ReportDiagnostic(
                            context,
                            DiagnosticDescriptors.ConvertHasFlagCallToBitwiseOperationOrViceVersa,
                            invocation);
                    }

                    break;
                }

                case "Select":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 2:
            {
                switch (invocationInfo.NameText)
                {
                case "IsMatch":
                case "Match":
                case "Matches":
                case "Split":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "Select":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 3:
            {
                switch (invocationInfo.NameText)
                {
                case "IsMatch":
                case "Match":
                case "Matches":
                case "Split":
                case "Replace":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "Compare":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall))
                    {
                        OptimizeMethodCallAnalysis.OptimizeStringCompare(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 4:
            {
                switch (invocationInfo.NameText)
                {
                case "Replace":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }
            }

            switch (methodName)
            {
            case "ElementAtOrDefault":
            case "FirstOrDefault":
            case "LastOrDefault":
            case "SingleOrDefault":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidNullReferenceException))
                {
                    if (argumentCount == 0 ||
                        argumentCount == 1 ||
                        argumentCount == 2)
                    {
                        AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo);
                    }
                }

                break;
            }

            case "Append":
            case "AppendLine":
            case "AppendFormat":
            case "Insert":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeStringBuilderAppendCall))
                {
                    OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo);
                }

                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidBoxingOfValueType))
                {
                    AvoidBoxingOfValueTypeAnalysis.Analyze(context, invocationInfo);
                }

                break;
            }

            case "Assert":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) &&
                    (argumentCount >= 1 && argumentCount <= 3))
                {
                    OptimizeMethodCallAnalysis.OptimizeDebugAssert(context, invocationInfo);
                }

                break;
            }

            case "Join":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) &&
                    argumentCount >= 2)
                {
                    OptimizeMethodCallAnalysis.OptimizeStringJoin(context, invocationInfo);
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseMethodChaining) &&
                UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression);
            }
        }
        private static void AnalyzeUsings(SyntaxNodeAnalysisContext context, SyntaxList <UsingDirectiveSyntax> usings)
        {
            int count = usings.Count;

            if (count <= 1)
            {
                return;
            }

            UsingDirectiveSyntax usingDirective1 = usings[0];

            for (int i = 1; i < count; i++, usingDirective1 = usings[i - 1])
            {
                if (usingDirective1.StaticKeyword.IsKind(SyntaxKind.StaticKeyword))
                {
                    return;
                }

                if (usingDirective1.Alias != null)
                {
                    return;
                }

                UsingDirectiveSyntax usingDirective2 = usings[i];

                if (usingDirective2.StaticKeyword.IsKind(SyntaxKind.StaticKeyword))
                {
                    return;
                }

                if (usingDirective2.Alias != null)
                {
                    return;
                }

                SyntaxTriviaList trailingTrivia = usingDirective1.GetTrailingTrivia();

                if (!SyntaxTriviaAnalysis.IsOptionalWhitespaceThenOptionalSingleLineCommentThenEndOfLineTrivia(trailingTrivia))
                {
                    continue;
                }

                IdentifierNameSyntax rootNamespace1 = usingDirective1.GetRootNamespace();

                if (rootNamespace1 == null)
                {
                    continue;
                }

                IdentifierNameSyntax rootNamespace2 = usingDirective2.GetRootNamespace();

                if (rootNamespace2 == null)
                {
                    continue;
                }

                SyntaxTriviaList leadingTrivia = usingDirective2.GetLeadingTrivia();

                bool isEmptyLine = SyntaxTriviaAnalysis.StartsWithOptionalWhitespaceThenEndOfLineTrivia(leadingTrivia);

                if (string.Equals(rootNamespace1.Identifier.ValueText, rootNamespace2.Identifier.ValueText, StringComparison.Ordinal))
                {
                    if (isEmptyLine)
                    {
                        DiagnosticHelpers.ReportDiagnosticIfNotSuppressed(
                            context,
                            DiagnosticDescriptors.RemoveEmptyLineBetweenUsingDirectivesWithSameRootNamespace,
                            Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0)));
                    }
                }
                else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddEmptyLineBetweenUsingDirectivesWithDifferentRootNamespaceOrViceVersa))
                {
                    if (isEmptyLine)
                    {
                        if (!context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace))
                        {
                            DiagnosticHelpers.ReportDiagnostic(
                                context,
                                DiagnosticDescriptors.ReportOnly.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace,
                                Location.Create(context.Node.SyntaxTree, leadingTrivia[0].Span.WithLength(0)),
                                properties: DiagnosticProperties.AnalyzerOption_Invert);
                        }
                    }
                    else if (context.IsAnalyzerSuppressed(AnalyzerOptions.RemoveEmptyLineBetweenUsingDirectivesWithDifferentRootNamespace))
                    {
                        DiagnosticHelpers.ReportDiagnostic(
                            context,
                            DiagnosticDescriptors.AddEmptyLineBetweenUsingDirectivesWithDifferentRootNamespaceOrViceVersa,
                            Location.Create(context.Node.SyntaxTree, trailingTrivia.Last().Span.WithLength(0)));
                    }
                }
            }
        }
        private static void ProcessUsings(SyntaxNodeAnalysisContext context, SyntaxList<UsingDirectiveSyntax> usings)
        {
            var usingDirectives = new List<UsingDirectiveSyntax>();
            var systemUsingDirectives = new List<UsingDirectiveSyntax>();

            foreach (var usingDirective in usings)
            {
                if (usingDirective.IsPrecededByPreprocessorDirective())
                {
                    CheckIncorrectlyOrderedUsingsAndReportDiagnostic(context, usingDirectives);
                    CheckIncorrectlyOrderedUsingsAndReportDiagnostic(context, systemUsingDirectives);
                    usingDirectives.Clear();
                    systemUsingDirectives.Clear();
                }

                if (IsAliasOrStaticUsingDirective(usingDirective))
                {
                    continue;
                }

                if (usingDirective.HasNamespaceAliasQualifier()
                    || !usingDirective.IsSystemUsingDirective()
                    || context.IsAnalyzerSuppressed(SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId))
                {
                    usingDirectives.Add(usingDirective);
                }
                else
                {
                    systemUsingDirectives.Add(usingDirective);
                }
            }

            CheckIncorrectlyOrderedUsingsAndReportDiagnostic(context, usingDirectives);
            CheckIncorrectlyOrderedUsingsAndReportDiagnostic(context, systemUsingDirectives);
        }
        private static void AnalyzeAccessorDeclarationBlock(
            SyntaxNodeAnalysisContext context,
            AccessorDeclarationSyntax accessor,
            BlockSyntax body)
        {
            if (body.ContainsDirectives)
            {
                return;
            }

            if (accessor.AttributeLists.Any())
            {
                return;
            }

            bool isGetter = accessor.IsKind(SyntaxKind.GetAccessorDeclaration);

            BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(body, allowExpressionStatement: !isGetter);

            ExpressionSyntax expression = analysis.Expression;

            if (expression == null)
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine) &&
                expression.IsMultiLine())
            {
                return;
            }

            if (isGetter &&
                accessor.Parent is AccessorListSyntax accessorList &&
                accessorList.Accessors.Count == 1)
            {
                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessorList.OpenBraceToken))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessor.Keyword))
                {
                    return;
                }

                if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
                {
                    return;
                }

                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenDeclarationIsMultiLine))
                {
                    switch (accessorList.Parent.Kind())
                    {
                    case SyntaxKind.PropertyDeclaration:
                    {
                        if (accessor.SyntaxTree.IsMultiLineSpan(((PropertyDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                        {
                            return;
                        }

                        break;
                    }

                    case SyntaxKind.IndexerDeclaration:
                    {
                        if (accessor.SyntaxTree.IsMultiLineSpan(((IndexerDeclarationSyntax)accessorList.Parent).HeaderSpan()))
                        {
                            return;
                        }

                        break;
                    }

                    default:
                    {
                        Debug.Fail(accessorList.Parent.Kind().ToString());
                        break;
                    }
                    }

                    return;
                }

                ReportDiagnostic(context, accessorList, expression);
                ReportFadeOut(context, accessor.Keyword, body);
                return;
            }

            if (!accessor.Keyword.TrailingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken))
            {
                return;
            }

            if (!accessor.Keyword.LeadingTrivia.IsEmptyOrWhitespace())
            {
                return;
            }

            ReportDiagnostic(context, body, expression);
        }
Example #25
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ExpressionSyntax condition = conditionalExpression.Condition;

            if (condition.IsMissing)
            {
                return;
            }

            ExpressionSyntax whenTrue = conditionalExpression.WhenTrue;

            if (whenTrue.IsMissing)
            {
                return;
            }

            if (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(condition, conditionalExpression.QuestionToken, whenTrue))
            {
                if (context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt))
                {
                    ReportDiagnostic(DiagnosticDescriptors.AddNewLineBeforeConditionalOperatorInsteadOfAfterItOrViceVersa, conditionalExpression.QuestionToken, ImmutableDictionary <string, string> .Empty);
                    return;
                }
            }
            else if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(condition, conditionalExpression.QuestionToken, whenTrue))
            {
                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt))
                {
                    ReportDiagnostic(DiagnosticDescriptors.ReportOnly.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt, conditionalExpression.QuestionToken, DiagnosticProperties.AnalyzerOption_Invert);
                    return;
                }
            }

            ExpressionSyntax whenFalse = conditionalExpression.WhenFalse;

            if (!whenFalse.IsMissing)
            {
                if (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(whenTrue, conditionalExpression.ColonToken, whenFalse))
                {
                    if (context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt))
                    {
                        ReportDiagnostic(DiagnosticDescriptors.AddNewLineBeforeConditionalOperatorInsteadOfAfterItOrViceVersa, conditionalExpression.ColonToken, ImmutableDictionary <string, string> .Empty);
                    }
                }
                else if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(whenTrue, conditionalExpression.ColonToken, whenFalse))
                {
                    if (!context.IsAnalyzerSuppressed(AnalyzerOptions.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt))
                    {
                        ReportDiagnostic(DiagnosticDescriptors.ReportOnly.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt, conditionalExpression.ColonToken, DiagnosticProperties.AnalyzerOption_Invert);
                    }
                }
            }

            void ReportDiagnostic(DiagnosticDescriptor descriptor, SyntaxToken token, ImmutableDictionary <string, string> properties)
            {
                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    descriptor,
                    Location.Create(token.SyntaxTree, token.Span.WithLength(0)),
                    properties: properties);
            }
        }
Example #26
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind trueKind  = info.WhenTrue.Kind();
            SyntaxKind falseKind = info.WhenFalse.Kind();

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? true : false >>> a
                // a ? true : b >>> a || b
                if (falseKind == SyntaxKind.FalseLiteralExpression ||
                    context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    ReportDiagnostic();
                }
            }
            else if (trueKind == SyntaxKind.FalseLiteralExpression)
            {
                /// a ? false : true >>> !a
                if (falseKind == SyntaxKind.TrueLiteralExpression)
                {
                    ReportDiagnostic();
                }
                /// a ? false : b >>> !a && b
                else if (!context.IsAnalyzerSuppressed(AnalyzerOptions.SimplifyConditionalExpressionWhenItIncludesNegationOfCondition) &&
                         context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    ReportDiagnostic();
                }
            }
            else if (falseKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? b : true >>> !a || b
                if (!context.IsAnalyzerSuppressed(AnalyzerOptions.SimplifyConditionalExpressionWhenItIncludesNegationOfCondition) &&
                    context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    ReportDiagnostic();
                }
            }
            else if (falseKind == SyntaxKind.FalseLiteralExpression)
            {
                // a ? b : false >>> a && b
                if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    ReportDiagnostic();
                }
            }

            void ReportDiagnostic()
            {
                DiagnosticHelpers.ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
            }
        }
        private static void CheckChildStatement(SyntaxNodeAnalysisContext context, SyntaxNode node, StatementSyntax childStatement)
        {
            if (childStatement == null || childStatement.IsMissing)
            {
                return;
            }

            if (childStatement is BlockSyntax)
            {
                // BlockSyntax child statements are handled by HandleBlock
                return;
            }

            // We are only interested in the first instance of this violation on a line.
            if (!node.GetFirstToken().IsFirstInLine())
            {
                return;
            }

            // We are only interested in the case where statement and childStatement start on the same line. Use
            // IsFirstInLine to detect this condition easily.
            SyntaxToken firstChildToken = childStatement.GetFirstToken();
            if (firstChildToken.IsMissingOrDefault() || firstChildToken.IsFirstInLine())
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(SA1519CurlyBracketsMustNotBeOmittedFromMultiLineChildStatement.DiagnosticId))
            {
                // diagnostics for multi-line statements is handled by SA1519, as long as it's not suppressed
                FileLinePositionSpan lineSpan = childStatement.GetLineSpan();
                if (lineSpan.StartLinePosition.Line != lineSpan.EndLinePosition.Line)
                {
                    return;
                }
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, childStatement.GetLocation()));
        }
        private static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!documentationComment.IsPartOfMemberDeclaration())
            {
                return;
            }

            bool containsInheritDoc       = false;
            bool containsIncludeOrExclude = false;
            bool containsSummaryElement   = false;
            bool containsContentElement   = false;
            bool isFirst = true;

            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxList <XmlNodeSyntax> content = documentationComment.Content;

            for (int i = 0; i < content.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                XmlElementInfo info = SyntaxInfo.XmlElementInfo(content[i]);

                if (info.Success)
                {
                    switch (info.GetElementKind())
                    {
                    case XmlElementKind.Include:
                    case XmlElementKind.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlElementKind.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlElementKind.Content:
                    {
                        containsContentElement = true;
                        break;
                    }

                    case XmlElementKind.Summary:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryToDocumentationComment, info.Element);
                        }

                        containsSummaryElement = true;
                        break;
                    }

                    case XmlElementKind.Code:
                    case XmlElementKind.Example:
                    case XmlElementKind.Remarks:
                    case XmlElementKind.Returns:
                    case XmlElementKind.Value:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportUnusedElement(context, info.Element, i, content);
                        }

                        break;
                    }
                    }

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        containsIncludeOrExclude = false;
                    }
                }
            }

            if (containsInheritDoc ||
                containsIncludeOrExclude)
            {
                return;
            }

            if (!containsSummaryElement &&
                !containsContentElement)
            {
                ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryElementToDocumentationComment, documentationComment);
            }

            SyntaxNode parent = documentationComment.ParentTrivia.Token.Parent;

            bool unusedElement = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnusedElementInDocumentationComment);
            bool orderParams   = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.OrderElementsInDocumentationComment);
            bool addParam      = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddParamElementToDocumentationComment);
            bool addTypeParam  = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddTypeParamElementToDocumentationComment);

            if (addParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <ParameterSyntax> parameters = ParameterListInfo.Create(parent).Parameters;

                if (addParam &&
                    parameters.Any())
                {
                    foreach (ParameterSyntax parameter in parameters)
                    {
                        if (IsMissing(documentationComment, parameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, parameters, XmlElementKind.Param, (nodes, name) => nodes.IndexOf(name));
                }
            }

            if (addTypeParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <TypeParameterSyntax> typeParameters = TypeParameterListInfo.Create(parent).Parameters;

                if (addTypeParam &&
                    typeParameters.Any())
                {
                    foreach (TypeParameterSyntax typeParameter in typeParameters)
                    {
                        if (IsMissing(documentationComment, typeParameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddTypeParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, typeParameters, XmlElementKind.TypeParam, (nodes, name) => nodes.IndexOf(name));
                }
            }
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (invocationExpression.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return;
            }

            ISymbol symbol = null;

            string methodName = invocationInfo.NameText;

            switch (invocationInfo.Arguments.Count)
            {
            case 0:
            {
                switch (methodName)
                {
                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingFirst();
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingElementAt();
                    }

                    break;
                }

                case "IsKind":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryNullCheck))
                    {
                        AnalyzeUnnecessaryNullCheck();
                    }

                    break;
                }
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseReturnValue) &&
                invocationExpression.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                UseReturnValue();
            }

            void AnalyzeUnnecessaryNullCheck()
            {
                ExpressionSyntax expression = invocationInfo.InvocationExpression.WalkUpParentheses();

                SyntaxNode parent = expression.Parent;

                if (!parent.IsKind(SyntaxKind.LogicalAndExpression))
                {
                    return;
                }

                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (expression != binaryExpression.Right)
                {
                    return;
                }

                if (binaryExpression.Left.ContainsDirectives)
                {
                    return;
                }

                if (binaryExpression.OperatorToken.ContainsDirectives)
                {
                    return;
                }

                NullCheckExpressionInfo nullCheckInfo = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, NullCheckStyles.CheckingNotNull & ~NullCheckStyles.HasValue);

                if (!nullCheckInfo.Success)
                {
                    return;
                }

                if (!CSharpFactory.AreEquivalent(invocationInfo.Expression, nullCheckInfo.Expression))
                {
                    return;
                }

                if (!CSharpSymbolUtility.IsIsKindExtensionMethod(invocationExpression, context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(binaryExpression.Left.SpanStart, binaryExpression.OperatorToken.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UnnecessaryNullCheck,
                    Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingFirst()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingElementAt()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !symbol.ContainingType.OriginalDefinition.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxTriviaList))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseReturnValue()
            {
                if (symbol == null)
                {
                    symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);
                }

                if (symbol?.Kind != SymbolKind.Method)
                {
                    return;
                }

                if (!RoslynSymbolUtility.IsRoslynType(symbol.ContainingType))
                {
                    return;
                }

                var methodSymbol = (IMethodSymbol)symbol;

                if (!RoslynSymbolUtility.IsRoslynType(methodSymbol.ReturnType))
                {
                    return;
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReturnValue, invocationExpression);
            }
        }
Example #30
0
        private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.ContainsDiagnostics)
            {
                return;
            }

            if (ifStatement.SpanContainsDirectives())
            {
                return;
            }

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements;

            if (!statements.Any())
            {
                return;
            }

            if (IsPartOfLazyInitialization())
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(
                ifStatement.Condition,
                semanticModel: context.SemanticModel,
                allowedStyles: NullCheckStyles.CheckingNull,
                cancellationToken: context.CancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault());

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, nullCheck.Expression))
            {
                return;
            }

            if (!assignmentInfo.Right.IsSingleLine())
            {
                return;
            }

            int index = statements.IndexOf(ifStatement);

            if (index > 0 &&
                !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression))
            {
                StatementSyntax previousStatement = statements[index - 1];

                if (!previousStatement.ContainsDiagnostics &&
                    !previousStatement.GetTrailingTrivia().Any(f => f.IsDirective) &&
                    !ifStatement.GetLeadingTrivia().Any(f => f.IsDirective) &&
                    CanUseCoalesceExpression(previousStatement, nullCheck.Expression))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, previousStatement);
                }
            }

            if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.InlineLazyInitialization))
            {
                return;
            }

            if (index == statements.Count - 1)
            {
                return;
            }

            StatementSyntax nextStatement = statements[index + 1];

            if (nextStatement.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression))
            {
                return;
            }

            if (ifStatement.GetTrailingTrivia().Any(f => f.IsDirective))
            {
                return;
            }

            if (nextStatement.SpanOrLeadingTriviaContainsDirectives())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.InlineLazyInitialization, ifStatement);

            bool IsPartOfLazyInitialization()
            {
                return(statements.Count == 2 &&
                       statements.IndexOf(ifStatement) == 0 &&
                       statements[1].IsKind(SyntaxKind.ReturnStatement));
            }
        }
Example #31
0
        private static void HandleQueryExpression(SyntaxNodeAnalysisContext context)
        {
            var queryExpression = (QueryExpressionSyntax)context.Node;
            var tokensToCheck   = new List <SyntaxToken>();

            HandleQueryClause(queryExpression.FromClause, tokensToCheck);
            HandleQueryBody(queryExpression.Body, tokensToCheck);

            bool isEnabledSA1102 = !context.IsAnalyzerSuppressed(SA1102Identifier);
            bool isEnabledSA1103 = !context.IsAnalyzerSuppressed(SA1103Identifier);
            bool isEnabledSA1104 = !context.IsAnalyzerSuppressed(SA1104Identifier);
            bool isEnabledSA1105 = !context.IsAnalyzerSuppressed(SA1105Identifier);

            bool allOnSameLine     = true;
            bool allOnSeparateLine = true;
            bool suppressSA1103    = false;

            for (var i = 0; i < tokensToCheck.Count - 1; i++)
            {
                var token1  = tokensToCheck[i];
                var token2  = tokensToCheck[i + 1];
                var parent1 = token1.Parent;
                var parent2 = token2.Parent;

                if (parent2 is QueryContinuationSyntax)
                {
                    continue;
                }

                // The node before the query clause may encompass the entire query clause,
                // so we need to use the token within that node for the line determination.
                var location1 = !(parent1 is QueryContinuationSyntax) ? parent1.GetLineSpan() : token1.GetLineSpan();
                var location2 = parent2.GetLineSpan();

                if (((location2.StartLinePosition.Line - location1.EndLinePosition.Line) > 1) &&
                    isEnabledSA1102 &&
                    !token2.LeadingTrivia.Any(trivia => trivia.IsDirective))
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1102Descriptor, token2.GetLocation()));
                }

                var onSameLine = location1.EndLinePosition.Line == location2.StartLinePosition.Line;

                if (onSameLine &&
                    isEnabledSA1104 &&
                    !(parent1 is QueryContinuationSyntax) &&
                    parent1.SpansMultipleLines())
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1104Descriptor, token2.GetLocation()));

                    // Make sure that SA1103 will not be reported, as there is a more specific diagnostic reported.
                    suppressSA1103 = true;
                }

                if (onSameLine &&
                    isEnabledSA1105 &&
                    parent2.SpansMultipleLines())
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1105Descriptor, token2.GetLocation()));

                    // Make sure that SA1103 will not be reported, as there is a more specific diagnostic reported.
                    suppressSA1103 = true;
                }

                allOnSameLine     = allOnSameLine && onSameLine;
                allOnSeparateLine = allOnSeparateLine && !onSameLine;
            }

            if (!allOnSameLine && !allOnSeparateLine && !suppressSA1103 && isEnabledSA1103)
            {
                context.ReportDiagnostic(Diagnostic.Create(SA1103Descriptor, queryExpression.FromClause.FromKeyword.GetLocation()));
            }
        }
Example #32
0
        private static void AnalyzeAccessorList(SyntaxNodeAnalysisContext context)
        {
            var accessorList = (AccessorListSyntax)context.Node;

            SyntaxList <AccessorDeclarationSyntax> accessors = accessorList.Accessors;

            if (accessors.Any(f => f.BodyOrExpressionBody() != null))
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddNewLineBeforeAccessorOfFullProperty))
                {
                    SyntaxToken token = accessorList.OpenBraceToken;

                    foreach (AccessorDeclarationSyntax accessor in accessors)
                    {
                        if (accessor.BodyOrExpressionBody() != null &&
                            accessor.SyntaxTree.IsSingleLineSpan(TextSpan.FromBounds(token.Span.End, accessor.SpanStart)))
                        {
                            DiagnosticHelpers.ReportDiagnostic(
                                context,
                                DiagnosticDescriptors.AddNewLineBeforeAccessorOfFullProperty,
                                Location.Create(accessor.SyntaxTree, new TextSpan(accessor.SpanStart, 0)));

                            break;
                        }

                        token = accessor.Body?.CloseBraceToken ?? accessor.SemicolonToken;

                        if (!token.Equals(accessor.GetLastToken()))
                        {
                            break;
                        }
                    }
                }

                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveNewLinesFromAccessorWithSingleLineExpression) &&
                    !accessorList.IsSingleLine(includeExteriorTrivia: false))
                {
                    foreach (AccessorDeclarationSyntax accessor in accessors)
                    {
                        if (CanRemoveNewLinesFromAccessor(accessor))
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveNewLinesFromAccessorWithSingleLineExpression, accessor);
                        }
                    }
                }
            }
            else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveNewLinesFromAccessorListOfAutoProperty))
            {
                SyntaxNode parent = accessorList.Parent;

                switch (parent?.Kind())
                {
                case SyntaxKind.PropertyDeclaration:
                {
                    if (accessors.All(f => !f.AttributeLists.Any()) &&
                        !accessorList.IsSingleLine(includeExteriorTrivia: false))
                    {
                        var         propertyDeclaration = (PropertyDeclarationSyntax)parent;
                        SyntaxToken identifier          = propertyDeclaration.Identifier;

                        if (!identifier.IsMissing)
                        {
                            SyntaxToken closeBrace = accessorList.CloseBraceToken;

                            if (!closeBrace.IsMissing)
                            {
                                TextSpan span = TextSpan.FromBounds(identifier.Span.End, closeBrace.SpanStart);

                                if (propertyDeclaration
                                    .DescendantTrivia(span)
                                    .All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                                {
                                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveNewLinesFromAccessorListOfAutoProperty, accessorList);
                                }
                            }
                        }
                    }

                    break;
                }

                case SyntaxKind.IndexerDeclaration:
                {
                    if (accessors.All(f => !f.AttributeLists.Any()) &&
                        !accessorList.IsSingleLine(includeExteriorTrivia: false))
                    {
                        var indexerDeclaration = (IndexerDeclarationSyntax)parent;

                        BracketedParameterListSyntax parameterList = indexerDeclaration.ParameterList;

                        if (parameterList != null)
                        {
                            SyntaxToken closeBracket = parameterList.CloseBracketToken;

                            if (!closeBracket.IsMissing)
                            {
                                SyntaxToken closeBrace = accessorList.CloseBraceToken;

                                if (!closeBrace.IsMissing)
                                {
                                    TextSpan span = TextSpan.FromBounds(closeBracket.Span.End, closeBrace.SpanStart);

                                    if (indexerDeclaration
                                        .DescendantTrivia(span)
                                        .All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                                    {
                                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveNewLinesFromAccessorListOfAutoProperty, accessorList);
                                    }
                                }
                            }
                        }
                    }

                    break;
                }
                }
            }
        }
        private static void HandlePrefixUnaryExpression(SyntaxNodeAnalysisContext context)
        {
            var unaryExpression = (PrefixUnaryExpressionSyntax)context.Node;
            var precedingToken = unaryExpression.OperatorToken.GetPreviousToken();
            var followingToken = unaryExpression.OperatorToken.GetNextToken();
            var followingTrivia = TriviaHelper.MergeTriviaLists(unaryExpression.OperatorToken.TrailingTrivia, followingToken.LeadingTrivia);

            /* let the outer operator handle things like the following, so no error is reported for '++':
             *   c ^= *++buf4;
             *
             * if the unary expression is inside parenthesis or an indexer, there should be no leading space
             */
            var mustHaveLeadingWhitespace = !(unaryExpression.Parent is PrefixUnaryExpressionSyntax)
                && !(unaryExpression.Parent is CastExpressionSyntax)
                && !precedingToken.IsKind(SyntaxKind.OpenParenToken)
                && !precedingToken.IsKind(SyntaxKind.OpenBracketToken)
                && !(precedingToken.IsKind(SyntaxKind.OpenBraceToken) && (precedingToken.Parent is InterpolationSyntax));

            bool analyze;
            switch (unaryExpression.OperatorToken.Kind())
            {
            case SyntaxKind.PlusToken:
                analyze = context.IsAnalyzerSuppressed(SA1022PositiveSignsMustBeSpacedCorrectly.DiagnosticId);
                break;
            case SyntaxKind.MinusToken:
                analyze = context.IsAnalyzerSuppressed(SA1021NegativeSignsMustBeSpacedCorrectly.DiagnosticId);
                break;
            case SyntaxKind.PlusPlusToken:
            case SyntaxKind.MinusMinusToken:
                analyze = context.IsAnalyzerSuppressed(SA1020IncrementDecrementSymbolsMustBeSpacedCorrectly.DiagnosticId);
                break;
            default:
                analyze = true;
                break;
            }

            if (analyze)
            {
                if (followingTrivia.Any(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia)) || followingTrivia.Any(t => t.IsKind(SyntaxKind.MultiLineCommentTrivia)))
                {
                    context.ReportDiagnostic(Diagnostic.Create(DescriptorNotFollowedByComment, unaryExpression.OperatorToken.GetLocation(), unaryExpression.OperatorToken.Text));
                }
                else
                {
                    CheckToken(context, unaryExpression.OperatorToken, mustHaveLeadingWhitespace, false, false);
                }
            }
        }
        private static void HandleQueryExpression(SyntaxNodeAnalysisContext context)
        {
            var queryExpression = (QueryExpressionSyntax)context.Node;
            var tokensToCheck = new List<SyntaxToken>();

            HandleQueryClause(queryExpression.FromClause, tokensToCheck);
            HandleQueryBody(queryExpression.Body, tokensToCheck);

            bool isEnabledSA1102 = !context.IsAnalyzerSuppressed(SA1102Identifier);
            bool isEnabledSA1103 = !context.IsAnalyzerSuppressed(SA1103Identifier);
            bool isEnabledSA1104 = !context.IsAnalyzerSuppressed(SA1104Identifier);
            bool isEnabledSA1105 = !context.IsAnalyzerSuppressed(SA1105Identifier);

            bool allOnSameLine = true;
            bool allOnSeparateLine = true;
            bool suppressSA1103 = false;

            for (var i = 0; i < tokensToCheck.Count - 1; i++)
            {
                var token1 = tokensToCheck[i];
                var token2 = tokensToCheck[i + 1];
                var parent1 = token1.Parent;
                var parent2 = token2.Parent;

                if (parent2 is QueryContinuationSyntax)
                {
                    continue;
                }

                // The node before the query clause may encompass the entire query clause,
                // so we need to use the token within that node for the line determination.
                var location1 = !(parent1 is QueryContinuationSyntax) ? parent1.GetLineSpan() : token1.GetLineSpan();
                var location2 = parent2.GetLineSpan();

                if (((location2.StartLinePosition.Line - location1.EndLinePosition.Line) > 1)
                    && isEnabledSA1102
                    && !token2.LeadingTrivia.Any(trivia => trivia.IsDirective))
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1102Descriptor, token2.GetLocation()));
                }

                var onSameLine = location1.EndLinePosition.Line == location2.StartLinePosition.Line;

                if (onSameLine
                    && isEnabledSA1104
                    && !(parent1 is QueryContinuationSyntax)
                    && parent1.SpansMultipleLines())
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1104Descriptor, token2.GetLocation()));

                    // Make sure that SA1103 will not be reported, as there is a more specific diagnostic reported.
                    suppressSA1103 = true;
                }

                if (onSameLine
                    && isEnabledSA1105
                    && parent2.SpansMultipleLines())
                {
                    context.ReportDiagnostic(Diagnostic.Create(SA1105Descriptor, token2.GetLocation()));

                    // Make sure that SA1103 will not be reported, as there is a more specific diagnostic reported.
                    suppressSA1103 = true;
                }

                allOnSameLine = allOnSameLine && onSameLine;
                allOnSeparateLine = allOnSeparateLine && !onSameLine;
            }

            if (!allOnSameLine && !allOnSeparateLine && !suppressSA1103 && isEnabledSA1103)
            {
                context.ReportDiagnostic(Diagnostic.Create(SA1103Descriptor, queryExpression.FromClause.FromKeyword.GetLocation()));
            }
        }
        private static void HandleFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node;

            if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax))
            {
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword))
            {
                // this analyzer only applies to readonly fields
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.PublicKeyword) &&
                !syntax.Modifiers.Any(SyntaxKind.ProtectedKeyword) &&
                !syntax.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                // this analyzer only applies to non-private fields
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                // SA1307 is taken precedence here. SA1307 should be reported if the field is accessible.
                // So if SA1307 is enabled this diagnostic will only be reported for internal fields.
                if (!context.IsAnalyzerSuppressed(SA1307AccessibleFieldsMustBeginWithUpperCaseLetter.Descriptor))
                {
                    return;
                }
            }

            var variables = syntax.Declaration?.Variables;

            if (variables == null)
            {
                return;
            }

            foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value)
            {
                if (variableDeclarator == null)
                {
                    continue;
                }

                var identifier = variableDeclarator.Identifier;
                if (identifier.IsMissing)
                {
                    continue;
                }

                string name = identifier.ValueText;
                if (string.IsNullOrEmpty(name) || !char.IsLower(name[0]))
                {
                    continue;
                }

                // Non-private readonly fields should begin with upper-case letter.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation()));
            }
        }