Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lfx pre test lsp quick fix #1038

Merged
merged 15 commits into from
Feb 19, 2024
1 change: 1 addition & 0 deletions kclvm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kclvm/error/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ atty = "0.2"
annotate-snippets = { version = "0.9.2", default-features = false, features = ["color"] }
termize = "0.1.1"
indexmap = "1.0"
serde_json = "1.0.86"
25 changes: 21 additions & 4 deletions kclvm/error/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,23 @@ use std::hash::Hash;
use crate::{ErrorKind, WarningKind};

/// Diagnostic structure.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Diagnostic {
pub level: Level,
pub messages: Vec<Message>,
pub code: Option<DiagnosticId>,
pub data: Option<serde_json::Value>,
Peefy marked this conversation as resolved.
Show resolved Hide resolved
}

impl Hash for Diagnostic {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.level.hash(state);
for message in &self.messages {
message.hash(state);
}
self.code.hash(state);
// The `data` field is not included in the hash calculation due to complexity.
}
}

/// Position describes an arbitrary source position including the filename,
Expand Down Expand Up @@ -106,18 +118,23 @@ impl Diagnostic {
note: Option<&str>,
range: Range,
code: Option<DiagnosticId>,
suggested_replacement: Option<String>,
suggestions: Option<Vec<String>>,
Peefy marked this conversation as resolved.
Show resolved Hide resolved
) -> Self {
let data = suggestions.clone().map(|suggs| {
serde_json::json!({ "suggested_replacements": suggs })
});
// println!("Data received: {:?}", data);
Diagnostic {
level,
messages: vec![Message {
range,
style: Style::LineAndColumn,
message: message.to_string(),
note: note.map(|s| s.to_string()),
suggested_replacement,
note: note.map(String::from),
suggested_replacement: None, // Assuming your Message struct has such a field
}],
code,
data, // Now includes suggestions if provided
}
}

Expand Down
23 changes: 20 additions & 3 deletions kclvm/error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,31 @@ impl Handler {
}

/// Construct a type error and put it into the handler diagnostic buffer
pub fn add_compile_error(&mut self, msg: &str, range: Range) -> &mut Self {
pub fn add_compile_error(
&mut self,
msg: &str,
range: Range
) -> &mut Self {
self.add_compile_error_with_suggestions(msg, range, None)
}

pub fn add_compile_error_with_suggestions(
&mut self,
msg: &str,
range: Range,
suggestions: Option<Vec<String>>,
) -> &mut Self {
let diag = Diagnostic::new_with_code(
Level::Error,
msg,
None,
range,
Some(DiagnosticId::Error(E2L23.kind)),
None,
suggestions,
);
// println!("{:?}",suggestions.clone());
shashank-iitbhu marked this conversation as resolved.
Show resolved Hide resolved
self.add_diagnostic(diag);

self
}

Expand Down Expand Up @@ -165,6 +179,7 @@ impl Handler {
level: Level::Error,
messages: msgs.to_owned(),
code: Some(DiagnosticId::Error(err)),
data: None,
};
self.add_diagnostic(diag);

Expand All @@ -183,6 +198,7 @@ impl Handler {
suggested_replacement: None,
}],
code: Some(DiagnosticId::Suggestions),
data: None,
});
});

Expand All @@ -208,6 +224,7 @@ impl Handler {
level: Level::Warning,
messages: msgs.to_owned(),
code: Some(DiagnosticId::Warning(warning)),
data: None,
};
self.add_diagnostic(diag);

