コード例 #1
0
        /// <summary>
        /// Checks the built-in types and empty strings within a document.
        /// </summary>
        /// <param name="document">
        /// The document containing the tokens.
        /// </param>
        /// <param name="settings">
        /// The current settings.
        /// </param>
        private void IterateTokenList(CsDocument document, Settings settings)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(settings);

            for (Node <CsToken> tokenNode = document.Tokens.First; tokenNode != null; tokenNode = tokenNode.Next)
            {
                CsToken token = tokenNode.Value;

                if (token.CsTokenClass == CsTokenClass.Type || token.CsTokenClass == CsTokenClass.GenericType)
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType(tokenNode, document);

                    if (token.CsTokenClass == CsTokenClass.GenericType)
                    {
                        this.CheckShorthandForNullableTypes(tokenNode.Value);
                    }
                }
                else if (token.CsTokenType == CsTokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(tokenNode);
                }
                else if (token.CsTokenClass == CsTokenClass.RegionDirective && settings.DoNotUseRegions)
                {
                    Region region = (Region)token;
                    if (region.Beginning && !region.Generated && !region.IsGeneratedCodeRegion)
                    {
                        // There should not be any regions in the code.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.DoNotUseRegions);
                    }
                }
                else if (settings.AvoidStringFormatUseStringInterpolation && token.CsTokenType == CsTokenType.Other && token.Text == "Format")
                {
                    // Check this rule only if project target framework version is greater or equal 4.6
                    if (document.SourceCode.Project.TargetFrameworkVersion >= 4.6)
                    {
                        MemberAccessExpression expression = token.Parent?.Parent as MemberAccessExpression;

                        // Check if literal expression is not null and check text to avoid user's custom code like enumeration.
                        if (expression != null && expression.Text == "string.Format")
                        {
                            CsToken region = (CsToken)token;
                            if (!region.Generated)
                            {
                                // There should not be any regions in the code.
                                this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.AvoidStringFormatUseStringInterpolation);
                            }
                        }
                    }
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Checks a string to determine whether it is using an incorrect empty string notation.
        /// </summary>
        /// <param name="stringNode">
        /// The node containing the string to check.
        /// </param>
        private void CheckEmptyString(Node <CsToken> stringNode)
        {
            Param.AssertNotNull(stringNode, "stringNode");

            CsToken @string = stringNode.Value;

            Debug.Assert(@string.CsTokenType == CsTokenType.String, "The token must be a string.");

            if (string.Equals(@string.Text, "\"\"", StringComparison.Ordinal) || string.Equals(@string.Text, "@\"\"", StringComparison.Ordinal) || string.Equals(@string.Text, "$\"\"", StringComparison.Ordinal))
            {
                // Look at the previous non-whitespace token. If it is the 'case' keyword, then do not throw this
                // exception. It is illegal to write case String.Empty : and instead case "": must be written.
                // We also check that the node is not part of a method parameter as these must be "" also.
                Node <CsToken> previousToken = null;
                for (Node <CsToken> previousNode = stringNode.Previous; previousNode != null; previousNode = previousNode.Previous)
                {
                    if (previousNode.Value.CsTokenType != CsTokenType.WhiteSpace && previousNode.Value.CsTokenType != CsTokenType.EndOfLine &&
                        previousNode.Value.CsTokenType != CsTokenType.SingleLineComment && previousNode.Value.CsTokenType != CsTokenType.MultiLineComment)
                    {
                        previousToken = previousNode;
                        break;
                    }
                }

                if (previousToken == null ||
                    (previousToken.Value.CsTokenType != CsTokenType.Case && !IsConstVariableDeclaration(previousToken) && !IsMethodParameterDeclaration(previousToken)))
                {
                    this.AddViolation(@string.FindParentElement(), @string.LineNumber, Rules.UseStringEmptyForEmptyStrings);
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Checks the built-in types and empty strings within a document.
        /// </summary>
        /// <param name="document">
        /// The document containing the tokens.
        /// </param>
        /// <param name="settings">
        /// The current settings.
        /// </param>
        private void IterateTokenList(CsDocument document, Settings settings)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(settings);

            for (Node <CsToken> tokenNode = document.Tokens.First; tokenNode != null; tokenNode = tokenNode.Next)
            {
                CsToken token = tokenNode.Value;

                if (token.CsTokenClass == CsTokenClass.Type || token.CsTokenClass == CsTokenClass.GenericType)
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType(tokenNode, document);

                    if (token.CsTokenClass == CsTokenClass.GenericType)
                    {
                        this.CheckShorthandForNullableTypes(tokenNode.Value);
                    }
                }
                else if (token.CsTokenType == CsTokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(tokenNode);
                }
                else if (token.CsTokenClass == CsTokenClass.RegionDirective && settings.DoNotUseRegions)
                {
                    Region region = (Region)token;
                    if (region.Beginning && !region.Generated && !region.IsGeneratedCodeRegion)
                    {
                        // There should not be any regions in the code.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.DoNotUseRegions);
                    }
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Checks for tabs in the given comment.
        /// </summary>
        /// <param name="comment">
        /// The comment token.
        /// </param>
        private void CheckTabsInComment(CsToken comment)
        {
            Param.AssertNotNull(comment, "comment");

            int lineEnds = 0;

            for (int i = 0; i < comment.Text.Length; ++i)
            {
                if (comment.Text[i] == '\t')
                {
                    this.AddViolation(comment.FindParentElement(), comment.Location, Rules.TabsMustNotBeUsed);
                }
                else if (comment.Text[i] == '\n')
                {
                    ++lineEnds;
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Checks to make sure that preprocessor type keyword is not preceded by a space.
        /// </summary>
        /// <param name="preprocessor">
        /// The preprocessor token.
        /// </param>
        private void CheckPreprocessorSpacing(CsToken preprocessor)
        {
            Param.AssertNotNull(preprocessor, "preprocessor");

            if (preprocessor.Text.Length > 1)
            {
                if (preprocessor.Text[0] == '#')
                {
                    if (preprocessor.Text[1] == ' ' || preprocessor.Text[1] == '\t')
                    {
                        this.AddViolation(preprocessor.FindParentElement(), preprocessor.Location, Rules.PreprocessorKeywordsMustNotBePrecededBySpace);
                    }
                }
            }
        }
コード例 #6
0
        private void CheckLineSpacingNonWhitespace(
            CsDocument document, Node<CsToken> precedingTokenNode, CsToken token, bool fileHeader, bool firstTokenOnLine, int count)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(precedingTokenNode);
            Param.AssertNotNull(token, "token");
            Param.Ignore(fileHeader);
            Param.Ignore(firstTokenOnLine);
            Param.AssertGreaterThanOrEqualToZero(count, "count");

            // Skip generated tokens.
            if (!token.Generated)
            {
                // If there is at least one blank line in front of the current token.
                if (count > 1)
                {
                    if (token.CsTokenType == CsTokenType.CloseCurlyBracket)
                    {
                        // The blank line is just before a closing curly bracket.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.ClosingCurlyBracketsMustNotBePrecededByBlankLine);
                    }
                    else if (token.CsTokenType == CsTokenType.OpenCurlyBracket)
                    {
                        bool throwViolation = false;

                        // The blank line is just before an opening curly bracket.
                        // If next element back is if,while,catch,try,finally,do,else,lock,switch,unsafe, using, array init, delegate, it's a violation.
                        if (precedingTokenNode == null)
                        {
                            throwViolation = true;
                        }
                        else
                        {
                            Statement parentStatement = precedingTokenNode.Value.FindParentStatement();
                            if (parentStatement == null)
                            {
                                throwViolation = true;
                            }
                            else
                            {
                                StatementType statementType = parentStatement.StatementType;

                                if (statementType == StatementType.If || statementType == StatementType.While || statementType == StatementType.Catch
                                    || statementType == StatementType.Try || statementType == StatementType.Finally || statementType == StatementType.DoWhile
                                    || statementType == StatementType.Else || statementType == StatementType.Lock || statementType == StatementType.Switch
                                    || statementType == StatementType.Unsafe || statementType == StatementType.Using)
                                {
                                    throwViolation = true;
                                }
                                else if (statementType == StatementType.VariableDeclaration && precedingTokenNode.Value.CsTokenType != CsTokenType.Semicolon)
                                {
                                    throwViolation = true;
                                }
                                else if (statementType == StatementType.Expression && precedingTokenNode.Value.CsTokenType == CsTokenType.Delegate)
                                {
                                    throwViolation = true;
                                }
                            }
                        }

                        if (throwViolation)
                        {
                            this.AddViolation(token.FindParentElement(), token.Location, Rules.OpeningCurlyBracketsMustNotBePrecededByBlankLine);
                        }
                    }
                    else if (token.CsTokenType == CsTokenType.Else || token.CsTokenType == CsTokenType.Catch || token.CsTokenType == CsTokenType.Finally)
                    {
                        // The blank line is just before an else, catch, or finally statement.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.ChainedStatementBlocksMustNotBePrecededByBlankLine);
                    }
                    else if (token.CsTokenType == CsTokenType.WhileDo)
                    {
                        // The blank line is just before the while keyword from a do/while statement.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.WhileDoFooterMustNotBePrecededByBlankLine);
                    }

                    // Check if there is a blank line after a single-line comment. The exceptions
                    // are if this is the file header, or if the line after the blank line contains
                    // another comment or an Xml header. This is ok if the comment is not
                    // the first item on its line.
                    if (!fileHeader && precedingTokenNode != null && precedingTokenNode.Value.CsTokenType == CsTokenType.SingleLineComment
                        && token.CsTokenType != CsTokenType.SingleLineComment && token.CsTokenType != CsTokenType.MultiLineComment
                        && token.CsTokenType != CsTokenType.XmlHeader)
                    {
                        // Now check whether the comment is the first item on its line. If the comment
                        // is not the first item on the line, then this is not a violation.
                        bool tokenSeen = false;
                        if (precedingTokenNode != null)
                        {
                            foreach (CsToken lineToken in document.Tokens.ReverseIterator(precedingTokenNode.Previous))
                            {
                                if (lineToken.CsTokenType == CsTokenType.EndOfLine)
                                {
                                    break;
                                }
                                else if (lineToken.CsTokenType != CsTokenType.WhiteSpace)
                                {
                                    tokenSeen = true;
                                    break;
                                }
                            }
                        }

                        // Now make sure this comment does not begin with '////'. If so, this is the signal
                        // that StyleCop should ignore this particular error. This is used when the 
                        // developer is commenting out a line of code. In this case it is not a true comment.
                        string trimmedComment = precedingTokenNode.Value.Text.Trim();
                        if (!tokenSeen && !trimmedComment.StartsWith(@"////", StringComparison.Ordinal))
                        {
                            // The blank line appears after a file header, we want to allow this.
                            if (!IsCommentInFileHeader(precedingTokenNode))
                            {
                                this.AddViolation(
                                    precedingTokenNode.Value.FindParentElement(), 
                                    precedingTokenNode.Value.LineNumber, 
                                    Rules.SingleLineCommentsMustNotBeFollowedByBlankLine);
                            }
                        }
                    }
                }
                else if (count == 1)
                {
                    // There is one line return in front of the current token, which means
                    // the line in front of the current token is not blank. Check if the current
                    // token is an Xml header.
                    if (token.CsTokenType == CsTokenType.XmlHeader)
                    {
                        // This is a violation unless the previous line contains another
                        // Xml header, an opening curly bracket, or a preprocessor directive.
                        if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType != CsTokenType.XmlHeader
                            && precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket
                            && precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective)
                        {
                            this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.ElementDocumentationHeaderMustBePrecededByBlankLine);
                        }
                    }
                    else if (token.CsTokenType == CsTokenType.SingleLineComment)
                    {
                        // The current line contains a single line comment and the previous line
                        // is not blank. This is a violation unless the previous line contains
                        // another single line comment, an opening curly bracket, a preprocessor
                        // directive, or if the last character on the previous line is a colon,
                        // which can only mean that it is a label or a case statement, in which
                        // case this is ok.
                        if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType != CsTokenType.SingleLineComment
                            && precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket && precedingTokenNode.Value.CsTokenType != CsTokenType.LabelColon
                            && precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective)
                        {
                            // Now make sure this comment does not begin with '////'. If so, this is the signal
                            // that StyleCop should ignore this particular error. This is used when the 
                            // developer is commenting out a line of code. In this case it is not a true comment.
                            string trimmedComment = token.Text.Trim();
                            if (!trimmedComment.StartsWith(@"////", StringComparison.Ordinal) && !Utils.IsAReSharperComment(token))
                            {
                                CsElement element = token.FindParentElement();

                                if (element != null)
                                {
                                    this.AddViolation(element, token.LineNumber, Rules.SingleLineCommentMustBePrecededByBlankLine);
                                }
                            }
                        }
                    }
                    else if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType == CsTokenType.CloseCurlyBracket)
                    {
                        // Closing curly brackets cannot be followed directly by another bracket keyword.
                        Bracket closingCurlyBracket = precedingTokenNode.Value as Bracket;
                        if (closingCurlyBracket.MatchingBracket != null && closingCurlyBracket.MatchingBracket.LineNumber != closingCurlyBracket.LineNumber
                            && firstTokenOnLine && token.CsTokenType != CsTokenType.CloseCurlyBracket && token.CsTokenType != CsTokenType.Finally
                            && token.CsTokenType != CsTokenType.Catch && token.CsTokenType != CsTokenType.WhileDo && token.CsTokenType != CsTokenType.Else
                            && token.CsTokenType != CsTokenType.PreprocessorDirective && token.CsTokenType != CsTokenType.Select && token.CsTokenType != CsTokenType.From
                            && token.CsTokenType != CsTokenType.Let && token.CsTokenType != CsTokenType.OperatorSymbol && token.CsTokenType != CsTokenType.By)
                        {
                            this.AddViolation(closingCurlyBracket.FindParentElement(), closingCurlyBracket.LineNumber, Rules.ClosingCurlyBracketMustBeFollowedByBlankLine);
                        }
                    }
                }
            }
        }