From 66ddbf44c5a484f0f018baf40976ef17bf266e4c Mon Sep 17 00:00:00 2001 From: Dan Wallis Date: Wed, 31 Jul 2024 15:19:34 +0100 Subject: [PATCH] Support multi-directive statements --- .../Sniffs/Files/DeclareStatementSniff.php | 107 ++++++++++-------- .../Files/DeclareStatementUnitTest.1.inc | 12 ++ .../DeclareStatementUnitTest.1.inc.fixed | 12 ++ 3 files changed, 83 insertions(+), 48 deletions(-) diff --git a/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php b/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php index 10e632795b..c931bca9ea 100644 --- a/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php +++ b/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php @@ -82,70 +82,81 @@ public function process(File $phpcsFile, $stackPtr) $closeParen = $tokens[$openParen]['parenthesis_closer']; - $directive = $phpcsFile->findNext(T_STRING, ($openParen + 1), $closeParen); + $tokenBeforeDirective = $openParen; - if ($directive === false) { - // Live coding / parse error. - return; - } + do { + $directive = $phpcsFile->findNext(T_STRING, ($tokenBeforeDirective + 1), $closeParen); - // There should be no space between open parenthesis and the directive. - $this->complainIfTokensNotAdjacent( - $phpcsFile, - $openParen, - $directive, - 'SpaceFoundBeforeDirective' - ); + if ($directive === false) { + // Live coding / parse error. + return; + } - // The directive must be in lowercase. - if ($tokens[$directive]['content'] !== strtolower($tokens[$directive]['content'])) { - $error = 'The directive of a declare statement must be in lowercase'; - $fix = $phpcsFile->addFixableError($error, $directive, 'DirectiveNotLowercase'); - if ($fix === true) { - $phpcsFile->fixer->replaceToken($directive, strtolower($tokens[$directive]['content'])); + if ($tokens[$tokenBeforeDirective]['code'] === T_OPEN_PARENTHESIS) { + // There should be no space between open parenthesis and the directive. + $this->complainIfTokensNotAdjacent( + $phpcsFile, + $tokenBeforeDirective, + $directive, + 'SpaceFoundBeforeDirective' + ); + // There's no 'else' clause here, because PSR12 makes no mention of + // formatting of the comma in a multi-directive statement. } - } - // When wishing to declare strict types in files containing markup outside PHP opening - // and closing tags, the declaration MUST be on the first line of the file and include - // an opening PHP tag, the strict types declaration and closing tag. - if ($tokens[$stackPtr]['line'] !== 1 && strtolower($tokens[$directive]['content']) === 'strict_types') { - $nonPHP = $phpcsFile->findNext(T_INLINE_HTML, 0); - if ($nonPHP !== false) { - $error = 'When declaring strict_types in a file with markup outside PHP tags, the declare statement must be on the first line'; - $phpcsFile->addError($error, $stackPtr, 'DeclareNotOnFirstLine'); + // The directive must be in lowercase. + if ($tokens[$directive]['content'] !== strtolower($tokens[$directive]['content'])) { + $error = 'The directive of a declare statement must be in lowercase'; + $fix = $phpcsFile->addFixableError($error, $directive, 'DirectiveNotLowercase'); + if ($fix === true) { + $phpcsFile->fixer->replaceToken($directive, strtolower($tokens[$directive]['content'])); + } } - } - $equals = $phpcsFile->findNext(T_EQUAL, ($directive + 1), $closeParen); + // When wishing to declare strict types in files containing markup outside PHP opening + // and closing tags, the declaration MUST be on the first line of the file and include + // an opening PHP tag, the strict types declaration and closing tag. + if ($tokens[$stackPtr]['line'] !== 1 && strtolower($tokens[$directive]['content']) === 'strict_types') { + $nonPHP = $phpcsFile->findNext(T_INLINE_HTML, 0); + if ($nonPHP !== false) { + $error = 'When declaring strict_types in a file with markup outside PHP tags, the declare statement must be on the first line'; + $phpcsFile->addError($error, $stackPtr, 'DeclareNotOnFirstLine'); + } + } - if ($equals === false) { - // Live coding / parse error. - return; - } + $equals = $phpcsFile->findNext(T_EQUAL, ($directive + 1), $closeParen); - // There should be no space between directive and the equal sign. - $this->complainIfTokensNotAdjacent( - $phpcsFile, - $directive, - $equals, - 'SpaceFoundAfterDirective' - ); + if ($equals === false) { + // Live coding / parse error. + return; + } - $value = $phpcsFile->findNext([T_LNUMBER, T_CONSTANT_ENCAPSED_STRING], ($equals + 1), $closeParen); + // There should be no space between directive and the equal sign. + $this->complainIfTokensNotAdjacent( + $phpcsFile, + $directive, + $equals, + 'SpaceFoundAfterDirective' + ); - if ($value === false) { - // Live coding / parse error. - return; - } + $value = $phpcsFile->findNext([T_LNUMBER, T_CONSTANT_ENCAPSED_STRING], ($equals + 1), $closeParen); - // There should be no space between equals sign and directive value. - $this->complainIfTokensNotAdjacent( + if ($value === false) { + // Live coding / parse error. + return; + } + + // There should be no space between equals sign and directive value. + $this->complainIfTokensNotAdjacent( $phpcsFile, $equals, $value, 'SpaceFoundBeforeDirectiveValue' - ); + ); + + // Handle multi-directive statements. + $tokenBeforeDirective = $phpcsFile->findNext(T_COMMA, $value + 1, $closeParen); + } while ($tokenBeforeDirective !== false); // $closeParen was defined earlier as $closeParen = $tokens[$openParen]['parenthesis_closer']; // There should be no space between directive value and closing parenthesis. diff --git a/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc b/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc index b1313267da..5fbfa6ec37 100644 --- a/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc +++ b/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc @@ -52,3 +52,15 @@ declare(ticks=1) { $test = true; // Ensure that we handle non-number values properly. declare(encoding='ISO-8859-1'); declare ( encoding = 'ISO-8859-1' ) ; + +// Multi-directive statements should be handled correctly too. +declare(strict_types=1,ticks=1); +// Note that PSR12 makes no mention of the formatting of the comma, so all of these should be valid. +declare(strict_types=1, ticks=1); +declare(strict_types=1, ticks=1); +declare(strict_types=1, +ticks=1); +declare(strict_types=1, + ticks=1); +declare(strict_types=1 , ticks=1); +declare(strict_types=1 ,ticks=1); diff --git a/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc.fixed b/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc.fixed index c50517ceca..ec6ec64cea 100644 --- a/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc.fixed +++ b/src/Standards/PSR12/Tests/Files/DeclareStatementUnitTest.1.inc.fixed @@ -60,3 +60,15 @@ declare(ticks=1) { // Ensure that we handle non-number values properly. declare(encoding='ISO-8859-1'); declare(encoding='ISO-8859-1'); + +// Multi-directive statements should be handled correctly too. +declare(strict_types=1,ticks=1); +// Note that PSR12 makes no mention of the formatting of the comma, so all of these should be valid. +declare(strict_types=1, ticks=1); +declare(strict_types=1, ticks=1); +declare(strict_types=1, +ticks=1); +declare(strict_types=1, + ticks=1); +declare(strict_types=1 , ticks=1); +declare(strict_types=1 ,ticks=1);