Skip to content

Commit

Permalink
PEAR/FunctionDeclaration: examine arrow function declarations
Browse files Browse the repository at this point in the history
PHP 7.4 arrow functions were not yet being taken into account for this sniff.

Fixed now.
Includes unit tests.
  • Loading branch information
jrfnl committed Sep 11, 2022
1 parent b860f75 commit 87aa11f
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 12 deletions.
53 changes: 41 additions & 12 deletions src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function register()
return [
T_FUNCTION,
T_CLOSURE,
T_FN,
];

}//end register()
Expand Down Expand Up @@ -75,7 +76,9 @@ public function process(File $phpcsFile, $stackPtr)
$openBracket = $tokens[$stackPtr]['parenthesis_opener'];
$closeBracket = $tokens[$stackPtr]['parenthesis_closer'];

if (strtolower($tokens[$stackPtr]['content']) === 'function') {
if (strtolower($tokens[$stackPtr]['content']) === 'function'
|| strtolower($tokens[$stackPtr]['content']) === 'fn'
) {
// Must be one space after the FUNCTION keyword.
if ($tokens[($stackPtr + 1)]['content'] === $phpcsFile->eolChar) {
$spaces = 'newline';
Expand All @@ -86,9 +89,13 @@ public function process(File $phpcsFile, $stackPtr)
}

if ($spaces !== 1) {
$error = 'Expected 1 space after FUNCTION keyword; %s found';
$data = [$spaces];
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterFunction', $data);
$error = 'Expected 1 space after %s keyword; %s found';
$data = [
strtoupper($tokens[$stackPtr]['content']),
$spaces,
];

$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterFunction', $data);
if ($fix === true) {
if ($spaces === 0) {
$phpcsFile->fixer->addContent($stackPtr, ' ');
Expand All @@ -99,9 +106,9 @@ public function process(File $phpcsFile, $stackPtr)
}
}//end if

// Must be no space before the opening parenthesis. For closures, this is
// enforced by the previous check because there is no content between the keywords
// and the opening parenthesis.
// Must be no space before the opening parenthesis. For closures and arrow functions,
// this is enforced by the previous check because there is no content between
// the keywords and the opening parenthesis.
// Unfinished closures are tokenized as T_FUNCTION however, and can be excluded
// by checking for the scope_opener.
if ($tokens[$stackPtr]['code'] === T_FUNCTION
Expand Down Expand Up @@ -257,6 +264,10 @@ public function isMultiLineDeclaration($phpcsFile, $stackPtr, $openBracket, $tok
*/
public function processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens)
{
if ($tokens[$stackPtr]['code'] === T_FN) {
return;
}

if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
$sniff = new OpeningFunctionBraceKernighanRitchieSniff();
} else {
Expand Down Expand Up @@ -300,12 +311,20 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
// The opening brace needs to be one space away from the closing parenthesis.
$opener = $tokens[$stackPtr]['scope_opener'];
if ($tokens[$opener]['line'] !== $tokens[$closeBracket]['line']) {
$error = 'The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line';
$fix = $phpcsFile->addFixableError($error, $opener, 'NewlineBeforeOpenBrace');
$error = 'The closing parenthesis and the %s of a multi-line function declaration must be on the same line';
$code = 'NewlineBeforeOpenBrace';
$data = ['opening brace'];

if ($tokens[$stackPtr]['code'] === T_FN) {
$code = 'NewlineBeforeArrow';
$data = ['arrow'];
}

$fix = $phpcsFile->addFixableError($error, $opener, $code, $data);
if ($fix === true) {
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), $closeBracket, true);
$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->addContent($prev, ' {');
$phpcsFile->fixer->addContent($prev, ' '.$tokens[$opener]['content']);

// If the opener is on a line by itself, removing it will create
// an empty line, so just remove the entire line instead.
Expand Down Expand Up @@ -340,8 +359,18 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
}

if ($length !== 1) {
$error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found %s spaces';
$fix = $phpcsFile->addFixableError($error, ($opener - 1), 'SpaceBeforeOpenBrace', [$length]);
$error = 'There must be a single space between the closing parenthesis and the %s of a multi-line function declaration; found %s spaces';
$code = 'SpaceBeforeOpenBrace';
$data = ['opening brace'];

if ($tokens[$stackPtr]['code'] === T_FN) {
$code = 'SpaceBeforeArrow';
$data = ['arrow'];
}

$data[] = $length;

$fix = $phpcsFile->addFixableError($error, ($opener - 1), $code, $data);
if ($fix === true) {
if ($length === 0) {
$phpcsFile->fixer->addContentBefore($opener, ' ');
Expand Down
21 changes: 21 additions & 0 deletions src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,24 @@ class ConstructorPropertyPromotionMultiLineAttributesIncorrectIndent
// Do something.
}
}

$arrowNoArgs = fn () => $retrievedfromscope;

$arrowSingleLineArgs = fn (Type $param1, int $param2, string $param3): \ReturnType => $retrievedfromscope;

$arrowMultiLineArgs = fn (
$longVar1,
$longerVar2,
&...$muchLongerVar3
) => $longVar1;

$arrowNoArgs = fn( )
=> $retrievedfromscope;

$arrowSingleLineArgs = fn( Type $param1 , int $param2, string $param3
) : \ReturnType => $retrievedfromscope;

$arrowMultiLineArgs = fn (
$longVar1, $longerVar2,

& ... $muchLongerVar3) => $longVar1;
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,24 @@ class ConstructorPropertyPromotionMultiLineAttributesIncorrectIndent
// Do something.
}
}

$arrowNoArgs = fn () => $retrievedfromscope;

$arrowSingleLineArgs = fn (Type $param1, int $param2, string $param3): \ReturnType => $retrievedfromscope;

$arrowMultiLineArgs = fn (
$longVar1,
$longerVar2,
&...$muchLongerVar3
) => $longVar1;

$arrowNoArgs = fn ( )
=> $retrievedfromscope;

$arrowSingleLineArgs = fn ( Type $param1 , int $param2, string $param3
) : \ReturnType => $retrievedfromscope;

$arrowMultiLineArgs = fn (
$longVar1, $longerVar2,
& ... $muchLongerVar3
) => $longVar1;
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public function getErrorList($testFile='FunctionDeclarationUnitTest.inc')
371 => 1,
402 => 1,
406 => 1,
432 => 1,
435 => 1,
436 => 2,
440 => 1,
441 => 2,
];
} else {
$errors = [
Expand Down

0 comments on commit 87aa11f

Please sign in to comment.