Skip to content

Commit 57ba46f

Browse files
committed
Ruleset: hard deprecate support for sniffs not following the naming conventions
The new [About Standards for PHP_CodeSniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/About-Standards-for-PHP_CodeSniffer) wiki page outlines exactly what the naming conventions are. This PR adds a new Ruleset deprecation notice for when sniffs are encountered which do not follow these conventions. Support for sniffs not following the naming conventions will be removed in PHPCS 4.0. Includes tests. Includes removing two invalid sniffs from the `ExpandSniffDirectoryTest`. These type of sniffs, which don't comply with the PHPCS naming conventions, are now covered via the new tests. Related to 689
1 parent ee7e4f0 commit 57ba46f

12 files changed

+263
-37
lines changed

src/Ruleset.php

+13
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,19 @@ public function populateTokenListeners()
14551455
$this->sniffs[$sniffClass] = new $sniffClass();
14561456

14571457
$sniffCode = Common::getSniffCode($sniffClass);
1458+
1459+
if (substr($sniffCode, 0, 1) === '.'
1460+
|| substr($sniffCode, -1) === '.'
1461+
|| strpos($sniffCode, '..') !== false
1462+
|| preg_match('`(^|\.)Sniffs\.`', $sniffCode) === 1
1463+
|| preg_match('`[^\s\.-]+\\\\Sniffs\\\\[^\s\.-]+\\\\[^\s\.-]+Sniff`', $sniffClass) !== 1
1464+
) {
1465+
$message = "The sniff $sniffClass does not comply with the PHP_CodeSniffer naming conventions.";
1466+
$message .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
1467+
$message .= 'Contact the sniff author to fix the sniff.';
1468+
$this->msgCache->add($message, MessageCollector::DEPRECATED);
1469+
}
1470+
14581471
$this->sniffCodes[$sniffCode] = $sniffClass;
14591472

