Parse a single PHPStan message object into an LSP `Diagnostic`.
(msg: &serde_json::Value)
| 307 | |
| 308 | /// Parse a single PHPStan message object into an LSP `Diagnostic`. |
| 309 | fn parse_phpstan_message(msg: &serde_json::Value) -> Option<Diagnostic> { |
| 310 | let message = msg.get("message")?.as_str()?; |
| 311 | // PHPStan lines are 1-based; LSP lines are 0-based. |
| 312 | let line = msg.get("line").and_then(|l| l.as_u64()).unwrap_or(1); |
| 313 | let lsp_line = line.saturating_sub(1) as u32; |
| 314 | |
| 315 | // PHPStan may include an identifier (e.g. "argument.type", |
| 316 | // "return.type", "method.notFound") since PHPStan 1.11. |
| 317 | let identifier = msg |
| 318 | .get("identifier") |
| 319 | .and_then(|i| i.as_str()) |
| 320 | .unwrap_or("phpstan"); |
| 321 | |
| 322 | let tip = msg.get("tip").and_then(|t| t.as_str()); |
| 323 | |
| 324 | let full_message = if let Some(tip_text) = tip { |
| 325 | // Strip HTML tags that PHPStan sometimes includes in tips |
| 326 | // (e.g. <fg=cyan>...</>). |
| 327 | let clean_tip = strip_ansi_tags(tip_text); |
| 328 | format!("{}\n{}", message, clean_tip) |
| 329 | } else { |
| 330 | message.to_string() |
| 331 | }; |
| 332 | |
| 333 | // PHPStan includes `"ignorable": false` for errors that cannot be |
| 334 | // suppressed with `@phpstan-ignore` (e.g. visibility overrides). |
| 335 | // Store this in `Diagnostic.data` so code actions can check it. |
| 336 | // Default to `true` when the field is absent (older PHPStan versions). |
| 337 | let ignorable = msg |
| 338 | .get("ignorable") |
| 339 | .and_then(|v| v.as_bool()) |
| 340 | .unwrap_or(true); |
| 341 | |
| 342 | let data = Some(serde_json::json!({ "ignorable": ignorable })); |
| 343 | |
| 344 | Some(Diagnostic { |
| 345 | range: Range { |
| 346 | start: Position { |
| 347 | line: lsp_line, |
| 348 | character: 0, |
| 349 | }, |
| 350 | end: Position { |
| 351 | line: lsp_line, |
| 352 | character: u32::MAX, |
| 353 | }, |
| 354 | }, |
| 355 | severity: Some(DiagnosticSeverity::ERROR), |
| 356 | code: Some(NumberOrString::String(identifier.to_string())), |
| 357 | code_description: None, |
| 358 | source: Some("phpstan".to_string()), |
| 359 | message: full_message, |
| 360 | related_information: None, |
| 361 | tags: None, |
| 362 | data, |
| 363 | }) |
| 364 | } |
| 365 | |
| 366 | /// Check whether two file paths refer to the same file. |
no test coverage detected