Skip to content

Commit 3f2c56f

Browse files
committed
✨ New feature: Debug ruleset and sniff
This adds a new external PHPCS standard named `Debug` intended only for use by sniff developers. This `Debug` standard will contain sniffs which can help sniff developers _during the development of new sniffs_. Initially, this standard only contains one sniff: `Debug.Debug.TokenList`. This sniff will display compact, but detailed information about the tokens found in a (test) file. This sniff is compatible with PHPCS 3.0+. Typical usage: * Set up a test case file for a new sniff you intend to write. * Run PHPCS over the test case file using this standard to see the tokens found listed: `phpcs ./NewSniffNameUnitTest.inc --standard=Debug` * Or use it together with the new sniff you are developing: `phpcs ./NewSniffNameUnitTest.inc --standard=YourStandard,Debug --sniffs=YourStandard.Category.NewSniffName` PHPCS itself can also display this information using the `-vv` or `-vvv` verbosity flags, however, when using those, you will receive a *lot* more information than just the token list and while useful for debugging PHPCS itself, the additional information is mostly just noise when developing a sniff. Includes documentation. Includes unit tests.
1 parent 86cfb93 commit 3f2c56f

9 files changed

Lines changed: 284 additions & 0 deletions

File tree

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/.gitignore export-ignore
1010
/.travis.yml export-ignore
1111
/phpcs.xml.dist export-ignore
12+
/Debug/Tests export-ignore
1213

1314
#
1415
# Auto detect text files and perform LF normalization

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ jobs:
3636

3737
# Validate the xml file.
3838
# @link http://xmlsoft.org/xmllint.html
39+
- xmllint --noout --schema ./vendor/squizlabs/php_codesniffer/phpcs.xsd ./Debug/ruleset.xml
3940
- xmllint --noout --schema ./vendor/squizlabs/php_codesniffer/phpcs.xsd ./PHPCSDev/ruleset.xml
4041

4142
# Check the code-style consistency of the xml files.
43+
- diff -B ./Debug/ruleset.xml <(xmllint --format "./Debug/ruleset.xml")
4244
- diff -B ./PHPCSDev/ruleset.xml <(xmllint --format "./PHPCSDev/ruleset.xml")
4345

