diff --git a/coder_sniffer/Drupal/Sniffs/Arrays/ArraySniff.php b/coder_sniffer/Drupal/Sniffs/Arrays/ArraySniff.php index 1487570c..93660b3c 100644 --- a/coder_sniffer/Drupal/Sniffs/Arrays/ArraySniff.php +++ b/coder_sniffer/Drupal/Sniffs/Arrays/ArraySniff.php @@ -113,18 +113,13 @@ public function process(File $phpcsFile, $stackPtr) if ($isInlineArray === true) { // Check if this array has more than one element and exceeds the // line length defined by $this->lineLimit. - $currentLine = $tokens[$stackPtr]['line']; - $tokenCount = $stackPtr; - while ($tokenCount < ($phpcsFile->numTokens - 1) && $tokens[($tokenCount + 1)]['line'] === $currentLine) { - $tokenCount++; - }; - $lineLength = ($tokens[$tokenCount]['column'] + $tokens[$tokenCount]['length'] - 1); - - if ($lineLength > $this->lineLimit) { + $arrayEnding = $tokens[$tokens[$stackPtr][$parenthesisCloser]]['column']; + + if ($arrayEnding > $this->lineLimit) { $comma1 = $phpcsFile->findNext(T_COMMA, ($stackPtr + 1), $tokens[$stackPtr][$parenthesisCloser]); if ($comma1 !== false) { - $error = 'The array declaration line has %s characters (the limit is %s). The array content should be split up over multiple lines'; - $phpcsFile->addError($error, $stackPtr, 'LongLineDeclaration', [$lineLength, $this->lineLimit]); + $error = 'The array declaration extends to column %s (the limit is %s). The array content should be split up over multiple lines'; + $phpcsFile->addError($error, $stackPtr, 'LongLineDeclaration', [$arrayEnding, $this->lineLimit]); } } diff --git a/coder_sniffer/Drupal/Sniffs/Commenting/TodoCommentSniff.php b/coder_sniffer/Drupal/Sniffs/Commenting/TodoCommentSniff.php new file mode 100644 index 00000000..c804a87c --- /dev/null +++ b/coder_sniffer/Drupal/Sniffs/Commenting/TodoCommentSniff.php @@ -0,0 +1,158 @@ + + */ + public function register() + { + if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { + $this->debug = false; + } + + return [ + T_COMMENT, + T_DOC_COMMENT_TAG, + T_DOC_COMMENT_STRING, + ]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @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 + */ + public function process(File $phpcsFile, $stackPtr) + { + $debug = Config::getConfigData('todo_debug'); + if ($debug !== null) { + $this->debug = (bool) $debug; + } + + $tokens = $phpcsFile->getTokens(); + if ($this->debug === true) { + echo "\n------\n\$tokens[$stackPtr] = ".print_r($tokens[$stackPtr], true).PHP_EOL; + echo 'code = '.$tokens[$stackPtr]['code'].', type = '.$tokens[$stackPtr]['type']."\n"; + } + + // Standard comments and multi-line comments where the "@" is missing so + // it does not register as a T_DOC_COMMENT_TAG. + if ($tokens[$stackPtr]['code'] === T_COMMENT || $tokens[$stackPtr]['code'] === T_DOC_COMMENT_STRING) { + $comment = $tokens[$stackPtr]['content']; + if ($this->debug === true) { + echo "Getting \$comment from \$tokens[$stackPtr]['content']\n"; + } + + $this->checkTodoFormat($phpcsFile, $stackPtr, $comment); + } else if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_TAG) { + // Document comment tag (i.e. comments that begin with "@"). + // Determine if this is related at all and build the full comment line + // from the various segments that the line is parsed into. + $expression = '/^@to/i'; + $comment = $tokens[$stackPtr]['content']; + if ((bool) preg_match($expression, $comment) === true) { + if ($this->debug === true) { + echo "Attempting to build comment\n"; + } + + $index = ($stackPtr + 1); + while ($tokens[$index]['line'] === $tokens[$stackPtr]['line']) { + $comment .= $tokens[$index]['content']; + $index++; + } + + if ($this->debug === true) { + echo "Result comment = $comment\n"; + } + + $this->checkTodoFormat($phpcsFile, $stackPtr, $comment); + }//end if + }//end if + + }//end process() + + + /** + * Checks a comment string for the correct syntax. + * + * @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. + * @param string $comment The comment text. + * + * @return void + */ + private function checkTodoFormat(File $phpcsFile, $stackPtr, string $comment) + { + if ($this->debug === true) { + echo "Checking \$comment = '$comment'\n"; + } + + $expression = '/(?x) # Set free-space mode to allow this commenting + ^(\/\/)? # At the start optionally match two forward slashes + \s* # then any amount of whitespace + (?i) # set case-insensitive mode + (?=( # start a postive non-consuming look-ahead to find all possible todos + @+to(-|\s|)+do # if one or more @ allow space or - between the to and do + | # or + to(-)*do # if no @ then only accept todo or to-do or to--do, etc + )) + (?-i) # Reset to case-sensitive + (?! # Start another non-consuming look-ahead, this time negative + @todo\s # It has to match lower-case @todo followed by one space + (?!-|:)\S # and then any non-space except - or : + )/m'; + + if ((bool) preg_match($expression, $comment) === true) { + if ($this->debug === true) { + echo "Failed regex - give message\n"; + } + + $comment = trim($comment, " /\r\n"); + $phpcsFile->addError("'%s' should match the format '@todo Some task'", $stackPtr, 'TodoFormat', [$comment]); + } + + }//end checkTodoFormat() + + +}//end class diff --git a/coder_sniffer/Drupal/ruleset.xml b/coder_sniffer/Drupal/ruleset.xml index dadea2bf..bc8ec695 100644 --- a/coder_sniffer/Drupal/ruleset.xml +++ b/coder_sniffer/Drupal/ruleset.xml @@ -280,6 +280,7 @@ + diff --git a/tests/Drupal/Arrays/ArrayUnitTest.1.inc b/tests/Drupal/Arrays/ArrayUnitTest.1.inc index 8a09e63d..101b2737 100644 --- a/tests/Drupal/Arrays/ArrayUnitTest.1.inc +++ b/tests/Drupal/Arrays/ArrayUnitTest.1.inc @@ -18,4 +18,8 @@ $array = array( 'inline_two_elements_ok' => array('one-two-three', 'the-2nd-element-is-within-the-limit'), 'inline_two_elements_ok2' => array('one-two-three-four', 'the-2nd-element-is-right-on-the-limit'), 'inline_two_elements_not_ok' => array('one-two-three-four-five', 'the-2nd-element-extends-beyond-the-limit'), + 'inline_two_elements_ok3' => func(['one-two-three-four', 'five'], 'other text which goes past the limit'), + 'inline_two_elements_ok4' => func(['one-two-three-four', 'this-2nd-element-is-right-on-the-limit'], 'other text'), + 'inline_two_elements_ok5' => func(['one-two-three-four'], ['second_array' => 'this-is-ok'], 'other text'), + 'inline_two_elements_not_ok' => func(['one-two'], ['second_array' => 'three', 'four-five' => 'six'], 'other text'), ); diff --git a/tests/Drupal/Arrays/ArrayUnitTest.php b/tests/Drupal/Arrays/ArrayUnitTest.php index bd954561..f6e38b7b 100644 --- a/tests/Drupal/Arrays/ArrayUnitTest.php +++ b/tests/Drupal/Arrays/ArrayUnitTest.php @@ -32,9 +32,9 @@ protected function getErrorList(string $testFile): array case 'ArrayUnitTest.1.inc': return [ 14 => 1, - 15 => 1, 17 => 1, 20 => 1, + 24 => 1, ]; } diff --git a/tests/Drupal/Commenting/TodoCommentUnitTest.inc b/tests/Drupal/Commenting/TodoCommentUnitTest.inc new file mode 100644 index 00000000..fd06b1b5 --- /dev/null +++ b/tests/Drupal/Commenting/TodoCommentUnitTest.inc @@ -0,0 +1,61 @@ + + */ + protected function getErrorList(string $testFile): array + { + $errorList = (array_fill_keys(range(13, 31), 1) + array_fill_keys(range(42, 60), 1)); + return $errorList; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @param string $testFile The name of the file being tested. + * + * @return array + */ + protected function getWarningList(string $testFile): array + { + return []; + + }//end getWarningList() + + +}//end class diff --git a/tests/Drupal/bad/BadUnitTest.php b/tests/Drupal/bad/BadUnitTest.php index 43b5c203..473b24d4 100644 --- a/tests/Drupal/bad/BadUnitTest.php +++ b/tests/Drupal/bad/BadUnitTest.php @@ -376,7 +376,8 @@ protected function getErrorList(string $testFile): array 827 => 1, 829 => 1, 836 => 1, - 838 => 2, + 846 => 2, + 852 => 2, ]; }//end switch diff --git a/tests/Drupal/bad/bad.php b/tests/Drupal/bad/bad.php index 6e9fa345..bcdfa21d 100644 --- a/tests/Drupal/bad/bad.php +++ b/tests/Drupal/bad/bad.php @@ -835,4 +835,18 @@ function test28() { // Multiple statements on one line are not allowed. echo 'Hi!';; +/** + * A test class. + */ +class ScopeKeyword { + + /** + * Much weird spacing here. + */ + public static function test() { + + } + +} + ?> \ No newline at end of file diff --git a/tests/Drupal/bad/bad.php.fixed b/tests/Drupal/bad/bad.php.fixed index 4eeb3137..bb85c050 100644 --- a/tests/Drupal/bad/bad.php.fixed +++ b/tests/Drupal/bad/bad.php.fixed @@ -882,3 +882,17 @@ function test28() { // Multiple statements on one line are not allowed. echo 'Hi!'; ; + +/** + * A test class. + */ +class ScopeKeyword { + + /** + * Much weird spacing here. + */ + public static function test() { + + } + +} diff --git a/tests/Drupal/good/good.php b/tests/Drupal/good/good.php index 0efcf91c..2f36e561 100644 --- a/tests/Drupal/good/good.php +++ b/tests/Drupal/good/good.php @@ -1185,10 +1185,10 @@ function test6(array $names) { /** * Some short description. * - * @todo TODOs are allowed here. - * * @param string $x * Some parameter. + * + * @todo These are allowed here. */ function test7($x) { @@ -1205,8 +1205,8 @@ class ListContainsTest extends RulesIntegrationTestBase {} /** * Provides a 'Delete any path alias' action. * - * @todo: Add access callback information from Drupal 7. - * @todo: Add group information from Drupal 7. + * @todo Add access callback information from Drupal 7. + * @todo Add group information from Drupal 7. * * @Action( * id = "rules_path_alias_delete",