1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\SourceLocator\Ast\Exception;
6:
7: use PhpParser\Error;
8: use PHPStan\BetterReflection\SourceLocator\Located\LocatedSource;
9: use RuntimeException;
10: use Throwable;
11:
12: use function array_slice;
13: use function count;
14: use function explode;
15: use function implode;
16: use function max;
17: use function min;
18: use function sprintf;
19:
20: class ParseToAstFailure extends RuntimeException
21: {
22: public static function fromLocatedSource(LocatedSource $locatedSource, Throwable $previous): self
23: {
24: $additionalInformation = '';
25:
26: $fileName = $locatedSource->getFileName();
27:
28: if ($fileName !== null) {
29: $additionalInformation = sprintf(' in file %s', $fileName);
30: }
31:
32: if ($previous instanceof Error) {
33: $errorStartLine = $previous->getStartLine();
34:
35: $source = null;
36:
37: if ($errorStartLine !== -1) {
38: $additionalInformation .= sprintf(' (line %d)', $errorStartLine);
39:
40: $lines = explode("\n", $locatedSource->getSource());
41:
42: $minLine = max(1, $errorStartLine - 5);
43: $maxLine = min(count($lines), $errorStartLine + 5);
44:
45: $source = implode("\n", array_slice($lines, $minLine - 1, $maxLine - $minLine + 1));
46: }
47:
48: $additionalInformation .= sprintf(': %s', $previous->getRawMessage());
49:
50: if ($source !== null) {
51: $additionalInformation .= sprintf("\n\n%s", $source);
52: }
53: } else {
54: $additionalInformation .= sprintf(': %s', $previous->getMessage());
55: }
56:
57: return new self(sprintf('AST failed to parse in located source%s', $additionalInformation), 0, $previous);
58: }
59: }
60: