Mercurial > hg > isophonics-drupal-site
comparison vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/Arrays/ArraySniff.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
1 <?php | |
2 /** | |
3 * \Drupal\Sniffs\Arrays\ArraySniff. | |
4 * | |
5 * @category PHP | |
6 * @package PHP_CodeSniffer | |
7 * @link http://pear.php.net/package/PHP_CodeSniffer | |
8 */ | |
9 | |
10 namespace Drupal\Sniffs\Arrays; | |
11 | |
12 use PHP_CodeSniffer\Files\File; | |
13 use PHP_CodeSniffer\Sniffs\Sniff; | |
14 use PHP_CodeSniffer\Util\Tokens; | |
15 | |
16 /** | |
17 * ArraySniff. | |
18 * | |
19 * Checks if the array's are styled in the Drupal way. | |
20 * - Comma after the last array element | |
21 * - Indentation is 2 spaces for multi line array definitions | |
22 * | |
23 * @category PHP | |
24 * @package PHP_CodeSniffer | |
25 * @link http://pear.php.net/package/PHP_CodeSniffer | |
26 */ | |
27 class ArraySniff implements Sniff | |
28 { | |
29 | |
30 | |
31 /** | |
32 * Returns an array of tokens this test wants to listen for. | |
33 * | |
34 * @return array | |
35 */ | |
36 public function register() | |
37 { | |
38 return array( | |
39 T_ARRAY, | |
40 T_OPEN_SHORT_ARRAY, | |
41 ); | |
42 | |
43 }//end register() | |
44 | |
45 | |
46 /** | |
47 * Processes this test, when one of its tokens is encountered. | |
48 * | |
49 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. | |
50 * @param int $stackPtr The position of the current token in | |
51 * the stack passed in $tokens. | |
52 * | |
53 * @return void | |
54 */ | |
55 public function process(File $phpcsFile, $stackPtr) | |
56 { | |
57 $tokens = $phpcsFile->getTokens(); | |
58 | |
59 // Support long and short syntax. | |
60 $parenthesis_opener = 'parenthesis_opener'; | |
61 $parenthesis_closer = 'parenthesis_closer'; | |
62 if ($tokens[$stackPtr]['code'] === T_OPEN_SHORT_ARRAY) { | |
63 $parenthesis_opener = 'bracket_opener'; | |
64 $parenthesis_closer = 'bracket_closer'; | |
65 } | |
66 | |
67 // Sanity check: this can sometimes be NULL if the array was not correctly | |
68 // parsed. | |
69 if ($tokens[$stackPtr][$parenthesis_closer] === null) { | |
70 return; | |
71 } | |
72 | |
73 $lastItem = $phpcsFile->findPrevious( | |
74 Tokens::$emptyTokens, | |
75 ($tokens[$stackPtr][$parenthesis_closer] - 1), | |
76 $stackPtr, | |
77 true | |
78 ); | |
79 | |
80 // Empty array. | |
81 if ($lastItem === $tokens[$stackPtr][$parenthesis_opener]) { | |
82 return; | |
83 } | |
84 | |
85 // Inline array. | |
86 $isInlineArray = $tokens[$tokens[$stackPtr][$parenthesis_opener]]['line'] === $tokens[$tokens[$stackPtr][$parenthesis_closer]]['line']; | |
87 | |
88 // Check if the last item in a multiline array has a "closing" comma. | |
89 if ($tokens[$lastItem]['code'] !== T_COMMA && $isInlineArray === false | |
90 && $tokens[($lastItem + 1)]['code'] !== T_CLOSE_PARENTHESIS | |
91 && $tokens[($lastItem + 1)]['code'] !== T_CLOSE_SHORT_ARRAY | |
92 && isset(Tokens::$heredocTokens[$tokens[$lastItem]['code']]) === false | |
93 ) { | |
94 $data = array($tokens[$lastItem]['content']); | |
95 $fix = $phpcsFile->addFixableWarning('A comma should follow the last multiline array item. Found: %s', $lastItem, 'CommaLastItem', $data); | |
96 if ($fix === true) { | |
97 $phpcsFile->fixer->addContent($lastItem, ','); | |
98 } | |
99 | |
100 return; | |
101 } | |
102 | |
103 if ($isInlineArray === true) { | |
104 // Check if this array contains at least 3 elements and exceeds the 80 | |
105 // character line length. | |
106 if ($tokens[$tokens[$stackPtr][$parenthesis_closer]]['column'] > 80) { | |
107 $comma1 = $phpcsFile->findNext(T_COMMA, ($stackPtr + 1), $tokens[$stackPtr][$parenthesis_closer]); | |
108 if ($comma1 !== false) { | |
109 $comma2 = $phpcsFile->findNext(T_COMMA, ($comma1 + 1), $tokens[$stackPtr][$parenthesis_closer]); | |
110 if ($comma2 !== false) { | |
111 $error = 'If the line declaring an array spans longer than 80 characters, each element should be broken into its own line'; | |
112 $phpcsFile->addError($error, $stackPtr, 'LongLineDeclaration'); | |
113 } | |
114 } | |
115 } | |
116 | |
117 // Only continue for multi line arrays. | |
118 return; | |
119 } | |
120 | |
121 // Find the first token on this line. | |
122 $firstLineColumn = $tokens[$stackPtr]['column']; | |
123 for ($i = $stackPtr; $i >= 0; $i--) { | |
124 // If there is a PHP open tag then this must be a template file where we | |
125 // don't check indentation. | |
126 if ($tokens[$i]['code'] === T_OPEN_TAG) { | |
127 return; | |
128 } | |
129 | |
130 // Record the first code token on the line. | |
131 if ($tokens[$i]['code'] !== T_WHITESPACE) { | |
132 $firstLineColumn = $tokens[$i]['column']; | |
133 // This could be a multi line string or comment beginning with white | |
134 // spaces. | |
135 $trimmed = ltrim($tokens[$i]['content']); | |
136 if ($trimmed !== $tokens[$i]['content']) { | |
137 $firstLineColumn = ($firstLineColumn + strpos($tokens[$i]['content'], $trimmed)); | |
138 } | |
139 } | |
140 | |
141 // It's the start of the line, so we've found our first php token. | |
142 if ($tokens[$i]['column'] === 1) { | |
143 break; | |
144 } | |
145 }//end for | |
146 | |
147 $lineStart = $stackPtr; | |
148 // Iterate over all lines of this array. | |
149 while ($lineStart < $tokens[$stackPtr][$parenthesis_closer]) { | |
150 // Find next line start. | |
151 $newLineStart = $lineStart; | |
152 $current_line = $tokens[$newLineStart]['line']; | |
153 while ($current_line >= $tokens[$newLineStart]['line']) { | |
154 $newLineStart = $phpcsFile->findNext( | |
155 Tokens::$emptyTokens, | |
156 ($newLineStart + 1), | |
157 ($tokens[$stackPtr][$parenthesis_closer] + 1), | |
158 true | |
159 ); | |
160 | |
161 if ($newLineStart === false) { | |
162 break 2; | |
163 } | |
164 | |
165 // Long array syntax: Skip nested arrays, they are checked in a next | |
166 // run. | |
167 if ($tokens[$newLineStart]['code'] === T_ARRAY) { | |
168 $newLineStart = $tokens[$newLineStart]['parenthesis_closer']; | |
169 $current_line = $tokens[$newLineStart]['line']; | |
170 } | |
171 | |
172 // Short array syntax: Skip nested arrays, they are checked in a next | |
173 // run. | |
174 if ($tokens[$newLineStart]['code'] === T_OPEN_SHORT_ARRAY) { | |
175 $newLineStart = $tokens[$newLineStart]['bracket_closer']; | |
176 $current_line = $tokens[$newLineStart]['line']; | |
177 } | |
178 | |
179 // Nested structures such as closures: skip those, they are checked | |
180 // in other sniffs. If the conditions of a token are different it | |
181 // means that it is in a different nesting level. | |
182 if ($tokens[$newLineStart]['conditions'] !== $tokens[$stackPtr]['conditions']) { | |
183 $current_line++; | |
184 } | |
185 }//end while | |
186 | |
187 if ($newLineStart === $tokens[$stackPtr][$parenthesis_closer]) { | |
188 // End of the array reached. | |
189 if ($tokens[$newLineStart]['column'] !== $firstLineColumn) { | |
190 $error = 'Array closing indentation error, expected %s spaces but found %s'; | |
191 $data = array( | |
192 $firstLineColumn - 1, | |
193 $tokens[$newLineStart]['column'] - 1, | |
194 ); | |
195 $fix = $phpcsFile->addFixableError($error, $newLineStart, 'ArrayClosingIndentation', $data); | |
196 if ($fix === true) { | |
197 if ($tokens[$newLineStart]['column'] === 1) { | |
198 $phpcsFile->fixer->addContentBefore($newLineStart, str_repeat(' ', ($firstLineColumn - 1))); | |
199 } else { | |
200 $phpcsFile->fixer->replaceToken(($newLineStart - 1), str_repeat(' ', ($firstLineColumn - 1))); | |
201 } | |
202 } | |
203 } | |
204 | |
205 break; | |
206 } | |
207 | |
208 $expectedColumn = ($firstLineColumn + 2); | |
209 // If the line starts with "->" then we assume an additional level of | |
210 // indentation. | |
211 if ($tokens[$newLineStart]['code'] === T_OBJECT_OPERATOR) { | |
212 $expectedColumn += 2; | |
213 } | |
214 | |
215 if ($tokens[$newLineStart]['column'] !== $expectedColumn) { | |
216 // Skip lines in nested structures such as a function call within an | |
217 // array, no defined coding standard for those. | |
218 $innerNesting = empty($tokens[$newLineStart]['nested_parenthesis']) === false | |
219 && end($tokens[$newLineStart]['nested_parenthesis']) < $tokens[$stackPtr][$parenthesis_closer]; | |
220 // Skip lines that are part of a multi-line string. | |
221 $isMultiLineString = $tokens[($newLineStart - 1)]['code'] === T_CONSTANT_ENCAPSED_STRING | |
222 && substr($tokens[($newLineStart - 1)]['content'], -1) === $phpcsFile->eolChar; | |
223 // Skip NOWDOC or HEREDOC lines. | |
224 $nowDoc = isset(Tokens::$heredocTokens[$tokens[$newLineStart]['code']]); | |
225 if ($innerNesting === false && $isMultiLineString === false && $nowDoc === false) { | |
226 $error = 'Array indentation error, expected %s spaces but found %s'; | |
227 $data = array( | |
228 $expectedColumn - 1, | |
229 $tokens[$newLineStart]['column'] - 1, | |
230 ); | |
231 $fix = $phpcsFile->addFixableError($error, $newLineStart, 'ArrayIndentation', $data); | |
232 if ($fix === true) { | |
233 if ($tokens[$newLineStart]['column'] === 1) { | |
234 $phpcsFile->fixer->addContentBefore($newLineStart, str_repeat(' ', ($expectedColumn - 1))); | |
235 } else { | |
236 $phpcsFile->fixer->replaceToken(($newLineStart - 1), str_repeat(' ', ($expectedColumn - 1))); | |
237 } | |
238 } | |
239 } | |
240 }//end if | |
241 | |
242 $lineStart = $newLineStart; | |
243 }//end while | |
244 | |
245 }//end process() | |
246 | |
247 | |
248 }//end class |