Example #1
0
        /// <summary>
        /// Creates a text string based on the child tokens in the token.
        /// </summary>
        protected override void CreateTextString()
        {
            var text = new StringBuilder();

            for (LexicalElement lex = this.FindFirstDescendentLexicalElement(); lex != null; lex = lex.FindNextDescendentLexicalElementOf(this))
            {
                if (lex.Children.LexicalElementCount == 0)
                {
                    text.Append(lex.Text);
                }
            }

            this.Text = text.ToString();
        }
Example #2
0
        /// <summary>
        /// Calculates the location of the given element, and advances the starting location past this element for the next item.
        /// </summary>
        /// <param name="lex">The element.</param>
        /// <param name="lineNumber">The starting line number.</param>
        /// <param name="indexOnLine">The starting index of the item on the line.</param>
        /// <param name="indexInDocument">The start index of the item within the document.</param>
        /// <returns>Returns the location of the item.</returns>
        private static CodeLocation CalculateLocation(LexicalElement lex, ref int lineNumber, ref int indexOnLine, ref int indexInDocument)
        {
            Param.AssertNotNull(lex, "lex");
            Param.AssertGreaterThanZero(lineNumber, "lineNumber");
            Param.AssertGreaterThanOrEqualToZero(indexOnLine, "indexOnLine");
            Param.AssertGreaterThanOrEqualToZero(indexInDocument, "indexInDocument");

            string text = lex.Text;

            if (string.IsNullOrEmpty(text))
            {
                return(new CodeLocation(indexInDocument, indexInDocument, indexOnLine, indexOnLine, lineNumber, lineNumber));
            }

            int endLineNumber      = lineNumber;
            int endIndexOnLine     = indexOnLine;
            int endIndexInDocument = indexInDocument;

            for (int i = 0; i < text.Length; ++i)
            {
                ++endIndexInDocument;

                if (i > 0 && text[i - 1] == '\n')
                {
                    ++endLineNumber;
                    endIndexOnLine = 0;
                }
                else
                {
                    ++endIndexOnLine;
                }
            }

            var location = new CodeLocation(indexInDocument, endIndexInDocument, indexOnLine, endIndexOnLine, lineNumber, endLineNumber);

            lineNumber      = endLineNumber;
            indexOnLine     = endIndexOnLine + 1;
            indexInDocument = endIndexInDocument + 1;

            if (text[text.Length - 1] == '\n')
            {
                ++lineNumber;
                indexOnLine = 0;
            }

            return(location);
        }
Example #3
0
        /// <summary>
        /// Fills in the locations of child elements within a lexical element.
        /// </summary>
        /// <param name="lex">The lexical element.</param>
        private static void SetLexicalElementChildLocations(LexicalElement lex)
        {
            Param.AssertNotNull(lex, "lex");

            int lineNumber      = lex.Location.StartPoint.LineNumber;
            int indexOnLine     = lex.Location.StartPoint.Index;
            int indexInDocument = lex.Location.StartPoint.Index;

            for (LexicalElement child = lex.FindFirstChildLexicalElement(); child != null; child = child.FindNextSiblingLexicalElement())
            {
                child.Location = CalculateLocation(child, ref lineNumber, ref indexOnLine, ref indexInDocument);

                if (child.Children.Count > 0)
                {
                    SetLexicalElementChildLocations(child);
                }
            }
        }
Example #4
0
        /// <summary>
        /// Determines whether the type of the given token is allowed
        /// to appear after a closing parenthesis, with no space between
        /// the parenthesis and the token.
        /// </summary>
        /// <param name="item">The item to check.</param>
        /// <returns>True if it is allowed; false otherwise.</returns>
        private static bool IsAllowedAfterClosingParenthesis(LexicalElement item)
        {
            Param.AssertNotNull(item, "item");

            if (item.Is(TokenType.CloseParenthesis) ||
                item.Is(TokenType.OpenParenthesis) ||
                item.Is(TokenType.CloseSquareBracket) ||
                item.Is(TokenType.OpenSquareBracket) ||
                item.Is(TokenType.CloseAttributeBracket) ||
                item.Is(TokenType.Semicolon) ||
                item.Is(TokenType.Comma) ||
                item.Is(OperatorType.Decrement) ||
                item.Is(OperatorType.Increment) ||
                item.Is(OperatorType.MemberAccess) ||
                item.Is(OperatorType.Pointer))
            {
                return true;
            }

            return false;
        }
Example #5
0
        /// <summary>
        /// Writes the contents of the document to the given writer.
        /// </summary>
        /// <param name="writer">The writer.</param>
        public void Write(TextWriter writer)
        {
            Param.RequireNotNull(writer, "writer");

            for (LexicalElement item = this.FindFirstLexicalElement(); item != null; item = item.FindNextLexicalElement())
            {
                if (item.LexicalElementType == LexicalElementType.PreprocessorDirective || item.Children.LexicalElementCount == 0)
                {
                    if (item.LexicalElementType == LexicalElementType.EndOfLine)
                    {
                        writer.WriteLine();
                    }
                    else
                    {
                        writer.Write(item.Text);
                    }
                }

                if (item.LexicalElementType == LexicalElementType.PreprocessorDirective)
                {
                    item = item.FindLastLexicalElement();
                }
            }
        }
