From e6cc504cc4cfce64433a0cfe9a7d6b1face582da Mon Sep 17 00:00:00 2001 From: Klaus Purer Date: Sun, 30 Apr 2023 21:49:45 +0200 Subject: [PATCH 1/2] refactor(FullyQualifiedNamespace): Replace sniff in favor of a sniff from Slevomat --- coder_sniffer/Drupal/ruleset.xml | 18 +++++++++++++++++- ...FullyQualifiedNamespaceUnitTest.1.inc.fixed | 1 - tests/Drupal/good/GoodNamespace.php | 17 +++++++++++++++++ tests/Drupal/good/good.php | 13 ++----------- 4 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 tests/Drupal/good/GoodNamespace.php diff --git a/coder_sniffer/Drupal/ruleset.xml b/coder_sniffer/Drupal/ruleset.xml index ace0aebe..0c8fc8fd 100644 --- a/coder_sniffer/Drupal/ruleset.xml +++ b/coder_sniffer/Drupal/ruleset.xml @@ -122,6 +122,22 @@ + + + + + + + + + + + + *.api.php + + + 0 + @@ -298,7 +314,7 @@ */\.svn/* */\.hg/* */\.bzr/* - + *\.min\.css$ diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed b/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed index 930a791b..6aaa4c73 100644 --- a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed +++ b/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed @@ -8,7 +8,6 @@ * without them. * phpcs:disable Drupal.Commenting */ - use Foo\Bar; /** diff --git a/tests/Drupal/good/GoodNamespace.php b/tests/Drupal/good/GoodNamespace.php new file mode 100644 index 00000000..a1d144ba --- /dev/null +++ b/tests/Drupal/good/GoodNamespace.php @@ -0,0 +1,17 @@ + TRUE, - 'timeout' => 30, - 'headers' => [ - 'User-Agent' => 'Drupal/' . \Drupal::VERSION . ' (+https://www.drupal.org/) ' . \GuzzleHttp\default_user_agent(), - ], - 'handler' => $stack, -]; - // camelCase and snake_case variables are allowed. $snake_case = 1; $camelCase = 1; @@ -1819,3 +1808,5 @@ public function attributes(): void { } } + +$version = \Drupal::VERSION; From 8b062d42e1973cf6f1eb2c42e80f123ae07f7727 Mon Sep 17 00:00:00 2001 From: Klaus Purer Date: Sat, 6 May 2023 13:35:31 +0200 Subject: [PATCH 2/2] Test slevomat dev version and move test cases --- .../Classes/FullyQualifiedNamespaceSniff.php | 212 ------------------ composer.json | 2 +- .../FullyQualifiedNamespaceUnitTest.php | 78 ------- .../Commenting/ClassCommentUnitTest.inc.fixed | 4 +- .../FunctionCommentUnitTest.inc.fixed | 4 +- .../BadFullyQualifiedNamespace.1.inc} | 0 .../BadFullyQualifiedNamespace.1.inc.fixed} | 0 .../BadFullyQualifiedNamespace.inc} | 2 +- .../BadFullyQualifiedNamespace.inc.fixed} | 2 +- tests/Drupal/bad/BadUnitTest.php | 16 ++ tests/Drupal/good/GoodUnitTest.php | 20 +- .../drupal8/FullyQualifiedNamespace.api.php} | 5 + .../good/{ => drupal8}/GoodNamespace.php | 0 13 files changed, 42 insertions(+), 303 deletions(-) delete mode 100644 coder_sniffer/Drupal/Sniffs/Classes/FullyQualifiedNamespaceSniff.php delete mode 100644 tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.php rename tests/Drupal/{Classes/FullyQualifiedNamespaceUnitTest.1.inc => bad/BadFullyQualifiedNamespace.1.inc} (100%) rename tests/Drupal/{Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed => bad/BadFullyQualifiedNamespace.1.inc.fixed} (100%) rename tests/Drupal/{Classes/FullyQualifiedNamespaceUnitTest.inc => bad/BadFullyQualifiedNamespace.inc} (96%) rename tests/Drupal/{Classes/FullyQualifiedNamespaceUnitTest.inc.fixed => bad/BadFullyQualifiedNamespace.inc.fixed} (96%) rename tests/Drupal/{Classes/FullyQualifiedNamespaceUnitTest.api.php => good/drupal8/FullyQualifiedNamespace.api.php} (74%) rename tests/Drupal/good/{ => drupal8}/GoodNamespace.php (100%) diff --git a/coder_sniffer/Drupal/Sniffs/Classes/FullyQualifiedNamespaceSniff.php b/coder_sniffer/Drupal/Sniffs/Classes/FullyQualifiedNamespaceSniff.php deleted file mode 100644 index b70c4396..00000000 --- a/coder_sniffer/Drupal/Sniffs/Classes/FullyQualifiedNamespaceSniff.php +++ /dev/null @@ -1,212 +0,0 @@ - - */ - public function register() - { - return [T_NS_SEPARATOR]; - - }//end register() - - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where the - * token was found. - * @param int $stackPtr The position in the PHP_CodeSniffer - * file's token stack where the token - * was found. - * - * @return void|int Optionally returns a stack pointer. The sniff will not be - * called again on the current file until the returned stack - * pointer is reached. Return $phpcsFile->numTokens + 1 to skip - * the rest of the file. - */ - public function process(File $phpcsFile, $stackPtr) - { - $tokens = $phpcsFile->getTokens(); - - // Skip this sniff in *api.php files because they want to have fully - // qualified names for documentation purposes. - if (substr($phpcsFile->getFilename(), -8) === '.api.php') { - return ($phpcsFile->numTokens + 1); - } - - // We are only interested in a backslash embedded between strings, which - // means this is a class reference with more than once namespace part. - if ($tokens[($stackPtr - 1)]['code'] !== T_STRING || $tokens[($stackPtr + 1)]['code'] !== T_STRING) { - return; - } - - // Check if this is a use statement and ignore those. - $before = $phpcsFile->findPrevious([T_STRING, T_NS_SEPARATOR, T_WHITESPACE, T_COMMA, T_AS], $stackPtr, null, true); - if ($tokens[$before]['code'] === T_USE || $tokens[$before]['code'] === T_NAMESPACE) { - return $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_WHITESPACE, T_COMMA, T_AS], ($stackPtr + 1), null, true); - } else { - $before = $phpcsFile->findPrevious([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], $stackPtr, null, true); - } - - // If this is a namespaced function call then ignore this because use - // statements for functions are not possible in PHP 5.5 and lower. - $after = $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], $stackPtr, null, true); - if ($tokens[$after]['code'] === T_OPEN_PARENTHESIS && $tokens[$before]['code'] !== T_NEW) { - return ($after + 1); - } - - $fullName = $phpcsFile->getTokensAsString(($before + 1), ($after - 1 - $before)); - $fullName = trim($fullName, "\ \n"); - $parts = explode('\\', $fullName); - $className = end($parts); - - // Check if there is a use statement already for this class and - // namespace. - $conflict = false; - $alreadyUsed = false; - $aliasName = false; - $useStatement = $phpcsFile->findNext(T_USE, 0); - while ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) { - $endPtr = $phpcsFile->findEndOfStatement($useStatement); - $useEnd = ($phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], ($useStatement + 1), null, true) - 1); - $useFullName = trim($phpcsFile->getTokensAsString(($useStatement + 1), ($useEnd - $useStatement))); - - // Check if use statement contains an alias. - $asPtr = $phpcsFile->findNext(T_AS, ($useEnd + 1), $endPtr); - if ($asPtr !== false) { - $aliasName = trim($phpcsFile->getTokensAsString(($asPtr + 1), ($endPtr - 1 - $asPtr))); - } - - if (strcasecmp($useFullName, $fullName) === 0) { - $alreadyUsed = true; - break; - } - - $parts = explode('\\', $useFullName); - $useClassName = end($parts); - - // Check if the resulting classname would conflict with another - // use statement. - if ($aliasName === $className || $useClassName === $className) { - $conflict = true; - break; - } - - $aliasName = false; - // Check if we're currently in a multi-use statement. - if ($tokens[$endPtr]['code'] === T_COMMA) { - $useStatement = $endPtr; - continue; - } - - $useStatement = $phpcsFile->findNext(T_USE, ($endPtr + 1)); - }//end while - - if ($conflict === false) { - $classStatement = $phpcsFile->findNext(T_CLASS, 0); - while ($classStatement !== false) { - $afterClassStatement = $phpcsFile->findNext(T_WHITESPACE, ($classStatement + 1), null, true); - // Check for 'class ClassName' declarations. - if ($tokens[$afterClassStatement]['code'] === T_STRING) { - $declaredName = $tokens[$afterClassStatement]['content']; - if ($declaredName === $className) { - $conflict = true; - break; - } - } - - $classStatement = $phpcsFile->findNext(T_CLASS, ($classStatement + 1)); - } - } - - $error = 'Namespaced classes/interfaces/traits should be referenced with use statements'; - if ($conflict === true) { - $fix = false; - $phpcsFile->addError($error, $stackPtr, 'UseStatementMissing'); - } else { - $fix = $phpcsFile->addFixableError($error, $stackPtr, 'UseStatementMissing'); - } - - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); - - // Replace the fully qualified name with the local name. - for ($i = ($before + 1); $i < $after; $i++) { - if ($tokens[$i]['code'] !== T_WHITESPACE) { - $phpcsFile->fixer->replaceToken($i, ''); - } - } - - // Use alias name if available. - if ($aliasName !== false) { - $phpcsFile->fixer->addContentBefore(($after - 1), $aliasName); - } else { - $phpcsFile->fixer->addContentBefore(($after - 1), $className); - } - - // Insert use statement at the beginning of the file if it is not there - // already. Also check if another sniff (for example - // UnusedUseStatementSniff) has already deleted the use statement, then - // we need to add it back. - if ($alreadyUsed === false - || $phpcsFile->fixer->getTokenContent($useStatement) !== $tokens[$useStatement]['content'] - ) { - if ($aliasName !== false) { - $use = "use $fullName as $aliasName;"; - } else { - $use = "use $fullName;"; - } - - // Check if there is a group of use statements and add it there. - $useStatement = $phpcsFile->findNext(T_USE, 0); - if ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) { - $phpcsFile->fixer->addContentBefore($useStatement, "$use\n"); - } else { - // Check if there is an @file comment. - $beginning = 0; - $fileComment = $phpcsFile->findNext(T_WHITESPACE, ($beginning + 1), null, true); - if ($tokens[$fileComment]['code'] === T_DOC_COMMENT_OPEN_TAG) { - $beginning = $tokens[$fileComment]['comment_closer']; - $phpcsFile->fixer->addContent($beginning, "\n\n$use\n"); - } else { - $phpcsFile->fixer->addContent($beginning, "$use\n"); - } - } - }//end if - - $phpcsFile->fixer->endChangeset(); - }//end if - - // Continue after this class reference so that errors for this are not - // flagged multiple times. - return $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR], ($stackPtr + 1), null, true); - - }//end process() - - -}//end class diff --git a/composer.json b/composer.json index 4e32ffa2..9d4c8bc6 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "ext-mbstring": "*", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1 || ^1.0.0", "sirbrillig/phpcs-variable-analysis": "^2.11.7", - "slevomat/coding-standard": "^8.11", + "slevomat/coding-standard": "dev-master", "squizlabs/php_codesniffer": "^3.7.1", "symfony/yaml": ">=3.4.0" }, diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.php b/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.php deleted file mode 100644 index cf9255c1..00000000 --- a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.php +++ /dev/null @@ -1,78 +0,0 @@ - - */ - protected function getErrorList(string $testFile): array - { - switch ($testFile) { - case 'FullyQualifiedNamespaceUnitTest.inc': - return [ - 29 => 1, - 36 => 1, - 43 => 1, - 57 => 1, - 64 => 1, - 71 => 2, - 78 => 1, - ]; - case 'FullyQualifiedNamespaceUnitTest.1.inc': - return [16 => 1]; - } - - return []; - - }//end getErrorList() - - - /** - * Returns the lines where warnings should occur. - * - * The key of the array should represent the line number and the value - * should represent the number of warnings that should occur on that line. - * - * @param string $testFile The name of the file being tested. - * - * @return array - */ - protected function getWarningList(string $testFile): array - { - return []; - - }//end getWarningList() - - - /** - * Returns a list of test files that should be checked. - * - * @param string $testFileBase The base path that the unit tests files will have. - * - * @return array - */ - protected function getTestFiles($testFileBase): array - { - return [ - __DIR__.'/FullyQualifiedNamespaceUnitTest.inc', - __DIR__.'/FullyQualifiedNamespaceUnitTest.1.inc', - __DIR__.'/FullyQualifiedNamespaceUnitTest.api.php', - ]; - - }//end getTestFiles() - - -}//end class diff --git a/tests/Drupal/Commenting/ClassCommentUnitTest.inc.fixed b/tests/Drupal/Commenting/ClassCommentUnitTest.inc.fixed index 3c04bade..805cb8a3 100644 --- a/tests/Drupal/Commenting/ClassCommentUnitTest.inc.fixed +++ b/tests/Drupal/Commenting/ClassCommentUnitTest.inc.fixed @@ -5,6 +5,8 @@ * Testing class/trait comments. */ +use Some\Attribute; + /** * */ @@ -60,7 +62,7 @@ class WrongSpacing { /** * This is correct. */ -#[Some\Attribute(foo: 'bar')] +#[Attribute(foo: 'bar')] #[Other\Attribute(baz: 'qux')] class DoubleAttribute { diff --git a/tests/Drupal/Commenting/FunctionCommentUnitTest.inc.fixed b/tests/Drupal/Commenting/FunctionCommentUnitTest.inc.fixed index f9308b2d..c5891152 100644 --- a/tests/Drupal/Commenting/FunctionCommentUnitTest.inc.fixed +++ b/tests/Drupal/Commenting/FunctionCommentUnitTest.inc.fixed @@ -5,6 +5,8 @@ * Some function comment tests. */ +use Some\Attribute; + /** * Test. * @@ -579,7 +581,7 @@ class Test41 { /** * Method docblock. */ - #[Some\Attribute(foo: 'bar')] + #[Attribute(foo: 'bar')] #[Other\Attribute(baz: 'qux')] public function method() { } diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc b/tests/Drupal/bad/BadFullyQualifiedNamespace.1.inc similarity index 100% rename from tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc rename to tests/Drupal/bad/BadFullyQualifiedNamespace.1.inc diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed b/tests/Drupal/bad/BadFullyQualifiedNamespace.1.inc.fixed similarity index 100% rename from tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.1.inc.fixed rename to tests/Drupal/bad/BadFullyQualifiedNamespace.1.inc.fixed diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc b/tests/Drupal/bad/BadFullyQualifiedNamespace.inc similarity index 96% rename from tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc rename to tests/Drupal/bad/BadFullyQualifiedNamespace.inc index 1819ef46..641182ce 100644 --- a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc +++ b/tests/Drupal/bad/BadFullyQualifiedNamespace.inc @@ -12,7 +12,7 @@ use Test\MultiLine as MultiLineAlias, Test\MultiLineSecond; /** - * Example. + * Example with lots of variations. */ class Example { diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc.fixed b/tests/Drupal/bad/BadFullyQualifiedNamespace.inc.fixed similarity index 96% rename from tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc.fixed rename to tests/Drupal/bad/BadFullyQualifiedNamespace.inc.fixed index 93fe2e4e..5ecab062 100644 --- a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.inc.fixed +++ b/tests/Drupal/bad/BadFullyQualifiedNamespace.inc.fixed @@ -13,7 +13,7 @@ use Test\MultiLineSecond; use Test\NotUsed; /** - * Example. + * Example with lots of variations. */ class Example { diff --git a/tests/Drupal/bad/BadUnitTest.php b/tests/Drupal/bad/BadUnitTest.php index 6b1a9afd..f6eeab86 100644 --- a/tests/Drupal/bad/BadUnitTest.php +++ b/tests/Drupal/bad/BadUnitTest.php @@ -382,6 +382,20 @@ protected function getErrorList(string $testFile): array 846 => 2, 852 => 2, ]; + case 'BadFullyQualifiedNamespace.inc': + return [ + 10 => 1, + 11 => 1, + 29 => 1, + 36 => 1, + 43 => 1, + 57 => 1, + 64 => 1, + 71 => 2, + 78 => 1, + ]; + case 'BadFullyQualifiedNamespace.1.inc': + return [16 => 1]; }//end switch return []; @@ -431,6 +445,8 @@ protected function getWarningList(string $testFile): array 823 => 1, 824 => 1, ]; + case 'BadFullyQualifiedNamespace.inc': + return [9 => 1]; }//end switch return []; diff --git a/tests/Drupal/good/GoodUnitTest.php b/tests/Drupal/good/GoodUnitTest.php index 33eeee04..e48cfaa9 100644 --- a/tests/Drupal/good/GoodUnitTest.php +++ b/tests/Drupal/good/GoodUnitTest.php @@ -57,17 +57,21 @@ protected function getWarningList(string $testFile): array */ protected function getTestFiles($testFileBase): array { - $di = new \DirectoryIterator(__DIR__); - - foreach ($di as $file) { - $path = $file->getPathname(); - if ($path !== __FILE__ && $file->isFile() === true) { - $testFiles[] = $path; + $directories = [ + __DIR__, + __DIR__.'/drupal8', + ]; + foreach ($directories as $directory) { + $di = new \DirectoryIterator($directory); + + foreach ($di as $file) { + $path = $file->getPathname(); + if ($path !== __FILE__ && $file->isFile() === true) { + $testFiles[] = $path; + } } } - $testFiles[] = __DIR__.'/drupal8/LongNamespace.php'; - // Get them in order. sort($testFiles); return $testFiles; diff --git a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.api.php b/tests/Drupal/good/drupal8/FullyQualifiedNamespace.api.php similarity index 74% rename from tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.api.php rename to tests/Drupal/good/drupal8/FullyQualifiedNamespace.api.php index 0837d081..e729bb60 100644 --- a/tests/Drupal/Classes/FullyQualifiedNamespaceUnitTest.api.php +++ b/tests/Drupal/good/drupal8/FullyQualifiedNamespace.api.php @@ -1,4 +1,9 @@