Skip to content

Commit 9a152b4

Browse files
authored
feat(ConstName): Support const keyword in constant name prefix detection (#3358592)
1 parent a40711d commit 9a152b4

File tree

4 files changed

+96
-34
lines changed

4 files changed

+96
-34
lines changed

coder_sniffer/Drupal/Sniffs/Semantics/ConstantNameSniff.php

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,78 +10,125 @@
1010
namespace Drupal\Sniffs\Semantics;
1111

1212
use PHP_CodeSniffer\Files\File;
13+
use PHP_CodeSniffer\Sniffs\Sniff;
14+
use PHP_CodeSniffer\Util\Tokens;
1315

1416
/**
1517
* Checks that constants introduced with define() in module or install files start
1618
* with the module's name.
1719
*
20+
* Largely copied from
21+
* \PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\UpperCaseConstantNameSniff.
22+
*
1823
* @category PHP
1924
* @package PHP_CodeSniffer
2025
* @link http://pear.php.net/package/PHP_CodeSniffer
2126
*/
22-
class ConstantNameSniff extends FunctionCall
27+
class ConstantNameSniff implements Sniff
2328
{
2429

2530

2631
/**
27-
* Returns an array of function names this test wants to listen for.
32+
* Returns an array of tokens this test wants to listen for.
2833
*
29-
* @return array<string>
34+
* @return array<int|string>
3035
*/
31-
public function registerFunctionNames()
36+
public function register()
3237
{
33-
return ['define'];
38+
return [
39+
T_STRING,
40+
T_CONST,
41+
];
3442

35-
}//end registerFunctionNames()
43+
}//end register()
3644

3745

3846
/**
39-
* Processes this function call.
47+
* Processes this test, when one of its tokens is encountered.
4048
*
41-
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
42-
* @param int $stackPtr The position of the function call in
43-
* the stack.
44-
* @param int $openBracket The position of the opening
45-
* parenthesis in the stack.
46-
* @param int $closeBracket The position of the closing
47-
* parenthesis in the stack.
49+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
50+
* @param int $stackPtr The position of the current token in the
51+
* stack passed in $tokens.
4852
*
49-
* @return void
53+
* @return void|int
5054
*/
51-
public function processFunctionCall(
52-
File $phpcsFile,
53-
$stackPtr,
54-
$openBracket,
55-
$closeBracket
56-
) {
55+
public function process(File $phpcsFile, $stackPtr)
56+
{
5757
$nameParts = explode('.', basename($phpcsFile->getFilename()));
5858
$fileExtension = end($nameParts);
5959
// Only check in *.module files.
6060
if ($fileExtension !== 'module' && $fileExtension !== 'install') {
61-
return;
61+
return ($phpcsFile->numTokens + 1);
6262
}
6363

64-
$tokens = $phpcsFile->getTokens();
65-
$argument = $this->getArgument(1);
66-
if ($tokens[$argument['start']]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
67-
// Not a string literal, so this is some obscure constant that we ignore.
64+
$tokens = $phpcsFile->getTokens();
65+
// Only check in the outer scope, not within classes.
66+
if (empty($tokens[$stackPtr]['conditions']) === false) {
6867
return;
6968
}
7069

7170
$moduleName = reset($nameParts);
7271
$expectedStart = strtoupper($moduleName);
73-
// Remove the quotes around the string litral.
74-
$constant = substr($tokens[$argument['start']]['content'], 1, -1);
75-
if (strpos($constant, $expectedStart) !== 0) {
72+
73+
if ($tokens[$stackPtr]['code'] === T_CONST) {
74+
// This is a class constant.
75+
$constant = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
76+
if ($constant === false) {
77+
return;
78+
}
79+
80+
$constName = $tokens[$constant]['content'];
81+
82+
if (strpos($constName, $expectedStart) !== 0) {
83+
$warning = 'All constants defined by a module must be prefixed with the module\'s name, expected "%s" but found "%s"';
84+
$data = [
85+
$expectedStart."_$constName",
86+
$constName,
87+
];
88+
$phpcsFile->addWarning($warning, $stackPtr, 'ConstConstantStart', $data);
89+
return;
90+
}//end if
91+
}
92+
93+
// Only interested in define statements now.
94+
if (strtolower($tokens[$stackPtr]['content']) !== 'define') {
95+
return;
96+
}
97+
98+
// Make sure this is not a method call.
99+
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
100+
if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR
101+
|| $tokens[$prev]['code'] === T_DOUBLE_COLON
102+
|| $tokens[$prev]['code'] === T_NULLSAFE_OBJECT_OPERATOR
103+
) {
104+
return;
105+
}
106+
107+
// If the next non-whitespace token after this token
108+
// is not an opening parenthesis then it is not a function call.
109+
$openBracket = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
110+
if ($openBracket === false) {
111+
return;
112+
}
113+
114+
// The next non-whitespace token must be the constant name.
115+
$constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true);
116+
if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
117+
return;
118+
}
119+
120+
$constName = $tokens[$constPtr]['content'];
121+
122+
if (strpos($constName, $expectedStart) !== 0) {
76123
$warning = 'All constants defined by a module must be prefixed with the module\'s name, expected "%s" but found "%s"';
77124
$data = [
78-
$expectedStart."_$constant",
79-
$constant,
125+
$expectedStart."_$constName",
126+
$constName,
80127
];
81128
$phpcsFile->addWarning($warning, $stackPtr, 'ConstantStart', $data);
82-
}
129+
}//end if
83130

84-
}//end processFunctionCall()
131+
}//end process()
85132

86133

87134
}//end class

tests/Drupal/Semantics/ConstantNameUnitTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ protected function getErrorList(string $testFile): array
5454
*/
5555
protected function getWarningList(string $testFile): array
5656
{
57-
return [3 => 1];
57+
return [
58+
3 => 1,
59+
5 => 1,
60+
];
5861

5962
}//end getWarningList()
6063

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
<?php
22

33
define('WRONG_CONSTANT_NAME', 'test');
4+
5+
const ANOTHER_WRONG_NAME = 'test';
6+
7+
class Test {
8+
const CLASS_CONSTANT = 'should be ignored';
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
<?php
22

33
define('WRONG_CONSTANT_NAME', 'test');
4+
5+
const ANOTHER_WRONG_NAME = 'test';
6+
7+
class Test {
8+
const CLASS_CONSTANT = 'should be ignored';
9+
}

0 commit comments

Comments
 (0)