Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 41 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
ValidGlobalNameSniff | |
0.00% |
0 / 41 |
|
0.00% |
0 / 2 |
156 | |
0.00% |
0 / 1 |
register | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
process | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
132 |
1 | <?php |
2 | /** |
3 | * Verify MediaWiki global variable naming convention. |
4 | * A global name must be prefixed with 'wg'. |
5 | */ |
6 | |
7 | namespace MediaWiki\Sniffs\NamingConventions; |
8 | |
9 | use PHP_CodeSniffer\Files\File; |
10 | use PHP_CodeSniffer\Sniffs\Sniff; |
11 | |
12 | class ValidGlobalNameSniff implements Sniff { |
13 | |
14 | /** |
15 | * https://php.net/manual/en/reserved.variables.argv.php |
16 | */ |
17 | private const PHP_RESERVED = [ |
18 | '$GLOBALS', |
19 | '$_SERVER', |
20 | '$_GET', |
21 | '$_POST', |
22 | '$_FILES', |
23 | '$_REQUEST', |
24 | '$_SESSION', |
25 | '$_ENV', |
26 | '$_COOKIE', |
27 | '$php_errormsg', |
28 | '$HTTP_RAW_POST_DATA', |
29 | '$http_response_header', |
30 | '$argc', |
31 | '$argv' |
32 | ]; |
33 | |
34 | /** |
35 | * A list of global variable prefixes allowed. |
36 | * |
37 | * @var array |
38 | */ |
39 | public array $allowedPrefixes = [ 'wg' ]; |
40 | |
41 | /** @var string[] */ |
42 | public array $ignoreList = []; |
43 | |
44 | /** |
45 | * @inheritDoc |
46 | */ |
47 | public function register(): array { |
48 | return [ T_GLOBAL ]; |
49 | } |
50 | |
51 | /** |
52 | * @param File $phpcsFile |
53 | * @param int $stackPtr The current token index. |
54 | * @return int|void |
55 | */ |
56 | public function process( File $phpcsFile, $stackPtr ) { |
57 | // If there are no prefixes specified, we have nothing to do for this file |
58 | if ( $this->allowedPrefixes === [] ) { |
59 | // @codeCoverageIgnoreStart |
60 | return $phpcsFile->numTokens; |
61 | // @codeCoverageIgnoreEnd |
62 | } |
63 | |
64 | $tokens = $phpcsFile->getTokens(); |
65 | |
66 | $nameIndex = $phpcsFile->findNext( T_VARIABLE, $stackPtr + 1 ); |
67 | if ( !$nameIndex ) { |
68 | // Avoid possibly running in an endless loop below |
69 | return; |
70 | } |
71 | |
72 | // Note: This requires at least 1 character after the prefix |
73 | $allowedPrefixesPattern = '/^\$(?:' . implode( '|', $this->allowedPrefixes ) . ')(.)/'; |
74 | $semicolonIndex = $phpcsFile->findNext( T_SEMICOLON, $stackPtr + 1 ); |
75 | |
76 | while ( $nameIndex < $semicolonIndex ) { |
77 | // Note, this skips dynamic identifiers. |
78 | if ( $tokens[$nameIndex ]['code'] === T_VARIABLE && $tokens[$nameIndex - 1]['code'] !== T_DOLLAR ) { |
79 | $globalName = $tokens[$nameIndex]['content']; |
80 | |
81 | if ( in_array( $globalName, $this->ignoreList ) || |
82 | in_array( $globalName, self::PHP_RESERVED ) |
83 | ) { |
84 | // need to manually increment $nameIndex here since |
85 | // we won't reach the line at the end that does it |
86 | $nameIndex++; |
87 | continue; |
88 | } |
89 | |
90 | // Determine if a simple error message can be used |
91 | |
92 | if ( count( $this->allowedPrefixes ) === 1 ) { |
93 | // Skip '$' and forge a valid global variable name |
94 | $expected = '"$' . $this->allowedPrefixes[0] . ucfirst( substr( $globalName, 1 ) ) . '"'; |
95 | |
96 | // Build message telling you the allowed prefix |
97 | $allowedPrefix = '\'' . $this->allowedPrefixes[0] . '\''; |
98 | } else { |
99 | // We already checked for an empty set of allowed prefixes earlier, |
100 | // so if the count is not 1 them it must be multiple; |
101 | // build a list of forged valid global variable names |
102 | $expected = 'one of "$' |
103 | . implode( ucfirst( substr( $globalName, 1 ) . '", "$' ), $this->allowedPrefixes ) |
104 | . ucfirst( substr( $globalName, 1 ) ) |
105 | . '"'; |
106 | |
107 | // Build message telling you which prefixes are allowed |
108 | $allowedPrefix = 'one of \'' |
109 | . implode( '\', \'', $this->allowedPrefixes ) |
110 | . '\''; |
111 | } |
112 | |
113 | // Verify global is prefixed with an allowed prefix |
114 | $isAllowed = preg_match( $allowedPrefixesPattern, $globalName, $matches ); |
115 | if ( !$isAllowed ) { |
116 | $phpcsFile->addError( |
117 | 'Global variable "%s" is lacking an allowed prefix (%s). Should be %s.', |
118 | $stackPtr, |
119 | 'allowedPrefix', |
120 | [ $globalName, $allowedPrefix, $expected ] |
121 | ); |
122 | } elseif ( ctype_lower( $matches[1] ) ) { |
123 | $phpcsFile->addError( |
124 | 'Global variable "%s" should use CamelCase: %s', |
125 | $stackPtr, |
126 | 'CamelCase', |
127 | [ $globalName, $expected ] |
128 | ); |
129 | } |
130 | } |
131 | $nameIndex++; |
132 | } |
133 | } |
134 | } |