diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ac9fc0a0..9e9d024d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -13,15 +13,11 @@ jobs: fail-fast: false matrix: php-version: - - "7.4" - - "8.0" - "8.1" + - "8.2" dependencies: - "lowest" - "highest" - exclude: - - php-version: "8.1" - dependencies: "lowest" name: Tests with PHP ${{ matrix.php-version }} and ${{ matrix.dependencies }} dependencies steps: @@ -93,4 +89,4 @@ jobs: run: composer install - name: Run rector - run: vendor/bin/rector process Magento2 Magento2Framework PHP_CodeSniffer --dry-run --autoload-file vendor/squizlabs/php_codesniffer/autoload.php --autoload-file vendor/phpcompatibility/php-compatibility/PHPCSAliases.php + run: vendor/bin/rector process Magento2 Magento2Framework PHP_CodeSniffer --dry-run --autoload-file vendor/squizlabs/php_codesniffer/autoload.php --autoload-file vendor/magento/php-compatibility-fork/PHPCSAliases.php diff --git a/.gitignore b/.gitignore index 422a08ec..d0326eff 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ .phpunit.result.cache .DS_Store +phpunit.xml diff --git a/Magento2/Helpers/Assert.php b/Magento2/Helpers/Assert.php new file mode 100644 index 00000000..9b3eb0dc --- /dev/null +++ b/Magento2/Helpers/Assert.php @@ -0,0 +1,55 @@ +getTokens(); + $nextPtr = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($nextPtr === false + || $tokens[$nextPtr]['code'] !== \T_OPEN_PARENTHESIS + || isset($tokens[$nextPtr]['parenthesis_owner']) + ) { + return false; + } + + $prevPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($prevPtr !== false) { + if (isset(Collections::objectOperators()[$tokens[$prevPtr]['code']]) + || $tokens[$prevPtr]['code'] === \T_NEW + ) { + return false; + } + + if ($tokens[$prevPtr]['code'] === \T_NS_SEPARATOR) { + $prevPrevPr = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prevPtr - 1), null, true); + if ($prevPrevPr !== false && \in_array($tokens[$prevPrevPr]['code'], [\T_STRING, \T_NAMESPACE], true)) { + return false; + } + } + } + + return true; + } +} diff --git a/Magento2/Helpers/PHPCSUtils/BackCompat/BCTokens.php b/Magento2/Helpers/PHPCSUtils/BackCompat/BCTokens.php deleted file mode 100644 index 4542f9c6..00000000 --- a/Magento2/Helpers/PHPCSUtils/BackCompat/BCTokens.php +++ /dev/null @@ -1,109 +0,0 @@ - => - */ - private static $ooScopeTokens = [ - \T_CLASS => \T_CLASS, - \T_ANON_CLASS => \T_ANON_CLASS, - \T_INTERFACE => \T_INTERFACE, - \T_TRAIT => \T_TRAIT, - ]; - - /** - * Tokens that open class and object scopes. - * - * Retrieve the OO scope tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 3.1.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$ooScopeTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function ooScopeTokens() - { - return self::$ooScopeTokens; - } - - /** - * Tokens that represent arithmetic operators. - * - * Retrieve the PHPCS arithmetic tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.5.0. - * - PHPCS 2.9.0: The PHP 5.6 `T_POW` token was added to the array. - * The `T_POW` token was introduced in PHPCS 2.4.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$arithmeticTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array or an empty array for PHPCS versions in - * which the PHPCS native comment tokens did not exist yet. - */ - public static function arithmeticTokens() - { - return Tokens::$arithmeticTokens + [\T_POW => \T_POW]; - } - - /** - * Tokens that represent assignment operators. - * - * Retrieve the PHPCS assignment tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.0.5. - * - PHPCS 2.9.0: The PHP 7.4 `T_COALESCE_EQUAL` token was added to the array. - * The `T_COALESCE_EQUAL` token was introduced in PHPCS 2.8.1. - * - PHPCS 3.2.0: The JS `T_ZSR_EQUAL` token was added to the array. - * The `T_ZSR_EQUAL` token was introduced in PHPCS 2.8.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$assignmentTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function assignmentTokens() - { - $tokens = Tokens::$assignmentTokens; - - /* - * The `T_COALESCE_EQUAL` token may be available pre-PHPCS 2.8.1 depending on - * the PHP version used to run PHPCS. - */ - if (\defined('T_COALESCE_EQUAL')) { - $tokens[\T_COALESCE_EQUAL] = \T_COALESCE_EQUAL; - } - - if (\defined('T_ZSR_EQUAL')) { - $tokens[\T_ZSR_EQUAL] = \T_ZSR_EQUAL; - } - - return $tokens; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/BackCompat/Helper.php b/Magento2/Helpers/PHPCSUtils/BackCompat/Helper.php deleted file mode 100644 index d82f39c2..00000000 --- a/Magento2/Helpers/PHPCSUtils/BackCompat/Helper.php +++ /dev/null @@ -1,242 +0,0 @@ -config` property should work - * in PHPCS 3.x and higher. - * - * @return bool Whether the setting of the data was successfull. - */ - public static function setConfigData($key, $value, $temp = false, $config = null) - { - if (\method_exists('\PHP_CodeSniffer\Config', 'setConfigData') === false) { - // PHPCS 2.x. - return \PHP_CodeSniffer::setConfigData($key, $value, $temp); - } - - if (isset($config) === true) { - // PHPCS 3.x and 4.x. - return $config->setConfigData($key, $value, $temp); - } - - if (\version_compare(self::getVersion(), '3.99.99', '>') === true) { - throw new RuntimeException('Passing the $config parameter is required in PHPCS 4.x'); - } - - // PHPCS 3.x. - return \PHP_CodeSniffer\Config::setConfigData($key, $value, $temp); - } - - /** - * Get the value of a single PHP_CodeSniffer config key. - * - * @see Helper::getCommandLineData() Alternative for the same which is more reliable - * if the `$phpcsFile` object is available. - * - * @since 1.0.0 - * - * @param string $key The name of the config value. - * - * @return string|null - */ - public static function getConfigData($key) - { - if (\method_exists('\PHP_CodeSniffer\Config', 'getConfigData') === false) { - // PHPCS 2.x. - return \PHP_CodeSniffer::getConfigData($key); - } - - // PHPCS 3.x. - return \PHP_CodeSniffer\Config::getConfigData($key); - } - - /** - * Get the value of a CLI overrulable single PHP_CodeSniffer config key. - * - * Use this for config keys which can be set in the `CodeSniffer.conf` file, - * on the command-line or in a ruleset. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed. - * @param string $key The name of the config value. - * - * @return string|null - */ - public static function getCommandLineData(File $phpcsFile, $key) - { - if (\class_exists('\PHP_CodeSniffer\Config') === false) { - // PHPCS 2.x. - $config = $phpcsFile->phpcs->cli->getCommandLineValues(); - if (isset($config[$key])) { - return $config[$key]; - } - } else { - // PHPCS 3.x. - $config = $phpcsFile->config; - if (isset($config->{$key})) { - return $config->{$key}; - } - } - - return null; - } - - /** - * Get the applicable tab width as passed to PHP_CodeSniffer from the - * command-line or the ruleset. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed. - * - * @return int Tab width. Defaults to the PHPCS native default of 4. - */ - public static function getTabWidth(File $phpcsFile) - { - $tabWidth = self::getCommandLineData($phpcsFile, 'tabWidth'); - if ($tabWidth > 0) { - return (int) $tabWidth; - } - - return self::DEFAULT_TABWIDTH; - } - - /** - * Get the applicable (file) encoding as passed to PHP_CodeSniffer from the - * command-line or the ruleset. - * - * @since 1.0.0-alpha3 - * - * @param \PHP_CodeSniffer\Files\File|null $phpcsFile Optional. The current file being processed. - * - * @return string Encoding. Defaults to the PHPCS native default, which is 'utf-8' - * for PHPCS 3.x and was 'iso-8859-1' for PHPCS 2.x. - */ - public static function getEncoding(File $phpcsFile = null) - { - static $default; - - if (isset($default) === false) { - $default = 'utf-8'; - if (\version_compare(self::getVersion(), '2.99.99', '<=') === true) { - // In PHPCS 2.x, the default encoding is `iso-8859-1`. - $default = 'iso-8859-1'; - } - } - - if ($phpcsFile instanceof File) { - // Most reliable. - $encoding = self::getCommandLineData($phpcsFile, 'encoding'); - if ($encoding === null) { - $encoding = $default; - } - - return $encoding; - } - - // Less reliable. - $encoding = self::getConfigData('encoding'); - if ($encoding === null) { - $encoding = $default; - } - - return $encoding; - } - - /** - * Check whether the "--ignore-annotations" option is in effect. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File|null $phpcsFile Optional. The current file being processed. - * - * @return bool `TRUE` if annotations should be ignored, `FALSE` otherwise. - */ - public static function ignoreAnnotations(File $phpcsFile = null) - { - if (\class_exists('\PHP_CodeSniffer\Config') === false) { - // PHPCS 2.x does not support `--ignore-annotations`. - return false; - } - - // PHPCS 3.x. - if (isset($phpcsFile, $phpcsFile->config->annotations)) { - return ! $phpcsFile->config->annotations; - } - - $annotations = \PHP_CodeSniffer\Config::getConfigData('annotations'); - if (isset($annotations)) { - return ! $annotations; - } - - return false; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/Magento2/Helpers/PHPCSUtils/TestUtils/UtilityMethodTestCase.php deleted file mode 100644 index 7ffcc1e3..00000000 --- a/Magento2/Helpers/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ /dev/null @@ -1,450 +0,0 @@ -getTargetToken($commentString, [\T_TOKEN_CONSTANT, \T_ANOTHER_TOKEN]); - * $class = new ClassUnderTest(); - * $result = $class->MyMethod(self::$phpcsFile, $stackPtr); - * // Or for static utility methods: - * $result = ClassUnderTest::MyMethod(self::$phpcsFile, $stackPtr); - * - * $this->assertSame($expected, $result); - * } - * - * /** - * * Data Provider. - * * - * * @see ClassUnderTestUnitTest::testMyMethod() For the array format. - * * - * * @return array - * * / - * public function dataMyMethod() - * { - * return array( - * array('/* testTestCaseDescription * /', false), - * ); - * } - * } - * ``` - * - * Note: - * - Remove the space between the comment closers `* /` for a working example. - * - Each test case separator comment MUST start with `/* test`. - * This is to allow the {@see UtilityMethodTestCase::getTargetToken()} method to - * distinquish between the test separation comments and comments which may be part - * of the test case. - * - The test case file and unit test file should be placed in the same directory. - * - For working examples using this abstract class, have a look at the unit tests - * for the PHPCSUtils utility functions themselves. - * - * @since 1.0.0 - */ -abstract class UtilityMethodTestCase extends TestCase -{ - - /** - * The PHPCS version the tests are being run on. - * - * @since 1.0.0-alpha3 - * - * @var string - */ - protected static $phpcsVersion = '0'; - - /** - * The file extension of the test case file (without leading dot). - * - * This allows concrete test classes to overrule the default `"inc"` with, for instance, - * `"js"` or `"css"` when applicable. - * - * @since 1.0.0 - * - * @var string - */ - protected static $fileExtension = 'inc'; - - /** - * Full path to the test case file associated with the concrete test class. - * - * Optional. If left empty, the case file will be presumed to be in - * the same directory and named the same as the test class, but with an - * `"inc"` file extension. - * - * @since 1.0.0 - * - * @var string - */ - protected static $caseFile = ''; - - /** - * The tab width setting to use when tokenizing the file. - * - * This allows for test case files to use a different tab width than the default. - * - * @since 1.0.0 - * - * @var int - */ - protected static $tabWidth = 4; - - /** - * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. - * - * @since 1.0.0 - * - * @var \PHP_CodeSniffer\Files\File - */ - protected static $phpcsFile; - - /** - * Set the name of a sniff to pass to PHPCS to limit the run (and force it to record errors). - * - * Normally, this propery won't need to be overloaded, but for utility methods which record - * violations and contain fixers, setting a dummy sniff name equal to the sniff name passed - * in the error code for `addError()`/`addWarning()` during the test, will allow for testing - * the recording of these violations, as well as testing the fixer. - * - * @since 1.0.0 - * - * @var array - */ - protected static $selectedSniff = ['Dummy.Dummy.Dummy']; - - /** - * Initialize PHPCS & tokenize the test case file. - * - * The test case file for a unit test class has to be in the same directory - * directory and use the same file name as the test class, using the `.inc` extension - * or be explicitly set using the {@see UtilityMethodTestCase::$fileExtension}/ - * {@see UtilityMethodTestCase::$caseFile} properties. - * - * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::setUpBeforeClass()} - * method. - * - * @since 1.0.0 - * - * @beforeClass - * - * @return void - */ - public static function setUpTestFile() - { - parent::setUpBeforeClass(); - - self::$phpcsVersion = Helper::getVersion(); - - $caseFile = static::$caseFile; - if (\is_string($caseFile) === false || $caseFile === '') { - $testClass = \get_called_class(); - $testFile = (new ReflectionClass($testClass))->getFileName(); - $caseFile = \substr($testFile, 0, -3) . static::$fileExtension; - } - - if (\is_readable($caseFile) === false) { - parent::fail("Test case file missing. Expected case file location: $caseFile"); - } - - $contents = \file_get_contents($caseFile); - - if (\version_compare(self::$phpcsVersion, '2.99.99', '>')) { - // PHPCS 3.x. - $config = new \PHP_CodeSniffer\Config(); - - /* - * We just need to provide a standard so PHPCS will tokenize the file. - * The standard itself doesn't actually matter for testing utility methods, - * so use the smallest one to get the fastest results. - */ - $config->standards = ['PSR1']; - - /* - * Limiting the run to just one sniff will make it, yet again, slightly faster. - * Picked the simplest/fastest sniff available which is registered in PSR1. - */ - $config->sniffs = static::$selectedSniff; - - // Disable caching. - $config->cache = false; - - // Also set a tab-width to enable testing tab-replaced vs `orig_content`. - $config->tabWidth = static::$tabWidth; - - $ruleset = new \PHP_CodeSniffer\Ruleset($config); - - // Make sure the file gets parsed correctly based on the file type. - $contents = 'phpcs_input_file: ' . $caseFile . \PHP_EOL . $contents; - - self::$phpcsFile = new \PHP_CodeSniffer\Files\DummyFile($contents, $ruleset, $config); - - // Only tokenize the file, do not process it. - try { - self::$phpcsFile->parse(); - } catch (TokenizerException $e) { - // PHPCS 3.5.0 and higher. - } catch (RuntimeException $e) { - // PHPCS 3.0.0 < 3.5.0. - } - } else { - // PHPCS 2.x. - $phpcs = new \PHP_CodeSniffer(null, static::$tabWidth); - self::$phpcsFile = new \PHP_CodeSniffer_File( - $caseFile, - [], - [], - $phpcs - ); - - /* - * Using error silencing to drown out "undefined index" notices for tokenizer - * issues in PHPCS 2.x which won't get fixed anymore anyway. - */ - @self::$phpcsFile->start($contents); - } - - // Fail the test if the case file failed to tokenize. - if (self::$phpcsFile->numTokens === 0) { - parent::fail("Tokenizing of the test case file failed for case file: $caseFile"); - } - } - - /** - * Skip JS and CSS related tests on PHPCS 4.x. - * - * PHPCS 4.x drops support for the JS and CSS tokenizers. - * This method takes care of automatically skipping tests involving JS/CSS case files - * when the tests are being run with PHPCS 4.x. - * - * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::setUp()} - * method. - * - * @since 1.0.0-alpha3 - * - * @before - * - * @return void - */ - public function skipJSCSSTestsOnPHPCS4() - { - if (static::$fileExtension !== 'js' && static::$fileExtension !== 'css') { - return; - } - - if (\version_compare(self::$phpcsVersion, '3.99.99', '<=')) { - return; - } - - $this->markTestSkipped('JS and CSS support has been removed in PHPCS 4.'); - } - - /** - * Clean up after finished test. - * - * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} - * method. - * - * @since 1.0.0 - * - * @afterClass - * - * @return void - */ - public static function resetTestFile() - { - self::$phpcsFile = null; - } - - /** - * Check whether or not the PHP 8.0 identifier name tokens will be in use. - * - * The expected token positions/token counts for certain tokens will differ depending - * on whether the PHP 8.0 identifier name tokenization is used or the PHP < 8.0 - * identifier name tokenization. - * - * Tests can use this method to determine which flavour of tokenization to expect and - * to set test expectations accordingly. - * - * @codeCoverageIgnore Nothing to test. - * - * @since 1.0.0 - * - * @return bool - */ - public static function usesPhp8NameTokens() - { - $version = Helper::getVersion(); - if ((\version_compare(\PHP_VERSION_ID, '80000', '>=') === true - && \version_compare($version, '3.5.7', '<') === true) - || \version_compare($version, '4.0.0', '>=') === true - ) { - return true; - } - - return false; - } - - /** - * Get the token pointer for a target token based on a specific comment. - * - * Note: the test delimiter comment MUST start with `/* test` to allow this function to - * distinguish between comments used *in* a test and test delimiters. - * - * If the delimiter comment is not found, the test will automatically be failed. - * - * @since 1.0.0 - * - * @param string $commentString The complete delimiter comment to look for as a string. - * This string should include the comment opener and closer. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. - * @param bool $failTest Optional. Whether the test should be marked as failed when - * the target token cannot be found. Defaults to `true`. - * When set to `false`, a catchable PHP native `RuntimeException` - * will be thrown instead. - * - * @return int - * - * @throws \RuntimeException When the target token cannot be found and `$failTest` has been set to `false`. - */ - public function getTargetToken($commentString, $tokenType, $tokenContent = null, $failTest = true) - { - $start = (self::$phpcsFile->numTokens - 1); - $comment = self::$phpcsFile->findPrevious( - \T_COMMENT, - $start, - null, - false, - $commentString - ); - - if ($comment === false) { - $msg = 'Failed to find the test marker: ' . $commentString; - $this->fail($msg); - } - - $tokens = self::$phpcsFile->getTokens(); - $end = ($start + 1); - - // Limit the token finding to between this and the next delimiter comment. - for ($i = ($comment + 1); $i < $end; $i++) { - if ($tokens[$i]['code'] !== \T_COMMENT) { - continue; - } - - if (\stripos($tokens[$i]['content'], '/* test') === 0) { - $end = $i; - break; - } - } - - $target = self::$phpcsFile->findNext( - $tokenType, - ($comment + 1), - $end, - false, - $tokenContent - ); - - if ($target === false) { - $msg = 'Failed to find test target token for comment string: ' . $commentString; - if ($tokenContent !== null) { - $msg .= ' With token content: ' . $tokenContent; - } - - if ($failTest === false) { - throw new PHPRuntimeException($msg); - } - - $this->fail($msg); - } - - return $target; - } - - /** - * Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit and PHPCS cross-version - * compatible manner. - * - * @since 1.0.0 - * - * @param string $msg The expected exception message. - * @param string $type The PHPCS native exception type to expect. Either 'runtime' or 'tokenizer'. - * Defaults to 'runtime'. - * - * @return void - */ - public function expectPhpcsException($msg, $type = 'runtime') - { - $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - if ($type === 'tokenizer') { - $exception = 'PHP_CodeSniffer\Exceptions\TokenizerException'; - } - - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Tokens/Collections.php b/Magento2/Helpers/PHPCSUtils/Tokens/Collections.php deleted file mode 100644 index bc8e30a4..00000000 --- a/Magento2/Helpers/PHPCSUtils/Tokens/Collections.php +++ /dev/null @@ -1,369 +0,0 @@ - => - */ - public static $magicConstants = [ - \T_CLASS_C => \T_CLASS_C, - \T_DIR => \T_DIR, - \T_FILE => \T_FILE, - \T_FUNC_C => \T_FUNC_C, - \T_LINE => \T_LINE, - \T_METHOD_C => \T_METHOD_C, - \T_NS_C => \T_NS_C, - \T_TRAIT_C => \T_TRAIT_C, - ]; - - /** - * Object operators. - * - * @since 1.0.0-alpha3 - * - * @var array => - */ - public static $objectOperators = [ - \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, - \T_DOUBLE_COLON => \T_DOUBLE_COLON, - ]; - - /** - * Tokens types used for "forwarding" calls within OO structures. - * - * @link https://www.php.net/language.oop5.paamayim-nekudotayim PHP Manual on OO forwarding calls - * - * @since 1.0.0-alpha3 - * - * @var array => - */ - public static $OOHierarchyKeywords = [ - \T_PARENT => \T_PARENT, - \T_SELF => \T_SELF, - \T_STATIC => \T_STATIC, - ]; - - /** - * List of tokens which represent "closed" scopes. - * - * I.e. anything declared within that scope - except for other closed scopes - is - * outside of the global namespace. - * - * This list doesn't contain the `T_NAMESPACE` token on purpose as variables declared - * within a namespace scope are still global and not limited to that namespace. - * - * @since 1.0.0 - * - * @var array => - */ - public static $closedScopes = [ - \T_CLASS => \T_CLASS, - \T_ANON_CLASS => \T_ANON_CLASS, - \T_INTERFACE => \T_INTERFACE, - \T_TRAIT => \T_TRAIT, - \T_FUNCTION => \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, - ]; - - /** - * OO structures which can use the "extends" keyword. - * - * @since 1.0.0 - * - * @var array => - */ - public static $OOCanExtend = [ - \T_CLASS => \T_CLASS, - \T_ANON_CLASS => \T_ANON_CLASS, - \T_INTERFACE => \T_INTERFACE, - ]; - - /** - * Tokens which can start a - potentially multi-line - text string. - * - * @since 1.0.0 - * - * @var array => - */ - public static $textStingStartTokens = [ - \T_START_HEREDOC => \T_START_HEREDOC, - \T_START_NOWDOC => \T_START_NOWDOC, - \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, - \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, - ]; - - /** - * Tokens which can represent the arrow function keyword. - * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. - * - * @since 1.0.0-alpha2 - * - * @return array => - */ - public static function arrowFunctionTokensBC() - { - $tokens = [ - \T_STRING => \T_STRING, - ]; - - if (\defined('T_FN') === true) { - // PHP 7.4 or PHPCS 3.5.3+. - $tokens[\T_FN] = \T_FN; - } - - return $tokens; - } - - /** - * Tokens which can represent a keyword which starts a function declaration. - * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. - * - * Sister-method to the {@see Collections::functionDeclarationTokensBC()} method. - * This method supports PHPCS 3.5.3 and up. - * The {@see Collections::functionDeclarationTokensBC()} method supports PHPCS 2.6.0 and up. - * - * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC() Related method (PHPCS 2.6.0+). - * - * @since 1.0.0-alpha3 - * - * @return array => - */ - public static function functionDeclarationTokens() - { - $tokens = [ - \T_FUNCTION => \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, - ]; - - if (\defined('T_FN') === true) { - // PHP 7.4 or PHPCS 3.5.3+. - $tokens[\T_FN] = \T_FN; - } - - return $tokens; - } - - /** - * Tokens which can represent a keyword which starts a function declaration. - * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. - * - * Sister-method to the {@see Collections::functionDeclarationTokens()} method. - * The {@see Collections::functionDeclarationTokens()} method supports PHPCS 3.5.3 and up. - * This method supports PHPCS 2.6.0 and up. - * - * Notable difference: - * - This method accounts for when the `T_FN` token doesn't exist. - * - * Note: if this method is used, the {@see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction()} - * method needs to be used on arrow function tokens to verify whether it really is an arrow function - * declaration or not. - * - * It is recommended to use the {@see Collections::functionDeclarationTokens()} method instead of - * this method if a standard supports does not need to support PHPCS < 3.5.3. - * - * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() Related method (PHPCS 3.5.3+). - * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Arrow function verification. - * - * @since 1.0.0-alpha3 - * - * @return array => - */ - public static function functionDeclarationTokensBC() - { - $tokens = [ - \T_FUNCTION => \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, - ]; - - $tokens += self::arrowFunctionTokensBC(); - - return $tokens; - } - - /** - * The tokens used for "names", be it namespace, OO, function or constant names. - * - * Includes the tokens introduced in PHP 8.0 for "Namespaced names as single token" when available. - * - * Note: this is a method, not a property as the PHP 8.0 identifier name tokens may not exist. - * - * @link https://wiki.php.net/rfc/namespaced_names_as_token - * - * @since 1.0.0-alpha4 - * - * @return array => - */ - public static function nameTokens() - { - $tokens = [ - \T_STRING => \T_STRING, - ]; - - /* - * PHP >= 8.0 in combination with PHPCS < 3.5.7 and all PHP versions in combination - * with PHPCS >= 3.5.7, though when using PHPCS 3.5.7 < 4.0.0, these tokens are - * not yet in use, i.e. the PHP 8.0 change is "undone" for PHPCS 3.x. - */ - if (\defined('T_NAME_QUALIFIED') === true) { - $tokens[\T_NAME_QUALIFIED] = \T_NAME_QUALIFIED; - } - - if (\defined('T_NAME_FULLY_QUALIFIED') === true) { - $tokens[\T_NAME_FULLY_QUALIFIED] = \T_NAME_FULLY_QUALIFIED; - } - - if (\defined('T_NAME_RELATIVE') === true) { - $tokens[\T_NAME_RELATIVE] = \T_NAME_RELATIVE; - } - - return $tokens; - } - - /** - * Tokens types which can be encountered in a fully, partially or unqualified name. - * - * Example: - * ```php - * echo namespace\Sub\ClassName::method(); - * ``` - * - * @since 1.0.0-alpha4 - * - * @return array => - */ - public static function namespacedNameTokens() - { - $tokens = [ - \T_NS_SEPARATOR => \T_NS_SEPARATOR, - \T_NAMESPACE => \T_NAMESPACE, - ]; - - $tokens += self::nameTokens(); - - return $tokens; - } - /** - * Token types which can be encountered in a return type declaration. - * - * Note: this is a method, not a property as the `T_TYPE_UNION` token for PHP 8.0 union types may not exist. - * - * Sister-method to the {@see Collections::returnTypeTokensBC()} method. - * This method supports PHPCS 3.3.0 and up. - * The {@see Collections::returnTypeTokensBC()} method supports PHPCS 2.6.0 and up. - * - * Notable differences: - * - The {@see Collections::returnTypeTokensBC()} method will include the `T_ARRAY_HINT` - * and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. - * These token constants will no longer exist in PHPCS 4.x. - * - * It is recommended to use this method instead of the {@see Collections::returnTypeTokensBC()} - * method if a standard does not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). - * - * @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property. - * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. - * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. - * @since 1.0.0-alpha4 Added the T_TYPE_UNION token for union type support in PHPCS > 3.6.0. - * - * @return array => - */ - public static function returnTypeTokens() - { - $tokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_STATIC => \T_STATIC, - \T_FALSE => \T_FALSE, // Union types only. - \T_NULL => \T_NULL, // Union types only. - \T_ARRAY => \T_ARRAY, // Arrow functions PHPCS < 3.5.4 + union types. - \T_BITWISE_OR => \T_BITWISE_OR, // Union types for PHPCS < 3.6.0. - ]; - - $tokens += self::namespacedNameTokens(); - - // PHPCS > 3.6.0: a new token was introduced for the union type separator. - if (\defined('T_TYPE_UNION') === true) { - $tokens[\T_TYPE_UNION] = \T_TYPE_UNION; - } - - return $tokens; - } - - /** - * Token types which can be encountered in a return type declaration (cross-version). - * - * Sister-method to the {@see Collections::returnTypeTokens()} method. - * The {@see Collections::returnTypeTokens()} method supports PHPCS 3.3.0 and up. - * This method supports PHPCS 2.6.0 and up. - * - * Notable differences: - * - This method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when - * used with PHPCS 2.x and 3.x. - * These token constants will no longer exist in PHPCS 4.x. - * - * It is recommended to use the {@see Collections::returnTypeTokens()} method instead of - * this method if a standard does not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::returnTypeTokens() Related method (PHPCS 3.3.0+). - * - * @since 1.0.0-alpha3 - * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. - * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. - * - * @return array => - */ - public static function returnTypeTokensBC() - { - $tokens = self::returnTypeTokens(); - - /* - * PHPCS < 4.0. Needed for support of PHPCS 2.4.0 < 3.3.0. - * For PHPCS 3.3.0+ the constant is no longer used. - */ - if (\defined('T_RETURN_TYPE') === true) { - $tokens[\T_RETURN_TYPE] = \T_RETURN_TYPE; - } - - /* - * PHPCS < 4.0. Needed for support of PHPCS < 2.8.0 / PHPCS < 3.5.3 for arrow functions. - * For PHPCS 3.5.3+ the constant is no longer used. - */ - if (\defined('T_ARRAY_HINT') === true) { - $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } - - return $tokens; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/Conditions.php b/Magento2/Helpers/PHPCSUtils/Utils/Conditions.php deleted file mode 100644 index 4d34ed92..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/Conditions.php +++ /dev/null @@ -1,119 +0,0 @@ -getTokens(); - - // Check for the existence of the token. - if (isset($tokens[$stackPtr]) === false) { - return false; - } - - // Make sure the token has conditions. - if (empty($tokens[$stackPtr]['conditions'])) { - return false; - } - - $types = (array) $types; - $conditions = $tokens[$stackPtr]['conditions']; - - if (empty($types) === true) { - // No types specified, just return the first/last condition pointer. - if ($first === false) { - \end($conditions); - } else { - \reset($conditions); - } - - return \key($conditions); - } - - if ($first === false) { - $conditions = \array_reverse($conditions, true); - } - - foreach ($conditions as $ptr => $type) { - if (isset($tokens[$ptr]) === true - && \in_array($type, $types, true) === true - ) { - // We found a token with the required type. - return $ptr; - } - } - - return false; - } - - /** - * Return the position of the last (innermost) condition of a certain type for the passed token. - * - * If no types are specified, the last condition for the token, independently of type, - * will be returned. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of the token we are checking. - * @param int|string|array $types Optional. The type(s) of tokens to search for. - * - * @return int|false Integer stack pointer to the condition; or `FALSE` if the token - * does not have the condition or has no conditions at all. - */ - public static function getLastCondition(File $phpcsFile, $stackPtr, $types = []) - { - return self::getCondition($phpcsFile, $stackPtr, $types, false); - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/FunctionDeclarations.php b/Magento2/Helpers/PHPCSUtils/Utils/FunctionDeclarations.php deleted file mode 100644 index 94641d48..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/FunctionDeclarations.php +++ /dev/null @@ -1,754 +0,0 @@ - 'public', // Public, private, or protected - * 'scope_specified' => true, // TRUE if the scope keyword was found. - * 'return_type' => '', // The return type of the method. - * 'return_type_token' => integer, // The stack pointer to the start of the return type - * // or FALSE if there is no return type. - * 'return_type_end_token' => integer, // The stack pointer to the end of the return type - * // or FALSE if there is no return type. - * 'nullable_return_type' => false, // TRUE if the return type is nullable. - * 'is_abstract' => false, // TRUE if the abstract keyword was found. - * 'is_final' => false, // TRUE if the final keyword was found. - * 'is_static' => false, // TRUE if the static keyword was found. - * 'has_body' => false, // TRUE if the method has a body - * ); - * ``` - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a T_FUNCTION - * or T_CLOSURE token, nor an arrow function. - */ - public static function getProperties(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); - - if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] !== \T_FUNCTION - && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $arrowOpenClose === false) - ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or an arrow function'); - } - - if ($tokens[$stackPtr]['code'] === \T_FUNCTION) { - $valid = Tokens::$methodPrefixes; - } else { - $valid = [\T_STATIC => \T_STATIC]; - } - - $valid += Tokens::$emptyTokens; - - $scope = 'public'; - $scopeSpecified = false; - $isAbstract = false; - $isFinal = false; - $isStatic = false; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case \T_PUBLIC: - $scope = 'public'; - $scopeSpecified = true; - break; - case \T_PRIVATE: - $scope = 'private'; - $scopeSpecified = true; - break; - case \T_PROTECTED: - $scope = 'protected'; - $scopeSpecified = true; - break; - case \T_ABSTRACT: - $isAbstract = true; - break; - case \T_FINAL: - $isFinal = true; - break; - case \T_STATIC: - $isStatic = true; - break; - } - } - - $returnType = ''; - $returnTypeToken = false; - $returnTypeEndToken = false; - $nullableReturnType = false; - $hasBody = false; - $returnTypeTokens = Collections::returnTypeTokensBC(); - - $parenthesisCloser = null; - if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { - $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; - } - - if (isset($parenthesisCloser) === true) { - $scopeOpener = null; - if (isset($tokens[$stackPtr]['scope_opener']) === true) { - $scopeOpener = $tokens[$stackPtr]['scope_opener']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $scopeOpener = $arrowOpenClose['scope_opener']; - } - - for ($i = $parenthesisCloser; $i < $phpcsFile->numTokens; $i++) { - if ($i === $scopeOpener) { - // End of function definition. - $hasBody = true; - break; - } - - if ($scopeOpener === null && $tokens[$i]['code'] === \T_SEMICOLON) { - // End of abstract/interface function definition. - break; - } - - if ($tokens[$i]['type'] === 'T_NULLABLE' - // Handle nullable tokens in PHPCS < 2.8.0. - || (\defined('T_NULLABLE') === false && $tokens[$i]['code'] === \T_INLINE_THEN) - // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. - || ($arrowOpenClose !== false && $tokens[$i]['code'] === \T_INLINE_THEN - && \version_compare(Helper::getVersion(), '2.9.1', '<') === true) - ) { - $nullableReturnType = true; - } - - if (isset($returnTypeTokens[$tokens[$i]['code']]) === true) { - if ($returnTypeToken === false) { - $returnTypeToken = $i; - } - - $returnType .= $tokens[$i]['content']; - $returnTypeEndToken = $i; - } - } - } - - if ($returnType !== '' && $nullableReturnType === true) { - $returnType = '?' . $returnType; - } - - return [ - 'scope' => $scope, - 'scope_specified' => $scopeSpecified, - 'return_type' => $returnType, - 'return_type_token' => $returnTypeToken, - 'return_type_end_token' => $returnTypeEndToken, - 'nullable_return_type' => $nullableReturnType, - 'is_abstract' => $isAbstract, - 'is_final' => $isFinal, - 'is_static' => $isStatic, - 'has_body' => $hasBody, - ]; - } - - /** - * Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer - * for an arrow function. - * - * Helper function for cross-version compatibility with both PHP as well as PHPCS. - * In PHPCS versions prior to PHPCS 3.5.3/3.5.4, the `T_FN` token is not yet backfilled - * and does not have parenthesis opener/closer nor scope opener/closer indexes assigned - * in the `$tokens` array. - * - * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Related function. - * - * @since 1.0.0 - * @since 1.0.0-alpha4 Handling of PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The token to retrieve the openers/closers for. - * Typically a `T_FN` or `T_STRING` token as those are the - * only two tokens which can be the arrow function keyword. - * - * @return array|false An array with the token pointers or `FALSE` if this is not an arrow function. - * The format of the return value is: - * ```php - * array( - * 'parenthesis_opener' => integer, // Stack pointer to the parenthesis opener. - * 'parenthesis_closer' => integer, // Stack pointer to the parenthesis closer. - * 'scope_opener' => integer, // Stack pointer to the scope opener (arrow). - * 'scope_closer' => integer, // Stack pointer to the scope closer. - * ) - * ``` - */ - public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]) === false - || isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false - || \strtolower($tokens[$stackPtr]['content']) !== 'fn' - ) { - return false; - } - - if ($tokens[$stackPtr]['type'] === 'T_FN' - && isset($tokens[$stackPtr]['scope_closer']) === true - && \version_compare(Helper::getVersion(), '3.5.4', '>') === true - ) { - // The keys will either all be set or none will be set, so no additional checks needed. - return [ - 'parenthesis_opener' => $tokens[$stackPtr]['parenthesis_opener'], - 'parenthesis_closer' => $tokens[$stackPtr]['parenthesis_closer'], - 'scope_opener' => $tokens[$stackPtr]['scope_opener'], - 'scope_closer' => $tokens[$stackPtr]['scope_closer'], - ]; - } - - /* - * This is either a T_STRING token pre-PHP 7.4, or T_FN on PHP 7.4 in combination - * with PHPCS < 3.5.3/4/5. - * - * Now see about finding the relevant arrow function tokens. - */ - $returnValue = []; - - $nextNonEmpty = $phpcsFile->findNext( - (Tokens::$emptyTokens + [\T_BITWISE_AND]), - ($stackPtr + 1), - null, - true - ); - if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== \T_OPEN_PARENTHESIS) { - return false; - } - - $returnValue['parenthesis_opener'] = $nextNonEmpty; - if (isset($tokens[$nextNonEmpty]['parenthesis_closer']) === false) { - return false; - } - - $returnValue['parenthesis_closer'] = $tokens[$nextNonEmpty]['parenthesis_closer']; - - $ignore = Tokens::$emptyTokens; - $ignore += Collections::returnTypeTokensBC(); - $ignore[\T_COLON] = \T_COLON; - $ignore[\T_INLINE_ELSE] = \T_INLINE_ELSE; // Return type colon on PHPCS < 2.9.1. - $ignore[\T_INLINE_THEN] = \T_INLINE_THEN; // Nullable type indicator on PHPCS < 2.9.1. - - if (\defined('T_NULLABLE') === true) { - $ignore[\T_NULLABLE] = \T_NULLABLE; - } - - $arrow = $phpcsFile->findNext( - $ignore, - ($tokens[$nextNonEmpty]['parenthesis_closer'] + 1), - null, - true - ); - - if ($arrow === false - || ($tokens[$arrow]['code'] !== \T_DOUBLE_ARROW && $tokens[$arrow]['type'] !== 'T_FN_ARROW') - ) { - return false; - } - - $returnValue['scope_opener'] = $arrow; - $inTernary = false; - $lastEndToken = null; - - for ($scopeCloser = ($arrow + 1); $scopeCloser < $phpcsFile->numTokens; $scopeCloser++) { - if (isset(self::$arrowFunctionEndTokens[$tokens[$scopeCloser]['code']]) === true - // BC for misidentified ternary else in some PHPCS versions. - && ($tokens[$scopeCloser]['code'] !== \T_COLON || $inTernary === false) - ) { - if ($lastEndToken !== null - && $tokens[$scopeCloser]['code'] === \T_CLOSE_PARENTHESIS - && $tokens[$scopeCloser]['parenthesis_opener'] < $arrow - ) { - $scopeCloser = $lastEndToken; - } - - break; - } - - if (isset(Collections::arrowFunctionTokensBC()[$tokens[$scopeCloser]['code']]) === true) { - $nested = self::getArrowFunctionOpenClose($phpcsFile, $scopeCloser); - if ($nested !== false && isset($nested['scope_closer'])) { - // We minus 1 here in case the closer can be shared with us. - $scopeCloser = ($nested['scope_closer'] - 1); - continue; - } - } - - if (isset($tokens[$scopeCloser]['scope_closer']) === true - && $tokens[$scopeCloser]['code'] !== \T_INLINE_ELSE - && $tokens[$scopeCloser]['code'] !== \T_END_HEREDOC - && $tokens[$scopeCloser]['code'] !== \T_END_NOWDOC - ) { - // We minus 1 here in case the closer can be shared with us. - $scopeCloser = ($tokens[$scopeCloser]['scope_closer'] - 1); - continue; - } - - if (isset($tokens[$scopeCloser]['parenthesis_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['parenthesis_closer']; - $lastEndToken = $scopeCloser; - continue; - } - - if (isset($tokens[$scopeCloser]['bracket_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['bracket_closer']; - $lastEndToken = $scopeCloser; - continue; - } - - if ($tokens[$scopeCloser]['code'] === \T_INLINE_THEN) { - $inTernary = true; - continue; - } - - if ($tokens[$scopeCloser]['code'] === \T_INLINE_ELSE) { - if ($inTernary === false) { - break; - } - - $inTernary = false; - } - } - - if ($scopeCloser === $phpcsFile->numTokens) { - return false; - } - - $returnValue['scope_closer'] = $scopeCloser; - - return $returnValue; - } - - /** - * Returns the declaration name for a function. - * - * Alias for the {@see \PHPCSUtils\Utils\ObjectDeclarations::getName()} method. - * - * @see \PHPCSUtils\BackCompat\BCFile::getDeclarationName() Original function. - * @see \PHPCSUtils\Utils\ObjectDeclarations::getName() PHPCSUtils native improved version. - * - * @since 1.0.0 - * - * @codeCoverageIgnore - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the function keyword token. - * - * @return string|null The name of the function; or `NULL` if the passed token doesn't exist, - * the function is anonymous or in case of a parse error/live coding. - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified token is not of type - * `T_FUNCTION`. - */ - public static function getName(File $phpcsFile, $stackPtr) - { - return ObjectDeclarations::getName($phpcsFile, $stackPtr); - } - - - /** - * Retrieves the method parameters for the specified function token. - * - * Also supports passing in a `T_USE` token for a closure use group. - * - * The returned array will contain the following information for each parameter: - * - * ```php - * 0 => array( - * 'name' => '$var', // The variable name. - * 'token' => integer, // The stack pointer to the variable name. - * 'content' => string, // The full content of the variable definition. - * 'pass_by_reference' => boolean, // Is the variable passed by reference? - * 'reference_token' => integer, // The stack pointer to the reference operator - * // or FALSE if the param is not passed by reference. - * 'variable_length' => boolean, // Is the param of variable length through use of `...` ? - * 'variadic_token' => integer, // The stack pointer to the ... operator - * // or FALSE if the param is not variable length. - * 'type_hint' => string, // The type hint for the variable. - * 'type_hint_token' => integer, // The stack pointer to the start of the type hint - * // or FALSE if there is no type hint. - * 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint - * // or FALSE if there is no type hint. - * 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability - * // operator. - * 'comma_token' => integer, // The stack pointer to the comma after the param - * // or FALSE if this is the last param. - * ) - * ``` - * - * Parameters with default values have the following additional array indexes: - * ```php - * 'default' => string, // The full content of the default value. - * 'default_token' => integer, // The stack pointer to the start of the default value. - * 'default_equal_token' => integer, // The stack pointer to the equals sign. - * ``` - * - * Parameters declared using PHP 8 constructor property promotion, have these additional array indexes: - * ```php - * 'property_visibility' => string, // The property visibility as declared. - * 'visibility_token' => integer, // The stack pointer to the visibility modifier token. - * ``` - * - * Main differences with the PHPCS version: - * - Defensive coding against incorrect calls to this method. - * - More efficient and more stable checking whether a `T_USE` token is a closure use. - * - More efficient and more stable looping of the default value. - * - Clearer exception message when a non-closure use token was passed to the function. - * - To allow for backward compatible handling of arrow functions, this method will also accept - * `T_STRING` tokens and examine them to check if these are arrow functions. - * - Support for PHP 8.0 identifier name tokens in parameter types, cross-version PHP & PHPCS. - * - * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. - * @see \PHPCSUtils\BackCompat\BCFile::getMethodParameters() Cross-version compatible version of the original. - * - * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. - * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. - * @since 1.0.0-alpha4 Added support for PHP 8.0 constructor property promotion. - * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position in the stack of the function token - * to acquire the parameters for. - * - * @return array - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of - * type `T_FUNCTION`, `T_CLOSURE` or `T_USE`, - * nor an arrow function. - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If a passed `T_USE` token is not a closure - * use token. - */ - public static function getParameters(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); - - if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] !== \T_FUNCTION - && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $tokens[$stackPtr]['code'] !== \T_USE - && $arrowOpenClose === false) - ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION, T_CLOSURE or T_USE or an arrow function'); - } - - if ($tokens[$stackPtr]['code'] === \T_USE) { - // This will work PHPCS 3.x/4.x cross-version without much overhead. - $opener = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($opener === false - || $tokens[$opener]['code'] !== \T_OPEN_PARENTHESIS - || UseStatements::isClosureUse($phpcsFile, $stackPtr) === false - ) { - throw new RuntimeException('$stackPtr was not a valid closure T_USE'); - } - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5. - $opener = $arrowOpenClose['parenthesis_opener']; - } else { - if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { - // Live coding or syntax error, so no params to find. - return []; - } - - $opener = $tokens[$stackPtr]['parenthesis_opener']; - } - - if (isset($tokens[$opener]['parenthesis_closer']) === false) { - // Live coding or syntax error, so no params to find. - return []; - } - - $closer = $tokens[$opener]['parenthesis_closer']; - - $vars = []; - $currVar = null; - $paramStart = ($opener + 1); - $defaultStart = null; - $equalToken = null; - $paramCount = 0; - $passByReference = false; - $referenceToken = false; - $variableLength = false; - $variadicToken = false; - $typeHint = ''; - $typeHintToken = false; - $typeHintEndToken = false; - $nullableType = false; - $visibilityToken = null; - - for ($i = $paramStart; $i <= $closer; $i++) { - // Changed from checking 'code' to 'type' to allow for T_NULLABLE not existing in PHPCS < 2.8.0. - switch ($tokens[$i]['type']) { - case 'T_BITWISE_AND': - $passByReference = true; - $referenceToken = $i; - break; - - case 'T_VARIABLE': - $currVar = $i; - break; - - case 'T_ELLIPSIS': - $variableLength = true; - $variadicToken = $i; - break; - - case 'T_ARRAY_HINT': // PHPCS < 3.3.0. - case 'T_CALLABLE': - case 'T_SELF': - case 'T_PARENT': - case 'T_STATIC': // Self and parent are valid, static invalid, but was probably intended as type hint. - case 'T_FALSE': // Union types. - case 'T_NULL': // Union types. - case 'T_STRING': - case 'T_NAMESPACE': - case 'T_NS_SEPARATOR': - case 'T_NAME_QUALIFIED': - case 'T_NAME_FULLY_QUALIFIED': - case 'T_NAME_RELATIVE': - case 'T_BITWISE_OR': // Union type separator PHPCS < 3.6.0. - case 'T_TYPE_UNION': // Union type separator PHPCS >= 3.6.0. - if ($typeHintToken === false) { - $typeHintToken = $i; - } - - $typeHint .= $tokens[$i]['content']; - $typeHintEndToken = $i; - break; - - case 'T_NULLABLE': - case 'T_INLINE_THEN': // PHPCS < 2.8.0. - $nullableType = true; - $typeHint .= $tokens[$i]['content']; - $typeHintEndToken = $i; - break; - - case 'T_PUBLIC': - case 'T_PROTECTED': - case 'T_PRIVATE': - $visibilityToken = $i; - break; - - case 'T_CLOSE_PARENTHESIS': - case 'T_COMMA': - // If it's null, then there must be no parameters for this - // method. - if ($currVar === null) { - continue 2; - } - - $vars[$paramCount] = []; - $vars[$paramCount]['token'] = $currVar; - $vars[$paramCount]['name'] = $tokens[$currVar]['content']; - $vars[$paramCount]['content'] = \trim( - GetTokensAsString::normal($phpcsFile, $paramStart, ($i - 1)) - ); - - if ($defaultStart !== null) { - $vars[$paramCount]['default'] = \trim( - GetTokensAsString::normal($phpcsFile, $defaultStart, ($i - 1)) - ); - $vars[$paramCount]['default_token'] = $defaultStart; - $vars[$paramCount]['default_equal_token'] = $equalToken; - } - - $vars[$paramCount]['pass_by_reference'] = $passByReference; - $vars[$paramCount]['reference_token'] = $referenceToken; - $vars[$paramCount]['variable_length'] = $variableLength; - $vars[$paramCount]['variadic_token'] = $variadicToken; - $vars[$paramCount]['type_hint'] = $typeHint; - $vars[$paramCount]['type_hint_token'] = $typeHintToken; - $vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken; - $vars[$paramCount]['nullable_type'] = $nullableType; - - if ($visibilityToken !== null) { - $vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content']; - $vars[$paramCount]['visibility_token'] = $visibilityToken; - } - - if ($tokens[$i]['code'] === \T_COMMA) { - $vars[$paramCount]['comma_token'] = $i; - } else { - $vars[$paramCount]['comma_token'] = false; - } - - // Reset the vars, as we are about to process the next parameter. - $currVar = null; - $paramStart = ($i + 1); - $defaultStart = null; - $equalToken = null; - $passByReference = false; - $referenceToken = false; - $variableLength = false; - $variadicToken = false; - $typeHint = ''; - $typeHintToken = false; - $typeHintEndToken = false; - $nullableType = false; - $visibilityToken = null; - - $paramCount++; - break; - - case 'T_EQUAL': - $defaultStart = $phpcsFile->findNext(Tokens::$emptyTokens, ($i + 1), null, true); - $equalToken = $i; - - // Skip past everything in the default value before going into the next switch loop. - for ($j = ($i + 1); $j <= $closer; $j++) { - // Skip past array()'s et al as default values. - if (isset($tokens[$j]['parenthesis_opener'], $tokens[$j]['parenthesis_closer'])) { - $j = $tokens[$j]['parenthesis_closer']; - - if ($j === $closer) { - // Found the end of the parameter. - break; - } - - continue; - } - - // Skip past short arrays et al as default values. - if (isset($tokens[$j]['bracket_opener'])) { - $j = $tokens[$j]['bracket_closer']; - continue; - } - - if ($tokens[$j]['code'] === \T_COMMA) { - break; - } - } - - $i = ($j - 1); - break; - } - } - - return $vars; - } - - /** - * Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function. - * - * Helper function for cross-version compatibility with both PHP as well as PHPCS. - * - PHP 7.4+ will tokenize most tokens with the content "fn" as `T_FN`, even when it isn't an arrow function. - * - PHPCS < 3.5.3 will tokenize arrow functions keywords as `T_STRING`. - * - PHPCS 3.5.3/3.5.4 will tokenize the keyword differently depending on which PHP version is used - * and similar to PHP will tokenize most tokens with the content "fn" as `T_FN`, even when it's not an - * arrow function. - * > Note: the tokens tokenized by PHPCS 3.5.3 - 3.5.4 as `T_FN` are not 100% the same as those tokenized - * by PHP 7.4+ as `T_FN`. - * - * Either way, the `T_FN` token is not a reliable search vector for finding or examining - * arrow functions, at least not until PHPCS 3.5.5. - * This function solves that and will give reliable results in the same way as this is now - * solved in PHPCS 3.5.5. - * - * > Note: Bugs are still being found and reported about how PHPCS tokenizes the arrow functions. - * This method will keep up with upstream changes and backport them, in as far possible, to allow - * for sniffing arrow functions in PHPCS < current. - * - * @see \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose() Related function. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The token to check. Typically a T_FN or - * T_STRING token as those are the only two - * tokens which can be the arrow function keyword. - * - * @return bool `TRUE` if the token is the "fn" keyword for an arrow function. `FALSE` when it's not - * or in case of live coding/parse error. - */ - public static function isArrowFunction(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - if (isset($tokens[$stackPtr]) === false) { - return false; - } - - if ($tokens[$stackPtr]['type'] === 'T_FN' - && isset($tokens[$stackPtr]['scope_closer']) === true - ) { - return true; - } - - if (isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false - || \strtolower($tokens[$stackPtr]['content']) !== 'fn' - ) { - return false; - } - - $openClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); - if ($openClose !== false && isset($openClose['scope_closer'])) { - return true; - } - - return false; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/GetTokensAsString.php b/Magento2/Helpers/PHPCSUtils/Utils/GetTokensAsString.php deleted file mode 100644 index c7267f5c..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/GetTokensAsString.php +++ /dev/null @@ -1,188 +0,0 @@ -getTokens(); - - if (\is_int($start) === false || isset($tokens[$start]) === false) { - throw new RuntimeException( - 'The $start position for GetTokensAsString methods must exist in the token stack' - ); - } - - if (\is_int($end) === false || $end < $start) { - return ''; - } - - $str = ''; - if ($end >= $phpcsFile->numTokens) { - $end = ($phpcsFile->numTokens - 1); - } - - $lastAdded = null; - for ($i = $start; $i <= $end; $i++) { - if ($stripComments === true && isset(Tokens::$commentTokens[$tokens[$i]['code']])) { - continue; - } - - if ($stripWhitespace === true && $tokens[$i]['code'] === \T_WHITESPACE) { - continue; - } - - if ($compact === true && $tokens[$i]['code'] === \T_WHITESPACE) { - if (isset($lastAdded) === false || $tokens[$lastAdded]['code'] !== \T_WHITESPACE) { - $str .= ' '; - $lastAdded = $i; - } - continue; - } - - // If tabs are being converted to spaces by the tokenizer, the - // original content should be used instead of the converted content. - if ($origContent === true && isset($tokens[$i]['orig_content']) === true) { - $str .= $tokens[$i]['orig_content']; - } else { - $str .= $tokens[$i]['content']; - } - - $lastAdded = $i; - } - - return $str; - } - - /** - * Retrieve the code-tokens only content of the tokens from the specified start position - * in the token stack to the specified end position (inclusive) without whitespace or comments. - * - * This is, for instance, useful to retrieve a namespace name without stray whitespace or comments. - * Use this function selectively and with care! - * - * @see \PHP_CodeSniffer\Files\File::getTokensAsString() Loosely related function. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $start The position to start from in the token stack. - * @param int $end The position to end at in the token stack (inclusive). - * - * @return string The token contents stripped off comments and whitespace. - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified start position does not exist. - */ - public static function noEmpties(File $phpcsFile, $start, $end) - { - return self::getString($phpcsFile, $start, $end, false, true, true); - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/ObjectDeclarations.php b/Magento2/Helpers/PHPCSUtils/Utils/ObjectDeclarations.php deleted file mode 100644 index fdb46adb..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/ObjectDeclarations.php +++ /dev/null @@ -1,363 +0,0 @@ -getTokens(); - - if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] === \T_ANON_CLASS || $tokens[$stackPtr]['code'] === \T_CLOSURE) - ) { - return null; - } - - $tokenCode = $tokens[$stackPtr]['code']; - - /* - * BC: Work-around JS ES6 classes not being tokenized as T_CLASS in PHPCS < 3.0.0. - */ - if (isset($phpcsFile->tokenizerType) - && $phpcsFile->tokenizerType === 'JS' - && $tokenCode === \T_STRING - && $tokens[$stackPtr]['content'] === 'class' - ) { - $tokenCode = \T_CLASS; - } - - if ($tokenCode !== \T_FUNCTION - && $tokenCode !== \T_CLASS - && $tokenCode !== \T_INTERFACE - && $tokenCode !== \T_TRAIT - ) { - throw new RuntimeException( - 'Token type "' . $tokens[$stackPtr]['type'] . '" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT' - ); - } - - if ($tokenCode === \T_FUNCTION - && \strtolower($tokens[$stackPtr]['content']) !== 'function' - ) { - // This is a function declared without the "function" keyword. - // So this token is the function name. - return $tokens[$stackPtr]['content']; - } - - /* - * Determine the name. Note that we cannot simply look for the first T_STRING - * because an (invalid) class name starting with a number will be multiple tokens. - * Whitespace or comment are however not allowed within a name. - */ - - $stopPoint = $phpcsFile->numTokens; - if ($tokenCode === \T_FUNCTION && isset($tokens[$stackPtr]['parenthesis_opener']) === true) { - $stopPoint = $tokens[$stackPtr]['parenthesis_opener']; - } elseif (isset($tokens[$stackPtr]['scope_opener']) === true) { - $stopPoint = $tokens[$stackPtr]['scope_opener']; - } - - $exclude = Tokens::$emptyTokens; - $exclude[] = \T_OPEN_PARENTHESIS; - $exclude[] = \T_OPEN_CURLY_BRACKET; - $exclude[] = \T_BITWISE_AND; - - $nameStart = $phpcsFile->findNext($exclude, ($stackPtr + 1), $stopPoint, true); - if ($nameStart === false) { - // Live coding or parse error. - return null; - } - - $tokenAfterNameEnd = $phpcsFile->findNext($exclude, $nameStart, $stopPoint); - - if ($tokenAfterNameEnd === false) { - $content = null; - - /* - * BC: In PHPCS 2.6.0, in case of live coding, the last token in a file will be tokenized - * as T_STRING, but won't have the `content` index set. - */ - if (isset($tokens[$nameStart]['content'])) { - $content = $tokens[$nameStart]['content']; - } - - return $content; - } - - // Name starts with number, so is composed of multiple tokens. - return GetTokensAsString::noEmpties($phpcsFile, $nameStart, ($tokenAfterNameEnd - 1)); - } - - /** - * Retrieves the implementation properties of a class. - * - * Main differences with the PHPCS version: - * - Bugs fixed: - * - Handling of PHPCS annotations. - * - Handling of unorthodox docblock placement. - * - A class cannot both be abstract as well as final, so this utility should not allow for that. - * - Defensive coding against incorrect calls to this method. - * - * @see \PHP_CodeSniffer\Files\File::getClassProperties() Original source. - * @see \PHPCSUtils\BackCompat\BCFile::getClassProperties() Cross-version compatible version of the original. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position in the stack of the `T_CLASS` - * token to acquire the properties for. - * - * @return array Array with implementation properties of a class. - * The format of the return value is: - * ```php - * array( - * 'is_abstract' => false, // TRUE if the abstract keyword was found. - * 'is_final' => false, // TRUE if the final keyword was found. - * ); - * ``` - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * `T_CLASS` token. - */ - public static function getClassProperties(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]) === false || $tokens[$stackPtr]['code'] !== \T_CLASS) { - throw new RuntimeException('$stackPtr must be of type T_CLASS'); - } - - $valid = Collections::$classModifierKeywords + Tokens::$emptyTokens; - $properties = [ - 'is_abstract' => false, - 'is_final' => false, - ]; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case \T_ABSTRACT: - $properties['is_abstract'] = true; - break 2; - - case \T_FINAL: - $properties['is_final'] = true; - break 2; - } - } - - return $properties; - } - - /** - * Retrieves the name of the class that the specified class extends. - * - * Works for classes, anonymous classes and interfaces, though it is strongly recommended - * to use the {@see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedInterfaceNames()} - * method to examine interfaces instead. Interfaces can extend multiple parent interfaces, - * and that use-case is not handled by this method. - * - * Main differences with the PHPCS version: - * - Bugs fixed: - * - Handling of PHPCS annotations. - * - Handling of comments. - * - Improved handling of parse errors. - * - The returned name will be clean of superfluous whitespace and/or comments. - * - * @see \PHP_CodeSniffer\Files\File::findExtendedClassName() Original source. - * @see \PHPCSUtils\BackCompat\BCFile::findExtendedClassName() Cross-version compatible version of - * the original. - * @see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedInterfaceNames() Similar method for extended interfaces. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The stack position of the class or interface. - * - * @return string|false The extended class name or `FALSE` on error or if there - * is no extended class name. - */ - public static function findExtendedClassName(File $phpcsFile, $stackPtr) - { - $names = self::findNames($phpcsFile, $stackPtr, \T_EXTENDS, Collections::$OOCanExtend); - if ($names === false) { - return false; - } - - // Classes can only extend one parent class. - return \array_shift($names); - } - - /** - * Retrieves the names of the interfaces that the specified class implements. - * - * Main differences with the PHPCS version: - * - Bugs fixed: - * - Handling of PHPCS annotations. - * - Handling of comments. - * - Improved handling of parse errors. - * - The returned name(s) will be clean of superfluous whitespace and/or comments. - * - * @see \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames() Original source. - * @see \PHPCSUtils\BackCompat\BCFile::findImplementedInterfaceNames() Cross-version compatible version of - * the original. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The stack position of the class. - * - * @return array|false Array with names of the implemented interfaces or `FALSE` on - * error or if there are no implemented interface names. - */ - public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr) - { - return self::findNames($phpcsFile, $stackPtr, \T_IMPLEMENTS, Collections::$OOCanImplement); - } - - /** - * Retrieves the names of the interfaces that the specified interface extends. - * - * @see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedClassName() Similar method for extended classes. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The stack position of the interface keyword. - * - * @return array|false Array with names of the extended interfaces or `FALSE` on - * error or if there are no extended interface names. - */ - public static function findExtendedInterfaceNames(File $phpcsFile, $stackPtr) - { - return self::findNames( - $phpcsFile, - $stackPtr, - \T_EXTENDS, - [\T_INTERFACE => \T_INTERFACE] - ); - } - - /** - * Retrieves the names of the extended classes or interfaces or the implemented - * interfaces that the specific class/interface declaration extends/implements. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The stack position of the - * class/interface declaration keyword. - * @param int $keyword The token constant for the keyword to examine. - * Either `T_EXTENDS` or `T_IMPLEMENTS`. - * @param array $allowedFor Array of OO types for which use of the keyword - * is allowed. - * - * @return array|false Returns an array of names or `FALSE` on error or when the object - * being declared does not extend/implement another object. - */ - private static function findNames(File $phpcsFile, $stackPtr, $keyword, $allowedFor) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]) === false - || isset($allowedFor[$tokens[$stackPtr]['code']]) === false - || isset($tokens[$stackPtr]['scope_opener']) === false - ) { - return false; - } - - $scopeOpener = $tokens[$stackPtr]['scope_opener']; - $keywordPtr = $phpcsFile->findNext($keyword, ($stackPtr + 1), $scopeOpener); - if ($keywordPtr === false) { - return false; - } - - $find = [ - \T_NS_SEPARATOR, - \T_STRING, - ]; - $find += Tokens::$emptyTokens; - - $names = []; - $end = $keywordPtr; - do { - $start = ($end + 1); - $end = $phpcsFile->findNext($find, $start, ($scopeOpener + 1), true); - $name = GetTokensAsString::noEmpties($phpcsFile, $start, ($end - 1)); - - if (\trim($name) !== '') { - $names[] = $name; - } - } while ($tokens[$end]['code'] === \T_COMMA); - - if (empty($names)) { - return false; - } - - return $names; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/Parentheses.php b/Magento2/Helpers/PHPCSUtils/Utils/Parentheses.php deleted file mode 100644 index 26ba1fd2..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/Parentheses.php +++ /dev/null @@ -1,155 +0,0 @@ - => - */ - private static $extraParenthesesOwners = [ - \T_LIST => \T_LIST, - \T_ISSET => \T_ISSET, - \T_UNSET => \T_UNSET, - \T_EMPTY => \T_EMPTY, - \T_EXIT => \T_EXIT, - \T_EVAL => \T_EVAL, - \T_ANON_CLASS => \T_ANON_CLASS, - // Work-around: anon classes were, in certain circumstances, tokenized as T_CLASS prior to PHPCS 3.4.0. - \T_CLASS => \T_CLASS, - ]; - - /** - * Get the stack pointer to the parentheses owner of an open/close parenthesis. - * - * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. - * - * @return int|false Integer stack pointer to the parentheses owner; or `FALSE` if the - * parenthesis does not have a (direct) owner or if the token passed - * was not a parenthesis. - */ - public static function getOwner(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]['parenthesis_owner'])) { - return $tokens[$stackPtr]['parenthesis_owner']; - } - - /* - * - `T_FN` was only backfilled in PHPCS 3.5.3/4/5. - * - On PHP 7.4 with PHPCS < 3.5.3, T_FN will not yet be a parentheses owner. - * - On PHP < 7.4 with PHPCS < 3.5.3, T_FN will be tokenized as T_STRING and not yet be a parentheses owner. - * - * {@internal As the 'parenthesis_owner' index is only set on parentheses, we didn't need to do any - * input validation before, but now we do.} - */ - if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] !== \T_OPEN_PARENTHESIS - && $tokens[$stackPtr]['code'] !== \T_CLOSE_PARENTHESIS) - ) { - return false; - } - - if ($tokens[$stackPtr]['code'] === \T_CLOSE_PARENTHESIS) { - $stackPtr = $tokens[$stackPtr]['parenthesis_opener']; - } - - $skip = Tokens::$emptyTokens; - $skip[\T_BITWISE_AND] = \T_BITWISE_AND; - - $prevNonEmpty = $phpcsFile->findPrevious($skip, ($stackPtr - 1), null, true); - if ($prevNonEmpty !== false - && (isset(self::$extraParenthesesOwners[$tokens[$prevNonEmpty]['code']]) - // Possibly an arrow function. - || FunctionDeclarations::isArrowFunction($phpcsFile, $prevNonEmpty) === true) - ) { - return $prevNonEmpty; - } - - return false; - } - - /** - * Check whether the parenthesis owner of an open/close parenthesis is within a limited - * set of valid owners. - * - * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. - * @param int|string|array $validOwners Array of token constants for the owners - * which should be considered valid. - * - * @return bool `TRUE` if the owner is within the list of `$validOwners`; `FALSE` if not and - * if the parenthesis does not have a (direct) owner. - */ - public static function isOwnerIn(File $phpcsFile, $stackPtr, $validOwners) - { - $owner = self::getOwner($phpcsFile, $stackPtr); - if ($owner === false) { - return false; - } - - $tokens = $phpcsFile->getTokens(); - $validOwners = (array) $validOwners; - - /* - * Work around tokenizer bug where anon classes were, in certain circumstances, tokenized - * as `T_CLASS` prior to PHPCS 3.4.0. - * As `T_CLASS` is normally not an parenthesis owner, we can safely add it to the array - * without doing a version check. - */ - if (\in_array(\T_ANON_CLASS, $validOwners, true)) { - $validOwners[] = \T_CLASS; - } - - /* - * Allow for T_FN token being tokenized as T_STRING before PHPCS 3.5.3. - */ - if (\defined('T_FN') && \in_array(\T_FN, $validOwners, true)) { - $validOwners += Collections::arrowFunctionTokensBC(); - } - - return \in_array($tokens[$owner]['code'], $validOwners, true); - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/Scopes.php b/Magento2/Helpers/PHPCSUtils/Utils/Scopes.php deleted file mode 100644 index 3975a6b3..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/Scopes.php +++ /dev/null @@ -1,80 +0,0 @@ -getTokens(); - $validScopes = (array) $validScopes; - - if (\in_array($tokens[$ptr]['code'], $validScopes, true) === true) { - return $ptr; - } - } - - return false; - } - - /** - * Check whether a T_FUNCTION token is a class/interface/trait method declaration. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack of the - * `T_FUNCTION` token to verify. - * - * @return bool - */ - public static function isOOMethod(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]) === false || $tokens[$stackPtr]['code'] !== \T_FUNCTION) { - return false; - } - - if (self::validDirectScope($phpcsFile, $stackPtr, BCTokens::ooScopeTokens()) !== false) { - return true; - } - - return false; - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/TextStrings.php b/Magento2/Helpers/PHPCSUtils/Utils/TextStrings.php deleted file mode 100644 index aca9ce09..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/TextStrings.php +++ /dev/null @@ -1,133 +0,0 @@ -getTokens(); - - // Must be the start of a text string token. - if (isset($tokens[$stackPtr], Collections::$textStingStartTokens[$tokens[$stackPtr]['code']]) === false) { - throw new RuntimeException( - '$stackPtr must be of type T_START_HEREDOC, T_START_NOWDOC, T_CONSTANT_ENCAPSED_STRING' - . ' or T_DOUBLE_QUOTED_STRING' - ); - } - - if ($tokens[$stackPtr]['code'] === \T_CONSTANT_ENCAPSED_STRING - || $tokens[$stackPtr]['code'] === \T_DOUBLE_QUOTED_STRING - ) { - $prev = $phpcsFile->findPrevious(\T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$stackPtr]['code'] === $tokens[$prev]['code']) { - throw new RuntimeException('$stackPtr must be the start of the text string'); - } - } - - $stripNewline = false; - - switch ($tokens[$stackPtr]['code']) { - case \T_START_HEREDOC: - $stripQuotes = false; - $stripNewline = true; - $targetType = \T_HEREDOC; - $current = ($stackPtr + 1); - break; - - case \T_START_NOWDOC: - $stripQuotes = false; - $stripNewline = true; - $targetType = \T_NOWDOC; - $current = ($stackPtr + 1); - break; - - default: - $targetType = $tokens[$stackPtr]['code']; - $current = $stackPtr; - break; - } - - $string = ''; - do { - $string .= $tokens[$current]['content']; - ++$current; - } while (isset($tokens[$current]) && $tokens[$current]['code'] === $targetType); - - if ($stripNewline === true) { - // Heredoc/nowdoc: strip the new line at the end of the string to emulate how PHP sees the string. - $string = \rtrim($string, "\r\n"); - } - - if ($stripQuotes === true) { - return self::stripQuotes($string); - } - - return $string; - } - - /** - * Strip text delimiter quotes from an arbitrary string. - * - * Intended for use with the "contents" of a `T_CONSTANT_ENCAPSED_STRING` / `T_DOUBLE_QUOTED_STRING`. - * - * - Prevents stripping mis-matched quotes. - * - Prevents stripping quotes from the textual content of the string. - * - * @since 1.0.0 - * - * @param string $string The raw string. - * - * @return string String without quotes around it. - */ - public static function stripQuotes($string) - { - return \preg_replace('`^([\'"])(.*)\1$`Ds', '$2', $string); - } -} diff --git a/Magento2/Helpers/PHPCSUtils/Utils/UseStatements.php b/Magento2/Helpers/PHPCSUtils/Utils/UseStatements.php deleted file mode 100644 index 5e965d33..00000000 --- a/Magento2/Helpers/PHPCSUtils/Utils/UseStatements.php +++ /dev/null @@ -1,412 +0,0 @@ -getTokens(); - - if (isset($tokens[$stackPtr]) === false - || $tokens[$stackPtr]['code'] !== \T_USE - ) { - throw new RuntimeException('$stackPtr must be of type T_USE'); - } - - $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($next === false) { - // Live coding or parse error. - return ''; - } - - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($prev !== false && $tokens[$prev]['code'] === \T_CLOSE_PARENTHESIS - && Parentheses::isOwnerIn($phpcsFile, $prev, \T_CLOSURE) === true - ) { - return 'closure'; - } - - $lastCondition = Conditions::getLastCondition($phpcsFile, $stackPtr); - if ($lastCondition === false || $tokens[$lastCondition]['code'] === \T_NAMESPACE) { - // Global or scoped namespace and not a closure use statement. - return 'import'; - } - - $traitScopes = BCTokens::ooScopeTokens(); - // Only classes and traits can import traits. - unset($traitScopes[\T_INTERFACE]); - - if (isset($traitScopes[$tokens[$lastCondition]['code']]) === true) { - return 'trait'; - } - - return ''; - } - - /** - * Determine whether a T_USE token represents a closure use statement. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the `T_USE` token. - * - * @return bool `TRUE` if the token passed is a closure use statement. - * `FALSE` if it's not. - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * `T_USE` token. - */ - public static function isClosureUse(File $phpcsFile, $stackPtr) - { - return (self::getType($phpcsFile, $stackPtr) === 'closure'); - } - - /** - * Determine whether a T_USE token represents a class/function/constant import use statement. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the `T_USE` token. - * - * @return bool `TRUE` if the token passed is an import use statement. - * `FALSE` if it's not. - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * `T_USE` token. - */ - public static function isImportUse(File $phpcsFile, $stackPtr) - { - return (self::getType($phpcsFile, $stackPtr) === 'import'); - } - - /** - * Determine whether a T_USE token represents a trait use statement. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the `T_USE` token. - * - * @return bool `TRUE` if the token passed is a trait use statement. - * `FALSE` if it's not. - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * `T_USE` token. - */ - public static function isTraitUse(File $phpcsFile, $stackPtr) - { - return (self::getType($phpcsFile, $stackPtr) === 'trait'); - } - - /** - * Split an import use statement into individual imports. - * - * Handles single import, multi-import and group-import use statements. - * - * @since 1.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack of the `T_USE` token. - * - * @return array A multi-level array containing information about the use statement. - * The first level is `'name'`, `'function'` and `'const'`. These keys will always exist. - * If any statements are found for any of these categories, the second level - * will contain the alias/name as the key and the full original use name as the - * value for each of the found imports or an empty array if no imports were found - * in this use statement for a particular category. - * - * For example, for this function group use statement: - * ```php - * use function Vendor\Package\{ - * LevelA\Name as Alias, - * LevelB\Another_Name, - * }; - * ``` - * the return value would look like this: - * ```php - * array( - * 'name' => array(), - * 'function' => array( - * 'Alias' => 'Vendor\Package\LevelA\Name', - * 'Another_Name' => 'Vendor\Package\LevelB\Another_Name', - * ), - * 'const' => array(), - * ) - * ``` - * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * `T_USE` token. - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the `T_USE` token is not for an import - * use statement. - */ - public static function splitImportUseStatement(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - if (isset($tokens[$stackPtr]) === false || $tokens[$stackPtr]['code'] !== \T_USE) { - throw new RuntimeException('$stackPtr must be of type T_USE'); - } - - if (self::isImportUse($phpcsFile, $stackPtr) === false) { - throw new RuntimeException('$stackPtr must be an import use statement'); - } - - $statements = [ - 'name' => [], - 'function' => [], - 'const' => [], - ]; - - $endOfStatement = $phpcsFile->findNext([\T_SEMICOLON, \T_CLOSE_TAG], ($stackPtr + 1)); - if ($endOfStatement === false) { - // Live coding or parse error. - return $statements; - } - - $endOfStatement++; - - $start = true; - $useGroup = false; - $hasAlias = false; - $baseName = ''; - $name = ''; - $type = ''; - $fixedType = false; - $alias = ''; - - for ($i = ($stackPtr + 1); $i < $endOfStatement; $i++) { - if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { - continue; - } - - $tokenCode = $tokens[$i]['code']; - - /* - * BC: Work round a tokenizer bug related to a parse error. - * - * If `function` or `const` is used as the alias, the semi-colon after it would - * be tokenized as T_STRING. - * For `function` this was fixed in PHPCS 2.8.0. For `const` the issue still exists - * in PHPCS 3.5.2. - * - * Along the same lines, the `}` T_CLOSE_USE_GROUP would also be tokenized as T_STRING. - */ - if ($tokenCode === \T_STRING) { - if ($tokens[$i]['content'] === ';') { - $tokenCode = \T_SEMICOLON; - } elseif ($tokens[$i]['content'] === '}') { - $tokenCode = \T_CLOSE_USE_GROUP; - } - } - - switch ($tokenCode) { - case \T_STRING: - // Only when either at the start of the statement or at the start of a new sub within a group. - if ($start === true && $fixedType === false) { - $content = \strtolower($tokens[$i]['content']); - if ($content === 'function' - || $content === 'const' - ) { - $type = $content; - $start = false; - if ($useGroup === false) { - $fixedType = true; - } - - break; - } else { - $type = 'name'; - } - } - - $start = false; - - if ($hasAlias === false) { - $name .= $tokens[$i]['content']; - } - - $alias = $tokens[$i]['content']; - break; - - case \T_AS: - $hasAlias = true; - break; - - case \T_OPEN_USE_GROUP: - $start = true; - $useGroup = true; - $baseName = $name; - $name = ''; - break; - - case \T_SEMICOLON: - case \T_CLOSE_TAG: - case \T_CLOSE_USE_GROUP: - case \T_COMMA: - if ($name !== '') { - if ($useGroup === true) { - $statements[$type][$alias] = $baseName . $name; - } else { - $statements[$type][$alias] = $name; - } - } - - if ($tokenCode !== \T_COMMA) { - break 2; - } - - // Reset. - $start = true; - $name = ''; - $hasAlias = false; - if ($fixedType === false) { - $type = ''; - } - break; - - case \T_NS_SEPARATOR: - $name .= $tokens[$i]['content']; - break; - - case \T_FUNCTION: - case \T_CONST: - /* - * BC: Work around tokenizer bug in PHPCS < 3.4.1. - * - * `function`/`const` in `use function`/`use const` tokenized as T_FUNCTION/T_CONST - * instead of T_STRING when there is a comment between the keywords. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2431 - */ - if ($start === true && $fixedType === false) { - $type = \strtolower($tokens[$i]['content']); - $start = false; - if ($useGroup === false) { - $fixedType = true; - } - - break; - } - - $start = false; - - if ($hasAlias === false) { - $name .= $tokens[$i]['content']; - } - - $alias = $tokens[$i]['content']; - break; - - /* - * Fall back in case reserved keyword is (illegally) used in name. - * Parse error, but not our concern. - */ - default: - if ($hasAlias === false) { - $name .= $tokens[$i]['content']; - } - - $alias = $tokens[$i]['content']; - break; - } - } - - return $statements; - } - - /** - * Split an import use statement into individual imports and merge it with an array of previously - * seen import use statements. - * - * Beware: this method should only be used to combine the import use statements found in *one* file. - * Do NOT combine the statements of multiple files as the result will be inaccurate and unreliable. - * - * In most cases when tempted to use this method, the {@see \PHPCSUtils\AbstractSniffs\AbstractFileContextSniff} - * (upcoming) should be used instead. - * - * @see \PHPCSUtils\AbstractSniffs\AbstractFileContextSniff - * @see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement() - * - * @since 1.0.0-alpha3 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position in the stack of the `T_USE` token. - * @param array $previousUseStatements The import `use` statements collected so far. - * This should be either the output of a - * previous call to this method or the output of - * an earlier call to the - * {@see UseStatements::splitImportUseStatement()} - * method. - * - * @return array A multi-level array containing information about the current `use` statement combined with - * the previously collected `use` statement information. - * See {@see UseStatements::splitImportUseStatement()} for more details about the array format. - */ - public static function splitAndMergeImportUseStatement(File $phpcsFile, $stackPtr, $previousUseStatements) - { - try { - $useStatements = self::splitImportUseStatement($phpcsFile, $stackPtr); - - if (isset($previousUseStatements['name']) === false) { - $previousUseStatements['name'] = $useStatements['name']; - } else { - $previousUseStatements['name'] += $useStatements['name']; - } - if (isset($previousUseStatements['function']) === false) { - $previousUseStatements['function'] = $useStatements['function']; - } else { - $previousUseStatements['function'] += $useStatements['function']; - } - if (isset($previousUseStatements['const']) === false) { - $previousUseStatements['const'] = $useStatements['const']; - } else { - $previousUseStatements['const'] += $useStatements['const']; - } - } catch (RuntimeException $e) { - // Not an import use statement. - } - - return $previousUseStatements; - } -} diff --git a/Magento2/Internal/Cache.php b/Magento2/Internal/Cache.php new file mode 100644 index 00000000..2717eece --- /dev/null +++ b/Magento2/Internal/Cache.php @@ -0,0 +1,87 @@ +isName($node->name, 'preg_split')) { + if (!$this->isName($node->name, 'preg_split') || !isset($node->args[2])) { return null; } + $value = $node->args[2]->value; - if ($node->args[2] !== LNumber::class) { + if ($value instanceof ConstFetch && $value->name->toString() === 'null') { $node->args[2] = $this->nodeFactory->createArg(-1); return $node; } diff --git a/Magento2/Rector/Tests/ReplacePregSplitNullLimit/Fixture/replace_null.php.inc b/Magento2/Rector/Tests/ReplacePregSplitNullLimit/Fixture/replace_null.php.inc index f0efbcf9..06116b3b 100644 --- a/Magento2/Rector/Tests/ReplacePregSplitNullLimit/Fixture/replace_null.php.inc +++ b/Magento2/Rector/Tests/ReplacePregSplitNullLimit/Fixture/replace_null.php.inc @@ -1,11 +1,17 @@ ----- diff --git a/Magento2/Sniffs/Annotation/MethodAnnotationStructureSniff.php b/Magento2/Sniffs/Annotation/MethodAnnotationStructureSniff.php index 538f80c9..a76240c7 100644 --- a/Magento2/Sniffs/Annotation/MethodAnnotationStructureSniff.php +++ b/Magento2/Sniffs/Annotation/MethodAnnotationStructureSniff.php @@ -51,13 +51,33 @@ public function register() public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $commentStartPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, ($stackPtr), 0); - $commentEndPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, ($stackPtr), 0); - if (!$commentStartPtr) { - $phpcsFile->addError('Comment block is missing', $stackPtr, 'MethodArguments'); + $commentEndPtr = $stackPtr; + $tokensToFind = [ + \T_SEMICOLON, + \T_OPEN_CURLY_BRACKET, + \T_CLOSE_CURLY_BRACKET, + \T_ATTRIBUTE_END, + \T_DOC_COMMENT_CLOSE_TAG + ]; + + do { + $commentEndPtr = $phpcsFile->findPrevious($tokensToFind, $commentEndPtr - 1); + if ($commentEndPtr !== false + && $tokens[$commentEndPtr]['code'] === \T_ATTRIBUTE_END + && isset($tokens[$commentEndPtr]['attribute_opener']) + ) { + $commentEndPtr = $tokens[$commentEndPtr]['attribute_opener']; + } + } while ($commentEndPtr !== false && !in_array($tokens[$commentEndPtr]['code'], $tokensToFind, true)); + + if ($commentEndPtr === false || $tokens[$commentEndPtr]['code'] !== \T_DOC_COMMENT_CLOSE_TAG) { + $phpcsFile->addError('Comment block is missing', $stackPtr, 'NoCommentBlock'); return; } + $commentStartPtr = $tokens[$commentEndPtr]['comment_opener'] + ?? $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $commentEndPtr - 1); + if ($this->PHPDocFormattingValidator->hasDeprecatedWellFormatted($commentStartPtr, $tokens) !== true) { $phpcsFile->addWarning( 'Motivation behind the added @deprecated tag MUST be explained. ' diff --git a/Magento2/Sniffs/Commenting/ClassAndInterfacePHPDocFormattingSniff.php b/Magento2/Sniffs/Commenting/ClassAndInterfacePHPDocFormattingSniff.php index 20c12851..b23b2858 100644 --- a/Magento2/Sniffs/Commenting/ClassAndInterfacePHPDocFormattingSniff.php +++ b/Magento2/Sniffs/Commenting/ClassAndInterfacePHPDocFormattingSniff.php @@ -63,8 +63,10 @@ public function process(File $phpcsFile, $stackPtr) return; } + $commentCloserPtr = $tokens[$commentStartPtr]['comment_closer']; + if ($this->PHPDocFormattingValidator->providesMeaning($namePtr, $commentStartPtr, $tokens) !== true) { - $phpcsFile->addWarning( + $fix = $phpcsFile->addFixableWarning( sprintf( '%s description must contain meaningful information beyond what its name provides or be removed.', ucfirst($tokens[$stackPtr]['content']) @@ -72,6 +74,18 @@ public function process(File $phpcsFile, $stackPtr) $stackPtr, 'InvalidDescription' ); + + if ($fix) { + for ($i = $commentStartPtr; $i <= $commentCloserPtr; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + if ($tokens[$commentStartPtr - 1]['code'] === T_WHITESPACE + && $tokens[$commentCloserPtr + 1]['code'] === T_WHITESPACE + ) { + $phpcsFile->fixer->replaceToken($commentCloserPtr + 1, ''); + } + } } if ($this->PHPDocFormattingValidator->hasDeprecatedWellFormatted($commentStartPtr, $tokens) !== true) { @@ -105,11 +119,35 @@ private function validateTags(File $phpcsFile, $commentStartPtr, $tokens) } if (in_array($tokens[$i]['content'], $this->forbiddenTags) === true) { - $phpcsFile->addWarning( + $fix = $phpcsFile->addFixableWarning( sprintf('Tag %s MUST NOT be used.', $tokens[$i]['content']), $i, 'ForbiddenTags' ); + + if ($fix) { + for ($j = $i - 1; $j > $commentStartPtr; $j--) { + if (!in_array($tokens[$j]['code'], [T_DOC_COMMENT_STAR, T_DOC_COMMENT_WHITESPACE], true)) { + break; + } + + if ($tokens[$j]['code'] === T_DOC_COMMENT_WHITESPACE && $tokens[$j]['content'] === "\n") { + break; + } + + $phpcsFile->fixer->replaceToken($j, ''); + } + + $phpcsFile->fixer->replaceToken($i, ''); + + for ($j = $i + 1; $j < $commentCloserPtr; $j++) { + $phpcsFile->fixer->replaceToken($j, ''); + + if ($tokens[$j]['code'] === T_DOC_COMMENT_WHITESPACE && $tokens[$j]['content'] === "\n") { + break; + } + } + } } } diff --git a/Magento2/Sniffs/Commenting/ClassPropertyPHPDocFormattingSniff.php b/Magento2/Sniffs/Commenting/ClassPropertyPHPDocFormattingSniff.php index 8c53669c..adeb03fa 100644 --- a/Magento2/Sniffs/Commenting/ClassPropertyPHPDocFormattingSniff.php +++ b/Magento2/Sniffs/Commenting/ClassPropertyPHPDocFormattingSniff.php @@ -32,6 +32,7 @@ class ClassPropertyPHPDocFormattingSniff extends AbstractVariableSniff T_NULLABLE, T_BITWISE_AND, T_TYPE_UNION, + T_READONLY, ]; /** diff --git a/Magento2/Sniffs/Functions/DiscouragedFunctionSniff.php b/Magento2/Sniffs/Functions/DiscouragedFunctionSniff.php index 51730217..45e00eb7 100644 --- a/Magento2/Sniffs/Functions/DiscouragedFunctionSniff.php +++ b/Magento2/Sniffs/Functions/DiscouragedFunctionSniff.php @@ -104,6 +104,7 @@ class DiscouragedFunctionSniff extends ForbiddenFunctionsSniff '^parsekit_compile_string$' => null, '^pathinfo$' => 'Magento\Framework\Filesystem\Io\File::getPathInfo', '^pcntl_.*$' => null, + '^posix_isatty$' => 'stream_isatty', '^posix_.*$' => null, '^pfpro_.*$' => null, '^pfsockopen$' => null, diff --git a/Magento2/Sniffs/Legacy/EscapeMethodsOnBlockClassSniff.php b/Magento2/Sniffs/Legacy/EscapeMethodsOnBlockClassSniff.php new file mode 100644 index 00000000..4d6d8288 --- /dev/null +++ b/Magento2/Sniffs/Legacy/EscapeMethodsOnBlockClassSniff.php @@ -0,0 +1,106 @@ + true, + 'escapeHtml' => true, + 'escapeHtmlAttr' => true, + 'escapeJs' => true, + 'escapeJsQuote' => true, + 'escapeQuote' => true, + 'escapeUrl' => true, + 'escapeXssInUrl' => true, + ]; + + /** + * @inheritDoc + */ + public function register() + { + return [ + T_OBJECT_OPERATOR, + ]; + } + + /** + * @inheritDoc + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($stackPtr <= 1 || !isset($tokens[$stackPtr + 2])) { + return; + } + + $objectPtr = $stackPtr - 1; + if ($tokens[$objectPtr]['code'] !== T_VARIABLE) { + $objectPtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, $objectPtr, null, true); + + if (!$objectPtr) { + return; + } + } + + if ($tokens[$objectPtr]['code'] !== T_VARIABLE + || $tokens[$objectPtr]['content'] !== '$block' + ) { + return; + } + + $methodPtr = $stackPtr + 1; + if ($tokens[$methodPtr]['code'] !== T_STRING) { + $methodPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $methodPtr, null, true); + + if (!$methodPtr) { + return; + } + } + + if ($tokens[$methodPtr]['code'] !== T_STRING + || !isset(self::ESCAPER_METHODS[$tokens[$methodPtr]['content']]) + ) { + return; + } + + $openParenPtr = $methodPtr + 1; + if ($tokens[$openParenPtr]['code'] !== T_OPEN_PARENTHESIS) { + $openParenPtr = $phpcsFile->findNext(Tokens::$emptyTokens, $openParenPtr, null, true); + + if (!$openParenPtr) { + return; + } + } + + if ($tokens[$openParenPtr]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $fix = $phpcsFile->addFixableWarning( + 'Using %s on $block is deprecated. Please use equivalent method on $escaper', + $methodPtr, + 'Found', + [ + $tokens[$methodPtr]['content'], // method name + ] + ); + + if ($fix) { + $phpcsFile->fixer->replaceToken($objectPtr, '$escaper'); + } + } +} diff --git a/Magento2/Sniffs/Legacy/_files/restricted_classes.php b/Magento2/Sniffs/Legacy/_files/restricted_classes.php index 3269caca..90092aa7 100644 --- a/Magento2/Sniffs/Legacy/_files/restricted_classes.php +++ b/Magento2/Sniffs/Legacy/_files/restricted_classes.php @@ -395,5 +395,10 @@ 'Magento/Ui/Test/Unit/Model/ManagerTest.php', 'Magento/Framework/View/Element/UiComponent/Config/Provider/Component/Definition.php', ] + ], + 'GraphQL\Language\Parser' => [ + 'warning_code' => 'GraphQLLanguageParserIsRestricted', + 'replacement' => 'Magento\Framework\GraphQl\Query\QueryParser', + 'exclude' => [] ] ]; diff --git a/Magento2/Sniffs/PHPCompatibility/ChangedIntToBoolParamTypeSniff.php b/Magento2/Sniffs/PHPCompatibility/ChangedIntToBoolParamTypeSniff.php deleted file mode 100644 index 673a0fe7..00000000 --- a/Magento2/Sniffs/PHPCompatibility/ChangedIntToBoolParamTypeSniff.php +++ /dev/null @@ -1,123 +0,0 @@ - [ - 1 => [ - 'name' => 'flag', - 'since' => '8.0', - ], - ], - 'sem_get' => [ - 4 => [ - 'name' => 'auto_release', - 'since' => '8.0', - ], - ], - ]; - - /** - * Do a version check to determine if this sniff needs to run at all. - * - * Checks against the first PHP version listed in the above array. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return ($this->supportsAbove('8.0') === false); - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - static $search; - - if (isset($search) === false) { - $search = [ - \T_LNUMBER => \T_LNUMBER, - \T_DNUMBER => \T_DNUMBER, - ]; - $search += BCTokens::arithmeticTokens(); - $search += Tokens::$emptyTokens; - } - - $functionLC = \strtolower($functionName); - $functionInfo = $this->targetFunctions[$functionLC]; - foreach ($functionInfo as $offset => $paramInfo) { - if (isset($parameters[$offset]) === false) { - continue; - } - - if ($this->supportsAbove($paramInfo['since']) === false) { - continue; - } - - $target = $parameters[$offset]; - - $hasNonNumeric = $phpcsFile->findNext($search, $target['start'], ($target['end'] + 1), true); - if ($hasNonNumeric !== false) { - // Not a purely numerical value. Ignore. - continue; - } - - $error = 'The $%s parameter of %s() expects a boolean value instead of an integer since PHP %s. Found: %s'; - $code = $this->stringToErrorCode($functionName . '_' . $paramInfo['name']) . 'NumericFound'; - $data = [ - $paramInfo['name'], - $functionLC, - $paramInfo['since'], - $target['raw'], - ]; - - $phpcsFile->addError($error, $target['start'], $code, $data); - } - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/ForbiddenFinalPrivateMethodsSniff.php b/Magento2/Sniffs/PHPCompatibility/ForbiddenFinalPrivateMethodsSniff.php deleted file mode 100644 index 85b2fe11..00000000 --- a/Magento2/Sniffs/PHPCompatibility/ForbiddenFinalPrivateMethodsSniff.php +++ /dev/null @@ -1,97 +0,0 @@ - Due to how common the usage of `final private function __construct` is and given that - * > the same results cannot be achieved with a protected visibility, an exception to this rule - * > is made for constructors. - * - * PHP version 8.0 - * - * @link https://wiki.php.net/rfc/inheritance_private_methods - * - * @since 10.0.0 - */ -class ForbiddenFinalPrivateMethodsSniff extends Sniff -{ - private const MESSAGE_FINAL = 'Private methods should not be declared as final since PHP 8.0'; - - /** - * Returns an array of tokens this test wants to listen for. - * - * @since 10.0.0 - * - * @return array - */ - public function register() - { - return [\T_FUNCTION]; - } - - /** - * Processes this test, when one of its tokens is encountered. - * - * @since 10.0.0 - * - * @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) - { - if (Scopes::isOOMethod($phpcsFile, $stackPtr) === false) { - // Function, not method. - return; - } - - $name = FunctionDeclarations::getName($phpcsFile, $stackPtr); - if (empty($name) === true) { - // Parse error or live coding. - return; - } - - if (\strtolower($name) === '__construct') { - // The rule does not apply to constructors. Bow out. - return; - } - - $properties = FunctionDeclarations::getProperties($phpcsFile, $stackPtr); - if ($properties['scope'] !== 'private' || $properties['is_final'] === false) { - // Not a private final method. - return; - } - - if ($phpcsFile->addFixableWarning(self::MESSAGE_FINAL, $stackPtr, 'Found') === true) { - $phpcsFile->fixer->beginChangeset(); - $prev = $phpcsFile->findPrevious(\T_FINAL, ($stackPtr - 1)); - $phpcsFile->fixer->replaceToken($prev, null); - // Remove extra space left out by previous replacement - $next = $phpcsFile->findNext(\T_WHITESPACE, $prev); - $phpcsFile->fixer->replaceToken($next, null); - $phpcsFile->fixer->endChangeset(); - } - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/RemovedAssertStringAssertionSniff.php b/Magento2/Sniffs/PHPCompatibility/RemovedAssertStringAssertionSniff.php deleted file mode 100644 index 294a4106..00000000 --- a/Magento2/Sniffs/PHPCompatibility/RemovedAssertStringAssertionSniff.php +++ /dev/null @@ -1,133 +0,0 @@ - Usage of a string as the assertion became deprecated. It now emits an E_DEPRECATED - * > notice when both assert.active and zend.assertions are set to 1. - * - * PHP 8.0: - * > assert() will no longer evaluate string arguments, instead they will be treated - * > like any other argument. `assert($a == $b)` should be used instead of `assert('$a == $b')`. - * - * PHP version 7.2 - * PHP version 8.0 - * - * @link https://wiki.php.net/rfc/deprecations_php_7_2#assert_with_string_argument - * @link https://github.com/php/php-src/blob/69888c3ff1f2301ead8e37b23ff8481d475e29d2/UPGRADING#L350-L354 - * @link https://www.php.net/manual/en/function.assert.php#refsect1-function.assert-changelog - * - * @since 10.0.0 - */ -class RemovedAssertStringAssertionSniff extends AbstractFunctionCallParameterSniff -{ - - /** - * Functions to check for. - * - * @since 10.0.0 - * - * @var array - */ - protected $targetFunctions = [ - 'assert' => true, - ]; - - /** - * Target tokens. - * - * If there is anything but any of these tokens in the parameter, we bow out as undetermined. - * - * @since 10.0.0 - * - * @var array - */ - private $targetTokens = []; - - /** - * Returns an array of tokens this test wants to listen for. - * - * @since 10.0.0 - * - * @return array - */ - public function register() - { - // Set $targetTokens only once. - $this->targetTokens = Tokens::$emptyTokens; - $this->targetTokens += Tokens::$stringTokens + Tokens::$heredocTokens; - $this->targetTokens[\T_STRING_CONCAT] = \T_STRING_CONCAT; - - return parent::register(); - } - - /** - * Do a version check to determine if this sniff needs to run at all. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return ($this->supportsAbove('7.2') === false); - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - if (isset($parameters[1]) === false) { - return; - } - - $targetParam = $parameters[1]; - $hasOther = $phpcsFile->findNext($this->targetTokens, $targetParam['start'], ($targetParam['end'] + 1), true); - if ($hasOther !== false) { - // Some other token was found, unclear whether this is really a text string. Bow out. - return; - } - - $error = 'Using a string as the assertion passed to assert() is deprecated since PHP 7.2%s. Found: %s'; - $code = 'Deprecated'; - $isError = false; - $data = [ - '', - $targetParam['raw'], - ]; - - if ($this->supportsAbove('8.0') === true) { - $data[0] = ' and removed since PHP 8.0'; - $isError = true; - $code = 'Removed'; - } - - $this->addMessage($phpcsFile, $error, $targetParam['start'], $isError, $code, $data); - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/RemovedCallingDestructAfterConstructorExitSniff.php b/Magento2/Sniffs/PHPCompatibility/RemovedCallingDestructAfterConstructorExitSniff.php deleted file mode 100644 index 8782039d..00000000 --- a/Magento2/Sniffs/PHPCompatibility/RemovedCallingDestructAfterConstructorExitSniff.php +++ /dev/null @@ -1,207 +0,0 @@ -supportsAbove('8.0') === false) { - return; - } - - $classPtr = Scopes::validDirectScope($phpcsFile, $stackPtr, [\T_CLASS, \T_ANON_CLASS, \T_TRAIT]); - if ($classPtr === false) { - // Function, not method. - return; - } - - $name = FunctionDeclarations::getName($phpcsFile, $stackPtr); - if (empty($name) === true) { - // Parse error or live coding. - return; - } - - if (\strtolower($name) !== '__construct') { - // The rule only applies to constructors. Bow out. - return; - } - - $tokens = $phpcsFile->getTokens(); - if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { - // Parse error or live coding. - return; - } - - $functionOpen = $tokens[$stackPtr]['scope_opener']; - $functionClose = $tokens[$stackPtr]['scope_closer']; - $exits = []; - for ($current = ($functionOpen + 1); $current < $functionClose; $current++) { - if (isset(Tokens::$emptyTokens[$tokens[$current]['code']]) === true) { - continue; - } - - if ($tokens[$current]['code'] === \T_EXIT) { - $exits[] = $current; - continue; - } - - // Skip over nested closed scopes as possible for efficiency. - // Ignore arrow functions as they aren't closed scopes. - if (isset(Collections::$closedScopes[$tokens[$current]['code']]) === true - && isset($tokens[$current]['scope_closer']) === true - ) { - $current = $tokens[$current]['scope_closer']; - continue; - } - - // Skip over array access and short arrays/lists, but not control structures. - if (isset($tokens[$current]['bracket_closer']) === true - && isset($tokens[$current]['scope_closer']) === false - ) { - $current = $tokens[$current]['bracket_closer']; - continue; - } - - // Skip over long array/lists as they can't contain an exit statement, except within a closed scope. - if (($tokens[$current]['code'] === \T_ARRAY || $tokens[$current]['code'] === \T_LIST) - && isset($tokens[$current]['parenthesis_closer']) === true - ) { - $current = $tokens[$current]['parenthesis_closer']; - continue; - } - } - - if (empty($exits) === true) { - // No calls to exit or die found. - return; - } - - if (isset($tokens[$classPtr]['scope_opener'], $tokens[$classPtr]['scope_closer']) === false) { - // Parse error, tokenizer error or live coding. - return; - } - - $hasDestruct = false; - $usesTraits = false; - $isError = false; - $classOpen = $tokens[$classPtr]['scope_opener']; - $classClose = $tokens[$classPtr]['scope_closer']; - $nextFunc = $classOpen; - - while (($nextFunc = $phpcsFile->findNext([\T_FUNCTION, \T_DOC_COMMENT_OPEN_TAG, \T_USE], ($nextFunc + 1), $classClose)) !== false) { - // Skip over docblocks. - if ($tokens[$nextFunc]['code'] === \T_DOC_COMMENT_OPEN_TAG) { - $nextFunc = $tokens[$nextFunc]['comment_closer']; - continue; - } - - if ($tokens[$nextFunc]['code'] === \T_USE - && UseStatements::isTraitUse($phpcsFile, $nextFunc) === true - ) { - $usesTraits = true; - continue; - } - - $functionScopeCloser = $nextFunc; - if (isset($tokens[$nextFunc]['scope_closer'])) { - // Normal (non-abstract) method. - $functionScopeCloser = $tokens[$nextFunc]['scope_closer']; - } - - $funcName = FunctionDeclarations::getName($phpcsFile, $nextFunc); - $nextFunc = $functionScopeCloser; // Set up to skip over the method content. - - if (empty($funcName) === true) { - continue; - } - - if (\strtolower($funcName) !== '__destruct') { - continue; - } - - $hasDestruct = true; - $isError = true; - break; - } - - if ($hasDestruct === false && $usesTraits === false) { - /* - * No destruct method or trait use found, check if this class extends another one - * which may contain a destruct method. - */ - $extends = ObjectDeclarations::findExtendedClassName($phpcsFile, $classPtr); - if (empty($extends) === true) { - // No destruct method and class doesn't extend nor uses traits, so the calls to exit can be ignored. - return; - } - } - - /* - * Ok, either a destruct method has been found and we can throw an error, or either a class extends - * or trait use has been found and no destruct method, in which case, we throw a warning. - */ - $error = 'When %s() is called within an object constructor, the object destructor will no longer be called since PHP 8.0'; - $errorCode = 'Found'; - if ($isError === false) { - $error .= ' While no __destruct() method was found in this class, one may be declared in the parent class or in a trait being used.'; - $errorCode = 'NeedsInspection'; - } - - foreach ($exits as $ptr) { - $this->addMessage($phpcsFile, $error, $ptr, $isError, $errorCode, [$tokens[$ptr]['content']]); - } - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseSniff.php b/Magento2/Sniffs/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseSniff.php deleted file mode 100644 index 0b26ea5e..00000000 --- a/Magento2/Sniffs/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseSniff.php +++ /dev/null @@ -1,83 +0,0 @@ - Calling `get_defined_functions()` with `$exclude_disabled` explicitly set to `false` - * > is deprecated. `get_defined_functions()` will never include disabled functions. - * - * PHP version 8.0 - * - * @link https://github.com/php/php-src/blob/69888c3ff1f2301ead8e37b23ff8481d475e29d2/UPGRADING#L514-L516 - * - * @since 10.0.0 - */ -class RemovedGetDefinedFunctionsExcludeDisabledFalseSniff extends AbstractFunctionCallParameterSniff -{ - - /** - * Functions to check for. - * - * @since 10.0.0 - * - * @var array - */ - protected $targetFunctions = [ - 'get_defined_functions' => true, - ]; - - /** - * Do a version check to determine if this sniff needs to run at all. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return ($this->supportsAbove('8.0') === false); - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - if (isset($parameters[1]) === false) { - return; - } - - if ($parameters[1]['raw'] !== 'false') { - return; - } - - $phpcsFile->addWarning( - 'Explicitly passing "false" as the value for $exclude_disabled to get_defined_functions() is deprecated since PHP 8.0.', - $parameters[1]['start'], - 'Deprecated' - ); - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/RemovedOptionalBeforeRequiredParamSniff.php b/Magento2/Sniffs/PHPCompatibility/RemovedOptionalBeforeRequiredParamSniff.php deleted file mode 100644 index 588ff7d2..00000000 --- a/Magento2/Sniffs/PHPCompatibility/RemovedOptionalBeforeRequiredParamSniff.php +++ /dev/null @@ -1,152 +0,0 @@ - Declaring a required parameter after an optional one is deprecated. As an - * > exception, declaring a parameter of the form "Type $param = null" before - * > a required one continues to be allowed, because this pattern was sometimes - * > used to achieve nullable types in older PHP versions. - * - * PHP version 8.0 - * - * @link https://github.com/php/php-src/blob/69888c3ff1f2301ead8e37b23ff8481d475e29d2/UPGRADING#L145-L151 - * - * @since 10.0.0 - */ -class RemovedOptionalBeforeRequiredParamSniff extends Sniff -{ - - /** - * Tokens allowed in the default value. - * - * This property will be enriched in the register() method. - * - * @since 10.0.0 - * - * @var array - */ - private $allowedInDefault = [ - \T_NULL => \T_NULL, - ]; - - /** - * Returns an array of tokens this test wants to listen for. - * - * @since 10.0.0 - * - * @return array - */ - public function register() - { - $this->allowedInDefault += Tokens::$emptyTokens; - - return Collections::functionDeclarationTokensBC(); - } - - /** - * Processes this test, when one of its tokens is encountered. - * - * @since 10.0.0 - * - * @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) - { - if ($this->supportsAbove('8.0') === false) { - return; - } - - try { - // Get all parameters from the function signature. - $parameters = FunctionDeclarations::getParameters($phpcsFile, $stackPtr); - if (empty($parameters)) { - return; - } - } catch (RuntimeException $e) { - // Most likely a T_STRING which wasn't an arrow function. - return; - } - - $error = 'Declaring a required parameter after an optional one is deprecated since PHP 8.0. Parameter %s is optional, while parameter %s is required.'; - - $paramCount = \count($parameters); - $lastKey = ($paramCount - 1); - $firstOptional = null; - - foreach ($parameters as $key => $param) { - /* - * Ignore variadic parameters, which are optional by nature. - * These always have to be declared last and this has been this way since their introduction. - */ - if ($param['variable_length'] === true) { - continue; - } - - // Handle optional parameters. - if (isset($param['default']) === true) { - if ($key === $lastKey) { - // This is the last parameter and it's optional, no further checking needed. - break; - } - - if (isset($firstOptional) === false) { - // Check if it's typed and has a null default value, in which case we can ignore it. - if ($param['type_hint'] !== '') { - $hasNull = $phpcsFile->findNext(\T_NULL, $param['default_token'], $param['comma_token']); - $hasNonNull = $phpcsFile->findNext( - $this->allowedInDefault, - $param['default_token'], - $param['comma_token'], - true - ); - - if ($hasNull !== false && $hasNonNull === false) { - continue; - } - } - - // Non-null default value. This is an optional param we need to take into account. - $firstOptional = $param['name']; - } - - continue; - } - - // Found a required parameter. - if (isset($firstOptional) === false) { - // No optional params found yet. - continue; - } - - // Found a required parameter with an optional param before it. - $data = [ - $firstOptional, - $param['name'], - ]; - - $phpcsFile->addWarning($error, $param['token'], 'Deprecated', $data); - } - } -} diff --git a/Magento2/Sniffs/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseSniff.php b/Magento2/Sniffs/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseSniff.php deleted file mode 100644 index 4f42c01f..00000000 --- a/Magento2/Sniffs/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseSniff.php +++ /dev/null @@ -1,84 +0,0 @@ - spl_autoload_register() will now always throw a TypeError on invalid - * > arguments, therefore the second argument $throw is ignored and a - * > notice will be emitted if it is set to false. - * - * PHP version 8.0 - * - * @link https://github.com/php/php-src/blob/c0172aa2bdb9ea223c8491bdb300995b93a857a0/UPGRADING#L393-L395 - * - * @since 10.0.0 - */ -class RemovedSplAutoloadRegisterThrowFalseSniff extends AbstractFunctionCallParameterSniff -{ - - /** - * Functions to check for. - * - * @since 10.0.0 - * - * @var array - */ - protected $targetFunctions = [ - 'spl_autoload_register' => true, - ]; - - /** - * Do a version check to determine if this sniff needs to run at all. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return ($this->supportsAbove('8.0') === false); - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - if (isset($parameters[2]) === false) { - return; - } - - if ($parameters[2]['raw'] !== 'false') { - return; - } - - $phpcsFile->addWarning( - 'Explicitly passing "false" as the value for $throw to spl_autoload_register() is deprecated since PHP 8.0.', - $parameters[2]['start'], - 'Deprecated' - ); - } -} diff --git a/Magento2/Sniffs/Security/XssTemplateSniff.php b/Magento2/Sniffs/Security/XssTemplateSniff.php index 2ba8e8c0..ba200daf 100644 --- a/Magento2/Sniffs/Security/XssTemplateSniff.php +++ b/Magento2/Sniffs/Security/XssTemplateSniff.php @@ -147,11 +147,11 @@ public function process(File $phpcsFile, $stackPtr) private function findSpecialAnnotation($stackPtr) { if ($this->tokens[$stackPtr]['code'] === T_ECHO) { - $startOfStatement = $this->file->findPrevious(T_OPEN_TAG, $stackPtr); + $startOfStatement = $this->file->findPrevious([T_OPEN_TAG, T_SEMICOLON], $stackPtr); return $this->file->findPrevious(T_COMMENT, $stackPtr, $startOfStatement); } if ($this->tokens[$stackPtr]['code'] === T_OPEN_TAG_WITH_ECHO) { - $endOfStatement = $this->file->findNext(T_CLOSE_TAG, $stackPtr); + $endOfStatement = $this->file->findNext([T_CLOSE_TAG, T_SEMICOLON], $stackPtr); return $this->file->findNext(T_COMMENT, $stackPtr, $endOfStatement); } return false; diff --git a/Magento2/Tests/Annotation/MethodAnnotationStructureUnitTest.inc b/Magento2/Tests/Annotation/MethodAnnotationStructureUnitTest.inc index 2e0fdf0e..94512c01 100644 --- a/Magento2/Tests/Annotation/MethodAnnotationStructureUnitTest.inc +++ b/Magento2/Tests/Annotation/MethodAnnotationStructureUnitTest.inc @@ -1,5 +1,5 @@ 1, 10 => 1, 18 => 1, 30 => 1, @@ -31,13 +32,18 @@ public function getErrorList() 185 => 1, 227 => 1, 235 => 1, + 261 => 1, 268 => 2, 269 => 1, 277 => 1, 278 => 1, 288 => 1, 289 => 1, - 298 => 1 + 298 => 1, + 396 => 1, + 407 => 1, + 418 => 1, + 424 => 1, ]; } diff --git a/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc b/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc index 4ffbea81..9c6af406 100644 --- a/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc +++ b/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc @@ -179,3 +179,10 @@ class AlsoDeprecatedButHandler } +/** + * @package this tag should not be used + */ +class OnlyUselessCommentContent +{ + +} diff --git a/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc.fixed b/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc.fixed new file mode 100644 index 00000000..33cbc544 --- /dev/null +++ b/Magento2/Tests/Commenting/ClassAndInterfacePHPDocFormattingUnitTest.1.inc.fixed @@ -0,0 +1,165 @@ + 1, 109 => 1, 118 => 1, - 127 => 1 + 127 => 1, + 183 => 1, ]; } } diff --git a/Magento2/Tests/Commenting/ClassPropertyPHPDocFormattingUnitTest.inc b/Magento2/Tests/Commenting/ClassPropertyPHPDocFormattingUnitTest.inc index 2925b6e0..d88c9d04 100644 --- a/Magento2/Tests/Commenting/ClassPropertyPHPDocFormattingUnitTest.inc +++ b/Magento2/Tests/Commenting/ClassPropertyPHPDocFormattingUnitTest.inc @@ -214,4 +214,14 @@ class correctlyFormattedClassMemberDocBlock private Test|Test2 $typedPropertyWithoutComment6; private ?Test $typedPropertyWithoutComment7; + + /** + * @var string + */ + protected readonly string $readOnlyString; + + /** + * @var int + */ + protected readonly int $readOnlyInteger; } diff --git a/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc new file mode 100644 index 00000000..260f0c93 --- /dev/null +++ b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc @@ -0,0 +1,87 @@ + + +
+

This unescaped output is fine here; other sniffs will complain about it though.

+ + getSomeString(); ?> + getSomeString(); ?> + getSomeString(); ?> + getSomeString(); ?> +
+ +
+

These should be using equivalent methods on the `$escaper` class, not the `$block` class.

+ + Note that I couldn't find any use of this method in any templates within Magento. + escapeCss($block->getSomeString()); ?> + + escapeHtml(__($block->getSomeString())) ?> + escapeHtml(__($block->getSomeString())); ?> + escapeHtml(__($block->getSomeString()), ['strong', 'em', 'span']) ?> + +
+
+
+ + + + The only example of this method being used was in a block class, rather than a template. + getItems() as $item) { + $item['sku'] = $block->escapeJsQuote($item['sku']); + } + ?> + + The only example of this method being used was in a block class, rather than a template. + escapeQuote(__($block->getData('welcome'))); ?> + + link text + + Note that I couldn't find any use of this method in any templates within Magento. + escapeXssInUrl($block->getSomeString()); ?> +
+ +
+

These are edge cases for formatting differences

+ + escapeHtml(''); + $block ->escapeHtml(''); + $block-> escapeHtml(''); + $block + ->escapeHtml(''); + $block + + ->escapeHtml(''); + $block-> + escapeHtml(''); + $block-> // comment + escapeHtml(''); + $block /* comment */ + ->escapeHtml(''); + + $block /* comment */ -> /* comment */ escapeHtml(''); + ?> +
+ +
+

These close-matches shouldn't be flagged by this sniff.

+ + escapeHTML(__($block->getSomeString())) ?> + escapeHtmlString(__($block->getSomeString())) ?> + escapeHtmlAttribute($block->getSomeString()) ?> + escapeCSS($block->getSomeString()); ?> + escapeJS($block->getData('html_id')) ?> + escapeJavaScript($block->getData('html_id')) ?> + escapeQuotes(__($block->getData('welcome'))); ?> + escapeURL($block->getUrl('adminhtml/notification/index')) ?> +
diff --git a/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc.fixed b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc.fixed new file mode 100644 index 00000000..80c4f22c --- /dev/null +++ b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.inc.fixed @@ -0,0 +1,87 @@ + + +
+

This unescaped output is fine here; other sniffs will complain about it though.

+ + getSomeString(); ?> + getSomeString(); ?> + getSomeString(); ?> + getSomeString(); ?> +
+ +
+

These should be using equivalent methods on the `$escaper` class, not the `$block` class.

+ + Note that I couldn't find any use of this method in any templates within Magento. + escapeCss($block->getSomeString()); ?> + + escapeHtml(__($block->getSomeString())) ?> + escapeHtml(__($block->getSomeString())); ?> + escapeHtml(__($block->getSomeString()), ['strong', 'em', 'span']) ?> + +
+
+
+ + + + The only example of this method being used was in a block class, rather than a template. + getItems() as $item) { + $item['sku'] = $escaper->escapeJsQuote($item['sku']); + } + ?> + + The only example of this method being used was in a block class, rather than a template. + escapeQuote(__($block->getData('welcome'))); ?> + + link text + + Note that I couldn't find any use of this method in any templates within Magento. + escapeXssInUrl($block->getSomeString()); ?> +
+ +
+

These are edge cases for formatting differences

+ + escapeHtml(''); + $escaper ->escapeHtml(''); + $escaper-> escapeHtml(''); + $escaper + ->escapeHtml(''); + $escaper + + ->escapeHtml(''); + $escaper-> + escapeHtml(''); + $escaper-> // comment + escapeHtml(''); + $escaper /* comment */ + ->escapeHtml(''); + + $escaper /* comment */ -> /* comment */ escapeHtml(''); + ?> +
+ +
+

These close-matches shouldn't be flagged by this sniff.

+ + escapeHTML(__($block->getSomeString())) ?> + escapeHtmlString(__($block->getSomeString())) ?> + escapeHtmlAttribute($block->getSomeString()) ?> + escapeCSS($block->getSomeString()); ?> + escapeJS($block->getData('html_id')) ?> + escapeJavaScript($block->getData('html_id')) ?> + escapeQuotes(__($block->getData('welcome'))); ?> + escapeURL($block->getUrl('adminhtml/notification/index')) ?> +
diff --git a/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.php b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.php new file mode 100644 index 00000000..feead3d1 --- /dev/null +++ b/Magento2/Tests/Legacy/EscapeMethodsOnBlockClassUnitTest.php @@ -0,0 +1,45 @@ + 1, + 21 => 1, + 22 => 1, + 23 => 1, + 25 => 1, + 26 => 1, + 27 => 1, + 31 => 1, + 40 => 1, + 45 => 1, + 47 => 1, + 50 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 61 => 1, + 64 => 1, + 66 => 1, + 68 => 1, + 70 => 1, + 72 => 1, + ]; + } +} diff --git a/Magento2/Tests/PHPCompatibility/BaseSniffTest.php b/Magento2/Tests/PHPCompatibility/BaseSniffTest.php deleted file mode 100644 index f6554540..00000000 --- a/Magento2/Tests/PHPCompatibility/BaseSniffTest.php +++ /dev/null @@ -1,422 +0,0 @@ - 3) - * - * @since 10.0.0 - * - * @var \PHP_CodeSniffer\Config - */ - public static $lastConfig = null; - - /** - * Reset the sniff file cache before/after each test class. - * - * @beforeClass - * @afterClass - * - * @since 7.0.4 - * @since 10.0.0 Renamed the method from `setUpBeforeClass()` to `resetSniffFiles()` and - * now using the `@beforeClass`/`@afterClass` annotations to allow for - * PHPUnit cross-version compatibility. - * - * @return void - */ - public static function resetSniffFiles() - { - self::$sniffFiles = []; - } - - /** - * Sets up this unit test. - * - * @before - * - * @since 5.5 - * @since 10.0.0 Renamed the method from `setUp()` to `setUpPHPCS()` and now using - * the `@before` annotation to allow for PHPUnit cross-version compatibility. - * - * @return void - */ - protected function setUpPHPCS() - { - if (\class_exists('\PHP_CodeSniffer') === true) { - /* - * PHPCS 2.x. - */ - if (self::$phpcs === null) { - self::$phpcs = new \PHP_CodeSniffer(); - } - - self::$phpcs->cli->setCommandLineValues(['-pq', '--colors']); - - // Restrict the sniffing of the test case files to the particular sniff being tested. - self::$phpcs->initStandard(self::STANDARD_NAME, [$this->getSniffCode()]); - - self::$phpcs->setIgnorePatterns([]); - } - } - - /** - * Reset the testVersion after each test. - * - * @after - * - * @since 5.5 - * @since 10.0.0 Renamed the method from `tearDwon()` to `resetTestVersion()` and now using - * the `@after` annotation to allow for PHPUnit cross-version compatibility. - * - * @return void - */ - public function resetTestVersion() - { - // Reset the targetPhpVersion. - Helper::setConfigData('testVersion', null, true, self::$lastConfig); - } - - /** - * Get the sniff code for the current sniff being tested. - * - * @since 7.1.3 - * - * @return string - */ - protected function getSniffCode() - { - $class = \get_class($this); - $parts = \explode('\\', $class); - $sniff = \array_pop($parts); - $sniff = \str_replace('UnitTest', '', $sniff); - $category = \array_pop($parts); - return self::STANDARD_NAME . '.' . $category . '.' . $sniff; - } - - /** - * Sniff a file and return resulting file object. - * - * @since 5.5 - * @since 9.0.0 Signature change. The `$filename` parameter was renamed to - * `$pathToFile` and now expects an absolute path instead of - * a relative one. - * - * @param string $pathToFile Absolute path to the file to sniff. - * Allows for passing __FILE__ from the unit test - * file. In that case, the test case file is presumed - * to have the same name, but with an `inc` extension. - * @param string $targetPhpVersion Value of 'testVersion' to set on PHPCS object. - * - * @return \PHP_CodeSniffer\Files\File|false File object. - */ - public function sniffFile($pathToFile, $targetPhpVersion = 'none') - { - if (\strpos($pathToFile, 'UnitTest.php') !== false) { - // Ok, so __FILE__ was passed, change the file extension. - $pathToFile = \str_replace('UnitTest.php', 'UnitTest.inc', $pathToFile); - } - $pathToFile = \realpath($pathToFile); - - if (isset(self::$sniffFiles[$pathToFile][$targetPhpVersion])) { - return self::$sniffFiles[$pathToFile][$targetPhpVersion]; - } - - try { - if (\class_exists('\PHP_CodeSniffer\Files\LocalFile')) { - // PHPCS 3.x, 4.x. - $config = new \PHP_CodeSniffer\Config(); - $config->cache = false; - $config->standards = [self::STANDARD_NAME]; - $config->sniffs = [$this->getSniffCode()]; - $config->ignored = []; - - if ($targetPhpVersion !== 'none') { - Helper::setConfigData('testVersion', $targetPhpVersion, true, $config); - } - - self::$lastConfig = $config; - - $ruleset = new \PHP_CodeSniffer\Ruleset($config); - - self::$sniffFiles[$pathToFile][$targetPhpVersion] = new \PHP_CodeSniffer\Files\LocalFile($pathToFile, $ruleset, $config); - self::$sniffFiles[$pathToFile][$targetPhpVersion]->process(); - } else { - // PHPCS 2.x. - self::$lastConfig = null; - - if ($targetPhpVersion !== 'none') { - Helper::setConfigData('testVersion', $targetPhpVersion, true); - } - - self::$sniffFiles[$pathToFile][$targetPhpVersion] = self::$phpcs->processFile($pathToFile); - } - } catch (\Exception $e) { - $this->fail('An unexpected exception has been caught when loading file "' . $pathToFile . '" : ' . $e->getMessage()); - return false; - } - - return self::$sniffFiles[$pathToFile][$targetPhpVersion]; - } - - /** - * Assert a PHPCS error on a particular line number. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer file object. - * @param int $lineNumber Line number. - * @param string $expectedMessage Expected error message (assertContains). - * - * @return bool - */ - public function assertError(File $file, $lineNumber, $expectedMessage) - { - $errors = $this->gatherErrors($file); - - return $this->assertForType($errors, 'error', $lineNumber, $expectedMessage); - } - - /** - * Assert a PHPCS warning on a particular line number. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer file object. - * @param int $lineNumber Line number. - * @param string $expectedMessage Expected message (assertContains). - * - * @return bool - */ - public function assertWarning(File $file, $lineNumber, $expectedMessage) - { - $warnings = $this->gatherWarnings($file); - - return $this->assertForType($warnings, 'warning', $lineNumber, $expectedMessage); - } - - /** - * Assert a PHPCS error or warning on a particular line number. - * - * @since 7.0.3 - * - * @param array $issues Array of issues of a particular type. - * @param string $type The type of issues, either 'error' or 'warning'. - * @param int $lineNumber Line number. - * @param string $expectedMessage Expected message (assertContains). - * - * @return bool - * - * @throws \Exception When no issues of a certain type where found on a line - * for which issues of that type where expected. - */ - private function assertForType($issues, $type, $lineNumber, $expectedMessage) - { - if (isset($issues[$lineNumber]) === false) { - $this->fail("Expected $type '$expectedMessage' on line number $lineNumber, but none found."); - } - - $insteadFoundMessages = []; - - // Concat any error messages so we can do an assertContains. - foreach ($issues[$lineNumber] as $issue) { - $insteadFoundMessages[] = $issue['message']; - } - - $insteadMessagesString = \implode(', ', $insteadFoundMessages); - - $msg = "Expected $type message '$expectedMessage' on line $lineNumber not found. Instead found: $insteadMessagesString."; - - if (\method_exists($this, 'assertStringContainsString') === false) { - // PHPUnit < 7. - return $this->assertContains($expectedMessage, $insteadMessagesString, $msg); - } - - return $this->assertStringContainsString($expectedMessage, $insteadMessagesString, $msg); - } - - /** - * Assert no violation (warning or error) on a given line number. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer File object. - * @param mixed $lineNumber Line number. - * - * @return bool - */ - public function assertNoViolation(File $file, $lineNumber = 0) - { - $errors = $this->gatherErrors($file); - $warnings = $this->gatherWarnings($file); - - if (empty($errors) && empty($warnings)) { - return $this->assertTrue(true); - } - - if ($lineNumber === 0) { - $failMessage = 'Failed asserting no violations in file. Found ' . \count($errors) . ' errors and ' . \count($warnings) . ' warnings.'; - $allMessages = $errors + $warnings; - // TODO: Update the fail message to give the tester some - // indication of what the errors or warnings were. - return $this->assertEmpty($allMessages, $failMessage); - } - - $encounteredMessages = []; - if (isset($errors[$lineNumber])) { - foreach ($errors[$lineNumber] as $error) { - $encounteredMessages[] = 'ERROR: ' . $error['message']; - } - } - - if (isset($warnings[$lineNumber])) { - foreach ($warnings[$lineNumber] as $warning) { - $encounteredMessages[] = 'WARNING: ' . $warning['message']; - } - } - - $failMessage = "Failed asserting no standards violation on line $lineNumber. Found: \n" - . \implode("\n", $encounteredMessages); - $this->assertCount(0, $encounteredMessages, $failMessage); - } - - /** - * Show violations in file by line number. - * - * This is useful for debugging sniffs on a file. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer file object. - * - * @return array - */ - public function showViolations(File $file) - { - $violations = [ - 'errors' => $this->gatherErrors($file), - 'warnings' => $this->gatherWarnings($file), - ]; - - return $violations; - } - - /** - * Gather all error messages by line number from phpcs file result. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer File object. - * - * @return array - */ - public function gatherErrors(File $file) - { - $foundErrors = $file->getErrors(); - - return $this->gatherIssues($foundErrors); - } - - /** - * Gather all warning messages by line number from phpcs file result. - * - * @since 5.5 - * - * @param \PHP_CodeSniffer\Files\File $file Codesniffer File object. - * - * @return array - */ - public function gatherWarnings(File $file) - { - $foundWarnings = $file->getWarnings(); - - return $this->gatherIssues($foundWarnings); - } - - /** - * Gather all messages or a particular type by line number. - * - * @since 7.0.3 - * - * @param array $issuesArray Array of a particular type of issues, - * i.e. errors or warnings. - * - * @return array - */ - private function gatherIssues($issuesArray) - { - $allIssues = []; - foreach ($issuesArray as $line => $lineIssues) { - foreach ($lineIssues as $column => $issues) { - foreach ($issues as $issue) { - - if (isset($allIssues[$line]) === false) { - $allIssues[$line] = []; - } - - $allIssues[$line][] = $issue; - } - } - } - - return $allIssues; - } -} diff --git a/Magento2/Tests/PHPCompatibility/ChangedIntToBoolParamTypeUnitTest.inc b/Magento2/Tests/PHPCompatibility/ChangedIntToBoolParamTypeUnitTest.inc deleted file mode 100644 index 31d6511c..00000000 --- a/Magento2/Tests/PHPCompatibility/ChangedIntToBoolParamTypeUnitTest.inc +++ /dev/null @@ -1,27 +0,0 @@ -sniffFile(__FILE__, $since); - $error = "The {$paramName} parameter of {$functionName}() expects a boolean value instead of an integer since PHP {$since}"; - - $this->assertError($file, $line, $error); - } - - /** - * Data provider. - * - * @see testChangedIntToBoolParamType) - * - * @return array - */ - public function dataChangedIntToBoolParamType() - { - return [ - [21, '8.0', '$auto_release', 'sem_get'], - [22, '8.0', '$auto_release', 'sem_get'], - [23, '8.0', '$auto_release', 'sem_get'], - [24, '8.0', '$auto_release', 'sem_get'], - [25, '8.0', '$auto_release', 'sem_get'], - [26, '8.0', '$auto_release', 'sem_get'], - [27, '8.0', '$flag', 'ob_implicit_flush'], - ]; - } - - /** - * Verify no false positives are thrown for valid code. - * - * @dataProvider dataNoFalsePositives - * - * @param int $line Line number. - * - * @return void - */ - public function testNoFalsePositives($line) - { - $file = $this->sniffFile(__FILE__, '99.0'); - $this->assertNoViolation($file, $line); - } - - /** - * Data provider. - * - * @see testNoFalsePositives() - * - * @return array - */ - public function dataNoFalsePositives() - { - $data = []; - - // No errors expected on the first 19 lines. - for ($line = 1; $line <= 19; $line++) { - $data[] = [$line]; - } - - return $data; - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.4'); // Version before first change. - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/ForbiddenFinalPrivateMethodsUnitTest.inc b/Magento2/Tests/PHPCompatibility/ForbiddenFinalPrivateMethodsUnitTest.inc deleted file mode 100644 index 660c6b57..00000000 --- a/Magento2/Tests/PHPCompatibility/ForbiddenFinalPrivateMethodsUnitTest.inc +++ /dev/null @@ -1,27 +0,0 @@ - 1, - 7 => 1, - 14 => 1, - 15 => 1, - 23 => 1, - 25 => 1, - ]; - } -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.inc b/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.inc deleted file mode 100644 index 2f0d9d2e..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.inc +++ /dev/null @@ -1,28 +0,0 @@ - 0); -EOT -); -assert( - 'is_int($int)' - . '&& $int > 10' -); diff --git a/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.php b/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.php deleted file mode 100644 index abb322c3..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedAssertStringAssertionUnitTest.php +++ /dev/null @@ -1,88 +0,0 @@ -sniffFile(__FILE__, '7.2'); - $error = 'Using a string as the assertion passed to assert() is deprecated since PHP 7.2'; - $this->assertWarning($file, $line, $error); - - $file = $this->sniffFile(__FILE__, '8.0'); - $error = 'Using a string as the assertion passed to assert() is deprecated since PHP 7.2 and removed since PHP 8.0'; - $this->assertError($file, $line, $error); - } - - /** - * Data provider. - * - * @see testRemovedAssertStringAssertion() - * - * @return array - */ - public function dataRemovedAssertStringAssertion() - { - return [ - [18], - [19], - [20], - [25], - ]; - } - - /** - * Verify there are no false positives on code this sniff should ignore. - * - * @return void - */ - public function testNoFalsePositives() - { - $file = $this->sniffFile(__FILE__, '7.2'); - - // No errors expected on the first 16 lines. - for ($line = 1; $line <= 16; $line++) { - $this->assertNoViolation($file, $line); - } - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.1'); - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.inc b/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.inc deleted file mode 100644 index db453a1d..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.inc +++ /dev/null @@ -1,124 +0,0 @@ - function() { exit; }, // Ignore, nested closed scope. - ]; - - $anon = new class { - function something() { - exit; // Ignore, nested closed scope. - } - }; - - $array = array( - 'closure' => function() { exit; }, // Ignore, nested closed scope. - ); - - die; // Error. - } - - /** - * This should be easily skipped over. - */ - abstract function something(); - - public function __DeStruct() { - // Destructor will not be called on exit() in constructor. - } -} - -trait CrossVersionInValid -{ - public function __construct() { - exit(1); // Error. - } - - public function __destruct() { - // Destructor will not be called on exit() in constructor. - } -} - -class DoesntExtendAndDoesntHaveDestructMethodButUsesTrait { - use TraitWhichMayOrMayNotContainADestructMethod; - - public function __construct() { - die(1); // Warning. - } -} - -/* - * Prevent false positives. - */ -class DoesntExtendAndDoesntHaveDestructMethod { - public function __construct() { - exit(1); - } -} - -trait CantExtendAndDoesntHaveDestructMethod { - public function __construct() { - exit(1); - } -} - -class ExitNotInFunctionScope { - public function __construct() { - $this->property = function($param) { - exit(1); - }; - } - - public function __destruct() {} -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.php b/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.php deleted file mode 100644 index e22ff211..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedCallingDestructAfterConstructorExitUnitTest.php +++ /dev/null @@ -1,118 +0,0 @@ -sniffFile(__FILE__, '8.0'); - $error = "When $name() is called within an object constructor, the object destructor will no longer be called since PHP 8.0"; - - if ($isError === true) { - $this->assertError($file, $line, $error); - } else { - $this->assertWarning($file, $line, $error); - } - } - - /** - * Data provider. - * - * @see testRemovedCallingDestructAfterConstructorExit() - * - * @return array - */ - public function dataRemovedCallingDestructAfterConstructorExit() - { - return [ - [33, 'exit'], - [44, 'die', false], - [46, 'exit', false], - [69, 'die'], - [85, 'exit'], - [97, 'die', false], - ]; - } - - /** - * Verify the sniff does not throw false positives for valid code. - * - * @dataProvider dataNoFalsePositives - * - * @param int $line The line number. - * - * @return void - */ - public function testNoFalsePositives($line) - { - $file = $this->sniffFile(__FILE__, '8.0'); - $this->assertNoViolation($file, $line); - } - - /** - * Data provider. - * - * @see testNoFalsePositives() - * - * @return array - */ - public function dataNoFalsePositives() - { - $cases = []; - // No errors expected on the first 26 lines. - for ($line = 1; $line <= 26; $line++) { - $cases[] = [$line]; - } - - $cases[] = [56]; - $cases[] = [61]; - $cases[] = [66]; - $cases[] = [106]; - $cases[] = [112]; - $cases[] = [119]; - - return $cases; - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.4'); - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseUnitTest.inc b/Magento2/Tests/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseUnitTest.inc deleted file mode 100644 index 40353bc7..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedGetDefinedFunctionsExcludeDisabledFalseUnitTest.inc +++ /dev/null @@ -1,11 +0,0 @@ -sniffFile(__FILE__, '8.0'); - $this->assertWarning($file, $line, 'Explicitly passing "false" as the value for $exclude_disabled to get_defined_functions() is deprecated since PHP 8.0.'); - } - - /** - * Data provider. - * - * @see testRemovedGetDefinedFunctionsExcludeDisabledFalse() - * - * @return array - */ - public function dataRemovedGetDefinedFunctionsExcludeDisabledFalse() - { - return [ - [11], - ]; - } - - /** - * Verify the sniff does not throw false positives for valid code. - * - * @return void - */ - public function testNoFalsePositives() - { - $file = $this->sniffFile(__FILE__, '8.0'); - - // No errors expected on the first 9 lines. - for ($line = 1; $line <= 9; $line++) { - $this->assertNoViolation($file, $line); - } - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.4'); - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.inc b/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.inc deleted file mode 100644 index 4cd62436..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.inc +++ /dev/null @@ -1,51 +0,0 @@ - $a ? (string) $b : ''; - -// Parse error, nothing in default, not our concern. Throw error anyway. -$closure = function ($a = /*comment*/, $b) {}; - -// Prevent false positives on variadic parameters. -function variadicIsOptionalByNature($a, int ...$b) {} -function variadicIsOptionalByNatureWithExtraOptional($a, $b = null, ...$c) {} -// Intentional parse error. This has always been an error though, so ignore for this sniff. -function variadicBeforeRequiredWasAlwaysAnError(...$a, $b) {} - -// Rule also applies to constructor property promotion. -class ConstructorPropertyPromotion { - public function __construct( - public $propA = 10, - protected $propB, - ) {} -} - -class MixedWithOptionalProperty { - public function __construct( - public $propA = false, - $normalParam - ) {} -} - -class MixedWithOptionalParam { - public function __construct( - public $propA, - $normalParam = 10, // OK. - ) {} -} - -// Intentional parse error. This has to be the last test in the file. -$closure = function( $a = [], $b diff --git a/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.php b/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.php deleted file mode 100644 index 3f558fdb..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedOptionalBeforeRequiredParamUnitTest.php +++ /dev/null @@ -1,115 +0,0 @@ -sniffFile(__FILE__, '8.0'); - $this->assertWarning($file, $line, 'Declaring a required parameter after an optional one is deprecated since PHP 8.0'); - } - - /** - * Data provider. - * - * @see testRemovedOptionalBeforeRequiredParam() - * - * @return array - */ - public function dataRemovedOptionalBeforeRequiredParam() - { - return [ - [13], // Warning x 2. - [14], - [16], - [17], - [20], - [32], - [39], - ]; - } - - /** - * Verify the sniff does not throw false positives for valid code. - * - * @dataProvider dataNoFalsePositives - * - * @param int $line The line number. - * - * @return void - */ - public function testNoFalsePositives($line) - { - $file = $this->sniffFile(__FILE__, '8.0'); - $this->assertNoViolation($file, $line); - } - - /** - * Data provider. - * - * @see testNoFalsePositives() - * - * @return array - */ - public function dataNoFalsePositives() - { - $cases = []; - // No errors expected on the first 9 lines. - for ($line = 1; $line <= 9; $line++) { - $cases[] = [$line]; - } - - // Don't error on variadic parameters. - $cases[] = [23]; - $cases[] = [24]; - $cases[] = [26]; - - // Constructor property promotion - valid example. - $cases[] = [46]; - - // Add parse error test case. - $cases[] = [51]; - - return $cases; - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.4'); - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseUnitTest.inc b/Magento2/Tests/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseUnitTest.inc deleted file mode 100644 index 7e7f3e09..00000000 --- a/Magento2/Tests/PHPCompatibility/RemovedSplAutoloadRegisterThrowFalseUnitTest.inc +++ /dev/null @@ -1,13 +0,0 @@ -sniffFile(__FILE__, '8.0'); - $this->assertWarning($file, $line, 'Explicitly passing "false" as the value for $throw to spl_autoload_register() is deprecated since PHP 8.0.'); - } - - /** - * Data provider. - * - * @see testRemovedSplAutoloadRegisterThrowFalse() - * - * @return array - */ - public function dataRemovedSplAutoloadRegisterThrowFalse() - { - return [ - [13], - ]; - } - - /** - * Verify the sniff does not throw false positives for valid code. - * - * @return void - */ - public function testNoFalsePositives() - { - $file = $this->sniffFile(__FILE__, '8.0'); - - // No errors expected on the first 11 lines. - for ($line = 1; $line <= 11; $line++) { - $this->assertNoViolation($file, $line); - } - } - - /** - * Verify no notices are thrown at all. - * - * @return void - */ - public function testNoViolationsInFileOnValidVersion() - { - $file = $this->sniffFile(__FILE__, '7.4'); - $this->assertNoViolation($file); - } -} diff --git a/Magento2/Tests/PHPCompatibility/Util/CoreMethodTestFrame.php b/Magento2/Tests/PHPCompatibility/Util/CoreMethodTestFrame.php deleted file mode 100644 index e4441380..00000000 --- a/Magento2/Tests/PHPCompatibility/Util/CoreMethodTestFrame.php +++ /dev/null @@ -1,51 +0,0 @@ -10 error + + 10 + error + 10 error @@ -350,7 +354,7 @@ 8 warning - + 7 @@ -484,7 +488,6 @@ 6 warning - */PHPCompatibility/* 6 @@ -755,6 +758,8 @@ */Test/* *Test.php */PHPCSUtils/* + + @@ -762,25 +767,11 @@ - + - - - - - - - - - - - - - + + diff --git a/Magento2Framework/Sniffs/Header/CopyrightAnotherExtensionsFilesSniff.php b/Magento2Framework/Sniffs/Header/CopyrightAnotherExtensionsFilesSniff.php index 3bafbb1f..3310e667 100644 --- a/Magento2Framework/Sniffs/Header/CopyrightAnotherExtensionsFilesSniff.php +++ b/Magento2Framework/Sniffs/Header/CopyrightAnotherExtensionsFilesSniff.php @@ -16,6 +16,7 @@ class CopyrightAnotherExtensionsFilesSniff implements Sniff private const COPYRIGHT_MAGENTO_TEXT = 'Copyright © Magento, Inc. All rights reserved.'; private const COPYRIGHT_ADOBE = '/Copyright \d+ Adobe/'; + private const COPYRIGHT_ADOBE_TEXT = 'ADOBE CONFIDENTIAL'; /** * Defines the tokenizers that this sniff is using. @@ -48,6 +49,7 @@ public function process(File $phpcsFile, $stackPtr) if (strpos($fileText, self::COPYRIGHT_MAGENTO_TEXT) !== false || preg_match(self::COPYRIGHT_ADOBE, $fileText) + || strpos($fileText, self::COPYRIGHT_ADOBE_TEXT) !== false ) { return; } diff --git a/Magento2Framework/Sniffs/Header/CopyrightGraphQLSniff.php b/Magento2Framework/Sniffs/Header/CopyrightGraphQLSniff.php index 1e488e69..5eae2b5e 100644 --- a/Magento2Framework/Sniffs/Header/CopyrightGraphQLSniff.php +++ b/Magento2Framework/Sniffs/Header/CopyrightGraphQLSniff.php @@ -16,6 +16,7 @@ class CopyrightGraphQLSniff implements Sniff private const COPYRIGHT_MAGENTO_TEXT = 'Copyright © Magento, Inc. All rights reserved.'; private const COPYRIGHT_ADOBE = '/Copyright \d+ Adobe/'; + private const COPYRIGHT_ADOBE_TEXT = 'ADOBE CONFIDENTIAL'; private const FILE_EXTENSION = 'graphqls'; @@ -44,7 +45,9 @@ public function process(File $phpcsFile, $stackPtr) // @phpcs:ignore Magento2.Functions.DiscouragedFunction.Discouraged $content = file_get_contents($phpcsFile->getFilename()); - if (strpos($content, self::COPYRIGHT_MAGENTO_TEXT) !== false || preg_match(self::COPYRIGHT_ADOBE, $content)) { + if (strpos($content, self::COPYRIGHT_MAGENTO_TEXT) !== false + || preg_match(self::COPYRIGHT_ADOBE, $content) + || strpos($content, self::COPYRIGHT_ADOBE_TEXT) !== false) { return; } diff --git a/Magento2Framework/Sniffs/Header/CopyrightSniff.php b/Magento2Framework/Sniffs/Header/CopyrightSniff.php index 81442207..e23aaba4 100644 --- a/Magento2Framework/Sniffs/Header/CopyrightSniff.php +++ b/Magento2Framework/Sniffs/Header/CopyrightSniff.php @@ -16,6 +16,7 @@ class CopyrightSniff implements Sniff private const COPYRIGHT_MAGENTO_TEXT = 'Copyright © Magento, Inc. All rights reserved.'; private const COPYRIGHT_ADOBE = '/Copyright \d+ Adobe/'; + private const COPYRIGHT_ADOBE_TEXT = 'ADOBE CONFIDENTIAL'; /** * @inheritdoc @@ -48,7 +49,9 @@ public function process(File $phpcsFile, $stackPtr) $content = $phpcsFile->getTokens()[$positionComment]['content']; $adobeCopyrightFound = preg_match(self::COPYRIGHT_ADOBE, $content); - if (strpos($content, self::COPYRIGHT_MAGENTO_TEXT) !== false || $adobeCopyrightFound) { + if (strpos($content, self::COPYRIGHT_MAGENTO_TEXT) !== false || + $adobeCopyrightFound || + strpos($content, self::COPYRIGHT_ADOBE_TEXT) !== false) { return; } diff --git a/Magento2Framework/ruleset.xml b/Magento2Framework/ruleset.xml index 5e16e7a1..e827ff13 100644 --- a/Magento2Framework/ruleset.xml +++ b/Magento2Framework/ruleset.xml @@ -4,10 +4,11 @@ + + 5 warning - */PHPCompatibility/* 5 @@ -18,7 +19,6 @@ 5 warning - */PHPCompatibility/* *\.php$ *\.phtml$ */PHPCSUtils/* diff --git a/README.md b/README.md index 3cfd6c0a..8ca973e1 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ npm run eslint -- path/to/analyze ``` ### RECTOR PHP -From `magento-condign-standard` project, you can execute rector php as follows: +From `magento-coding-standard` project, you can execute rector php as follows: ```bash vendor/bin/rector process Magento2 Magento2Framework PHP_CodeSniffer --dry-run --autoload-file vendor/squizlabs/php_codesniffer/autoload.php ``` diff --git a/composer.json b/composer.json index 58996ae3..70878734 100644 --- a/composer.json +++ b/composer.json @@ -6,19 +6,20 @@ "AFL-3.0" ], "type": "phpcodesniffer-standard", - "version": "31", + "version": "33", "require": { - "php": ">=7.4", + "php": "~8.1.0 || ~8.2.0", "webonyx/graphql-php": "^15.0", "ext-simplexml": "*", "ext-dom": "*", - "phpcompatibility/php-compatibility": "^9.3", "squizlabs/php_codesniffer": "^3.6.1", - "rector/rector": "^0.15.10", - "symfony/polyfill": "^1.16" + "rector/rector": "^0.17.12", + "phpcsstandards/phpcsutils": "^1.0.5", + "magento/php-compatibility-fork": "^0.1" }, "require-dev": { - "phpunit/phpunit": "^9.5.8" + "phpunit/phpunit": "^9.5.10", + "yoast/phpunit-polyfills": "^1.0" }, "autoload-dev": { "files": [ @@ -35,7 +36,12 @@ } }, "scripts": { - "post-install-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../phpcompatibility/php-compatibility/PHPCompatibility", - "post-update-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../phpcompatibility/php-compatibility/PHPCompatibility" + "post-install-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../magento/php-compatibility-fork/PHPCompatibility", + "post-update-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../magento/php-compatibility-fork/PHPCompatibility" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": false + } } } diff --git a/composer.lock b/composer.lock index e9e1ad93..9642857a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,34 +4,118 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "15fe639e2947bab4e7afcbd629e84805", + "content-hash": "e110c856856bed580d6d373c21e4b90e", "packages": [ { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "magento/php-compatibility-fork", + "version": "v0.1.0", + "source": { + "type": "git", + "url": "https://github.com/magento/PHPCompatibilityFork.git", + "reference": "1cf031c2a68e3e52e460c5690ed8d1d6d45f4653" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/magento/PHPCompatibilityFork/zipball/1cf031c2a68e3e52e460c5690ed8d1d6d45f4653", + "reference": "1cf031c2a68e3e52e460c5690ed8d1d6d45f4653", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.0.5", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "replace": { + "phpcompatibility/php-compatibility": "*", + "wimg/php-compatibility": "*" }, "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.3", + "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4 || ^10.1.0", + "yoast/phpunit-polyfills": "^1.0.5 || ^2.0.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, "type": "phpcodesniffer-standard", @@ -55,31 +139,106 @@ "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" } ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility. This is a fork of phpcompatibility/php-compatibility", "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", "keywords": [ "compatibility", "phpcs", - "standards" + "standards", + "static analysis" ], "support": { "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", "source": "https://github.com/PHPCompatibility/PHPCompatibility" }, - "time": "2019-12-27T09:44:58+00:00" + "time": "2023-11-29T22:34:17+00:00" + }, + { + "name": "phpcsstandards/phpcsutils", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", + "reference": "0cfef5193e68e8ff179333d8ae937db62939b656" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/0cfef5193e68e8ff179333d8ae937db62939b656", + "reference": "0cfef5193e68e8ff179333d8ae937db62939b656", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.7.1 || 4.0.x-dev@dev" + }, + "require-dev": { + "ext-filter": "*", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.3", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3", + "yoast/phpunit-polyfills": "^1.0.1" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPCSUtils/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" + } + ], + "description": "A suite of utility functions for use with PHP_CodeSniffer", + "homepage": "https://phpcsutils.com/", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "phpcs3", + "standards", + "static analysis", + "tokens", + "utility" + ], + "support": { + "docs": "https://phpcsutils.com/", + "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "source": "https://github.com/PHPCSStandards/PHPCSUtils" + }, + "time": "2023-04-17T16:27:27+00:00" }, { "name": "phpstan/phpstan", - "version": "1.9.14", + "version": "1.10.30", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e5fcc96289cf737304286a9b505fbed091f02e58" + "reference": "2910afdd3fe33e5afd71c09f3fb0d0845b48c410" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58", - "reference": "e5fcc96289cf737304286a9b505fbed091f02e58", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2910afdd3fe33e5afd71c09f3fb0d0845b48c410", + "reference": "2910afdd3fe33e5afd71c09f3fb0d0845b48c410", "shasum": "" }, "require": { @@ -108,8 +267,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.14" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -125,30 +287,29 @@ "type": "tidelift" } ], - "time": "2023-01-19T10:47:09+00:00" + "time": "2023-08-22T13:48:25+00:00" }, { "name": "rector/rector", - "version": "0.15.10", + "version": "0.17.12", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "000bfb6f7974449399f39e1a210458395b75c887" + "reference": "af3a14a8a9fffa3100b730571c356f6c658d5e09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/000bfb6f7974449399f39e1a210458395b75c887", - "reference": "000bfb6f7974449399f39e1a210458395b75c887", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/af3a14a8a9fffa3100b730571c356f6c658d5e09", + "reference": "af3a14a8a9fffa3100b730571c356f6c658d5e09", "shasum": "" }, "require": { "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.9.7" + "phpstan/phpstan": "^1.10.26" }, "conflict": { "rector/rector-doctrine": "*", "rector/rector-downgrade-php": "*", - "rector/rector-php-parser": "*", "rector/rector-phpunit": "*", "rector/rector-symfony": "*" }, @@ -156,11 +317,6 @@ "bin/rector" ], "type": "library", - "extra": { - "branch-alias": { - "dev-main": "0.14-dev" - } - }, "autoload": { "files": [ "bootstrap.php" @@ -171,9 +327,15 @@ "MIT" ], "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/0.15.10" + "source": "https://github.com/rectorphp/rector/tree/0.17.12" }, "funding": [ { @@ -181,7 +343,7 @@ "type": "github" } ], - "time": "2023-01-21T14:30:16+00:00" + "time": "2023-08-10T15:22:02+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -239,123 +401,6 @@ }, "time": "2022-06-18T07:21:10+00:00" }, - { - "name": "symfony/polyfill", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill.git", - "reference": "b78222a273aac3e5bab6358bf499d7f1fb88e48b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill/zipball/b78222a273aac3e5bab6358bf499d7f1fb88e48b", - "reference": "b78222a273aac3e5bab6358bf499d7f1fb88e48b", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "replace": { - "symfony/polyfill-apcu": "self.version", - "symfony/polyfill-ctype": "self.version", - "symfony/polyfill-iconv": "self.version", - "symfony/polyfill-intl-grapheme": "self.version", - "symfony/polyfill-intl-icu": "self.version", - "symfony/polyfill-intl-idn": "self.version", - "symfony/polyfill-intl-messageformatter": "self.version", - "symfony/polyfill-intl-normalizer": "self.version", - "symfony/polyfill-mbstring": "self.version", - "symfony/polyfill-php72": "self.version", - "symfony/polyfill-php73": "self.version", - "symfony/polyfill-php74": "self.version", - "symfony/polyfill-php80": "self.version", - "symfony/polyfill-php81": "self.version", - "symfony/polyfill-php82": "self.version", - "symfony/polyfill-php83": "self.version", - "symfony/polyfill-util": "self.version", - "symfony/polyfill-uuid": "self.version", - "symfony/polyfill-xml": "self.version" - }, - "require-dev": { - "symfony/intl": "^4.4|^5.0|^6.0", - "symfony/phpunit-bridge": "^5.3|^6.0", - "symfony/var-dumper": "^4.4|^5.1|^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - } - }, - "autoload": { - "files": [ - "src/bootstrap.php", - "src/Apcu/bootstrap.php", - "src/Ctype/bootstrap.php", - "src/Uuid/bootstrap.php", - "src/Iconv/bootstrap.php", - "src/Intl/Grapheme/bootstrap.php", - "src/Intl/Idn/bootstrap.php", - "src/Intl/Icu/bootstrap.php", - "src/Intl/MessageFormatter/bootstrap.php", - "src/Intl/Normalizer/bootstrap.php", - "src/Mbstring/bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\": "src/" - }, - "classmap": [ - "src/Intl/Icu/Resources/stubs", - "src/Intl/MessageFormatter/Resources/stubs", - "src/Intl/Normalizer/Resources/stubs", - "src/Php82/Resources/stubs", - "src/Php80/Resources/stubs", - "src/Php73/Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfills backporting features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compat", - "compatibility", - "polyfill", - "shim" - ], - "support": { - "issues": "https://github.com/symfony/polyfill/issues", - "source": "https://github.com/symfony/polyfill/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-10T10:11:03+00:00" - }, { "name": "webonyx/graphql-php", "version": "v15.0.0", @@ -2157,6 +2202,66 @@ } ], "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "yoast/phpunit-polyfills", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "3b59adeef77fb1c03ff5381dbb9d68b0aaff3171" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/3b59adeef77fb1c03ff5381dbb9d68b0aaff3171", + "reference": "3b59adeef77fb1c03ff5381dbb9d68b0aaff3171", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "require-dev": { + "yoast/yoastcs": "^2.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" + } + ], + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", + "keywords": [ + "phpunit", + "polyfill", + "testing" + ], + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2023-03-30T23:39:05+00:00" } ], "aliases": [], @@ -2165,10 +2270,10 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.4", + "php": "~8.1.0 || ~8.2.0", "ext-simplexml": "*", "ext-dom": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/eslint/.eslintrc-magento b/eslint/.eslintrc-magento index 5d403da3..69b47e83 100644 --- a/eslint/.eslintrc-magento +++ b/eslint/.eslintrc-magento @@ -18,7 +18,8 @@ "eol-last": 2, "eqeqeq": [2, "smart"], "guard-for-in": 2, - "keyword-spacing": [2, {}], + "indent": [2, 4], + "keyword-spacing": [2, {"after": true, "before": true}], "lines-around-comment": [ 2, { @@ -50,6 +51,7 @@ "no-fallthrough": 2, "no-floating-decimal": 2, "no-func-assign": 2, + "no-global-assign": 2, "no-implied-eval": 2, "no-inner-declarations": 2, "no-invalid-regexp": 2, @@ -81,10 +83,16 @@ } ], "no-use-before-define": 2, + "no-useless-call": 2, + "no-useless-computed-key": 2, + "no-useless-constructor": 2, + "no-useless-escape": 2, + "no-useless-rename": 2, + "no-useless-return": 2, "no-with": 2, "one-var": [2, "always"], "operator-assignment": [2, "always"], - "quotes": [2, "single"], + "quotes": [2, "single", {"allowTemplateLiterals": true}], "radix": 2, "semi": [2, "always"], "semi-spacing": 2, diff --git a/eslint/rules/utils.js b/eslint/rules/utils.js index ae181210..398e2b86 100644 --- a/eslint/rules/utils.js +++ b/eslint/rules/utils.js @@ -75,18 +75,18 @@ function getExpressionId(node) { while (node) { switch (node.type) { - case 'CallExpression': - node = node.callee; - break; - - case 'MemberExpression': - node = node.object; - break; - - case 'Identifier': - return node; - default: - return null; + case 'CallExpression': + node = node.callee; + break; + + case 'MemberExpression': + node = node.object; + break; + + case 'Identifier': + return node; + default: + return null; } } } diff --git a/phpunit-bootstrap.php b/phpunit-bootstrap.php index 487e0170..94f424dd 100644 --- a/phpunit-bootstrap.php +++ b/phpunit-bootstrap.php @@ -1,30 +1,9 @@ =') - && class_exists('PHPUnit_Framework_TestCase') === false -) { - class_alias('PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase'); -} - -unset($ds, $phpcsDir, $vendorDir); +require_once __DIR__ . '/vendor/squizlabs/php_codesniffer/tests/bootstrap.php';