14601473
if ($this->sniffs[$sniffClass] instanceof DeprecatedSniff) {

tests/Core/Ruleset/ExpandSniffDirectoryTest.php

+2-13
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,9 @@ public function testExpandSniffDirectory()
4949
$this->assertNotFalse($expectedPathToRuleset, 'Ruleset file could not be found');
5050
$this->assertContains($expectedPathToRuleset, $ruleset->paths, 'Ruleset file not included in the "seen ruleset paths"');
5151

52-
/*
53-
* Take note: the expectation includes some "undesirables" related to the convoluted directory structure
54-
* in the "standard" used as a test fixture.
55-
*
56-
* That is okay as (for now) non-standard directory layouts are supported.
57-
*
58-
* This test is not about the standard directory layout.
59-
*/
60-
6152
$expectedSniffCodes = [
62-
'.Sniffs.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\IncorrectLevelShouldStillBeFoundSniff',
63-
'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff',
64-
'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff',
65-
'Sniffs.SubDir.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\CategoryA\\SubDir\\IncorrectLevelShouldStillBeFoundSniff',
53+
'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff',
54+
'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff',
6655
];
6756

6857
// Sort the value to make the tests stable as different OSes will read directories
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\RulesetPopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
namespace BrokenNamingConventions\Sniffs\Category;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff as PHPCS_Sniff;
12+
13+
final class Sniff implements PHPCS_Sniff
14+
{
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\RulesetPopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
namespace BrokenNamingConventions\Sniffs\Category\SubDir;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
13+
final class TooDeeplyNestedSniff implements Sniff
14+
{
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\RulesetPopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
namespace BrokenNamingConventions\Sniffs;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
13+
final class MissingCategoryDirSniff implements Sniff
14+
{
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\PopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
use PHP_CodeSniffer\Files\File;
9+
use PHP_CodeSniffer\Sniffs\Sniff;
10+
11+
final class NoNamespaceSniff implements Sniff
12+
{
13+
public function register()
14+
{
15+
return [T_OPEN_TAG];
16+
}
17+
18+
public function process(File $phpcsFile, $stackPtr)
19+
{
20+
// Do something.
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\Ruleset\PopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
namespace Sniffs;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
13+
final class PartialNamespaceSniff implements Sniff
14+
{
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Test fixture.
4+
*
5+
* @see \PHP_CodeSniffer\Tests\Core\RulesetPopulateTokenListenersNamingConventionsTest
6+
*/
7+
8+
namespace BrokenNamingConventions\Sniffs\Sniffs;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
13+
final class CategoryCalledSniffsSniff implements Sniff
14+
{
15+
public function register()
16+
{
17+
return [T_OPEN_TAG];
18+
}
19+
20+
public function process(File $phpcsFile, $stackPtr)
21+
{
22+
// Do something.
23+
}
24+
}

tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/Subdir/IncorrectLevelShouldStillBeFoundSniff.php

-12
This file was deleted.

tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/IncorrectLevelShouldStillBeFoundSniff.php

-12
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
/**
3+
* Test the Ruleset::expandSniffDirectory() method.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Ruleset;
11+
12+
use PHP_CodeSniffer\Ruleset;
13+
use PHP_CodeSniffer\Tests\ConfigDouble;
14+
use PHPUnit\Framework\TestCase;
15+
16+
/**
17+
* Test handling of sniffs not following the PHPCS naming conventions in the Ruleset::populateTokenListeners() method.
18+
*
19+
* @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners
20+
*/
21+
final class PopulateTokenListenersNamingConventionsTest extends TestCase
22+
{
23+
24+
25+
/**
26+
* Verify a warning is shown for sniffs not complying with the PHPCS naming conventions.
27+
*
28+
* Including sniffs which do not comply with the PHPCS naming conventions is soft deprecated since
29+
* PHPCS 3.12.0, hard deprecated since PHPCS 3.13.0 and support will be removed in PHPCS 4.0.0.
30+
*
31+
* @return void
32+
*/
33+
public function testBrokenNamingConventions()
34+
{
35+
// Set up the ruleset.
36+
$standard = __DIR__.'/PopulateTokenListenersNamingConventionsTest.xml';
37+
$config = new ConfigDouble(["--standard=$standard"]);
38+
$ruleset = new Ruleset($config);
39+
40+
// The "Generic.PHP.BacktickOperator" sniff is the only valid sniff.
41+
$expectedSniffCodes = [
42+
'..NoNamespace' => 'NoNamespaceSniff',
43+
'.Sniffs.MissingCategoryDir' => 'BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff',
44+
'.Sniffs.PartialNamespace' => 'Sniffs\\PartialNamespaceSniff',
45+
'BrokenNamingConventions.Category.' => 'BrokenNamingConventions\\Sniffs\\Category\\Sniff',
46+
'BrokenNamingConventions.Sniffs.CategoryCalledSniffs' => 'BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff',
47+
'Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff',
48+
'Sniffs.SubDir.TooDeeplyNested' => 'BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff',
49+
];
50+
51+
// Sort the value to make the tests stable as different OSes will read directories
52+
// in a different order and the order is not relevant for these tests. Just the values.
53+
$actual = $ruleset->sniffCodes;
54+
ksort($actual);
55+
56+
$this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation');
57+
58+
$expectedMessage = 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff does not comply';
59+
$expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
60+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL;
61+
$expectedMessage .= 'DEPRECATED: The sniff NoNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.';
62+
$expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
63+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL;
64+
$expectedMessage .= 'DEPRECATED: The sniff Sniffs\\PartialNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.';
65+
$expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
66+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL;
67+
$expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\Sniff does not comply';
68+
$expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
69+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL;
70+
$expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff does not';
71+
$expectedMessage .= ' comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
72+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL;
73+
$expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff';
74+
$expectedMessage .= ' does not comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL;
75+
$expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL;
76+
77+
$this->expectOutputString($expectedMessage);
78+
79+
}//end testBrokenNamingConventions()
80+
81+
82+
}//end class
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PopulateTokenListenersNamingConventionsTest" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/PHPCSStandards/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<!--
5+
These sniff files are not in an installed standard, there is not even a ruleset.xml file for the "standard".
6+
Each of these sniff files breaks one of the naming convention rules.
7+
-->
8+
9+
<!-- Breaks: All sniffs MUST be located within a [CategoryName] directory. -->
10+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/MissingCategoryDirSniff.php"/>
11+
<!-- Breaks: The namespace and class name MUST follow PSR-4. -->
12+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/NoNamespaceSniff.php"/>
13+
<!-- Breaks: The namespace and class name MUST follow PSR-4. -->
14+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/PartialNamespaceSniff.php"/>
15+
<!-- Breaks: All sniffs MUST have a name, so a sniff class called just and only Sniff is not allowed. -->
16+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php"/>
17+
<!-- Breaks: The name "Sniffs" MUST NOT be used as a category name. -->
18+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/Sniffs/CategoryCalledSniffsSniff.php"/>
19+
<!-- Breaks: No directories should exist under the [CategoryName] directory. -->
20+
<rule ref="./Fixtures/BrokenNamingConventions/Sniffs/Category/SubDir/TooDeeplyNestedSniff.php"/>
21+
22+
<!-- Prevent a "no sniff were registered" error (once the above become errors). -->
23+
<rule ref="Generic.PHP.BacktickOperator"/>
24+
</ruleset>

0 commit comments

Comments
 (0)