This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Psalm; |
||
3 | |||
4 | use function explode; |
||
5 | use function max; |
||
6 | use function min; |
||
7 | use PhpParser; |
||
8 | use function preg_match; |
||
9 | use const PREG_OFFSET_CAPTURE; |
||
10 | use function preg_quote; |
||
11 | use function preg_replace; |
||
12 | use Psalm\Internal\Analyzer\CommentAnalyzer; |
||
13 | use function str_replace; |
||
14 | use function strlen; |
||
15 | use function strpos; |
||
16 | use function strrpos; |
||
17 | use function substr; |
||
18 | use function substr_count; |
||
19 | use function trim; |
||
20 | |||
21 | class CodeLocation |
||
22 | { |
||
23 | /** @var string */ |
||
24 | public $file_path; |
||
25 | |||
26 | /** @var string */ |
||
27 | public $file_name; |
||
28 | |||
29 | /** @var int */ |
||
30 | public $raw_line_number; |
||
31 | |||
32 | /** @var int */ |
||
33 | private $end_line_number = -1; |
||
34 | |||
35 | /** @var int */ |
||
36 | public $raw_file_start; |
||
37 | |||
38 | /** @var int */ |
||
39 | public $raw_file_end; |
||
40 | |||
41 | /** @var int */ |
||
42 | protected $file_start; |
||
43 | |||
44 | /** @var int */ |
||
45 | protected $file_end; |
||
46 | |||
47 | /** @var bool */ |
||
48 | protected $single_line; |
||
49 | |||
50 | /** @var int */ |
||
51 | protected $preview_start; |
||
52 | |||
53 | /** @var int */ |
||
54 | private $preview_end = -1; |
||
55 | |||
56 | /** @var int */ |
||
57 | private $selection_start = -1; |
||
58 | |||
59 | /** @var int */ |
||
60 | private $selection_end = -1; |
||
61 | |||
62 | /** @var int */ |
||
63 | private $column_from = -1; |
||
64 | |||
65 | /** @var int */ |
||
66 | private $column_to = -1; |
||
67 | |||
68 | /** @var string */ |
||
69 | private $snippet = ''; |
||
70 | |||
71 | /** @var null|string */ |
||
72 | private $text; |
||
73 | |||
74 | /** @var int|null */ |
||
75 | public $docblock_start; |
||
76 | |||
77 | /** @var int|null */ |
||
78 | public $docblock_end; |
||
79 | |||
80 | /** @var int|null */ |
||
81 | private $docblock_start_line_number; |
||
82 | |||
83 | /** @var int|null */ |
||
84 | private $docblock_line_number; |
||
85 | |||
86 | /** @var null|int */ |
||
87 | private $regex_type; |
||
88 | |||
89 | /** @var bool */ |
||
90 | private $have_recalculated = false; |
||
91 | |||
92 | /** @var null|CodeLocation */ |
||
93 | public $previous_location; |
||
94 | |||
95 | const VAR_TYPE = 0; |
||
96 | const FUNCTION_RETURN_TYPE = 1; |
||
97 | const FUNCTION_PARAM_TYPE = 2; |
||
98 | const FUNCTION_PHPDOC_RETURN_TYPE = 3; |
||
99 | const FUNCTION_PHPDOC_PARAM_TYPE = 4; |
||
100 | const FUNCTION_PARAM_VAR = 5; |
||
101 | const CATCH_VAR = 6; |
||
102 | const FUNCTION_PHPDOC_METHOD = 7; |
||
103 | |||
104 | /** |
||
105 | * @param bool $single_line |
||
106 | * @param null|CodeLocation $previous_location |
||
107 | * @param null|int $regex_type |
||
108 | * @param null|string $selected_text |
||
109 | */ |
||
110 | public function __construct( |
||
111 | FileSource $file_source, |
||
112 | PhpParser\Node $stmt, |
||
113 | CodeLocation $previous_location = null, |
||
114 | $single_line = false, |
||
115 | $regex_type = null, |
||
116 | $selected_text = null |
||
117 | ) { |
||
118 | $this->file_start = (int)$stmt->getAttribute('startFilePos'); |
||
119 | $this->file_end = (int)$stmt->getAttribute('endFilePos'); |
||
120 | $this->raw_file_start = $this->file_start; |
||
121 | $this->raw_file_end = $this->file_end; |
||
122 | $this->file_path = $file_source->getFilePath(); |
||
123 | $this->file_name = $file_source->getFileName(); |
||
124 | $this->single_line = $single_line; |
||
125 | $this->regex_type = $regex_type; |
||
126 | $this->previous_location = $previous_location; |
||
127 | $this->text = $selected_text; |
||
128 | |||
129 | $doc_comment = $stmt->getDocComment(); |
||
130 | |||
131 | $this->docblock_start = $doc_comment ? $doc_comment->getFilePos() : null; |
||
0 ignored issues
–
show
|
|||
132 | $this->docblock_end = $doc_comment ? $this->file_start : null; |
||
133 | $this->docblock_start_line_number = $doc_comment ? $doc_comment->getLine() : null; |
||
0 ignored issues
–
show
The method
PhpParser\Comment::getLine() has been deprecated with message: Use getStartLine() instead
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
134 | |||
135 | $this->preview_start = $this->docblock_start ?: $this->file_start; |
||
136 | |||
137 | $this->raw_line_number = $stmt->getLine(); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * @param int $line |
||
142 | * |
||
143 | * @return void |
||
144 | */ |
||
145 | public function setCommentLine($line) |
||
146 | { |
||
147 | $this->docblock_line_number = $line; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * @psalm-suppress MixedArrayAccess |
||
152 | * |
||
153 | * @return void |
||
154 | */ |
||
155 | private function calculateRealLocation() |
||
156 | { |
||
157 | if ($this->have_recalculated) { |
||
158 | return; |
||
159 | } |
||
160 | |||
161 | $this->have_recalculated = true; |
||
162 | |||
163 | $this->selection_start = $this->file_start; |
||
164 | $this->selection_end = $this->file_end + 1; |
||
165 | |||
166 | $project_analyzer = Internal\Analyzer\ProjectAnalyzer::getInstance(); |
||
167 | |||
168 | $codebase = $project_analyzer->getCodebase(); |
||
169 | |||
170 | $file_contents = $codebase->getFileContents($this->file_path); |
||
171 | |||
172 | $file_length = strlen($file_contents); |
||
173 | |||
174 | $search_limit = $this->single_line ? $this->selection_start : $this->selection_end; |
||
175 | |||
176 | if ($search_limit <= $file_length) { |
||
177 | $preview_end = strpos( |
||
178 | $file_contents, |
||
179 | "\n", |
||
180 | $search_limit |
||
181 | ); |
||
182 | } else { |
||
183 | $preview_end = false; |
||
184 | } |
||
185 | |||
186 | // if the string didn't contain a newline |
||
187 | if ($preview_end === false) { |
||
188 | $preview_end = $this->selection_end; |
||
189 | } |
||
190 | |||
191 | $this->preview_end = $preview_end; |
||
192 | |||
193 | if ($this->docblock_line_number && |
||
194 | $this->docblock_start_line_number && |
||
195 | $this->preview_start < $this->selection_start |
||
196 | ) { |
||
197 | $preview_lines = explode( |
||
198 | "\n", |
||
199 | substr( |
||
200 | $file_contents, |
||
201 | $this->preview_start, |
||
202 | $this->selection_start - $this->preview_start - 1 |
||
203 | ) |
||
204 | ); |
||
205 | |||
206 | $preview_offset = 0; |
||
207 | |||
208 | $comment_line_offset = $this->docblock_line_number - $this->docblock_start_line_number; |
||
209 | |||
210 | for ($i = 0; $i < $comment_line_offset; ++$i) { |
||
211 | $preview_offset += strlen($preview_lines[$i]) + 1; |
||
212 | } |
||
213 | |||
214 | if (!isset($preview_lines[$i])) { |
||
215 | throw new \Exception('Should have offset'); |
||
216 | } |
||
217 | |||
218 | $key_line = $preview_lines[$i]; |
||
219 | |||
220 | $indentation = (int)strpos($key_line, '@'); |
||
221 | |||
222 | $key_line = trim(preg_replace('@\**/\s*@', '', substr($key_line, $indentation))); |
||
223 | |||
224 | $this->selection_start = $preview_offset + $indentation + $this->preview_start; |
||
225 | $this->selection_end = $this->selection_start + strlen($key_line); |
||
226 | } |
||
227 | |||
228 | if ($this->regex_type !== null) { |
||
229 | switch ($this->regex_type) { |
||
230 | case self::VAR_TYPE: |
||
231 | $regex = '/@(psalm-)?var[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/'; |
||
232 | $match_offset = 2; |
||
233 | break; |
||
234 | |||
235 | case self::FUNCTION_RETURN_TYPE: |
||
236 | $regex = '/\\:\s+(\\??\s*[A-Za-z0-9_\\\\\[\]]+)/'; |
||
237 | $match_offset = 1; |
||
238 | break; |
||
239 | |||
240 | case self::FUNCTION_PARAM_TYPE: |
||
241 | $regex = '/^(\\??\s*[A-Za-z0-9_\\\\\[\]]+)\s/'; |
||
242 | $match_offset = 1; |
||
243 | break; |
||
244 | |||
245 | case self::FUNCTION_PHPDOC_RETURN_TYPE: |
||
246 | $regex = '/@(psalm-)?return[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/'; |
||
247 | $match_offset = 2; |
||
248 | break; |
||
249 | |||
250 | case self::FUNCTION_PHPDOC_METHOD: |
||
251 | $regex = '/@(psalm-)method[ \t]+.*/'; |
||
252 | $match_offset = 2; |
||
253 | break; |
||
254 | |||
255 | case self::FUNCTION_PHPDOC_PARAM_TYPE: |
||
256 | $regex = '/@(psalm-)?param[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/'; |
||
257 | $match_offset = 2; |
||
258 | break; |
||
259 | |||
260 | case self::FUNCTION_PARAM_VAR: |
||
261 | $regex = '/(\$[^ ]*)/'; |
||
262 | $match_offset = 1; |
||
263 | break; |
||
264 | |||
265 | case self::CATCH_VAR: |
||
266 | $regex = '/(\$[^ ^\)]*)/'; |
||
267 | $match_offset = 1; |
||
268 | break; |
||
269 | |||
270 | default: |
||
271 | throw new \UnexpectedValueException('Unrecognised regex type ' . $this->regex_type); |
||
272 | } |
||
273 | |||
274 | $preview_snippet = substr( |
||
275 | $file_contents, |
||
276 | $this->selection_start, |
||
277 | $this->selection_end - $this->selection_start |
||
278 | ); |
||
279 | |||
280 | if ($this->text) { |
||
281 | $regex = '/(' . str_replace(',', ',[ ]*', preg_quote($this->text, '/')) . ')/'; |
||
282 | $match_offset = 1; |
||
283 | } |
||
284 | |||
285 | if (preg_match($regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) { |
||
286 | $this->selection_start = $this->selection_start + (int)$matches[$match_offset][1]; |
||
287 | $this->selection_end = $this->selection_start + strlen((string)$matches[$match_offset][0]); |
||
288 | } |
||
289 | } |
||
290 | |||
291 | // reset preview start to beginning of line |
||
292 | $this->preview_start = (int)strrpos( |
||
293 | $file_contents, |
||
294 | "\n", |
||
295 | min($this->preview_start, $this->selection_start) - strlen($file_contents) |
||
296 | ) + 1; |
||
297 | |||
298 | $this->selection_start = max($this->preview_start, $this->selection_start); |
||
299 | $this->selection_end = min($this->preview_end, $this->selection_end); |
||
300 | |||
301 | if ($this->preview_end - $this->selection_end > 200) { |
||
302 | $this->preview_end = (int)strrpos( |
||
303 | $file_contents, |
||
304 | "\n", |
||
305 | $this->selection_end + 200 - strlen($file_contents) |
||
306 | ); |
||
307 | |||
308 | // if the line is over 200 characters long |
||
309 | if ($this->preview_end < $this->selection_end) { |
||
310 | $this->preview_end = $this->selection_end + 50; |
||
311 | } |
||
312 | } |
||
313 | |||
314 | $this->snippet = substr($file_contents, $this->preview_start, $this->preview_end - $this->preview_start); |
||
315 | $this->text = substr($file_contents, $this->selection_start, $this->selection_end - $this->selection_start); |
||
316 | |||
317 | // reset preview start to beginning of line |
||
318 | $this->column_from = $this->selection_start - |
||
319 | (int)strrpos($file_contents, "\n", $this->selection_start - strlen($file_contents)); |
||
320 | |||
321 | $newlines = substr_count($this->text, "\n"); |
||
322 | |||
323 | if ($newlines) { |
||
324 | $this->column_to = $this->selection_end - |
||
325 | (int)strrpos($file_contents, "\n", $this->selection_end - strlen($file_contents)); |
||
326 | } else { |
||
327 | $this->column_to = $this->column_from + strlen($this->text); |
||
328 | } |
||
329 | |||
330 | $this->end_line_number = $this->getLineNumber() + $newlines; |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * @return int |
||
335 | */ |
||
336 | public function getLineNumber() |
||
337 | { |
||
338 | return $this->docblock_line_number ?: $this->raw_line_number; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * @return int |
||
343 | */ |
||
344 | public function getEndLineNumber() |
||
345 | { |
||
346 | $this->calculateRealLocation(); |
||
347 | |||
348 | return $this->end_line_number; |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * @return string |
||
353 | */ |
||
354 | public function getSnippet() |
||
355 | { |
||
356 | $this->calculateRealLocation(); |
||
357 | |||
358 | return $this->snippet; |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * @return string |
||
363 | */ |
||
364 | public function getSelectedText() |
||
365 | { |
||
366 | $this->calculateRealLocation(); |
||
367 | |||
368 | return (string)$this->text; |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * @return int |
||
373 | */ |
||
374 | public function getColumn() |
||
375 | { |
||
376 | $this->calculateRealLocation(); |
||
377 | |||
378 | return $this->column_from; |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * @return int |
||
383 | */ |
||
384 | public function getEndColumn() |
||
385 | { |
||
386 | $this->calculateRealLocation(); |
||
387 | |||
388 | return $this->column_to; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * @return array{0: int, 1: int} |
||
0 ignored issues
–
show
The doc-type
array{0: could not be parsed: Unknown type name "array{0:" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
393 | */ |
||
394 | public function getSelectionBounds() |
||
395 | { |
||
396 | $this->calculateRealLocation(); |
||
397 | |||
398 | return [$this->selection_start, $this->selection_end]; |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * @return array{0: int, 1: int} |
||
0 ignored issues
–
show
The doc-type
array{0: could not be parsed: Unknown type name "array{0:" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
403 | */ |
||
404 | public function getSnippetBounds() |
||
405 | { |
||
406 | $this->calculateRealLocation(); |
||
407 | |||
408 | return [$this->preview_start, $this->preview_end]; |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * @return string |
||
413 | */ |
||
414 | public function getHash() |
||
415 | { |
||
416 | return (string) $this->file_start; |
||
417 | } |
||
418 | |||
419 | public function getShortSummary() : string |
||
420 | { |
||
421 | return $this->file_name . ':' . $this->getLineNumber() . ':' . $this->getColumn(); |
||
422 | } |
||
423 | } |
||
424 |
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.