Loading coder_sniffer/Drupal/Sniffs/Commenting/InlineCommentSniff.php +204 −185 Original line number Diff line number Diff line Loading @@ -92,12 +92,16 @@ class InlineCommentSniff implements Sniff T_ABSTRACT, T_CONST, T_PROPERTY, T_INCLUDE, T_INCLUDE_ONCE, T_REQUIRE, T_REQUIRE_ONCE, T_VAR, ]; // Also ignore all doc blocks defined in the outer scope (no scope // conditions are set). if (in_array($tokens[$nextToken]['code'], $ignore) === true if (in_array($tokens[$nextToken]['code'], $ignore, true) === true || empty($tokens[$stackPtr]['conditions']) === true ) { return; Loading Loading @@ -152,8 +156,8 @@ class InlineCommentSniff implements Sniff } } // We don't want end of block comments. If the last comment is a closing // curly brace. // We don't want end of block comments. Check if the last token before the // comment is a closing curly brace. $previousContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$previousContent]['line'] === $tokens[$stackPtr]['line']) { if ($tokens[$previousContent]['code'] === T_CLOSE_CURLY_BRACKET) { Loading @@ -171,10 +175,8 @@ class InlineCommentSniff implements Sniff } } $comment = rtrim($tokens[$stackPtr]['content']); // Only want inline comments. if (substr($comment, 0, 2) !== '//') { if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { return; } Loading @@ -183,46 +185,148 @@ class InlineCommentSniff implements Sniff return; } // Verify the indentation of this comment line. $this->processIndentation($phpcsFile, $stackPtr); $commentTokens = [$stackPtr]; // If the current line starts with a tag such as "@see" then the trailing dot // rules and upper case start rules don't apply. if (strpos(trim(substr($tokens[$stackPtr]['content'], 2)), '@') === 0) { return; $nextComment = $stackPtr; $lastComment = $stackPtr; while (($nextComment = $phpcsFile->findNext(T_COMMENT, ($nextComment + 1), null, false)) !== false) { if ($tokens[$nextComment]['line'] !== ($tokens[$lastComment]['line'] + 1)) { break; } // The below section determines if a comment block is correctly capitalised, // and ends in a full-stop. It will find the last comment in a block, and // work its way up. $nextComment = $phpcsFile->findNext([T_COMMENT], ($stackPtr + 1), null, false); if (($nextComment !== false) && (($tokens[$nextComment]['line']) === ($tokens[$stackPtr]['line'] + 1)) // A tag such as @todo means a separate comment block. && strpos(trim(substr($tokens[$nextComment]['content'], 2)), '@') !== 0 ) { return; // Only want inline comments. if (substr($tokens[$nextComment]['content'], 0, 2) !== '//') { break; } $topComment = $stackPtr; $lastComment = $stackPtr; while (($topComment = $phpcsFile->findPrevious([T_COMMENT], ($lastComment - 1), null, false)) !== false) { if ($tokens[$topComment]['line'] !== ($tokens[$lastComment]['line'] - 1)) { // There is a comment on the very next line. If there is // no code between the comments, they are part of the same // comment block. $prevNonWhitespace = $phpcsFile->findPrevious(T_WHITESPACE, ($nextComment - 1), $lastComment, true); if ($prevNonWhitespace !== $lastComment) { break; } $lastComment = $topComment; // A comment starting with "@" means a new comment section. if (preg_match('|^//[\s]*@|', $tokens[$nextComment]['content']) === 1) { break; } $topComment = $lastComment; $commentTokens[] = $nextComment; $lastComment = $nextComment; }//end while $commentText = ''; foreach ($commentTokens as $lastCommentToken) { $comment = rtrim($tokens[$lastCommentToken]['content']); if (trim(substr($comment, 2)) === '') { continue; } $spaceCount = 0; $tabFound = false; $commentLength = strlen($comment); for ($i = 2; $i < $commentLength; $i++) { if ($comment[$i] === "\t") { $tabFound = true; break; } for ($i = $topComment; $i <= $stackPtr; $i++) { if ($tokens[$i]['code'] === T_COMMENT) { $commentText .= trim(substr($tokens[$i]['content'], 2)); if ($comment[$i] !== ' ') { break; } $spaceCount++; } $fix = false; if ($tabFound === true) { $error = 'Tab found before comment text; expected "// %s" but found "%s"'; $data = [ ltrim(substr($comment, 2)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'TabBefore', $data); } else if ($spaceCount === 0) { $error = 'No space found before comment text; expected "// %s" but found "%s"'; $data = [ substr($comment, 2), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'NoSpaceBefore', $data); }//end if if ($fix === true) { $newComment = '// '.ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } if ($spaceCount > 1) { // Check if there is a comment on the previous line that justifies the // indentation. $prevComment = $phpcsFile->findPrevious([T_COMMENT], ($lastCommentToken - 1), null, false); if (($prevComment !== false) && (($tokens[$prevComment]['line']) === ($tokens[$lastCommentToken]['line'] - 1))) { $prevCommentText = rtrim($tokens[$prevComment]['content']); $prevSpaceCount = 0; for ($i = 2; $i < strlen($prevCommentText); $i++) { if ($prevCommentText[$i] !== ' ') { break; } $prevSpaceCount++; } if ($spaceCount > $prevSpaceCount && $prevSpaceCount > 0) { // A previous comment could be a list item or @todo. $indentationStarters = [ '-', '@todo', ]; $words = preg_split('/\s+/', $prevCommentText); $numberedList = (bool) preg_match('/^[0-9]+\./', $words[1]); if (in_array($words[1], $indentationStarters) === true) { if ($spaceCount !== ($prevSpaceCount + 2)) { $error = 'Comment indentation error after %s element, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', [$words[1], ($prevSpaceCount + 2)]); if ($fix === true) { $newComment = '//'.str_repeat(' ', ($prevSpaceCount + 2)).ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } } } else if ($numberedList === true) { $expectedSpaceCount = ($prevSpaceCount + strlen($words[1]) + 1); if ($spaceCount !== $expectedSpaceCount) { $error = 'Comment indentation error, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', [$expectedSpaceCount]); if ($fix === true) { $newComment = '//'.str_repeat(' ', $expectedSpaceCount).ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } } } else { $error = 'Comment indentation error, expected only %s spaces'; $phpcsFile->addError($error, $lastCommentToken, 'SpacingBefore', [$prevSpaceCount]); }//end if }//end if } else { $error = '%s spaces found before inline comment; expected "// %s" but found "%s"'; $data = [ $spaceCount, substr($comment, (2 + $spaceCount)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($lastCommentToken, '// '.substr($comment, (2 + $spaceCount)).$phpcsFile->eolChar); } }//end if }//end if $commentText .= trim(substr($tokens[$lastCommentToken]['content'], 2)); }//end foreach if ($commentText === '') { $error = 'Blank comments are not allowed'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Empty'); Loading @@ -230,36 +334,37 @@ class InlineCommentSniff implements Sniff $phpcsFile->fixer->replaceToken($stackPtr, ''); } return; return ($lastCommentToken + 1); } $words = preg_split('/\s+/', $commentText); if (preg_match('|\p{Lu}|u', $commentText[0]) === 0 && $commentText[0] !== '@') { if (preg_match('/^\p{Ll}/u', $commentText) === 1) { // Allow special lower cased words that contain non-alpha characters // (function references, machine names with underscores etc.). $matches = []; preg_match('/[a-z]+/', $words[0], $matches); if (isset($matches[0]) === true && $matches[0] === $words[0]) { $error = 'Inline comments must start with a capital letter'; $fix = $phpcsFile->addFixableError($error, $topComment, 'NotCapital'); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotCapital'); if ($fix === true) { $newComment = preg_replace("/$words[0]/", ucfirst($words[0]), $tokens[$topComment]['content'], 1); $phpcsFile->fixer->replaceToken($topComment, $newComment); $newComment = preg_replace("/$words[0]/", ucfirst($words[0]), $tokens[$stackPtr]['content'], 1); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } // Only check the end of comment character if the start of the comment // is a letter, indicating that the comment is just standard text. if (preg_match('/^\p{L}/u', $commentText) === 1) { $commentCloser = $commentText[(strlen($commentText) - 1)]; $acceptedClosers = [ 'full-stops' => '.', 'exclamation marks' => '!', 'colons' => ':', 'question marks' => '?', 'colons' => ':', 'or closing parentheses' => ')', ]; // Allow @tag style comments without punctuation. if (in_array($commentCloser, $acceptedClosers) === false && $commentText[0] !== '@') { // Allow special last words like URLs or function references // without punctuation. $lastWord = $words[(count($words) - 1)]; Loading @@ -272,7 +377,9 @@ class InlineCommentSniff implements Sniff // Also allow closing tags like @endlink or @endcode. $isEndTag = $lastWord[0] === '@'; if ($isUrl === false && $isFunction === false && $isEndTag === false) { if (in_array($commentCloser, $acceptedClosers, true) === false && $isUrl === false && $isFunction === false && $isEndTag === false ) { $error = 'Inline comments must end in %s'; $ender = ''; foreach ($acceptedClosers as $closerName => $symbol) { Loading @@ -281,37 +388,59 @@ class InlineCommentSniff implements Sniff $ender = trim($ender, ' ,'); $data = [$ender]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'InvalidEndChar', $data); $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'InvalidEndChar', $data); if ($fix === true) { $newContent = preg_replace('/(\s+)$/', '.$1', $tokens[$stackPtr]['content']); $phpcsFile->fixer->replaceToken($stackPtr, $newContent); $newContent = preg_replace('/(\s+)$/', '.$1', $tokens[$lastCommentToken]['content']); $phpcsFile->fixer->replaceToken($lastCommentToken, $newContent); } } }//end if // Finally, the line below the last comment cannot be empty if this inline // comment is on a line by itself. if ($tokens[$previousContent]['line'] < $tokens[$stackPtr]['line'] && ($stackPtr + 1) < $phpcsFile->numTokens) { for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['line'] === ($tokens[$stackPtr]['line'] + 1)) { if ($tokens[$i]['code'] !== T_WHITESPACE || $i === ($phpcsFile->numTokens - 1)) { return; if ($tokens[$previousContent]['line'] < $tokens[$stackPtr]['line']) { $next = $phpcsFile->findNext(T_WHITESPACE, ($lastCommentToken + 1), null, true); if ($next === false) { // Ignore if the comment is the last non-whitespace token in a file. return ($lastCommentToken + 1); } } else if ($tokens[$i]['line'] > ($tokens[$stackPtr]['line'] + 1)) { break; if ($tokens[$next]['code'] === T_DOC_COMMENT_OPEN_TAG) { // If this inline comment is followed by a docblock, // ignore spacing as docblock/function etc spacing rules // are likely to conflict with our rules. return ($lastCommentToken + 1); } $errorCode = 'SpacingAfter'; if (isset($tokens[$stackPtr]['conditions']) === true) { $conditions = $tokens[$stackPtr]['conditions']; $type = end($conditions); $conditionPtr = key($conditions); if (($type === T_FUNCTION || $type === T_CLOSURE) && $tokens[$conditionPtr]['scope_closer'] === $next ) { $errorCode = 'SpacingAfterAtFunctionEnd'; } } $warning = 'There must be no blank line following an inline comment'; $fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'SpacingAfter'); if ($fix === true) { $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); if ($next === ($phpcsFile->numTokens - 1)) { return; for ($i = ($lastCommentToken + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['line'] === ($tokens[$lastCommentToken]['line'] + 1)) { if ($tokens[$i]['code'] !== T_WHITESPACE) { return ($lastCommentToken + 1); } } else if ($tokens[$i]['line'] > ($tokens[$lastCommentToken]['line'] + 1)) { break; } } $error = 'There must be no blank line following an inline comment'; $fix = $phpcsFile->addFixableWarning($error, $lastCommentToken, $errorCode); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); for ($i = ($stackPtr + 1); $i < $next; $i++) { for ($i = ($lastCommentToken + 1); $i < $next; $i++) { if ($tokens[$i]['line'] === $tokens[$next]['line']) { break; } Loading @@ -323,6 +452,8 @@ class InlineCommentSniff implements Sniff } }//end if return ($lastCommentToken + 1); }//end process() Loading @@ -339,6 +470,10 @@ class InlineCommentSniff implements Sniff protected function isInCodeExample(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content'] === '// @code'.$phpcsFile->eolChar) { return true; } $prevComment = $stackPtr; $lastComment = $stackPtr; while (($prevComment = $phpcsFile->findPrevious([T_COMMENT], ($lastComment - 1), null, false)) !== false) { Loading @@ -362,120 +497,4 @@ class InlineCommentSniff implements Sniff }//end isInCodeExample() /** * Checks the indentation level of the comment contents. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ protected function processIndentation(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $comment = rtrim($tokens[$stackPtr]['content']); $spaceCount = 0; $tabFound = false; $commentLength = strlen($comment); for ($i = 2; $i < $commentLength; $i++) { if ($comment[$i] === "\t") { $tabFound = true; break; } if ($comment[$i] !== ' ') { break; } $spaceCount++; } $fix = false; if ($tabFound === true) { $error = 'Tab found before comment text; expected "// %s" but found "%s"'; $data = [ ltrim(substr($comment, 2)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'TabBefore', $data); } else if ($spaceCount === 0 && strlen($comment) > 2) { $error = 'No space found before comment text; expected "// %s" but found "%s"'; $data = [ substr($comment, 2), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceBefore', $data); }//end if if ($fix === true) { $newComment = '// '.ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } if ($spaceCount > 1) { // Check if there is a comment on the previous line that justifies the // indentation. $prevComment = $phpcsFile->findPrevious([T_COMMENT], ($stackPtr - 1), null, false); if (($prevComment !== false) && (($tokens[$prevComment]['line']) === ($tokens[$stackPtr]['line'] - 1))) { $prevCommentText = rtrim($tokens[$prevComment]['content']); $prevSpaceCount = 0; for ($i = 2; $i < strlen($prevCommentText); $i++) { if ($prevCommentText[$i] !== ' ') { break; } $prevSpaceCount++; } if ($spaceCount > $prevSpaceCount && $prevSpaceCount > 0) { // A previous comment could be a list item or @todo. $indentationStarters = [ '-', '@todo', ]; $words = preg_split('/\s+/', $prevCommentText); $numberedList = (bool) preg_match('/^[0-9]+\./', $words[1]); if (in_array($words[1], $indentationStarters) === true) { if ($spaceCount !== ($prevSpaceCount + 2)) { $error = 'Comment indentation error after %s element, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', [$words[1], ($prevSpaceCount + 2)]); if ($fix === true) { $newComment = '//'.str_repeat(' ', ($prevSpaceCount + 2)).ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } else if ($numberedList === true) { $expectedSpaceCount = ($prevSpaceCount + strlen($words[1]) + 1); if ($spaceCount !== $expectedSpaceCount) { $error = 'Comment indentation error, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', [$expectedSpaceCount]); if ($fix === true) { $newComment = '//'.str_repeat(' ', $expectedSpaceCount).ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } else { $error = 'Comment indentation error, expected only %s spaces'; $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', [$prevSpaceCount]); }//end if }//end if } else { $error = '%s spaces found before inline comment; expected "// %s" but found "%s"'; $data = [ $spaceCount, substr($comment, (2 + $spaceCount)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr, '// '.substr($comment, (2 + $spaceCount)).$phpcsFile->eolChar); } }//end if }//end if }//end processIndentation() }//end class coder_sniffer/Drupal/Test/Commenting/InlineCommentUnitTest.inc.fixed +1 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ function example_custom_block_view($delta = '') { switch ($delta) { case 'my_block': // $block['subject'] = t('custom twitter feed');. // $block['subject'] = t('custom twitter feed'); $block['content'] = test();; break; } Loading coder_sniffer/Drupal/Test/Commenting/InlineCommentUnitTest.php +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ class InlineCommentUnitTest extends CoderSniffUnitTest 24 => 1, 44 => 1, 47 => 1, 59 => 2, 59 => 1, 81 => 1, 83 => 1, ]; Loading coder_sniffer/Drupal/Test/bad/BadUnitTest.php +1 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ class BadUnitTest extends CoderSniffUnitTest 10 => 1, 12 => 1, 16 => 1, 18 => 1, 19 => 2, 20 => 1, 21 => 1, Loading coder_sniffer/Drupal/Test/bad/bad.php.fixed +1 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ // - should be only 2 additional spaces. // - this one is correct. // Blank comments are not allowed outside of a comment block. // PHP Constants should be written in CAPITAL letters // PHP Constants should be written in CAPITAL letters. // Comments should be on a separate line. TRUE; FALSE; Loading Loading
coder_sniffer/Drupal/Sniffs/Commenting/InlineCommentSniff.php +204 −185 Original line number Diff line number Diff line Loading @@ -92,12 +92,16 @@ class InlineCommentSniff implements Sniff T_ABSTRACT, T_CONST, T_PROPERTY, T_INCLUDE, T_INCLUDE_ONCE, T_REQUIRE, T_REQUIRE_ONCE, T_VAR, ]; // Also ignore all doc blocks defined in the outer scope (no scope // conditions are set). if (in_array($tokens[$nextToken]['code'], $ignore) === true if (in_array($tokens[$nextToken]['code'], $ignore, true) === true || empty($tokens[$stackPtr]['conditions']) === true ) { return; Loading Loading @@ -152,8 +156,8 @@ class InlineCommentSniff implements Sniff } } // We don't want end of block comments. If the last comment is a closing // curly brace. // We don't want end of block comments. Check if the last token before the // comment is a closing curly brace. $previousContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$previousContent]['line'] === $tokens[$stackPtr]['line']) { if ($tokens[$previousContent]['code'] === T_CLOSE_CURLY_BRACKET) { Loading @@ -171,10 +175,8 @@ class InlineCommentSniff implements Sniff } } $comment = rtrim($tokens[$stackPtr]['content']); // Only want inline comments. if (substr($comment, 0, 2) !== '//') { if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { return; } Loading @@ -183,46 +185,148 @@ class InlineCommentSniff implements Sniff return; } // Verify the indentation of this comment line. $this->processIndentation($phpcsFile, $stackPtr); $commentTokens = [$stackPtr]; // If the current line starts with a tag such as "@see" then the trailing dot // rules and upper case start rules don't apply. if (strpos(trim(substr($tokens[$stackPtr]['content'], 2)), '@') === 0) { return; $nextComment = $stackPtr; $lastComment = $stackPtr; while (($nextComment = $phpcsFile->findNext(T_COMMENT, ($nextComment + 1), null, false)) !== false) { if ($tokens[$nextComment]['line'] !== ($tokens[$lastComment]['line'] + 1)) { break; } // The below section determines if a comment block is correctly capitalised, // and ends in a full-stop. It will find the last comment in a block, and // work its way up. $nextComment = $phpcsFile->findNext([T_COMMENT], ($stackPtr + 1), null, false); if (($nextComment !== false) && (($tokens[$nextComment]['line']) === ($tokens[$stackPtr]['line'] + 1)) // A tag such as @todo means a separate comment block. && strpos(trim(substr($tokens[$nextComment]['content'], 2)), '@') !== 0 ) { return; // Only want inline comments. if (substr($tokens[$nextComment]['content'], 0, 2) !== '//') { break; } $topComment = $stackPtr; $lastComment = $stackPtr; while (($topComment = $phpcsFile->findPrevious([T_COMMENT], ($lastComment - 1), null, false)) !== false) { if ($tokens[$topComment]['line'] !== ($tokens[$lastComment]['line'] - 1)) { // There is a comment on the very next line. If there is // no code between the comments, they are part of the same // comment block. $prevNonWhitespace = $phpcsFile->findPrevious(T_WHITESPACE, ($nextComment - 1), $lastComment, true); if ($prevNonWhitespace !== $lastComment) { break; } $lastComment = $topComment; // A comment starting with "@" means a new comment section. if (preg_match('|^//[\s]*@|', $tokens[$nextComment]['content']) === 1) { break; } $topComment = $lastComment; $commentTokens[] = $nextComment; $lastComment = $nextComment; }//end while $commentText = ''; foreach ($commentTokens as $lastCommentToken) { $comment = rtrim($tokens[$lastCommentToken]['content']); if (trim(substr($comment, 2)) === '') { continue; } $spaceCount = 0; $tabFound = false; $commentLength = strlen($comment); for ($i = 2; $i < $commentLength; $i++) { if ($comment[$i] === "\t") { $tabFound = true; break; } for ($i = $topComment; $i <= $stackPtr; $i++) { if ($tokens[$i]['code'] === T_COMMENT) { $commentText .= trim(substr($tokens[$i]['content'], 2)); if ($comment[$i] !== ' ') { break; } $spaceCount++; } $fix = false; if ($tabFound === true) { $error = 'Tab found before comment text; expected "// %s" but found "%s"'; $data = [ ltrim(substr($comment, 2)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'TabBefore', $data); } else if ($spaceCount === 0) { $error = 'No space found before comment text; expected "// %s" but found "%s"'; $data = [ substr($comment, 2), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'NoSpaceBefore', $data); }//end if if ($fix === true) { $newComment = '// '.ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } if ($spaceCount > 1) { // Check if there is a comment on the previous line that justifies the // indentation. $prevComment = $phpcsFile->findPrevious([T_COMMENT], ($lastCommentToken - 1), null, false); if (($prevComment !== false) && (($tokens[$prevComment]['line']) === ($tokens[$lastCommentToken]['line'] - 1))) { $prevCommentText = rtrim($tokens[$prevComment]['content']); $prevSpaceCount = 0; for ($i = 2; $i < strlen($prevCommentText); $i++) { if ($prevCommentText[$i] !== ' ') { break; } $prevSpaceCount++; } if ($spaceCount > $prevSpaceCount && $prevSpaceCount > 0) { // A previous comment could be a list item or @todo. $indentationStarters = [ '-', '@todo', ]; $words = preg_split('/\s+/', $prevCommentText); $numberedList = (bool) preg_match('/^[0-9]+\./', $words[1]); if (in_array($words[1], $indentationStarters) === true) { if ($spaceCount !== ($prevSpaceCount + 2)) { $error = 'Comment indentation error after %s element, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', [$words[1], ($prevSpaceCount + 2)]); if ($fix === true) { $newComment = '//'.str_repeat(' ', ($prevSpaceCount + 2)).ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } } } else if ($numberedList === true) { $expectedSpaceCount = ($prevSpaceCount + strlen($words[1]) + 1); if ($spaceCount !== $expectedSpaceCount) { $error = 'Comment indentation error, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', [$expectedSpaceCount]); if ($fix === true) { $newComment = '//'.str_repeat(' ', $expectedSpaceCount).ltrim($tokens[$lastCommentToken]['content'], "/\t "); $phpcsFile->fixer->replaceToken($lastCommentToken, $newComment); } } } else { $error = 'Comment indentation error, expected only %s spaces'; $phpcsFile->addError($error, $lastCommentToken, 'SpacingBefore', [$prevSpaceCount]); }//end if }//end if } else { $error = '%s spaces found before inline comment; expected "// %s" but found "%s"'; $data = [ $spaceCount, substr($comment, (2 + $spaceCount)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'SpacingBefore', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($lastCommentToken, '// '.substr($comment, (2 + $spaceCount)).$phpcsFile->eolChar); } }//end if }//end if $commentText .= trim(substr($tokens[$lastCommentToken]['content'], 2)); }//end foreach if ($commentText === '') { $error = 'Blank comments are not allowed'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Empty'); Loading @@ -230,36 +334,37 @@ class InlineCommentSniff implements Sniff $phpcsFile->fixer->replaceToken($stackPtr, ''); } return; return ($lastCommentToken + 1); } $words = preg_split('/\s+/', $commentText); if (preg_match('|\p{Lu}|u', $commentText[0]) === 0 && $commentText[0] !== '@') { if (preg_match('/^\p{Ll}/u', $commentText) === 1) { // Allow special lower cased words that contain non-alpha characters // (function references, machine names with underscores etc.). $matches = []; preg_match('/[a-z]+/', $words[0], $matches); if (isset($matches[0]) === true && $matches[0] === $words[0]) { $error = 'Inline comments must start with a capital letter'; $fix = $phpcsFile->addFixableError($error, $topComment, 'NotCapital'); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotCapital'); if ($fix === true) { $newComment = preg_replace("/$words[0]/", ucfirst($words[0]), $tokens[$topComment]['content'], 1); $phpcsFile->fixer->replaceToken($topComment, $newComment); $newComment = preg_replace("/$words[0]/", ucfirst($words[0]), $tokens[$stackPtr]['content'], 1); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } // Only check the end of comment character if the start of the comment // is a letter, indicating that the comment is just standard text. if (preg_match('/^\p{L}/u', $commentText) === 1) { $commentCloser = $commentText[(strlen($commentText) - 1)]; $acceptedClosers = [ 'full-stops' => '.', 'exclamation marks' => '!', 'colons' => ':', 'question marks' => '?', 'colons' => ':', 'or closing parentheses' => ')', ]; // Allow @tag style comments without punctuation. if (in_array($commentCloser, $acceptedClosers) === false && $commentText[0] !== '@') { // Allow special last words like URLs or function references // without punctuation. $lastWord = $words[(count($words) - 1)]; Loading @@ -272,7 +377,9 @@ class InlineCommentSniff implements Sniff // Also allow closing tags like @endlink or @endcode. $isEndTag = $lastWord[0] === '@'; if ($isUrl === false && $isFunction === false && $isEndTag === false) { if (in_array($commentCloser, $acceptedClosers, true) === false && $isUrl === false && $isFunction === false && $isEndTag === false ) { $error = 'Inline comments must end in %s'; $ender = ''; foreach ($acceptedClosers as $closerName => $symbol) { Loading @@ -281,37 +388,59 @@ class InlineCommentSniff implements Sniff $ender = trim($ender, ' ,'); $data = [$ender]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'InvalidEndChar', $data); $fix = $phpcsFile->addFixableError($error, $lastCommentToken, 'InvalidEndChar', $data); if ($fix === true) { $newContent = preg_replace('/(\s+)$/', '.$1', $tokens[$stackPtr]['content']); $phpcsFile->fixer->replaceToken($stackPtr, $newContent); $newContent = preg_replace('/(\s+)$/', '.$1', $tokens[$lastCommentToken]['content']); $phpcsFile->fixer->replaceToken($lastCommentToken, $newContent); } } }//end if // Finally, the line below the last comment cannot be empty if this inline // comment is on a line by itself. if ($tokens[$previousContent]['line'] < $tokens[$stackPtr]['line'] && ($stackPtr + 1) < $phpcsFile->numTokens) { for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['line'] === ($tokens[$stackPtr]['line'] + 1)) { if ($tokens[$i]['code'] !== T_WHITESPACE || $i === ($phpcsFile->numTokens - 1)) { return; if ($tokens[$previousContent]['line'] < $tokens[$stackPtr]['line']) { $next = $phpcsFile->findNext(T_WHITESPACE, ($lastCommentToken + 1), null, true); if ($next === false) { // Ignore if the comment is the last non-whitespace token in a file. return ($lastCommentToken + 1); } } else if ($tokens[$i]['line'] > ($tokens[$stackPtr]['line'] + 1)) { break; if ($tokens[$next]['code'] === T_DOC_COMMENT_OPEN_TAG) { // If this inline comment is followed by a docblock, // ignore spacing as docblock/function etc spacing rules // are likely to conflict with our rules. return ($lastCommentToken + 1); } $errorCode = 'SpacingAfter'; if (isset($tokens[$stackPtr]['conditions']) === true) { $conditions = $tokens[$stackPtr]['conditions']; $type = end($conditions); $conditionPtr = key($conditions); if (($type === T_FUNCTION || $type === T_CLOSURE) && $tokens[$conditionPtr]['scope_closer'] === $next ) { $errorCode = 'SpacingAfterAtFunctionEnd'; } } $warning = 'There must be no blank line following an inline comment'; $fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'SpacingAfter'); if ($fix === true) { $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); if ($next === ($phpcsFile->numTokens - 1)) { return; for ($i = ($lastCommentToken + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['line'] === ($tokens[$lastCommentToken]['line'] + 1)) { if ($tokens[$i]['code'] !== T_WHITESPACE) { return ($lastCommentToken + 1); } } else if ($tokens[$i]['line'] > ($tokens[$lastCommentToken]['line'] + 1)) { break; } } $error = 'There must be no blank line following an inline comment'; $fix = $phpcsFile->addFixableWarning($error, $lastCommentToken, $errorCode); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); for ($i = ($stackPtr + 1); $i < $next; $i++) { for ($i = ($lastCommentToken + 1); $i < $next; $i++) { if ($tokens[$i]['line'] === $tokens[$next]['line']) { break; } Loading @@ -323,6 +452,8 @@ class InlineCommentSniff implements Sniff } }//end if return ($lastCommentToken + 1); }//end process() Loading @@ -339,6 +470,10 @@ class InlineCommentSniff implements Sniff protected function isInCodeExample(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content'] === '// @code'.$phpcsFile->eolChar) { return true; } $prevComment = $stackPtr; $lastComment = $stackPtr; while (($prevComment = $phpcsFile->findPrevious([T_COMMENT], ($lastComment - 1), null, false)) !== false) { Loading @@ -362,120 +497,4 @@ class InlineCommentSniff implements Sniff }//end isInCodeExample() /** * Checks the indentation level of the comment contents. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ protected function processIndentation(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $comment = rtrim($tokens[$stackPtr]['content']); $spaceCount = 0; $tabFound = false; $commentLength = strlen($comment); for ($i = 2; $i < $commentLength; $i++) { if ($comment[$i] === "\t") { $tabFound = true; break; } if ($comment[$i] !== ' ') { break; } $spaceCount++; } $fix = false; if ($tabFound === true) { $error = 'Tab found before comment text; expected "// %s" but found "%s"'; $data = [ ltrim(substr($comment, 2)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'TabBefore', $data); } else if ($spaceCount === 0 && strlen($comment) > 2) { $error = 'No space found before comment text; expected "// %s" but found "%s"'; $data = [ substr($comment, 2), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceBefore', $data); }//end if if ($fix === true) { $newComment = '// '.ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } if ($spaceCount > 1) { // Check if there is a comment on the previous line that justifies the // indentation. $prevComment = $phpcsFile->findPrevious([T_COMMENT], ($stackPtr - 1), null, false); if (($prevComment !== false) && (($tokens[$prevComment]['line']) === ($tokens[$stackPtr]['line'] - 1))) { $prevCommentText = rtrim($tokens[$prevComment]['content']); $prevSpaceCount = 0; for ($i = 2; $i < strlen($prevCommentText); $i++) { if ($prevCommentText[$i] !== ' ') { break; } $prevSpaceCount++; } if ($spaceCount > $prevSpaceCount && $prevSpaceCount > 0) { // A previous comment could be a list item or @todo. $indentationStarters = [ '-', '@todo', ]; $words = preg_split('/\s+/', $prevCommentText); $numberedList = (bool) preg_match('/^[0-9]+\./', $words[1]); if (in_array($words[1], $indentationStarters) === true) { if ($spaceCount !== ($prevSpaceCount + 2)) { $error = 'Comment indentation error after %s element, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', [$words[1], ($prevSpaceCount + 2)]); if ($fix === true) { $newComment = '//'.str_repeat(' ', ($prevSpaceCount + 2)).ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } else if ($numberedList === true) { $expectedSpaceCount = ($prevSpaceCount + strlen($words[1]) + 1); if ($spaceCount !== $expectedSpaceCount) { $error = 'Comment indentation error, expected %s spaces'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', [$expectedSpaceCount]); if ($fix === true) { $newComment = '//'.str_repeat(' ', $expectedSpaceCount).ltrim($tokens[$stackPtr]['content'], "/\t "); $phpcsFile->fixer->replaceToken($stackPtr, $newComment); } } } else { $error = 'Comment indentation error, expected only %s spaces'; $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', [$prevSpaceCount]); }//end if }//end if } else { $error = '%s spaces found before inline comment; expected "// %s" but found "%s"'; $data = [ $spaceCount, substr($comment, (2 + $spaceCount)), $comment, ]; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr, '// '.substr($comment, (2 + $spaceCount)).$phpcsFile->eolChar); } }//end if }//end if }//end processIndentation() }//end class
coder_sniffer/Drupal/Test/Commenting/InlineCommentUnitTest.inc.fixed +1 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ function example_custom_block_view($delta = '') { switch ($delta) { case 'my_block': // $block['subject'] = t('custom twitter feed');. // $block['subject'] = t('custom twitter feed'); $block['content'] = test();; break; } Loading
coder_sniffer/Drupal/Test/Commenting/InlineCommentUnitTest.php +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ class InlineCommentUnitTest extends CoderSniffUnitTest 24 => 1, 44 => 1, 47 => 1, 59 => 2, 59 => 1, 81 => 1, 83 => 1, ]; Loading
coder_sniffer/Drupal/Test/bad/BadUnitTest.php +1 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ class BadUnitTest extends CoderSniffUnitTest 10 => 1, 12 => 1, 16 => 1, 18 => 1, 19 => 2, 20 => 1, 21 => 1, Loading
coder_sniffer/Drupal/Test/bad/bad.php.fixed +1 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ // - should be only 2 additional spaces. // - this one is correct. // Blank comments are not allowed outside of a comment block. // PHP Constants should be written in CAPITAL letters // PHP Constants should be written in CAPITAL letters. // Comments should be on a separate line. TRUE; FALSE; Loading