diff --git a/package.xml b/package.xml index a4ff185840..3f974048e3 100644 --- a/package.xml +++ b/package.xml @@ -55,6 +55,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> - Squiz ComparisonOperatorUsageSniff no longer hangs on JS FOR loops that don't use semicolons - PHP_CodesSniffer now includes the composer autoload.php file, if there is one -- Thanks to Klaus Purer for the patch + - PEAR and Squiz FunctionComment sniffs now support variadic functions (request #841) - Fixed bug #622 : Wrong detection of Squiz.CSS.DuplicateStyleDefinition with media queries - Fixed bug #752 : The missing exception error is reported in first found DocBlock - Fixed bug #794 : PSR2 MultiLineFunctionDeclaration forbids comments after opening parenthesis of a multiline call diff --git a/src/Files/File.php b/src/Files/File.php index c83f3a1b10..05585bce26 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -1200,6 +1200,7 @@ public function getMethodParameters($stackPtr) $defaultStart = null; $paramCount = 0; $passByReference = false; + $variableLength = false; $typeHint = ''; for ($i = ($opener + 1); $i <= $closer; $i++) { @@ -1228,6 +1229,9 @@ public function getMethodParameters($stackPtr) case T_VARIABLE: $currVar = $i; break; + case T_ELLIPSIS: + $variableLength = true; + break; case T_ARRAY_HINT: case T_CALLABLE: $typeHint = $this->tokens[$i]['content']; @@ -1287,11 +1291,13 @@ public function getMethodParameters($stackPtr) } $vars[$paramCount]['pass_by_reference'] = $passByReference; + $vars[$paramCount]['variable_length'] = $variableLength; $vars[$paramCount]['type_hint'] = $typeHint; // Reset the vars, as we are about to process the next parameter. $defaultStart = null; $passByReference = false; + $variableLength = false; $typeHint = ''; $paramCount++; diff --git a/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php b/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php index 01e7d7b0c2..d55b4b3965 100644 --- a/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php +++ b/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php @@ -213,7 +213,7 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $comment = ''; if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) { $matches = array(); - preg_match('/([^$&]+)(?:((?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); + preg_match('/([^$&.]+)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); $typeLen = strlen($matches[1]); $type = trim($matches[1]); @@ -272,6 +272,14 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $realParams = $phpcsFile->getMethodParameters($stackPtr); $foundParams = array(); + // We want to use ... for all variable length arguments, so added + // this prefix to the variable name so comparisons are easier. + foreach ($realParams as $pos => $param) { + if ($param['variable_length'] === true) { + $realParams[$pos]['name'] = '...'.$realParams[$pos]['name']; + } + } + foreach ($params as $pos => $param) { if ($param['var'] === '') { continue; diff --git a/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc b/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc index 77e68175d6..83f99b9e23 100644 --- a/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc +++ b/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc @@ -297,3 +297,26 @@ class Baz { public function completeStep($status, array $array = [Class1::class, 'test'], $note = '') { echo 'foo'; } + +/** + * Variadic function. + * + * @param string $name1 Comment. + * @param string ...$name2 Comment. + * + * @return void + */ +public function myFunction(string $name1, string ...$name2) { +} + + +/** + * Variadic function. + * + * @param string $name1 Comment. + * @param string $name2 Comment. + * + * @return void + */ +public function myFunction(string $name1, string ...$name2) { +} diff --git a/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php b/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php index b0dd789fb8..b77ca30448 100644 --- a/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php +++ b/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php @@ -55,6 +55,8 @@ public function getErrorList() 206 => 1, 234 => 1, 272 => 1, + 313 => 1, + 317 => 1, ); }//end getErrorList() diff --git a/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php b/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php index 2011f859cc..f837486705 100644 --- a/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php +++ b/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php @@ -235,7 +235,7 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $commentLines = array(); if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) { $matches = array(); - preg_match('/([^$&]+)(?:((?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); + preg_match('/([^$&.]+)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); $typeLen = strlen($matches[1]); $type = trim($matches[1]); @@ -311,6 +311,14 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $realParams = $phpcsFile->getMethodParameters($stackPtr); $foundParams = array(); + // We want to use ... for all variable length arguments, so added + // this prefix to the variable name so comparisons are easier. + foreach ($realParams as $pos => $param) { + if ($param['variable_length'] === true) { + $realParams[$pos]['name'] = '...'.$realParams[$pos]['name']; + } + } + foreach ($params as $pos => $param) { // If the type is empty, the whole line is empty. if ($param['type'] === '') { diff --git a/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc b/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc index f315012a0e..683e3172e1 100644 --- a/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc +++ b/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc @@ -728,3 +728,26 @@ public function callableCallback(callable $cb) { */ public function myFunction (string $name1, int $name2, float $name3, bool $name4) { } + +/** + * Variadic function. + * + * @param string $name1 Comment. + * @param string ...$name2 Comment. + * + * @return void + */ +public function myFunction(string $name1, string ...$name2) { +} + + +/** + * Variadic function. + * + * @param string $name1 Comment. + * @param string $name2 Comment. + * + * @return void + */ +public function myFunction(string $name1, string ...$name2) { +} diff --git a/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.php b/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.php index afa754fe6f..3039b42913 100644 --- a/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.php +++ b/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.php @@ -95,6 +95,8 @@ public function getErrorList() 548 => 1, 641 => 1, 669 => 1, + 744 => 1, + 748 => 1, ); // The yield tests will only work in PHP versions where yield exists and @@ -117,6 +119,8 @@ public function getErrorList() $errors[627] = 1; } else { $errors[729] = 4; + $errors[740] = 2; + $errors[752] = 2; } return $errors; diff --git a/tests/Core/File/GetMethodParametersTest.php b/tests/Core/File/GetMethodParametersTest.php index 601b19049b..f2683a63bf 100644 --- a/tests/Core/File/GetMethodParametersTest.php +++ b/tests/Core/File/GetMethodParametersTest.php @@ -69,6 +69,7 @@ public function testPassByReference() $expected[0] = array( 'name' => '$var', 'pass_by_reference' => true, + 'variable_length' => false, 'type_hint' => '', ); @@ -98,6 +99,7 @@ public function testArrayHint() $expected[0] = array( 'name' => '$var', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => 'array', ); @@ -127,12 +129,14 @@ public function testTypeHint() $expected[0] = array( 'name' => '$var1', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => 'foo', ); $expected[1] = array( 'name' => '$var2', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => 'bar', ); @@ -162,6 +166,7 @@ public function testVariable() $expected[0] = array( 'name' => '$var', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => '', ); @@ -192,6 +197,7 @@ public function testSingleDefaultValue() 'name' => '$var1', 'default' => 'self::CONSTANT', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => '', ); @@ -222,12 +228,14 @@ public function testDefaultValues() 'name' => '$var1', 'default' => '1', 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => '', ); $expected[1] = array( 'name' => '$var2', 'default' => "'value'", 'pass_by_reference' => false, + 'variable_length' => false, 'type_hint' => '', );