private void CheckForEmptyComments(Comment comment, Element parentElement) { Param.AssertNotNull(comment, "comment"); Param.AssertNotNull(parentElement, "parentElement"); // Skip generated code. if (!comment.Generated) { // Check for the two comment types. if (comment.CommentType == CommentType.SingleLineComment) { this.CheckSingleLineComment(comment, parentElement); } else if (comment.CommentType == CommentType.MultilineComment) { this.CheckMultilineComment(comment, parentElement); } } }
/// <summary> /// Checks to make sure that the slashes in in the comment are followed by a space. /// </summary> /// <param name="root">The container to parse.</param> /// <param name="comment">The comment.</param> private void CheckSingleLineComment(CodeUnit root, Comment comment) { Param.AssertNotNull(root, "root"); Param.AssertNotNull(comment, "comment"); // If the token length is less then two, this is not a valid comment so just ignore it. string text = comment.Text; if (text.Length > 2) { // The first character in the comment must be a space, except for the following four cases: // 1. The comment may start with three or more slashes: ///whatever // 2. The command may start with a backwards slash: //\whatever // 3. The comment may start with a dash if there are at last two dashes: //-- // 4. The character after the second slash may be a newline character. if (text[2] != ' ' && text[2] != '\t' && text[2] != '/' && text[2] != '\\' && text[1] != '\n' && text[1] != '\r' && (text.Length < 4 || text[2] != '-' || text[3] != '-')) { // The comment does not start with a single space. this.AddViolation(comment.FindParentElement(), comment.LineNumber, Rules.SingleLineCommentsMustBeginWithSingleSpace); } else if (text.Length > 3 && (text[3] == ' ' || text[3] == '\t') && text[2] != '\\') { // The comment starts with more than one space. This is only a violation if this is the first // single-line comment in a row. If there is another single-line comment directly above this one // with no blank line between them, this is not a violation. bool first = true; int newLineCount = 0; for (LexicalElement previousItem = comment.FindPreviousLexicalElement(); previousItem != null; previousItem = previousItem.FindPreviousLexicalElement()) { if (previousItem.LexicalElementType == LexicalElementType.EndOfLine) { if (++newLineCount == 2) { break; } } else if (previousItem.Is(CommentType.SingleLineComment)) { first = false; break; } else if (previousItem.LexicalElementType != LexicalElementType.WhiteSpace) { break; } } if (first) { this.AddViolation(comment.FindParentElement(), comment.LineNumber, Rules.SingleLineCommentsMustBeginWithSingleSpace); } } } }
/// <summary> /// Determines whether the given xml header is empty. /// </summary> /// <param name="xmlHeaderLine">The xml header line token.</param> /// <returns>Returns true if the header is empty.</returns> private static bool IsXmlHeaderLineEmpty(Comment xmlHeaderLine) { Param.AssertNotNull(xmlHeaderLine, "xmlHeaderLine"); Debug.Assert(xmlHeaderLine.CommentType == CommentType.ElementHeaderLine, "The token should be an xml header line"); int slashCount = 0; for (int i = 0; i < xmlHeaderLine.Text.Length; ++i) { char character = xmlHeaderLine.Text[i]; if (slashCount < 3) { if (character == '/') { ++slashCount; } else { return false; } } else { if (!char.IsWhiteSpace(character)) { return false; } } } return true; }
/// <summary> /// Checks a single-line comment to see if it is empty. /// </summary> /// <param name="comment">The comment.</param> /// <param name="parentElement">The parent element.</param> private void CheckSingleLineComment(Comment comment, Element parentElement) { Param.AssertNotNull(comment, "comment"); Param.AssertNotNull(parentElement, "parentElement"); // This is a single line comment. int slashCount = 0; bool found = false; // Loop through the characters in the comment text. for (int character = 0; character < comment.Text.Length; ++character) { // See if we've found the slashes at the beginning of the comment if (slashCount == 2) { // Check whether there's anything here other than whitespace. // If so, then this comment is ok. if (comment.Text[character] != ' ' && comment.Text[character] != '\t' && comment.Text[character] != '\r' && comment.Text[character] != '\n') { found = true; break; } } else if (comment.Text[character] == '/') { ++slashCount; } } // Check whether the comment contained any text. if (!found) { // This is only allowed if this comment is sandwiched in between two other comments. bool isComment = false; int lines = 0; for (LexicalElement item = comment.FindPreviousLexicalElement(); item != null; item = item.FindPreviousLexicalElement()) { if (item.Text == "\n") { ++lines; if (lines > 1) { break; } } else if (item.Is(CommentType.SingleLineComment)) { isComment = true; break; } else if (item.LexicalElementType != LexicalElementType.WhiteSpace) { break; } } if (!isComment) { this.AddViolation(parentElement, comment.LineNumber, Rules.CommentsMustContainText); } else { isComment = false; lines = 0; for (LexicalElement item = comment.FindNextLexicalElement(); item != null; item = item.FindNextLexicalElement()) { if (item.Text == "\n") { ++lines; if (lines > 1) { break; } } else if (item.Is(CommentType.SingleLineComment)) { isComment = true; break; } else if (item.LexicalElementType != LexicalElementType.WhiteSpace) { break; } } if (!isComment) { this.AddViolation(parentElement, comment.LineNumber, Rules.CommentsMustContainText); } } } }
/// <summary> /// Checks a single-line comment to see if it is empty. /// </summary> /// <param name="comment">The comment.</param> /// <param name="parentElement">The parent element.</param> private void CheckMultilineComment(Comment comment, Element parentElement) { Param.AssertNotNull(comment, "comment"); Param.AssertNotNull(parentElement, "parentElement"); // The is a multi-line comment. Get the start of the comment. int start = comment.Text.IndexOf("/*", StringComparison.Ordinal); if (start > -1) { // Get the end of the comment int end = comment.Text.IndexOf("*/", start + 2, StringComparison.Ordinal); if (end > -1) { // Look at the characters between the start and the end and see if there // is anything here besides whitespace. bool found = false; for (int character = start + 2; character < end; ++character) { if (comment.Text[character] != ' ' && comment.Text[character] != '\t' && comment.Text[character] != '\r' && comment.Text[character] != '\n') { found = true; break; } } // Check whether the comment contained any text. if (!found) { this.AddViolation(parentElement, comment.LineNumber, Rules.CommentsMustContainText); } } } }
/// <summary> /// Determines whether the given token is part of a file header. It is considered /// part of a file header if the only tokens in front of it are single-line comments, /// whitespace, or newlines. /// </summary> /// <param name="comment">The comment to check.</param> /// <returns>Returns true if the comment is part of a file header.</returns> private static bool IsCommentInFileHeader(Comment comment) { Param.AssertNotNull(comment, "comment"); LexicalElement item = comment; while (item != null) { if (!item.Is(CommentType.SingleLineComment) && item.LexicalElementType != LexicalElementType.WhiteSpace && item.LexicalElementType != LexicalElementType.EndOfLine) { return false; } item = item.FindPreviousLexicalElement(); } return true; }