solidity_language_server/
lint.rs1use serde::{Deserialize, Serialize};
2use std::path::Path;
3use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
4
5pub fn lint_output_to_diagnostics(
6 forge_output: &serde_json::Value,
7 target_file: &str,
8) -> Vec<Diagnostic> {
9 let mut diagnostics = Vec::new();
10
11 if let serde_json::Value::Array(items) = forge_output {
12 for item in items {
13 if let Ok(forge_diag) = serde_json::from_value::<ForgeDiagnostic>(item.clone()) {
14 for span in &forge_diag.spans {
16 let target_path = Path::new(target_file)
17 .canonicalize()
18 .unwrap_or_else(|_| Path::new(target_file).to_path_buf());
19 let span_path = Path::new(&span.file_name)
20 .canonicalize()
21 .unwrap_or_else(|_| Path::new(&span.file_name).to_path_buf());
22 if target_path == span_path && span.is_primary {
23 let diagnostic = Diagnostic {
24 range: Range {
25 start: Position {
26 line: (span.line_start - 1), character: (span.column_start - 1), },
29 end: Position {
30 line: (span.line_end - 1),
31 character: (span.column_end - 1),
32 },
33 },
34 severity: Some(match forge_diag.level.as_str() {
35 "error" => DiagnosticSeverity::ERROR,
36 "warning" => DiagnosticSeverity::WARNING,
37 "note" => DiagnosticSeverity::INFORMATION,
38 "help" => DiagnosticSeverity::HINT,
39 _ => DiagnosticSeverity::INFORMATION,
40 }),
41 code: forge_diag.code.as_ref().map(|c| {
42 tower_lsp::lsp_types::NumberOrString::String(c.code.clone())
43 }),
44 code_description: None,
45 source: Some("forge-lint".to_string()),
46 message: format!("[forge lint] {}", forge_diag.message),
47 related_information: None,
48 tags: None,
49 data: None,
50 };
51 diagnostics.push(diagnostic);
52 break; }
54 }
55 }
56 }
57 }
58
59 diagnostics
60}
61
62#[derive(Debug, Deserialize, Serialize)]
63pub struct ForgeDiagnostic {
64 #[serde(rename = "$message_type")]
65 pub message_type: String,
66 pub message: String,
67 pub code: Option<ForgeLintCode>,
68 pub level: String,
69 pub spans: Vec<ForgeLintSpan>,
70 pub children: Vec<ForgeLintChild>,
71 pub rendered: Option<String>,
72}
73
74#[derive(Debug, Deserialize, Serialize)]
75pub struct ForgeLintCode {
76 pub code: String,
77 pub explanation: Option<String>,
78}
79
80#[derive(Debug, Deserialize, Serialize)]
81pub struct ForgeLintSpan {
82 pub file_name: String,
83 pub byte_start: u32,
84 pub byte_end: u32,
85 pub line_start: u32,
86 pub line_end: u32,
87 pub column_start: u32,
88 pub column_end: u32,
89 pub is_primary: bool,
90 pub text: Vec<ForgeLintText>,
91 pub label: Option<String>,
92}
93
94#[derive(Debug, Deserialize, Serialize)]
95pub struct ForgeLintText {
96 pub text: String,
97 pub highlight_start: u32,
98 pub highlight_end: u32,
99}
100
101#[derive(Debug, Deserialize, Serialize)]
102pub struct ForgeLintChild {
103 pub message: String,
104 pub code: Option<String>,
105 pub level: String,
106 pub spans: Vec<ForgeLintSpan>,
107 pub children: Vec<ForgeLintChild>,
108 pub rendered: Option<String>,
109}
110
111