Skip to content

Commit c574cf3

Browse files
bors[bot]Veykril
andauthored
Merge #11214
11214: feat: poke user when supplying faulty configurations r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 8887d20 + dd20a6f commit c574cf3

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

crates/rust-analyzer/src/bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ fn run_server() -> Result<()> {
150150

151151
let mut config = Config::new(root_path, initialize_params.capabilities);
152152
if let Some(json) = initialize_params.initialization_options {
153-
config.update(json);
153+
let _ = config.update(json);
154154
}
155155

156156
let server_capabilities = rust_analyzer::server_capabilities(&config);

crates/rust-analyzer/src/config.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ config_data! {
341341

342342
impl Default for ConfigData {
343343
fn default() -> Self {
344-
ConfigData::from_json(serde_json::Value::Null)
344+
ConfigData::from_json(serde_json::Value::Null, &mut Vec::new())
345345
}
346346
}
347347

@@ -492,16 +492,21 @@ impl Config {
492492
snippets: Default::default(),
493493
}
494494
}
495-
pub fn update(&mut self, mut json: serde_json::Value) {
495+
pub fn update(
496+
&mut self,
497+
mut json: serde_json::Value,
498+
) -> Result<(), Vec<(String, serde_json::Error)>> {
496499
tracing::info!("updating config from JSON: {:#}", json);
497500
if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
498-
return;
501+
return Ok(());
499502
}
500-
self.detached_files = get_field::<Vec<PathBuf>>(&mut json, "detachedFiles", None, "[]")
501-
.into_iter()
502-
.map(AbsPathBuf::assert)
503-
.collect();
504-
self.data = ConfigData::from_json(json);
503+
let mut errors = Vec::new();
504+
self.detached_files =
505+
get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
506+
.into_iter()
507+
.map(AbsPathBuf::assert)
508+
.collect();
509+
self.data = ConfigData::from_json(json, &mut errors);
505510
self.snippets.clear();
506511
for (name, def) in self.data.completion_snippets.iter() {
507512
if def.prefix.is_empty() && def.postfix.is_empty() {
@@ -524,6 +529,11 @@ impl Config {
524529
None => tracing::info!("Invalid snippet {}", name),
525530
}
526531
}
532+
if errors.is_empty() {
533+
Ok(())
534+
} else {
535+
Err(errors)
536+
}
527537
}
528538

529539
pub fn json_schema() -> serde_json::Value {
@@ -1116,10 +1126,11 @@ macro_rules! _config_data {
11161126
#[derive(Debug, Clone)]
11171127
struct $name { $($field: $ty,)* }
11181128
impl $name {
1119-
fn from_json(mut json: serde_json::Value) -> $name {
1129+
fn from_json(mut json: serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name {
11201130
$name {$(
11211131
$field: get_field(
11221132
&mut json,
1133+
error_sink,
11231134
stringify!($field),
11241135
None$(.or(Some(stringify!($alias))))*,
11251136
$default,
@@ -1156,6 +1167,7 @@ use _config_data as config_data;
11561167

11571168
fn get_field<T: DeserializeOwned>(
11581169
json: &mut serde_json::Value,
1170+
error_sink: &mut Vec<(String, serde_json::Error)>,
11591171
field: &'static str,
11601172
alias: Option<&'static str>,
11611173
default: &str,
@@ -1174,6 +1186,7 @@ fn get_field<T: DeserializeOwned>(
11741186
Ok(it) => Some(it),
11751187
Err(e) => {
11761188
tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
1189+
error_sink.push((pointer, e));
11771190
None
11781191
}
11791192
})

crates/rust-analyzer/src/main_loop.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::{
99
use always_assert::always;
1010
use crossbeam_channel::{select, Receiver};
1111
use ide_db::base_db::{SourceDatabaseExt, VfsPath};
12+
use itertools::Itertools;
1213
use lsp_server::{Connection, Notification, Request};
1314
use lsp_types::notification::Notification as _;
1415
use vfs::{ChangeKind, FileId};
@@ -731,7 +732,17 @@ impl GlobalState {
731732
// Note that json can be null according to the spec if the client can't
732733
// provide a configuration. This is handled in Config::update below.
733734
let mut config = Config::clone(&*this.config);
734-
config.update(json.take());
735+
if let Err(errors) = config.update(json.take()) {
736+
let errors = errors
737+
.iter()
738+
.format_with("\n", |(key, e),f| {
739+
f(key)?;
740+
f(&": ")?;
741+
f(e)
742+
});
743+
let msg= format!("Failed to deserialize config key(s):\n{}", errors);
744+
this.show_message(lsp_types::MessageType::WARNING, msg);
745+
}
735746
this.update_configuration(config);
736747
}
737748
}

crates/rust-analyzer/tests/slow-tests/support.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl<'a> Project<'a> {
137137
},
138138
);
139139
config.discovered_projects = Some(discovered_projects);
140-
config.update(self.config);
140+
let _ = config.update(self.config);
141141

142142
Server::new(tmp_dir, config)
143143
}

0 commit comments

Comments
 (0)