Skip to content

Commit

Permalink
feat: diagnostic related info (#646)
Browse files Browse the repository at this point in the history
feat: diagnostic related info. Add diagnostic related information to display multiple position diagnostic
  • Loading branch information
He1pa authored Aug 8, 2023
1 parent fed70fb commit 327cb1e
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 11 deletions.
5 changes: 4 additions & 1 deletion kclvm/tools/src/LSP/src/test_data/diagnostics.k
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ a =
b: str = 1
c: Person = Person {
age: 1
}
}

d = 1
d = 2
57 changes: 55 additions & 2 deletions kclvm/tools/src/LSP/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ use kclvm_sema::resolver::scope::ProgramScope;
use lsp_types::request::GotoTypeDefinitionResponse;
use lsp_types::CompletionResponse;
use lsp_types::Diagnostic;
use lsp_types::DiagnosticRelatedInformation;
use lsp_types::DiagnosticSeverity;
use lsp_types::DocumentSymbol;
use lsp_types::DocumentSymbolResponse;
use lsp_types::Location;
use lsp_types::MarkedString;
use lsp_types::SymbolKind;
use lsp_types::Url;
Expand Down Expand Up @@ -80,7 +82,33 @@ fn diagnostics_test() {
pos: (u32, u32, u32, u32),
message: String,
severity: Option<DiagnosticSeverity>,
related_info: Vec<(String, (u32, u32, u32, u32), String)>,
) -> Diagnostic {
let related_information = if related_info.is_empty() {
None
} else {
Some(
related_info
.iter()
.map(|(file, pos, msg)| DiagnosticRelatedInformation {
location: Location {
uri: Url::from_file_path(file).unwrap(),
range: Range {
start: Position {
line: pos.0,
character: pos.1,
},
end: Position {
line: pos.2,
character: pos.3,
},
},
},
message: msg.clone(),
})
.collect(),
)
};
Diagnostic {
range: lsp_types::Range {
start: Position {
Expand All @@ -97,7 +125,7 @@ fn diagnostics_test() {
code_description: None,
source: None,
message,
related_information: None,
related_information,
tags: None,
data: None,
}
Expand Down Expand Up @@ -127,11 +155,13 @@ fn diagnostics_test() {
"expected one of [\"identifier\", \"literal\", \"(\", \"[\", \"{\"] got newline"
.to_string(),
Some(DiagnosticSeverity::ERROR),
vec![],
),
build_lsp_diag(
(0, 0, 0, 10),
"pkgpath abc not found in the program".to_string(),
Some(DiagnosticSeverity::ERROR),
vec![],
),
build_lsp_diag(
(0, 0, 0, 10),
Expand All @@ -140,20 +170,43 @@ fn diagnostics_test() {
path.to_str().unwrap()
),
Some(DiagnosticSeverity::ERROR),
vec![],
),
build_lsp_diag(
(8, 0, 8, 1),
"Can not change the value of 'd', because it was declared immutable".to_string(),
Some(DiagnosticSeverity::ERROR),
vec![(
file.to_string(),
(7, 0, 7, 1),
"The variable 'd' is declared here".to_string(),
)],
),
build_lsp_diag(
(7, 0, 7, 1),
"The variable 'd' is declared here".to_string(),
Some(DiagnosticSeverity::ERROR),
vec![(
file.to_string(),
(8, 0, 8, 1),
"Can not change the value of 'd', because it was declared immutable".to_string(),
)],
),
build_lsp_diag(
(2, 0, 2, 1),
"expected str, got int(1)".to_string(),
Some(DiagnosticSeverity::ERROR),
vec![],
),
build_lsp_diag(
(0, 0, 0, 10),
"Module 'abc' imported but unused".to_string(),
Some(DiagnosticSeverity::WARNING),
vec![],
),
];
for (get, expected) in diagnostics.iter().zip(expected_diags.iter()) {
assert_eq!(get, expected);
assert_eq!(get, expected)
}
}

Expand Down
47 changes: 39 additions & 8 deletions kclvm/tools/src/LSP/src/to_lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,43 @@ pub fn lsp_pos(pos: &KCLPos) -> Position {
}

/// Convert KCL Message to LSP Diagnostic
fn kcl_msg_to_lsp_diags(msg: &Message, severity: DiagnosticSeverity) -> Diagnostic {
fn kcl_msg_to_lsp_diags(
msg: &Message,
severity: DiagnosticSeverity,
related_msg: Vec<Message>,
) -> Diagnostic {
let range = msg.range.clone();
let start_position = lsp_pos(&range.0);
let end_position = lsp_pos(&range.1);

let related_information = if related_msg.is_empty() {
None
} else {
Some(
related_msg
.iter()
.map(|m| DiagnosticRelatedInformation {
location: Location {
uri: Url::from_file_path(m.range.0.filename.clone()).unwrap(),
range: Range {
start: lsp_pos(&m.range.0),
end: lsp_pos(&m.range.1),
},
},
message: m.message.clone(),
})
.collect(),
)
};

Diagnostic {
range: Range::new(start_position, end_position),
severity: Some(severity),
code: None,
code_description: None,
source: None,
message: msg.message.clone(),
related_information: None,
related_information,
tags: None,
data: None,
}
Expand All @@ -48,13 +72,20 @@ fn kcl_err_level_to_severity(level: Level) -> DiagnosticSeverity {
}

/// Convert KCL Diagnostic to LSP Diagnostics.
/// Because the diagnostic of KCL contains multiple messages, and each messages corresponds to a diagnostic of LSP, the return value is a vec
pub fn kcl_diag_to_lsp_diags(diag: &KCLDiagnostic, file_name: &str) -> Vec<Diagnostic> {
diag.messages
.iter()
.filter(|msg| msg.range.0.filename == file_name)
.map(|msg| kcl_msg_to_lsp_diags(msg, kcl_err_level_to_severity(diag.level)))
.collect()
let mut diags = vec![];
for (idx, msg) in diag.messages.iter().enumerate() {
if msg.range.0.filename == file_name {
let mut related_msg = diag.messages.clone();
related_msg.remove(idx);
diags.push(kcl_msg_to_lsp_diags(
msg,
kcl_err_level_to_severity(diag.level),
related_msg,
))
}
}
diags
}

/// Returns the `Url` associated with the specified `FileId`.
Expand Down

0 comments on commit 327cb1e

Please sign in to comment.