Example #6
0
        /// <summary>
        /// Checks for tabs in the given comment.
        /// </summary>
        /// <param name="comment">The comment token.</param>
        private void CheckTabsInComment(LexicalElement 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.LineNumber + lineEnds, Rules.TabsMustNotBeUsed);
                }
                else if (comment.Text[i] == '\n')
                {
                    ++lineEnds;
                }
            }
        }
Example #7
0
        /// <summary>
        /// Updates the regions, generated code status, and locations of items in the document.
        /// </summary>
        internal void Update()
        {
            int lineNumber      = 1;
            int indexOnLine     = 0;
            int indexInDocument = 0;

            int generatedCount = 0;
            Stack <RegionDirective> regionStack = new Stack <RegionDirective>();

            // If the document is marked as generated, then treat everything in the document as generated.
            if (this.Generated)
            {
                ++generatedCount;
            }

            for (LexicalElement lex = this.FindFirstLexicalElement(); lex != null; lex = lex.FindNextLexicalElement())
            {
                if (!lex.Parent.Is(CodeUnitType.LexicalElement))
                {
                    lex.Location = CalculateLocation(lex, ref lineNumber, ref indexOnLine, ref indexInDocument);
                }

                if (lex.Children.LexicalElementCount > 0)
                {
                    SetLexicalElementChildLocations(lex);
                }

                lex.Generated = generatedCount > 0;

                if (lex.Is(PreprocessorType.Region))
                {
                    RegionDirective region = (RegionDirective)lex;
                    regionStack.Push(region);

                    if (region.IsGeneratedCodeRegion)
                    {
                        ++generatedCount;
                    }
                }
                else if (lex.Is(PreprocessorType.EndRegion))
                {
                    EndRegionDirective endRegion = (EndRegionDirective)lex;

                    if (regionStack.Count == 0)
                    {
                        throw new SyntaxException(this.Document, endRegion.LineNumber, Strings.NoMatchingRegion);
                    }

                    RegionDirective region = regionStack.Pop();

                    endRegion.Partner = region;
                    region.Partner    = endRegion;

                    if (region.IsGeneratedCodeRegion)
                    {
                        --generatedCount;
                    }
                }
            }

            if (regionStack.Count > 0)
            {
                throw new SyntaxException(this.Document, this.LineNumber, Strings.NoMatchingEndregion);
            }
        }
Example #8
0
        /// <summary>
        /// Processes a newline character found while checking line spacing rules.
        /// </summary>
        /// <param name="precedingItem">The preceding item before the newline.</param>
        /// <param name="item">The newline item.</param>
        /// <param name="count">The current newline count.</param>
        private void CheckLineSpacingNewline(LexicalElement precedingItem, LexicalElement item, int count)
        {
            Param.Ignore(precedingItem);
            Param.AssertNotNull(item, "item");
            Param.AssertGreaterThanOrEqualToZero(count, "count");

            // If we've seen two end-of-line characters in a row, then there is a blank
            // line in the code. 
            if (count == 2)
            {
                // Check whether we've seen at least one token before this blank line.
                if (precedingItem != null && !precedingItem.Generated)
                {
                    if (precedingItem.Is(TokenType.OpenCurlyBracket))
                    {
                        // The blank line comes just after an opening curly bracket.
                        this.AddViolation(
                            precedingItem.FindParentElement(),
                            precedingItem.LineNumber,
                            Rules.OpeningCurlyBracketsMustNotBeFollowedByBlankLine);
                    }
                    else if (IsXmlHeader(precedingItem))
                    {
                        // The blank line comes just after an Xml header.
                        this.AddViolation(
                            precedingItem.FindParentElement(),
                            precedingItem.LineNumber,
                            Rules.ElementDocumentationHeadersMustNotBeFollowedByBlankLine);
                    }
                }
            }
            else if (count == 3 && !item.Generated)
            {
                // There are two or more blank lines in a row.
                this.AddViolation(
                    item.FindParentElement(),
                    item.LineNumber,
                    Rules.CodeMustNotContainMultipleBlankLinesInARow);
            }
        }
