/// <summary>
        /// Measures the number of lines taken up by comments between two tokens.
        /// </summary>
        /// <param name="start">The start token.</param>
        /// <param name="end">The end token.</param>
        /// <param name="includeAttributes">Indicates whether to also count attributes.</param>
        /// <returns>Returns the number of lines takes up by comments.</returns>
        private static int MeasureCommentLinesBetween(CodeUnit start, CodeUnit end, bool includeAttributes)
        {
            Param.AssertNotNull(start, "start");
            Param.AssertNotNull(end, "end");
            Param.Ignore(includeAttributes);

            int lineSpan = 0;

            int previousLineSpan      = -1;
            int previousEndLineNumber = -1;

            for (CodeUnit next = start.FindNext(); next != null && next != end; next = next.FindNext())
            {
                if (next.Is(LexicalElementType.Comment) || (next.Is(CodeUnitType.Attribute) && includeAttributes))
                {
                    int itemLineSpan = ParameterPrewordOffset(next);

                    if (previousEndLineNumber > 0 && next.LineNumber == previousEndLineNumber && previousLineSpan > 0)
                    {
                        --itemLineSpan;
                    }

                    lineSpan             += itemLineSpan;
                    previousLineSpan      = itemLineSpan;
                    previousEndLineNumber = next.Location.EndPoint.LineNumber;
                }
            }

            return(lineSpan);
        }
        /// <summary>
        /// Gets the non-whitespace item that appears after the given item.
        /// </summary>
        /// <param name="item">The original item.</param>
        /// <returns>Returns the next item.</returns>
        private static CodeUnit GetNextNonWhitespaceItem(CodeUnit item)
        {
            Param.AssertNotNull(item, "item");

            for (CodeUnit next = item.FindNext(); next != null; next = next.FindNext())
            {
                if (!next.Is(LexicalElementType.EndOfLine) && !next.Is(LexicalElementType.WhiteSpace))
                {
                    return(next);
                }
            }

            return(null);
        }
        /// <summary>
        /// Gets the non-whitespace item that appears after the given item.
        /// </summary>
        /// <param name="item">The original item.</param>
        /// <returns>Returns the next item.</returns>
        private static CodeUnit GetNextNonWhitespaceItem(CodeUnit item)
        {
            Param.AssertNotNull(item, "item");

            for (CodeUnit next = item.FindNext(); next != null; next = next.FindNext())
            {
                if (!next.Is(LexicalElementType.EndOfLine) && !next.Is(LexicalElementType.WhiteSpace))
                {
                    return next;
                }
            }

            return null;
        }
        /// <summary>
        /// Measures the number of lines taken up by comments after the start item before the first word.
        /// </summary>
        /// <param name="start">The start item.</param>
        /// <returns>Returns the number of lines takes up by comments.</returns>
        private static int MeasureCommentLinesAfter(CodeUnit start)
        {
            Param.AssertNotNull(start, "start");

            int lineSpan = 0;

            int previousLineSpan      = -1;
            int previousEndLineNumber = -1;

            for (CodeUnit next = start.FindNext(); next != null; next = next.FindNext())
            {
                if (next.Is(LexicalElementType.Comment) || next.Is(CodeUnitType.Attribute))
                {
                    int itemLineSpan = ParameterPrewordOffset(next);

                    if (previousEndLineNumber > 0 && next.LineNumber == previousEndLineNumber && previousLineSpan > 0)
                    {
                        --itemLineSpan;
                    }

                    lineSpan             += itemLineSpan;
                    previousLineSpan      = itemLineSpan;
                    previousEndLineNumber = next.Location.EndPoint.LineNumber;
                    next = next.FindLast();
                }
                else if (!next.Is(LexicalElementType.WhiteSpace) &&
                         !next.Is(LexicalElementType.EndOfLine) &&
                         !next.Is(CodeUnitType.ParameterList) &&
                         !next.Is(CodeUnitType.ArgumentList) &&
                         !next.Is(CodeUnitType.Parameter) &&
                         !next.Is(CodeUnitType.Argument))
                {
                    break;
                }
            }

            return(lineSpan);
        }
        /// <summary>
        /// Determines the amount of offset to add to the line number of the next argument
        /// for a comment or attribute.
        /// </summary>
        /// <param name="item">The starting item.</param>
        /// <returns>Returns the amount of offset to add.</returns>
        private static int ParameterPrewordOffset(CodeUnit item)
        {
            Param.AssertNotNull(item, "tokenNode");

            Debug.Assert(item.Is(CodeUnitType.Attribute) || item.Is(LexicalElementType.Comment), "The item must be an attribute or a comment.");

            // Find the start of the next argument.
            for (CodeUnit next = item.FindLast().FindNext(); next != null; next = next.FindNext())
            {
                if (next.Is(LexicalElementType.EndOfLine))
                {
                    return(item.Location.LineSpan);
                }
                else if (!next.Is(LexicalElementType.WhiteSpace) &&
                         !next.Is(LexicalElementType.WhiteSpace) &&
                         !next.Is(CodeUnitType.Attribute))
                {
                    return(Math.Max(0, next.Location.StartPoint.LineNumber - item.Location.StartPoint.LineNumber));
                }
            }

            return(0);
        }