1: | <?php declare(strict_types = 1); |
2: | |
3: | namespace PHPStan\Analyser; |
4: | |
5: | use Exception; |
6: | use JsonSerializable; |
7: | use PhpParser\Node; |
8: | use PHPStan\ShouldNotHappenException; |
9: | use ReturnTypeWillChange; |
10: | use Throwable; |
11: | use function is_bool; |
12: | |
13: | |
14: | class Error implements JsonSerializable |
15: | { |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | public function __construct( |
24: | private string $message, |
25: | private string $file, |
26: | private ?int $line = null, |
27: | private bool|Throwable $canBeIgnored = true, |
28: | private ?string $filePath = null, |
29: | private ?string $traitFilePath = null, |
30: | private ?string $tip = null, |
31: | private ?int $nodeLine = null, |
32: | private ?string $nodeType = null, |
33: | private ?string $identifier = null, |
34: | private array $metadata = [], |
35: | ) |
36: | { |
37: | } |
38: | |
39: | public function getMessage(): string |
40: | { |
41: | return $this->message; |
42: | } |
43: | |
44: | public function getFile(): string |
45: | { |
46: | return $this->file; |
47: | } |
48: | |
49: | public function getFilePath(): string |
50: | { |
51: | if ($this->filePath === null) { |
52: | return $this->file; |
53: | } |
54: | |
55: | return $this->filePath; |
56: | } |
57: | |
58: | public function changeFilePath(string $newFilePath): self |
59: | { |
60: | if ($this->traitFilePath !== null) { |
61: | throw new ShouldNotHappenException('Errors in traits not yet supported'); |
62: | } |
63: | |
64: | return new self( |
65: | $this->message, |
66: | $newFilePath, |
67: | $this->line, |
68: | $this->canBeIgnored, |
69: | $newFilePath, |
70: | null, |
71: | $this->tip, |
72: | $this->nodeLine, |
73: | $this->nodeType, |
74: | $this->identifier, |
75: | $this->metadata, |
76: | ); |
77: | } |
78: | |
79: | public function changeTraitFilePath(string $newFilePath): self |
80: | { |
81: | return new self( |
82: | $this->message, |
83: | $this->file, |
84: | $this->line, |
85: | $this->canBeIgnored, |
86: | $this->filePath, |
87: | $newFilePath, |
88: | $this->tip, |
89: | $this->nodeLine, |
90: | $this->nodeType, |
91: | $this->identifier, |
92: | $this->metadata, |
93: | ); |
94: | } |
95: | |
96: | public function getTraitFilePath(): ?string |
97: | { |
98: | return $this->traitFilePath; |
99: | } |
100: | |
101: | public function getLine(): ?int |
102: | { |
103: | return $this->line; |
104: | } |
105: | |
106: | public function canBeIgnored(): bool |
107: | { |
108: | return $this->canBeIgnored === true; |
109: | } |
110: | |
111: | public function hasNonIgnorableException(): bool |
112: | { |
113: | return $this->canBeIgnored instanceof Throwable; |
114: | } |
115: | |
116: | public function getTip(): ?string |
117: | { |
118: | return $this->tip; |
119: | } |
120: | |
121: | public function withoutTip(): self |
122: | { |
123: | if ($this->tip === null) { |
124: | return $this; |
125: | } |
126: | |
127: | return new self( |
128: | $this->message, |
129: | $this->file, |
130: | $this->line, |
131: | $this->canBeIgnored, |
132: | $this->filePath, |
133: | $this->traitFilePath, |
134: | null, |
135: | $this->nodeLine, |
136: | $this->nodeType, |
137: | ); |
138: | } |
139: | |
140: | public function doNotIgnore(): self |
141: | { |
142: | if (!$this->canBeIgnored()) { |
143: | return $this; |
144: | } |
145: | |
146: | return new self( |
147: | $this->message, |
148: | $this->file, |
149: | $this->line, |
150: | false, |
151: | $this->filePath, |
152: | $this->traitFilePath, |
153: | $this->tip, |
154: | $this->nodeLine, |
155: | $this->nodeType, |
156: | ); |
157: | } |
158: | |
159: | public function getNodeLine(): ?int |
160: | { |
161: | return $this->nodeLine; |
162: | } |
163: | |
164: | |
165: | |
166: | |
167: | public function getNodeType(): ?string |
168: | { |
169: | return $this->nodeType; |
170: | } |
171: | |
172: | public function getIdentifier(): ?string |
173: | { |
174: | return $this->identifier; |
175: | } |
176: | |
177: | |
178: | |
179: | |
180: | public function getMetadata(): array |
181: | { |
182: | return $this->metadata; |
183: | } |
184: | |
185: | |
186: | |
187: | |
188: | #[ReturnTypeWillChange] |
189: | public function jsonSerialize() |
190: | { |
191: | return [ |
192: | 'message' => $this->message, |
193: | 'file' => $this->file, |
194: | 'line' => $this->line, |
195: | 'canBeIgnored' => is_bool($this->canBeIgnored) ? $this->canBeIgnored : 'exception', |
196: | 'filePath' => $this->filePath, |
197: | 'traitFilePath' => $this->traitFilePath, |
198: | 'tip' => $this->tip, |
199: | 'nodeLine' => $this->nodeLine, |
200: | 'nodeType' => $this->nodeType, |
201: | 'identifier' => $this->identifier, |
202: | 'metadata' => $this->metadata, |
203: | ]; |
204: | } |
205: | |
206: | |
207: | |
208: | |
209: | public static function decode(array $json): self |
210: | { |
211: | return new self( |
212: | $json['message'], |
213: | $json['file'], |
214: | $json['line'], |
215: | $json['canBeIgnored'] === 'exception' ? new Exception() : $json['canBeIgnored'], |
216: | $json['filePath'], |
217: | $json['traitFilePath'], |
218: | $json['tip'], |
219: | $json['nodeLine'] ?? null, |
220: | $json['nodeType'] ?? null, |
221: | $json['identifier'] ?? null, |
222: | $json['metadata'] ?? [], |
223: | ); |
224: | } |
225: | |
226: | |
227: | |
228: | |
229: | public static function __set_state(array $properties): self |
230: | { |
231: | return new self( |
232: | $properties['message'], |
233: | $properties['file'], |
234: | $properties['line'], |
235: | $properties['canBeIgnored'], |
236: | $properties['filePath'], |
237: | $properties['traitFilePath'], |
238: | $properties['tip'], |
239: | $properties['nodeLine'] ?? null, |
240: | $properties['nodeType'] ?? null, |
241: | $properties['identifier'] ?? null, |
242: | $properties['metadata'] ?? [], |
243: | ); |
244: | } |
245: | |
246: | } |
247: | |