4446

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<documentation title="Token List">
2+
<standard>
3+
<![CDATA[
4+
Lists how PHPCS tokenizes code.
5+
6+
This sniff will not throw any warnings or errors, but is solely intended as a tool for sniff developers.
7+
]]>
8+
</standard>
9+
</documentation>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
/**
3+
* PHPCSDevTools, tools for PHP_CodeSniffer sniff developers.
4+
*
5+
* @package PHPCSDevTools
6+
* @copyright 2019 PHPCSDevTools Contributors
7+
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
8+
* @link https://github.com/PHPCSStandards/PHPCSDevTools
9+
*/
10+
11+
namespace PHPCSStandards\Debug\Sniffs\Debug;
12+
13+
use PHP_CodeSniffer\Sniffs\Sniff;
14+
use PHP_CodeSniffer\Files\File;
15+
16+
/**
17+
* Lists how PHPCS tokenizes code.
18+
*
19+
* This sniff will not throw any warnings or errors, but is solely intended
20+
* as a tool for sniff developers.
21+
*
22+
* @since 1.0.0
23+
*/
24+
class TokenListSniff implements Sniff
25+
{
26+
27+
/**
28+
* A list of tokenizers this sniff supports.
29+
*
30+
* @var array
31+
*/
32+
public $supportedTokenizers = [
33+
'PHP',
34+
'JS',
35+
'CSS',
36+
];
37+
38+
/**
39+
* Returns an array of tokens this test wants to listen for.
40+
*
41+
* @return array
42+
*/
43+
public function register()
44+
{
45+
return [
46+
\T_OPEN_TAG,
47+
\T_OPEN_TAG_WITH_ECHO,
48+
];
49+
}
50+
51+
/**
52+
* Processes this test, when one of its tokens is encountered.
53+
*
54+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
55+
* @param int $stackPtr The position of the current
56+
* token in the stack.
57+
*
58+
* @return void
59+
*/
60+
public function process(File $phpcsFile, $stackPtr)
61+
{
62+
$tokens = $phpcsFile->getTokens();
63+
64+
$oldIniValue = \ini_set('xdebug.overload_var_dump', 1);
65+
66+
echo \PHP_EOL;
67+
foreach ($tokens as $ptr => $token) {
68+
if (isset($token['length']) === false) {
69+
$token['length'] = strlen($token['content']);
70+
}
71+
72+
$content = $token['content'];
73+
if ($token['code'] === \T_WHITESPACE
74+
|| (defined('T_DOC_COMMENT_WHITESPACE')
75+
&& $token['code'] === \T_DOC_COMMENT_WHITESPACE)
76+
) {
77+
if (strpos($token['content'], "\t") !== false) {
78+
$content = str_replace("\t", '\t', $token['content']);
79+
}
80+
if (isset($token['orig_content'])) {
81+
$content .= ' :: Orig: ' . str_replace("\t", '\t', $token['orig_content']);
82+
}
83+
}
84+
85+
echo $ptr, ' :: L', \str_pad($token['line'], 3, '0', \STR_PAD_LEFT), ' :: C', $token['column'],
86+
' :: ', $token['type'], ' :: (', $token['length'], ') :: ', $content, \PHP_EOL;
87+
}
88+
89+
// If necessary, reset the ini setting.
90+
if ($oldIniValue !== false) {
91+
\ini_set('xdebug.overload_var_dump', $oldIniValue);
92+
}
93+
94+
// Only do this once per file.
95+
return ($phpcsFile->numTokens + 1);
96+
}
97+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
/**
3+
* PHPCSDevTools, tools for PHP_CodeSniffer sniff developers.
4+
*
5+
* @package PHPCSDevTools
6+
* @copyright 2019 PHPCSDevTools Contributors
7+
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
8+
* @link https://github.com/PHPCSStandards/PHPCSDevTools
9+
*/
10+
11+
namespace PHPCSStandards\Debug\Tests\Debug;
12+
13+
use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest;
14+
15+
/**
16+
* Unit test class for the TokenList sniff.
17+
*
18+
* @covers PHPCSStandards\Debug\Sniffs\Debug::TokenListSniff
19+
*
20+
* @since 1.0.0
21+
*/
22+
class TokenListUnitTest extends AbstractSniffUnitTest
23+
{
24+
25+
/**
26+
* Cache any output generated during the test.
27+
*
28+
* @var string
29+
*/
30+
public static $output = '';
31+
32+
/**
33+
* Sets up this unit test.
34+
*
35+
* @return void
36+
*/
37+
protected function setUp()
38+
{
39+
parent::setUp();
40+
41+
ob_start();
42+
}
43+
44+
/**
45+
* Clean up.
46+
*
47+
* @return void
48+
*/
49+
protected function tearDown()
50+
{
51+
self::$output = ob_get_flush();
52+
53+
parent::tearDown();
54+
}
55+
56+
/**
57+
* Returns the lines where errors should occur.
58+
*
59+
* @return array <int line number> => <int number of errors>
60+
*/
61+
public function getErrorList()
62+
{
63+
return [];
64+
}
65+
66+
/**
67+
* Returns the lines where warnings should occur.
68+
*
69+
* @return array <int line number> => <int number of warnings>
70+
*/
71+
public function getWarningList()
72+
{
73+
return [];
74+
}
75+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/**
3+
* PHPCSDevTools, tools for PHP_CodeSniffer sniff developers.
4+
*
5+
* @package PHPCSDevTools
6+
* @copyright 2019 PHPCSDevTools Contributors
7+
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
8+
* @link https://github.com/PHPCSStandards/PHPCSDevTools
9+
*/
10+
11+
namespace PHPCSStandards\Debug\Tests\Debug;
12+
13+
use PHPUnit\Framework\TestCase;
14+
15+
/**
16+
* Unit test class for the TokenList sniff.
17+
*
18+
* @covers PHPCSStandards\Debug\Sniffs\Debug::TokenListSniff
19+
*
20+
* @since 1.0.0
21+
*/
22+
class TokenListZUnitTest extends TestCase
23+
{
24+
25+
/**
26+
* Test the actual output of the TokenList sniff.
27+
*
28+
* @return void
29+
*/
30+
public function testOutput()
31+
{
32+
$output = trim(TokenListUnitTest::$output);
33+
34+
$this->assertNotEmpty($output);
35+
36+
$expected = '0 :: L001 :: C1 :: T_OPEN_TAG :: (5) :: <?php';
37+
$this->assertSame($expected, $output);
38+
}
39+
}

Debug/ruleset.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0"?>
2+
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Debug" namespace="PHPCSStandards\Debug" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
3+
4+
<description>Sniffs which can be used as debugging tools for PHPCS developers</description>
5+
6+
</ruleset>

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This is a set of tools to aid developers of sniffs for [PHP CodeSniffer](https:/
2424
+ [Stand-alone Installation](#stand-alone-installation)
2525
* [Features](#features)
2626
+ [Checking whether all sniffs in a PHPCS standard are feature complete](#checking-whether-all-sniffs-in-a-phpcs-standard-are-feature-complete)
27+
+ [Sniff Debugging](#sniff-debugging)
2728
+ [PHPCSDev ruleset for sniff repos](#phpcsdev-ruleset-for-sniff-repos)
2829
* [Contributing](#contributing)
2930
* [License](#license)
@@ -112,6 +113,59 @@ directories One or more specific directories to examine.
112113
```
113114

114115

116+
### Sniff Debugging
117+
118+
Once this project is installed, you will see a new `Debug` ruleset in the list of installed standards when you run `phpcs -i`.
119+
120+
For now, this standard only contains one sniff: `Debug.Debug.TokenList`.
121+
This sniff will display compact, but detailed information about the tokens found in a (test case) file.
122+
123+
This sniff is compatible with PHPCS 3.0+.
124+
125+
Typical usage:
126+
* Set up a test case file for a new sniff you intend to write.
127+
* Run PHPCS over the test case file using this standard to see a list of the tokens found in the file:
128+
```bash
129+
phpcs ./SniffNameUnitTest.inc --standard=Debug
130+
```
131+
* Or use it together with the new sniff you are developing:
132+
```bash
133+
phpcs ./SniffNameUnitTest.inc --standard=YourStandard,Debug --sniffs=YourStandard.Category.NewSniffName,Debug.Debug.TokenList
134+
```
135+
136+
The output will look something along the lines of:
137+
```
138+
0 :: L001 :: C1 :: T_OPEN_TAG :: (5) :: <?php
139+
140+
1 :: L002 :: C1 :: T_WHITESPACE :: (0) ::
141+
142+
2 :: L003 :: C1 :: T_COMMENT :: (32) :: // Boolean not operator: All OK.
143+
144+
3 :: L004 :: C1 :: T_IF :: (2) :: if
145+
4 :: L004 :: C3 :: T_WHITESPACE :: (1) ::
146+
5 :: L004 :: C4 :: T_OPEN_PARENTHESIS :: (1) :: (
147+
6 :: L004 :: C5 :: T_WHITESPACE :: (1) ::
148+
7 :: L004 :: C6 :: T_CONSTANT_ENCAPSED_STRING :: (4) :: 'bb'
149+
8 :: L004 :: C10 :: T_WHITESPACE :: (1) ::
150+
9 :: L004 :: C11 :: T_IS_NOT_IDENTICAL :: (3) :: !==
151+
10 :: L004 :: C14 :: T_WHITESPACE :: (1) ::
152+
11 :: L004 :: C15 :: T_CONSTANT_ENCAPSED_STRING :: (4) :: 'bb'
153+
12 :: L004 :: C19 :: T_WHITESPACE :: (1) ::
154+
13 :: L004 :: C20 :: T_CLOSE_PARENTHESIS :: (1) :: )
155+
14 :: L004 :: C21 :: T_WHITESPACE :: (1) ::
156+
15 :: L004 :: C22 :: T_OPEN_CURLY_BRACKET :: (1) :: {
157+
16 :: L004 :: C23 :: T_WHITESPACE :: (0) ::
158+
159+
17 :: L005 :: C1 :: T_WHITESPACE :: (1) :: \t
160+
18 :: L005 :: C2 :: T_IF :: (2) :: if
161+
19 :: L005 :: C4 :: T_WHITESPACE :: (1) ::
162+
20 :: L005 :: C5 :: T_OPEN_PARENTHESIS :: (1) :: (
163+
21 :: L005 :: C6 :: T_WHITESPACE :: (0) ::
164+
```
165+
166+
PHPCS itself can also display similar information using the `-vv` or `-vvv` verbosity flags, however, when using those, you will receive a *lot* more information than just the token list and, while useful for debugging PHPCS itself, the additional information is mostly just noise when developing a sniff.
167+
168+
115169
### PHPCSDev ruleset for sniff repos
116170

117171
Once this project is installed, you will see a new `PHPCSDev` ruleset in the list of installed standards when you run `phpcs -i`.

0 commit comments

Comments
 (0)