Example #9
0
        private void CheckLineSpacingNonWhitespace(
            CsDocument document, LexicalElement precedingItem, LexicalElement item, bool fileHeader, bool firstTokenOnLine, int count)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(precedingItem);
            Param.AssertNotNull(item, "item");
            Param.Ignore(fileHeader);
            Param.Ignore(firstTokenOnLine);
            Param.AssertGreaterThanOrEqualToZero(count, "count");

            // Skip generated tokens.
            if (!item.Generated)
            {
                // If there is at least one blank line in front of the current token.
                if (count > 1)
                {
                    if (item.Is(TokenType.CloseCurlyBracket))
                    {
                        // The blank line is just before a closing curly bracket.
                        this.AddViolation(
                            item.FindParentElement(),
                            item.LineNumber,
                            Rules.ClosingCurlyBracketsMustNotBePrecededByBlankLine);
                    }
                    else if (item.Is(TokenType.OpenCurlyBracket))
                    {
                        // The blank line is just before an opening curly bracket.
                        this.AddViolation(
                            item.FindParentElement(),
                            item.LineNumber,
                            Rules.OpeningCurlyBracketsMustNotBePrecededByBlankLine);
                    }
                    else if (item.Is(TokenType.Else) ||
                        item.Is(TokenType.Catch) ||
                        item.Is(TokenType.Finally))
                    {
                        // The blank line is just before an else, catch, or finally statement.
                        this.AddViolation(
                            item.FindParentElement(),
                            item.LineNumber,
                            Rules.ChainedStatementBlocksMustNotBePrecededByBlankLine);
                    }
                    else if (item.Is(TokenType.WhileDo))
                    {
                        // The blank line is just before the while keyword from a do/while statement.
                        this.AddViolation(
                            item.FindParentElement(),
                            item.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 &&
                        precedingItem != null &&
                        precedingItem.Is(CommentType.SingleLineComment) &&
                        !item.Is(LexicalElementType.Comment) &&
                        !IsXmlHeader(item))
                    {
                        Comment precedingComment = (Comment)precedingItem;

                        // 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 itemSeen = false;
                        for (LexicalElement lineItem = precedingComment.FindPreviousLexicalElement(); lineItem != null; lineItem = lineItem.FindPreviousLexicalElement())
                        {
                            if (lineItem.LexicalElementType == LexicalElementType.EndOfLine)
                            {
                                break;
                            }
                            else if (lineItem.LexicalElementType != LexicalElementType.WhiteSpace)
                            {
                                itemSeen = 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 = precedingComment.Text.Trim();
                        if (!itemSeen && !trimmedComment.StartsWith(@"////", StringComparison.Ordinal))
                        {
                            // The blank line appears after a file header, we want to allow this.
                            if (!IsCommentInFileHeader(precedingComment))
                            {
                                this.AddViolation(
                                    precedingComment.FindParentElement(),
                                    precedingComment.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 (IsXmlHeader(item))
                    {
                        // This is a violation unless the previous line contains another
                        // Xml header, an opening curly bracket, or a preprocessor directive.
                        if (precedingItem != null &&
                            !IsXmlHeader(precedingItem) &&
                            !precedingItem.Is(TokenType.OpenCurlyBracket) &&
                            !IsPreprocessorDirective(precedingItem))
                        {
                            this.AddViolation(
                                item.FindParentElement(),
                                item.LineNumber,
                                Rules.ElementDocumentationHeaderMustBePrecededByBlankLine);
                        }
                    }
                    else if (item.Is(CommentType.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 (precedingItem != null &&
                            !precedingItem.Is(CommentType.SingleLineComment) &&
                            !precedingItem.Is(TokenType.OpenCurlyBracket) &&
                            !precedingItem.Is(TokenType.LabelColon) &&
                            !IsPreprocessorDirective(precedingItem))
                        {
                            // 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 = item.Text.Trim();
                            if (!trimmedComment.StartsWith(@"////", StringComparison.Ordinal))
                            {
                                this.AddViolation(
                                    item.FindParentElement(),
                                    item.LineNumber,
                                    Rules.SingleLineCommentMustBePrecededByBlankLine);
                            }
                        }
                    }

                    if (precedingItem != null && precedingItem.Is(TokenType.CloseCurlyBracket))
                    {
                        // Closing curly brackets cannot be followed directly by another bracket keyword.
                        CloseCurlyBracketToken closingCurlyBracket = (CloseCurlyBracketToken)precedingItem;
                        if (closingCurlyBracket.MatchingBracket != null &&
                            closingCurlyBracket.MatchingBracket.LineNumber != closingCurlyBracket.LineNumber &&
                            firstTokenOnLine &&
                            !item.Is(TokenType.CloseCurlyBracket) &&
                            !item.Is(TokenType.Finally) &&
                            !item.Is(TokenType.Catch) &&
                            !item.Is(TokenType.WhileDo) &&
                            !item.Is(TokenType.Else) &&
                            !IsPreprocessorDirective(item))
                        {
                            this.AddViolation(
                                closingCurlyBracket.FindParentElement(),
                                closingCurlyBracket.LineNumber,
                                Rules.ClosingCurlyBracketMustBeFollowedByBlankLine);
                        }
                    }
                }
            }
        }