From d2633f906626095aa328a11782e25ee533df79b6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 27 Mar 2020 09:41:22 +0100 Subject: [PATCH] :sparkles: PHP 7.4: New NewNumericLiteralSeparator sniff New sniff to detect PHP 7.4 numeric literals with an underscore separator. > Added support for underscore separators in numeric literals. Some examples: > > 6.674_083e-11; // float > 299_792_458; // decimal > 0xCAFE_F00D; // hexadecimal > 0b0101_1111; // binary Refs: * https://www.php.net/manual/en/migration74.new-features.php#migration74.new-features.core.numeric-literal-separator * https://github.com/php/php-src/blob/8f4e24eeef7bd1c39fabf5bea016abb287a4c606/UPGRADING#L189-L196 * https://wiki.php.net/rfc/numeric_literal_separator * https://github.com/php/php-src/pull/4165 * https://github.com/php/php-src/commit/f74109d9a4b1e4fbaeba4f68c8fc89950e19d265 Related to 808 --- .../NewNumericLiteralSeparatorSniff.php | 86 +++++++++++ .../NewNumericLiteralSeparatorUnitTest.inc | 41 +++++ .../NewNumericLiteralSeparatorUnitTest.php | 141 ++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 PHPCompatibility/Sniffs/Numbers/NewNumericLiteralSeparatorSniff.php create mode 100644 PHPCompatibility/Tests/Numbers/NewNumericLiteralSeparatorUnitTest.inc create mode 100644 PHPCompatibility/Tests/Numbers/NewNumericLiteralSeparatorUnitTest.php diff --git a/PHPCompatibility/Sniffs/Numbers/NewNumericLiteralSeparatorSniff.php b/PHPCompatibility/Sniffs/Numbers/NewNumericLiteralSeparatorSniff.php new file mode 100644 index 000000000..a5fe92461 --- /dev/null +++ b/PHPCompatibility/Sniffs/Numbers/NewNumericLiteralSeparatorSniff.php @@ -0,0 +1,86 @@ +supportsBelow('7.3') === false) { + return; + } + + try { + $numberInfo = Numbers::getCompleteNumber($phpcsFile, $stackPtr); + if ($numberInfo['orig_content'] === $numberInfo['content']) { + // Content is the same, i.e. no underscores found, move on. + return; + } + + $phpcsFile->addError( + 'The use of underscore separators in numeric literals is not supported in PHP 7.3 or lower. Found: %s', + $stackPtr, + 'Found', + array($numberInfo['orig_content']) + ); + + // Skip past the parts we've already taken into account to prevent double reporting. + return ($numberInfo['last_token'] + 1); + } catch (RuntimeException $e) { + // Running on an unsupport PHPCS version. + return; + } + } +} diff --git a/PHPCompatibility/Tests/Numbers/NewNumericLiteralSeparatorUnitTest.inc b/PHPCompatibility/Tests/Numbers/NewNumericLiteralSeparatorUnitTest.inc new file mode 100644 index 000000000..d4f4068d1 --- /dev/null +++ b/PHPCompatibility/Tests/Numbers/NewNumericLiteralSeparatorUnitTest.inc @@ -0,0 +1,41 @@ +markTestSkipped('PHPCS 3.5.3 is not supported for this sniff'); + } + + $file = $this->sniffFile(__FILE__, '7.3'); + $this->assertError($file, $line, 'The use of underscore separators in numeric literals is not supported in PHP 7.3 or lower. Found:'); + } + + /** + * Data provider. + * + * @see testNewNumericLiteralSeparator() + * + * @return array + */ + public function dataNewNumericLiteralSeparator() + { + $data = array( + array(14), + array(15), + array(16), + array(18), + array(19), + array(20), + array(21), + array(22), + array(23), + array(26), + ); + + // The test case on line 39 is half a valid numeric literal with underscore, half parse error. + // The sniff will behave differently on PHP 7.4 vs PHP < 7.4. + if (version_compare(\PHP_VERSION_ID, '70399', '>') || version_compare(Helper::getVersion(), '3.5.3', '<')) { + $data[] = array(41); + } + + return $data; + } + + + /** + * Verify there are no false positives for a PHP version on which this sniff throws errors. + * + * @dataProvider dataNoFalsePositives + * + * @param int $line The line number. + * + * @return void + */ + public function testNoFalsePositives($line) + { + $file = $this->sniffFile(__FILE__, '7.3'); + $this->assertNoViolation($file, $line); + } + + /** + * Data provider. + * + * @see testNoFalsePositives() + * + * @return array + */ + public function dataNoFalsePositives() + { + $data = array(); + + // No issues expected on the first 12 lines. + for ($i = 1; $i <= 12; $i++) { + $data[] = array($i); + } + + // Parse errors, should be ignored by the sniff. + $data[] = array(31); + $data[] = array(32); + $data[] = array(33); + $data[] = array(34); + $data[] = array(35); + $data[] = array(36); + $data[] = array(37); + $data[] = array(38); + + // The test case on line 39 is half a valid numeric literal with underscore, half parse error. + // The sniff will behave differently on PHP 7.4 vs PHP < 7.4. + if (version_compare(\PHP_VERSION_ID, '70399', '<=') && version_compare(Helper::getVersion(), '3.5.3', '>')) { + $data[] = array(41); + } + + return $data; + } + + + /** + * Verify no notices are thrown at all. + * + * @return void + */ + public function testNoViolationsInFileOnValidVersion() + { + $file = $this->sniffFile(__FILE__, '7.4'); + $this->assertNoViolation($file); + } +}