Expand Down
3 changes: 2 additions & 1 deletion kclvm/sema/src/resolver/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,13 +432,14 @@ impl<'ctx> Resolver<'ctx> {
if suggs.len() > 0 {
suggestion = format!(", did you mean '{:?}'?", suggs);
}
self.handler.add_compile_error(
self.handler.add_compile_error_with_suggestions(
&format!(
"name '{}' is not defined{}",
name.replace('@', ""),
suggestion
),
range,
Some(suggs.clone()),
);
self.any_ty()
}
Expand Down
48 changes: 45 additions & 3 deletions kclvm/tools/src/LSP/src/quick_fix.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
use std::collections::HashMap;

use kclvm_error::{DiagnosticId, WarningKind};
use kclvm_error::{DiagnosticId, WarningKind, ErrorKind};
use lsp_types::{
CodeAction, CodeActionKind, CodeActionOrCommand, Diagnostic, NumberOrString, TextEdit, Url,
CodeAction, CodeActionKind, CodeActionOrCommand, Diagnostic, NumberOrString, TextEdit, Url
};
use serde_json::Value;

pub(crate) fn quick_fix(uri: &Url, diags: &Vec<Diagnostic>) -> Vec<lsp_types::CodeActionOrCommand> {
let mut code_actions: Vec<lsp_types::CodeActionOrCommand> = vec![];
for diag in diags {
if let Some(code) = &diag.code {
if let Some(id) = conver_code_to_kcl_diag_id(code) {
match id {
DiagnosticId::Error(_) => continue,
DiagnosticId::Error(error) => match error {
ErrorKind::CompileError => {
let replacement_text = extract_suggested_replacements(&diag.data).unwrap_or_else(|| "".to_string());
let mut changes = HashMap::new();
changes.insert(
uri.clone(),
vec![TextEdit {
range: diag.range,
new_text: replacement_text,
}],
);
code_actions.push(CodeActionOrCommand::CodeAction(CodeAction {
title: ErrorKind::CompileError.name(),
Peefy marked this conversation as resolved.
Show resolved Hide resolved
kind: Some(CodeActionKind::QUICKFIX),
diagnostics: Some(vec![diag.clone()]),
edit: Some(lsp_types::WorkspaceEdit {
changes: Some(changes),
..Default::default()
}),
..Default::default()
}))
}
_ => continue,
},
DiagnosticId::Warning(warn) => match warn {
WarningKind::UnusedImportWarning => {
let mut changes = HashMap::new();
Expand Down Expand Up @@ -63,13 +87,31 @@ pub(crate) fn quick_fix(uri: &Url, diags: &Vec<Diagnostic>) -> Vec<lsp_types::Co
code_actions
}

fn extract_suggested_replacements(data: &Option<Value>) -> Option<String> {
data.as_ref().and_then(|data| {
match data {
Value::Object(obj) => {
obj.get("suggested_replacements").and_then(|val| {
match val {
Value::String(s) => Some(s.clone()),
Value::Array(arr) if !arr.is_empty() => arr.iter().filter_map(|v| v.as_str()).next().map(String::from),
_ => None,
}
})
},
_ => None,
}
})
}

pub(crate) fn conver_code_to_kcl_diag_id(code: &NumberOrString) -> Option<DiagnosticId> {
match code {
NumberOrString::Number(_) => None,
NumberOrString::String(code) => match code.as_str() {
"CompilerWarning" => Some(DiagnosticId::Warning(WarningKind::CompilerWarning)),
"UnusedImportWarning" => Some(DiagnosticId::Warning(WarningKind::UnusedImportWarning)),
"ReimportWarning" => Some(DiagnosticId::Warning(WarningKind::ReimportWarning)),
"CompileError" => Some(DiagnosticId::Error(ErrorKind::CompileError)),
"ImportPositionWarning" => {
Some(DiagnosticId::Warning(WarningKind::ImportPositionWarning))
}
Expand Down
14 changes: 12 additions & 2 deletions kclvm/tools/src/LSP/src/to_lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,22 @@ pub fn kcl_diag_to_lsp_diags(diag: &KCLDiagnostic, file_name: &str) -> Vec<Diagn
} else {
None
};
diags.push(kcl_msg_to_lsp_diags(

let data = diag.data.clone();

let lsp_diag = kcl_msg_to_lsp_diags(
msg,
kcl_err_level_to_severity(diag.level),
related_msg,
code,
))
);

let lsp_diag_with_data = Diagnostic {
data,
..lsp_diag
};

diags.push(lsp_diag_with_data);
}
}
diags
Expand Down
Loading