comparison vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.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 * Tokenizes doc block comments.
4 *
5 * @author Greg Sherwood <gsherwood@squiz.net>
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8 */
9
10 namespace PHP_CodeSniffer\Tokenizers;
11
12 use PHP_CodeSniffer\Util;
13
14 class Comment
15 {
16
17
18 /**
19 * Creates an array of tokens when given some PHP code.
20 *
21 * Starts by using token_get_all() but does a lot of extra processing
22 * to insert information about the context of the token.
23 *
24 * @param string $string The string to tokenize.
25 * @param string $eolChar The EOL character to use for splitting strings.
26 * @param int $stackPtr The position of the first token in the file.
27 *
28 * @return array
29 */
30 public function tokenizeString($string, $eolChar, $stackPtr)
31 {
32 if (PHP_CODESNIFFER_VERBOSITY > 1) {
33 echo "\t\t*** START COMMENT TOKENIZING ***".PHP_EOL;
34 }
35
36 $tokens = [];
37 $numChars = strlen($string);
38
39 /*
40 Doc block comments start with /*, but typically contain an
41 extra star when they are used for function and class comments.
42 */
43
44 $char = ($numChars - strlen(ltrim($string, '/*')));
45 $openTag = substr($string, 0, $char);
46 $string = ltrim($string, '/*');
47
48 $tokens[$stackPtr] = [
49 'content' => $openTag,
50 'code' => T_DOC_COMMENT_OPEN_TAG,
51 'type' => 'T_DOC_COMMENT_OPEN_TAG',
52 'comment_tags' => [],
53 ];
54
55 $openPtr = $stackPtr;
56 $stackPtr++;
57
58 if (PHP_CODESNIFFER_VERBOSITY > 1) {
59 $content = Util\Common::prepareForOutput($openTag);
60 echo "\t\tCreate comment token: T_DOC_COMMENT_OPEN_TAG => $content".PHP_EOL;
61 }
62
63 /*
64 Strip off the close tag so it doesn't interfere with any
65 of our comment line processing. The token will be added to the
66 stack just before we return it.
67 */
68
69 $closeTag = [
70 'content' => substr($string, strlen(rtrim($string, '/*'))),
71 'code' => T_DOC_COMMENT_CLOSE_TAG,
72 'type' => 'T_DOC_COMMENT_CLOSE_TAG',
73 'comment_opener' => $openPtr,
74 ];
75
76 if ($closeTag['content'] === false) {
77 $closeTag['content'] = '';
78 }
79
80 $string = rtrim($string, '/*');
81
82 /*
83 Process each line of the comment.
84 */
85
86 $lines = explode($eolChar, $string);
87 $numLines = count($lines);
88 foreach ($lines as $lineNum => $string) {
89 if ($lineNum !== ($numLines - 1)) {
90 $string .= $eolChar;
91 }
92
93 $char = 0;
94 $numChars = strlen($string);
95
96 // We've started a new line, so process the indent.
97 $space = $this->collectWhitespace($string, $char, $numChars);
98 if ($space !== null) {
99 $tokens[$stackPtr] = $space;
100 $stackPtr++;
101 if (PHP_CODESNIFFER_VERBOSITY > 1) {
102 $content = Util\Common::prepareForOutput($space['content']);
103 echo "\t\tCreate comment token: T_DOC_COMMENT_WHITESPACE => $content".PHP_EOL;
104 }
105
106 $char += strlen($space['content']);
107 if ($char === $numChars) {
108 break;
109 }
110 }
111
112 if ($string === '') {
113 continue;
114 }
115
116 if ($lineNum > 0 && $string[$char] === '*') {
117 // This is a function or class doc block line.
118 $char++;
119 $tokens[$stackPtr] = [
120 'content' => '*',
121 'code' => T_DOC_COMMENT_STAR,
122 'type' => 'T_DOC_COMMENT_STAR',
123 ];
124
125 $stackPtr++;
126
127 if (PHP_CODESNIFFER_VERBOSITY > 1) {
128 echo "\t\tCreate comment token: T_DOC_COMMENT_STAR => *".PHP_EOL;
129 }
130 }
131
132 // Now we are ready to process the actual content of the line.
133 $lineTokens = $this->processLine($string, $eolChar, $char, $numChars);
134 foreach ($lineTokens as $lineToken) {
135 $tokens[$stackPtr] = $lineToken;
136 if (PHP_CODESNIFFER_VERBOSITY > 1) {
137 $content = Util\Common::prepareForOutput($lineToken['content']);
138 $type = $lineToken['type'];
139 echo "\t\tCreate comment token: $type => $content".PHP_EOL;
140 }
141
142 if ($lineToken['code'] === T_DOC_COMMENT_TAG) {
143 $tokens[$openPtr]['comment_tags'][] = $stackPtr;
144 }
145
146 $stackPtr++;
147 }
148 }//end foreach
149
150 $tokens[$stackPtr] = $closeTag;
151 $tokens[$openPtr]['comment_closer'] = $stackPtr;
152 if (PHP_CODESNIFFER_VERBOSITY > 1) {
153 $content = Util\Common::prepareForOutput($closeTag['content']);
154 echo "\t\tCreate comment token: T_DOC_COMMENT_CLOSE_TAG => $content".PHP_EOL;
155 }
156
157 if (PHP_CODESNIFFER_VERBOSITY > 1) {
158 echo "\t\t*** END COMMENT TOKENIZING ***".PHP_EOL;
159 }
160
161 return $tokens;
162
163 }//end tokenizeString()
164
165
166 /**
167 * Process a single line of a comment.
168 *
169 * @param string $string The comment string being tokenized.
170 * @param string $eolChar The EOL character to use for splitting strings.
171 * @param int $start The position in the string to start processing.
172 * @param int $end The position in the string to end processing.
173 *
174 * @return array
175 */
176 private function processLine($string, $eolChar, $start, $end)
177 {
178 $tokens = [];
179
180 // Collect content padding.
181 $space = $this->collectWhitespace($string, $start, $end);
182 if ($space !== null) {
183 $tokens[] = $space;
184 $start += strlen($space['content']);
185 }
186
187 if (isset($string[$start]) === false) {
188 return $tokens;
189 }
190
191 if ($string[$start] === '@') {
192 // The content up until the first whitespace is the tag name.
193 $matches = [];
194 preg_match('/@[^\s]+/', $string, $matches, 0, $start);
195 if (isset($matches[0]) === true
196 && substr(strtolower($matches[0]), 0, 7) !== '@phpcs:'
197 ) {
198 $tagName = $matches[0];
199 $start += strlen($tagName);
200 $tokens[] = [
201 'content' => $tagName,
202 'code' => T_DOC_COMMENT_TAG,
203 'type' => 'T_DOC_COMMENT_TAG',
204 ];
205
206 // Then there will be some whitespace.
207 $space = $this->collectWhitespace($string, $start, $end);
208 if ($space !== null) {
209 $tokens[] = $space;
210 $start += strlen($space['content']);
211 }
212 }
213 }//end if
214
215 // Process the rest of the line.
216 $eol = strpos($string, $eolChar, $start);
217 if ($eol === false) {
218 $eol = $end;
219 }
220
221 if ($eol > $start) {
222 $tokens[] = [
223 'content' => substr($string, $start, ($eol - $start)),
224 'code' => T_DOC_COMMENT_STRING,
225 'type' => 'T_DOC_COMMENT_STRING',
226 ];
227 }
228
229 if ($eol !== $end) {
230 $tokens[] = [
231 'content' => substr($string, $eol, strlen($eolChar)),
232 'code' => T_DOC_COMMENT_WHITESPACE,
233 'type' => 'T_DOC_COMMENT_WHITESPACE',
234 ];
235 }
236
237 return $tokens;
238
239 }//end processLine()
240
241
242 /**
243 * Collect consecutive whitespace into a single token.
244 *
245 * @param string $string The comment string being tokenized.
246 * @param int $start The position in the string to start processing.
247 * @param int $end The position in the string to end processing.
248 *
249 * @return array|null
250 */
251 private function collectWhitespace($string, $start, $end)
252 {
253 $space = '';
254 for ($start; $start < $end; $start++) {
255 if ($string[$start] !== ' ' && $string[$start] !== "\t") {
256 break;
257 }
258
259 $space .= $string[$start];
260 }
261
262 if ($space === '') {
263 return null;
264 }
265
266 $token = [
267 'content' => $space,
268 'code' => T_DOC_COMMENT_WHITESPACE,
269 'type' => 'T_DOC_COMMENT_WHITESPACE',
270 ];
271
272 return $token;
273
274 }//end collectWhitespace()
275
276
277 }//end class