Repository: rust-lang/rust-analyzer
Pull request #16748 (2024-03-04 10:46:16)

internal: Compute syntax validation errors on demand
The LRU cache causes us to re-parse trees quite often, yet we don't use the validation errors at all. With this we push calculating them off to the caller who is interested in them.

Veykril: @bors r+
bors: :pushpin: Commit 11aba298ad11105953fdf1aa1971d0501e1a8974 has been approved by `Veykril`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust-analyzer) for this repository.

<!-- @bors r=Veykril 11aba298ad11105953fdf1aa1971d0501e1a8974 -->
<!-- homu: {"type":"Approved","sha":"11aba298ad11105953fdf1aa1971d0501e1a8974","approver":"Veykril","queue":"https://bors.rust-lang.org/homu/queue/rust-analyzer"} -->
bors: :hourglass: Testing commit 11aba298ad11105953fdf1aa1971d0501e1a8974 with merge a6ef2f0cff798d19c905fdab59ecf56be7ef2a28...
<!-- homu: {"type":"BuildStarted","head_sha":"11aba298ad11105953fdf1aa1971d0501e1a8974","merge_sha":"a6ef2f0cff798d19c905fdab59ecf56be7ef2a28"} -->

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 607b831f01..f074bb4e30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1462,12 +1462,12 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.40.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "371db64f1be25aae96650b5528c76066ac325f0fe23efec0aab1179d75eea5c3"
+checksum = "df5a0ba0d08af366cf235dbe8eb7226cced7a4fe502c98aa434ccf416defd746"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros 0.40.0",
+ "ra-ap-rustc_index_macros 0.37.0",
  "smallvec",
 ]
 
@@ -1485,9 +1485,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.40.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4a454193807f557a991f52157250fd2db95abfb96da65e85355e6949802a98"
+checksum = "1971ebf9a701e0e68387c264a32517dcb4861ad3a4862f2e2803c1121ade20d5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1517,11 +1517,11 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.40.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9cb49490fadb58e6b8cc825f73157a33730495bfd5c6e9eef067a4b50ad1836"
+checksum = "2c3c0e7ca9c5bdc66e3b590688e237a22ac47a48e4eac7f46b05b2abbfaf0abd"
 dependencies = [
- "ra-ap-rustc_index 0.40.0",
+ "ra-ap-rustc_index 0.37.0",
  "rustc-hash",
  "rustc_apfloat",
  "smallvec",
diff --git a/Cargo.toml b/Cargo.toml
index e68613c6d3..16dd510389 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -88,7 +88,7 @@ ra-ap-rustc_lexer = { version = "0.35.0", default-features = false }
 ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false }
 ra-ap-rustc_index = { version = "0.35.0", default-features = false }
 ra-ap-rustc_abi = { version = "0.35.0", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.40.0", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.37.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 sourcegen = { path = "./crates/sourcegen" }
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index f506864902..d4c1db8b95 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -788,11 +788,12 @@ impl<'a> AssocItemCollector<'a> {
             };
             self.diagnostics.push(diag);
         }
-        if let errors @ [_, ..] = parse.errors() {
+        let errors = parse.errors();
+        if !errors.is_empty() {
             self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
                 self.module_id.local_id,
                 error_call_kind(),
-                errors,
+                errors.into_boxed_slice(),
             ));
         }
 
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 18aefbf332..f9fe6d3b90 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -1384,7 +1384,9 @@ impl DefCollector<'_> {
         // First, fetch the raw expansion result for purposes of error reporting. This goes through
         // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
         // incrementality).
-        let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
+        // FIXME: This kind of error fetching feels a bit odd?
+        let ExpandResult { value: errors, err } =
+            self.db.parse_macro_expansion_error(macro_call_id);
         if let Some(err) = err {
             let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
             let diag = match err {
@@ -1398,7 +1400,7 @@ impl DefCollector<'_> {
 
             self.def_map.diagnostics.push(diag);
         }
-        if let errors @ [_, ..] = &*value {
+        if !errors.is_empty() {
             let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
             let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
             self.def_map.diagnostics.push(diag);
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index b5a302dbca..8c7fdaaf58 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -117,14 +117,11 @@ impl DefDiagnostic {
     pub(crate) fn macro_expansion_parse_error(
         container: LocalModuleId,
         ast: MacroCallKind,
-        errors: &[SyntaxError],
+        errors: Box<[SyntaxError]>,
     ) -> Self {
         Self {
             in_module: container,
-            kind: DefDiagnosticKind::MacroExpansionParseError {
-                ast,
-                errors: errors.to_vec().into_boxed_slice(),
-            },
+            kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
         }
     }
 
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index f1f0d8990f..3a65bc7c6e 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -303,7 +303,7 @@ fn parse_macro_expansion_error(
     macro_call_id: MacroCallId,
 ) -> ExpandResult<Box<[SyntaxError]>> {
     db.parse_macro_expansion(MacroFileId { macro_call_id })
-        .map(|it| it.0.errors().to_vec().into_boxed_slice())
+        .map(|it| it.0.errors().into_boxed_slice())
 }
 
 pub(crate) fn parse_with_map(
@@ -445,7 +445,7 @@ fn macro_arg(
 
         if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
             match parse.errors() {
-                [] => ValueResult::ok((Arc::new(tt), undo_info)),
+                errors if errors.is_empty() => ValueResult::ok((Arc::new(tt), undo_info)),
                 errors => ValueResult::new(
                     (Arc::new(tt), undo_info),
                     // Box::<[_]>::from(res.errors()), not stable yet
diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs
index 66ceb1b7d4..a500c24ce8 100644
--- a/crates/hir-expand/src/files.rs
+++ b/crates/hir-expand/src/files.rs
@@ -252,7 +252,7 @@ impl InFile<&SyntaxNode> {
             map_node_range_up(db, &db.expansion_span_map(file_id), self.value.text_range())?;
 
         // FIXME: Figure out an API that makes proper use of ctx, this only exists to
-        // keep pre-token map rewrite behaviour.
+        // keep pre-token map rewrite behavior.
         if !ctx.is_root() {
             return None;
         }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index ca8bd65510..cfda8d4f93 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -38,11 +38,10 @@ use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
-    ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
-    Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef,
-    Static, Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union,
-    Variant, VariantDef,
+    Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
+    DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
+    Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Struct, ToolModule, Trait,
+    TupleField, Type, TypeAlias, TypeParam, VariantDef,
 };
 
 pub enum DescendPreference {
@@ -224,68 +223,20 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_variant(record_lit).map(VariantDef::from)
     }
 
-    pub fn file_to_module_def(&self, file: FileId) -> Option<Module> {
-        self.imp.file_to_module_defs(file).next()
+    pub fn to_module_def(&self, file: FileId) -> Option<Module> {
+        self.imp.to_module_def(file).next()
     }
 
-    pub fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
-        self.imp.file_to_module_defs(file)
-    }
-
-    pub fn to_adt_def(&self, a: &ast::Adt) -> Option<Adt> {
-        self.imp.to_def(a).map(Adt::from)
-    }
-
-    pub fn to_const_def(&self, c: &ast::Const) -> Option<Const> {
-        self.imp.to_def(c).map(Const::from)
-    }
-
-    pub fn to_enum_def(&self, e: &ast::Enum) -> Option<Enum> {
-        self.imp.to_def(e).map(Enum::from)
-    }
-
-    pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<Variant> {
-        self.imp.to_def(v).map(Variant::from)
-    }
-
-    pub fn to_fn_def(&self, f: &ast::Fn) -> Option<Function> {
-        self.imp.to_def(f).map(Function::from)
-    }
-
-    pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
-        self.imp.to_def(i).map(Impl::from)
-    }
-
-    pub fn to_macro_def(&self, m: &ast::Macro) -> Option<Macro> {
-        self.imp.to_def(m).map(Macro::from)
-    }
-
-    pub fn to_module_def(&self, m: &ast::Module) -> Option<Module> {
-        self.imp.to_def(m).map(Module::from)
-    }
-
-    pub fn to_static_def(&self, s: &ast::Static) -> Option<Static> {
-        self.imp.to_def(s).map(Static::from)
+    pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
+        self.imp.to_module_def(file)
     }
 
     pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> {
         self.imp.to_def(s).map(Struct::from)
     }
 
-    pub fn to_trait_alias_def(&self, t: &ast::TraitAlias) -> Option<TraitAlias> {
-        self.imp.to_def(t).map(TraitAlias::from)
-    }
-
-    pub fn to_trait_def(&self, t: &ast::Trait) -> Option<Trait> {
-        self.imp.to_def(t).map(Trait::from)
-    }
-
-    pub fn to_type_alias_def(&self, t: &ast::TypeAlias) -> Option<TypeAlias> {
-        self.imp.to_def(t).map(TypeAlias::from)
-    }
-
-    pub fn to_union_def(&self, u: &ast::Union) -> Option<Union> {
-        self.imp.to_def(u).map(Union::from)
+    pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
+        self.imp.to_def(i).map(Impl::from)
     }
 }
 
@@ -1290,7 +1241,7 @@ impl<'db> SemanticsImpl<'db> {
         T::to_def(self, src)
     }
 
-    fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
+    fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
         self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
     }
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 4733ea5a35..ef4ed90ce3 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -118,7 +118,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
 
 impl SourceToDefCtx<'_, '_> {
     pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
-        let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def");
+        let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::to_module_def");
         let mut mods = SmallVec::new();
         for &crate_id in self.db.relevant_crates(file).iter() {
             // FIXME: inner items
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index e0bcd78c99..7a60287f92 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -116,7 +116,7 @@ impl Field {
     ) -> Option<Field> {
         let db = ctx.sema.db;
 
-        let module = ctx.sema.file_to_module_def(ctx.file_id())?;
+        let module = ctx.sema.to_module_def(ctx.file_id())?;
 
         let (name, range, ty) = match f {
             Either::Left(f) => {
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 50ec4347dc..2b9ed86e41 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -418,15 +418,24 @@ fn inline(
         let expr: &ast::Expr = expr;
 
         let mut insert_let_stmt = || {
-            let param_ty = param_ty.clone().map(|param_ty| {
-                if sema.hir_file_for(param_ty.syntax()).is_macro() {
-                    ast::Type::cast(insert_ws_into(param_ty.syntax().clone())).unwrap_or(param_ty)
-                } else {
-                    param_ty
+            let param_ty = match param_ty {
+                None => None,
+                Some(param_ty) => {
+                    if sema.hir_file_for(param_ty.syntax()).is_macro() {
+                        if let Some(param_ty) =
+                            ast::Type::cast(insert_ws_into(param_ty.syntax().clone()))
+                        {
+                            Some(param_ty)
+                        } else {
+                            Some(param_ty.clone_for_update())
+                        }
+                    } else {
+                        Some(param_ty.clone_for_update())
+                    }
                 }
-            });
-
-            let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);
+            };
+            let ty: Option<syntax::ast::Type> =
+                sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);
 
             let is_self = param
                 .name(sema.db)
@@ -1350,8 +1359,8 @@ macro_rules! define_foo {
 define_foo!();
 fn bar() -> u32 {
     {
-        let x = 0;
-        x
+      let x = 0;
+      x
     }
 }
 "#,
@@ -1664,7 +1673,7 @@ fn main() {
     let a: A = A{};
     let b = {
         let a = a;
-        a as A
+      a as A
     };
 }
 "#,
@@ -1783,7 +1792,7 @@ fn _hash2(self_: &u64, state: &mut u64) {
     {
         let inner_self_: &u64 = &self_;
         let state: &mut u64 = state;
-        _write_u64(state, *inner_self_)
+      _write_u64(state, *inner_self_)
     };
 }
 "#,
diff --git a/crates/ide-assists/src/handlers/inline_macro.rs b/crates/ide-assists/src/handlers/inline_macro.rs
index 4708be6169..0c9e971dd2 100644
--- a/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/crates/ide-assists/src/handlers/inline_macro.rs
@@ -288,11 +288,11 @@ macro_rules! foo {
 }
 fn main() {
     cfg_if!{
-    if #[cfg(test)]{
-        1;
-    }else {
-        1;
-    }
+  if #[cfg(test)]{
+    1;
+  }else {
+    1;
+  }
 };
 }
 "#,
diff --git a/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index a256f60c42..917d0b3671 100644
--- a/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -25,7 +25,7 @@ use crate::{
 // ```
 pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
-    let module = ctx.sema.file_to_module_def(ctx.file_id())?;
+    let module = ctx.sema.to_module_def(ctx.file_id())?;
     // Enable this assist if the user select all "meaningful" content in the source file
     let trimmed_selected_range = trimmed_text_range(&source_file, ctx.selection_trimmed());
     let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
diff --git a/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index a8a124eebb..b73270cd05 100644
--- a/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -25,7 +25,7 @@ use crate::{
 // ```
 pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
-    let module = ctx.sema.file_to_module_def(ctx.file_id())?;
+    let module = ctx.sema.to_module_def(ctx.file_id())?;
     // Enable this assist if the user select all "meaningful" content in the source file
     let trimmed_selected_range = trimmed_text_range(&source_file, ctx.selection_trimmed());
     let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
diff --git a/crates/ide-completion/src/completions/format_string.rs b/crates/ide-completion/src/completions/format_string.rs
index 5512ac2153..cecbe75391 100644
--- a/crates/ide-completion/src/completions/format_string.rs
+++ b/crates/ide-completion/src/completions/format_string.rs
@@ -1,7 +1,6 @@
 //! Completes identifiers in format string literals.
 
-use hir::{ModuleDef, ScopeDef};
-use ide_db::{syntax_helpers::format_string::is_format_string, SymbolKind};
+use ide_db::syntax_helpers::format_string::is_format_string;
 use itertools::Itertools;
 use syntax::{ast, AstToken, TextRange, TextSize};
 
@@ -34,23 +33,7 @@ pub(crate) fn format_string(
     ctx.locals.iter().for_each(|(name, _)| {
         CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str())
             .add_to(acc, ctx.db);
-    });
-    ctx.scope.process_all_names(&mut |name, scope| {
-        if let ScopeDef::ModuleDef(module_def) = scope {
-            let symbol_kind = match module_def {
-                ModuleDef::Const(..) => SymbolKind::Const,
-                ModuleDef::Static(..) => SymbolKind::Static,
-                _ => return,
-            };
-
-            CompletionItem::new(
-                CompletionItemKind::SymbolKind(symbol_kind),
-                source_range,
-                name.to_smol_str(),
-            )
-            .add_to(acc, ctx.db);
-        }
-    });
+    })
 }
 
 #[cfg(test)]
@@ -127,80 +110,6 @@ fn main() {
     let foobar = 1;
     format_args!("{foobar");
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn completes_constants() {
-        check_edit(
-            "FOOBAR",
-            r#"
-//- minicore: fmt
-fn main() {
-    const FOOBAR: usize = 42;
-    format_args!("{f$0");
-}
-"#,
-            r#"
-fn main() {
-    const FOOBAR: usize = 42;
-    format_args!("{FOOBAR");
-}
-"#,
-        );
-
-        check_edit(
-            "FOOBAR",
-            r#"
-//- minicore: fmt
-fn main() {
-    const FOOBAR: usize = 42;
-    format_args!("{$0");
-}
-"#,
-            r#"
-fn main() {
-    const FOOBAR: usize = 42;
-    format_args!("{FOOBAR");
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn completes_static_constants() {
-        check_edit(
-            "FOOBAR",
-            r#"
-//- minicore: fmt
-fn main() {
-    static FOOBAR: usize = 42;
-    format_args!("{f$0");
-}
-"#,
-            r#"
-fn main() {
-    static FOOBAR: usize = 42;
-    format_args!("{FOOBAR");
-}
-"#,
-        );
-
-        check_edit(
-            "FOOBAR",
-            r#"
-//- minicore: fmt
-fn main() {
-    static FOOBAR: usize = 42;
-    format_args!("{$0");
-}
-"#,
-            r#"
-fn main() {
-    static FOOBAR: usize = 42;
-    format_args!("{FOOBAR");
-}
 "#,
         );
     }
diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs
index 4ac8a7c4c4..0b5ad7060e 100644
--- a/crates/ide-db/src/helpers.rs
+++ b/crates/ide-db/src/helpers.rs
@@ -64,7 +64,7 @@ pub fn visit_file_defs(
     cb: &mut dyn FnMut(Definition),
 ) {
     let db = sema.db;
-    let module = match sema.file_to_module_def(file_id) {
+    let module = match sema.to_module_def(file_id) {
         Some(it) => it,
         None => return,
     };
diff --git a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
index 97b6d4a572..0b0fc66935 100644
--- a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
+++ b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
@@ -20,7 +20,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
     let after = Position::after;
 
     let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| {
-        (pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent)))
+        (pos(token.clone()), make::tokens::whitespace(&" ".repeat(2 * indent)))
     };
     let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| {
         (pos(token.clone()), make::tokens::single_space())
@@ -41,7 +41,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
                 if indent > 0 {
                     mods.push((
                         Position::after(node.clone()),
-                        make::tokens::whitespace(&" ".repeat(4 * indent)),
+                        make::tokens::whitespace(&" ".repeat(2 * indent)),
                     ));
                 }
                 if node.parent().is_some() {
@@ -91,7 +91,10 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
             LIFETIME_IDENT if is_next(is_text, true) => {
                 mods.push(do_ws(after, tok));
             }
-            AS_KW | DYN_KW | IMPL_KW | CONST_KW | MUT_KW => {
+            MUT_KW if is_next(|it| it == SELF_KW, false) => {
+                mods.push(do_ws(after, tok));
+            }
+            AS_KW | DYN_KW | IMPL_KW | CONST_KW => {
                 mods.push(do_ws(after, tok));
             }
             T![;] if is_next(|it| it != R_CURLY, true) => {
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index f92ba576d3..09daefd084 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -200,7 +200,7 @@ fn get_default_constructor(
         }
     }
 
-    let krate = ctx.sema.file_to_module_def(d.file.original_file(ctx.sema.db))?.krate();
+    let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate();
     let module = krate.root_module();
 
     // Look for a ::new() associated function
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 6c72dbb5ed..486bf6f95c 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -299,7 +299,7 @@ pub fn diagnostics(
     let mut res = Vec::new();
 
     // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
-    res.extend(parse.errors().iter().take(128).map(|err| {
+    res.extend(parse.errors().into_iter().take(128).map(|err| {
         Diagnostic::new(
             DiagnosticCode::RustcHardError("syntax-error"),
             format!("Syntax Error: {err}"),
@@ -315,7 +315,7 @@ pub fn diagnostics(
         handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config);
     }
 
-    let module = sema.file_to_module_def(file_id);
+    let module = sema.to_module_def(file_id);
 
     let ctx = DiagnosticsContext { config, sema, resolve };
     if module.is_none() {
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 9eb5a9db62..17c701ad03 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -308,8 +308,8 @@ f$0oo!();
             expect![[r#"
                 foo!
                 fn some_thing() -> u32 {
-                    let a = 0;
-                    a+10
+                  let a = 0;
+                  a+10
                 }"#]],
         );
     }
@@ -342,13 +342,13 @@ fn main() {
             expect![[r#"
                 match_ast!
                 {
-                    if let Some(it) = ast::TraitDef::cast(container.clone()){}
-                    else if let Some(it) = ast::ImplDef::cast(container.clone()){}
-                    else {
-                        {
-                            continue
-                        }
+                  if let Some(it) = ast::TraitDef::cast(container.clone()){}
+                  else if let Some(it) = ast::ImplDef::cast(container.clone()){}
+                  else {
+                    {
+                      continue
                     }
+                  }
                 }"#]],
         );
     }
@@ -397,12 +397,12 @@ fn main() {
             expect![[r#"
                 foo!
                 {
-                    macro_rules! bar {
-                        () => {
-                            42
-                        }
+                  macro_rules! bar {
+                    () => {
+                      42
                     }
-                    42
+                  }
+                  42
                 }"#]],
         );
     }
@@ -482,16 +482,16 @@ struct Foo {}
             expect![[r#"
                 Clone
                 impl < >$crate::clone::Clone for Foo< >where {
-                    fn clone(&self) -> Self {
-                        match self {
-                            Foo{}
-                             => Foo{}
-                            ,
+                  fn clone(&self) -> Self {
+                    match self {
+                      Foo{}
+                       => Foo{}
+                      ,
 
-                            }
-                    }
+                      }
+                  }
 
-                    }"#]],
+                  }"#]],
         );
     }
 
@@ -534,16 +534,16 @@ struct Foo {}
             expect![[r#"
                 Clone
                 impl < >$crate::clone::Clone for Foo< >where {
-                    fn clone(&self) -> Self {
-                        match self {
-                            Foo{}
-                             => Foo{}
-                            ,
+                  fn clone(&self) -> Self {
+                    match self {
+                      Foo{}
+                       => Foo{}
+                      ,
 
-                            }
-                    }
+                      }
+                  }
 
-                    }"#]],
+                  }"#]],
         );
     }
 }
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index ce7a6779e2..f67aea2d5b 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -48,7 +48,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
             .flat_map(|module| NavigationTarget::from_module_to_decl(db, module))
             .collect(),
         None => sema
-            .file_to_module_defs(position.file_id)
+            .to_module_defs(position.file_id)
             .flat_map(|module| NavigationTarget::from_module_to_decl(db, module))
             .collect(),
     }
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 8c2ae327c7..f78153df38 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -156,7 +156,7 @@ pub(crate) fn will_rename_file(
     new_name_stem: &str,
 ) -> Option<SourceChange> {
     let sema = Semantics::new(db);
-    let module = sema.file_to_module_def(file_id)?;
+    let module = sema.to_module_def(file_id)?;
     let def = Definition::Module(module);
     let mut change = if is_raw_identifier(new_name_stem) {
         def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()?
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 5fe46444ff..ae107a9604 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -178,7 +178,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
         }
     });
 
-    sema.file_to_module_defs(file_id)
+    sema.to_module_defs(file_id)
         .map(|it| runnable_mod_outline_definition(&sema, it))
         .for_each(|it| add_opt(it, None));
 
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index d2bd3bab14..dfcbaf54d4 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -223,7 +223,7 @@ fn traverse(
     krate: hir::Crate,
     range_to_highlight: TextRange,
 ) {
-    let is_unlinked = sema.file_to_module_def(file_id).is_none();
+    let is_unlinked = sema.to_module_def(file_id).is_none();
     let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
 
     enum AttrOrDerive {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 7e027c9f92..8762564a8f 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -371,7 +371,7 @@ impl flags::AnalysisStats {
 
             let parse = sema.parse(file_id);
             let file_txt = db.file_text(file_id);
-            let path = vfs.file_path(file_id).as_path().unwrap();
+            let path = vfs.file_path(file_id).as_path().unwrap().to_owned();
 
             for node in parse.syntax().descendants() {
                 let expr = match syntax::ast::Expr::cast(node.clone()) {
@@ -446,7 +446,7 @@ impl flags::AnalysisStats {
                     edit.apply(&mut txt);
 
                     if self.validate_term_search {
-                        std::fs::write(path, txt).unwrap();
+                        std::fs::write(&path, txt).unwrap();
 
                         let res = ws.run_build_scripts(&cargo_config, &|_| ()).unwrap();
                         if let Some(err) = res.error() {
@@ -495,7 +495,7 @@ impl flags::AnalysisStats {
             }
             // Revert file back to original state
             if self.validate_term_search {
-                std::fs::write(path, file_txt.to_string()).unwrap();
+                std::fs::write(&path, file_txt.to_string()).unwrap();
             }
 
             bar.inc(1);
@@ -1077,12 +1077,12 @@ fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: Pa
     format!("{path},{}:{},{}:{}", start.line + 1, start.col, end.line + 1, end.col)
 }
 
-fn expr_syntax_range<'a>(
+fn expr_syntax_range(
     db: &RootDatabase,
-    vfs: &'a Vfs,
+    vfs: &Vfs,
     sm: &BodySourceMap,
     expr_id: ExprId,
-) -> Option<(&'a VfsPath, LineCol, LineCol)> {
+) -> Option<(VfsPath, LineCol, LineCol)> {
     let src = sm.expr_syntax(expr_id);
     if let Ok(src) = src {
         let root = db.parse_or_expand(src.file_id);
@@ -1098,12 +1098,12 @@ fn expr_syntax_range<'a>(
         None
     }
 }
-fn pat_syntax_range<'a>(
+fn pat_syntax_range(
     db: &RootDatabase,
-    vfs: &'a Vfs,
+    vfs: &Vfs,
     sm: &BodySourceMap,
     pat_id: PatId,
-) -> Option<(&'a VfsPath, LineCol, LineCol)> {
+) -> Option<(VfsPath, LineCol, LineCol)> {
     let src = sm.pat_syntax(pat_id);
     if let Ok(src) = src {
         let root = db.parse_or_expand(src.file_id);
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 8b8d0ebcb9..eb47279205 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -297,7 +297,7 @@ impl GlobalState {
             let mut bytes = vec![];
             let mut modified_rust_files = vec![];
             for file in changed_files {
-                let vfs_path = vfs.file_path(file.file_id);
+                let vfs_path = &vfs.file_path(file.file_id);
                 if let Some(path) = vfs_path.as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.kind()) {
@@ -481,7 +481,7 @@ impl GlobalStateSnapshot {
     }
 
     pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
-        let mut base = self.vfs_read().file_path(path.anchor).clone();
+        let mut base = self.vfs_read().file_path(path.anchor);
         base.pop();
         let path = base.join(&path.path).unwrap();
         let path = path.as_path().unwrap();
@@ -489,7 +489,7 @@ impl GlobalStateSnapshot {
     }
 
     pub(crate) fn file_id_to_file_path(&self, file_id: FileId) -> vfs::VfsPath {
-        self.vfs_read().file_path(file_id).clone()
+        self.vfs_read().file_path(file_id)
     }
 
     pub(crate) fn cargo_target_for_crate_root(
@@ -497,7 +497,7 @@ impl GlobalStateSnapshot {
         crate_id: CrateId,
     ) -> Option<(&CargoWorkspace, Target)> {
         let file_id = self.analysis.crate_root(crate_id).ok()?;
-        let path = self.vfs_read().file_path(file_id).clone();
+        let path = self.vfs_read().file_path(file_id);
         let path = path.as_path()?;
         self.workspaces.iter().find_map(|ws| match ws {
             ProjectWorkspace::Cargo { cargo, .. } => {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 0e005975fb..04a0439542 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -2097,7 +2097,7 @@ pub(crate) fn fetch_dependency_list(
         .into_iter()
         .filter_map(|it| {
             let root_file_path = state.file_id_to_file_path(it.root_file_id);
-            crate_path(&root_file_path).and_then(to_url).map(|path| CrateInfoResult {
+            crate_path(root_file_path).and_then(to_url).map(|path| CrateInfoResult {
                 name: it.name,
                 version: it.version,
                 path,
@@ -2118,7 +2118,7 @@ pub(crate) fn fetch_dependency_list(
 /// An `Option` value representing the path to the directory of the crate with the given
 /// name, if such a crate is found. If no crate with the given name is found, this function
 /// returns `None`.
-fn crate_path(root_file_path: &VfsPath) -> Option<VfsPath> {
+fn crate_path(root_file_path: VfsPath) -> Option<VfsPath> {
     let mut current_dir = root_file_path.parent();
     while let Some(path) = current_dir {
         let cargo_toml_path = path.join("../Cargo.toml")?;
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 008c63c35a..28eae6079c 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -55,7 +55,7 @@ fn integrated_highlighting_benchmark() {
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
-    crate::tracing::hprof::init("*>100");
+    let _g = crate::tracing::hprof::init("*>150");
 
     {
         let _it = stdx::timeit("initial");
@@ -72,6 +72,8 @@ fn integrated_highlighting_benchmark() {
         host.apply_change(change);
     }
 
+    let _g = crate::tracing::hprof::init("*>50");
+
     {
         let _it = stdx::timeit("after change");
         let _span = profile::cpu_span();
diff --git a/crates/rust-analyzer/src/tracing/hprof.rs b/crates/rust-analyzer/src/tracing/hprof.rs
index 9064987329..5fcda6ba13 100644
--- a/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/crates/rust-analyzer/src/tracing/hprof.rs
@@ -52,7 +52,7 @@ use tracing_subscriber::{
 
 use crate::tracing::hprof;
 
-pub fn init(spec: &str) {
+pub fn init(spec: &str) -> tracing::subscriber::DefaultGuard {
     let (write_filter, allowed_names) = WriteFilter::from_spec(spec);
 
     // this filter the first pass for `tracing`: these are all the "profiling" spans, but things like
@@ -76,7 +76,7 @@ pub fn init(spec: &str) {
         .with_filter(profile_filter);
 
     let subscriber = Registry::default().with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    tracing::subscriber::set_default(subscriber)
 }
 
 #[derive(Default, Debug)]
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index e8bb9ee938..1bb82cc191 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -97,8 +97,11 @@ impl<T> Parse<T> {
     pub fn syntax_node(&self) -> SyntaxNode {
         SyntaxNode::new_root(self.green.clone())
     }
-    pub fn errors(&self) -> &[SyntaxError] {
-        self.errors.as_deref().unwrap_or_default()
+
+    pub fn errors(&self) -> Vec<SyntaxError> {
+        let mut errors = if let Some(e) = self.errors.as_deref() { e.to_vec() } else { vec![] };
+        validation::validate(&self.syntax_node(), &mut errors);
+        errors
     }
 }
 
@@ -111,10 +114,10 @@ impl<T: AstNode> Parse<T> {
         T::cast(self.syntax_node()).unwrap()
     }
 
-    pub fn ok(self) -> Result<T, Arc<[SyntaxError]>> {
-        match self.errors {
-            Some(e) => Err(e),
-            None => Ok(self.tree()),
+    pub fn ok(self) -> Result<T, Vec<SyntaxError>> {
+        match self.errors() {
+            errors if !errors.is_empty() => Err(errors),
+            _ => Ok(self.tree()),
         }
     }
 }
@@ -132,7 +135,7 @@ impl Parse<SyntaxNode> {
 impl Parse<SourceFile> {
     pub fn debug_dump(&self) -> String {
         let mut buf = format!("{:#?}", self.tree().syntax());
-        for err in self.errors.as_deref().into_iter().flat_map(<[_]>::iter) {
+        for err in self.errors() {
             format_to!(buf, "error {:?}: {}\n", err.range(), err);
         }
         buf
@@ -169,11 +172,9 @@ pub use crate::ast::SourceFile;
 impl SourceFile {
     pub fn parse(text: &str) -> Parse<SourceFile> {
         let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered();
-        let (green, mut errors) = parsing::parse_text(text);
+        let (green, errors) = parsing::parse_text(text);
         let root = SyntaxNode::new_root(green.clone());
 
-        errors.extend(validation::validate(&root));
-
         assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
         Parse {
             green,
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 5b3f449eee..dbfab537fe 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -15,34 +15,32 @@ use crate::{
     SyntaxNode, SyntaxToken, TextSize, T,
 };
 
-pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
+pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
     let _p = tracing::span!(tracing::Level::INFO, "parser::validate").entered();
     // FIXME:
     // * Add unescape validation of raw string literals and raw byte string literals
     // * Add validation of doc comments are being attached to nodes
 
-    let mut errors = Vec::new();
     for node in root.descendants() {
         match_ast! {
             match node {
-                ast::Literal(it) => validate_literal(it, &mut errors),
-                ast::Const(it) => validate_const(it, &mut errors),
-                ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
-                ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
-                ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
-                ast::Visibility(it) => validate_visibility(it, &mut errors),
-                ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
-                ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
-                ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
-                ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
-                ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
-                ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
-                ast::LetExpr(it) => validate_let_expr(it, &mut errors),
+                ast::Literal(it) => validate_literal(it, errors),
+                ast::Const(it) => validate_const(it, errors),
+                ast::BlockExpr(it) => block::validate_block_expr(it, errors),
+                ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), errors),
+                ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), errors),
+                ast::Visibility(it) => validate_visibility(it, errors),
+                ast::RangeExpr(it) => validate_range_expr(it, errors),
+                ast::PathSegment(it) => validate_path_keywords(it, errors),
+                ast::RefType(it) => validate_trait_object_ref_ty(it, errors),
+                ast::PtrType(it) => validate_trait_object_ptr_ty(it, errors),
+                ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
+                ast::MacroRules(it) => validate_macro_rules(it, errors),
+                ast::LetExpr(it) => validate_let_expr(it, errors),
                 _ => (),
             }
         }
     }
-    errors
 }
 
 fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) {
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index 824ce39870..34a85818eb 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -163,8 +163,8 @@ impl Vfs {
     /// # Panics
     ///
     /// Panics if the id is not present in the `Vfs`.
-    pub fn file_path(&self, file_id: FileId) -> &VfsPath {
-        self.interner.lookup(file_id)
+    pub fn file_path(&self, file_id: FileId) -> VfsPath {
+        self.interner.lookup(file_id).clone()
     }
 
     /// Returns an iterator over the stored ids and their corresponding paths.
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index 3fc63fc7d8..d9c6b6ac45 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -81,9 +81,8 @@ async function getDebugConfiguration(
     if (!editor) return;
 
     const knownEngines: Record<string, DebugConfigProvider> = {
-        "ms-vscode.cpptools": getCCppDebugConfig,
-        "vadimcn.vscode-lldb": getCodeLldbDebugConfig,
-        "webfreak.debug": getNativeDebugConfig,
+        "vadimcn.vscode-lldb": getLldbDebugConfig,
+        "ms-vscode.cpptools": getCppvsDebugConfig,
     };
     const debugOptions = ctx.config.debug;
 
@@ -98,14 +97,12 @@ async function getDebugConfiguration(
     }
 
     if (!debugEngine) {
-        const commandCCpp: string = createCommandLink("ms-vscode.cpptools");
         const commandCodeLLDB: string = createCommandLink("vadimcn.vscode-lldb");
-        const commandNativeDebug: string = createCommandLink("webfreak.debug");
+        const commandCpp: string = createCommandLink("ms-vscode.cpptools");
 
         await vscode.window.showErrorMessage(
             `Install [CodeLLDB](command:${commandCodeLLDB} "Open CodeLLDB")` +
-                `, [C/C++](command:${commandCCpp} "Open C/C++") ` +
-                `or [Native Debug](command:${commandNativeDebug} "Open Native Debug") for debugging.`,
+                ` or [C/C++](command:${commandCpp} "Open C/C++") extension for debugging.`,
         );
         return;
     }
@@ -187,26 +184,7 @@ async function getDebugExecutableInfo(
     return executableInfo;
 }
 
-function getCCppDebugConfig(
-    runnable: ra.Runnable,
-    executable: string,
-    cargoWorkspace: string,
-    env: Record<string, string>,
-    sourceFileMap?: Record<string, string>,
-): vscode.DebugConfiguration {
-    return {
-        type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg",
-        request: "launch",
-        name: runnable.label,
-        program: executable,
-        args: runnable.args.executableArgs,
-        cwd: cargoWorkspace || runnable.args.workspaceRoot,
-        sourceFileMap,
-        env,
-    };
-}
-
-function getCodeLldbDebugConfig(
+function getLldbDebugConfig(
     runnable: ra.Runnable,
     executable: string,
     cargoWorkspace: string,
@@ -226,37 +204,21 @@ function getCodeLldbDebugConfig(
     };
 }
 
-function getNativeDebugConfig(
+function getCppvsDebugConfig(
     runnable: ra.Runnable,
     executable: string,
     cargoWorkspace: string,
     env: Record<string, string>,
-    _sourceFileMap?: Record<string, string>,
+    sourceFileMap?: Record<string, string>,
 ): vscode.DebugConfiguration {
     return {
-        type: "gdb",
+        type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg",
         request: "launch",
         name: runnable.label,
-        target: executable,
-        // See https://github.com/WebFreak001/code-debug/issues/359
-        arguments: quote(runnable.args.executableArgs),
+        program: executable,
+        args: runnable.args.executableArgs,
         cwd: cargoWorkspace || runnable.args.workspaceRoot,
+        sourceFileMap,
         env,
-        valuesFormatting: "prettyPrinters",
     };
 }
-
-// Based on https://github.com/ljharb/shell-quote/blob/main/quote.js
-function quote(xs: string[]) {
-    return xs
-        .map(function (s) {
-            if (/["\s]/.test(s) && !/'/.test(s)) {
-                return "'" + s.replace(/(['\\])/g, "\\$1") + "'";
-            }
-            if (/["'\s]/.test(s)) {
-                return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
-            }
-            return s.replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
-        })
-        .join(" ");
-}
diff --git a/lib/lsp-server/src/req_queue.rs b/lib/lsp-server/src/req_queue.rs
index 347a9fb6fb..7b47f5388b 100644
--- a/lib/lsp-server/src/req_queue.rs
+++ b/lib/lsp-server/src/req_queue.rs
@@ -37,7 +37,7 @@ impl<I> Incoming<I> {
     }
 
     pub fn cancel(&mut self, id: RequestId) -> Option<Response> {
-        let _data = self.complete(&id)?;
+        let _data = self.complete(id.clone())?;
         let error = ResponseError {
             code: ErrorCode::RequestCanceled as i32,
             message: "canceled by client".to_owned(),
@@ -46,8 +46,8 @@ impl<I> Incoming<I> {
         Some(Response { id, result: None, error: Some(error) })
     }
 
-    pub fn complete(&mut self, id: &RequestId) -> Option<I> {
-        self.pending.remove(id)
+    pub fn complete(&mut self, id: RequestId) -> Option<I> {
+        self.pending.remove(&id)
     }
 
     pub fn is_completed(&self, id: &RequestId) -> bool {


Test patch:
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 3411133f50..b9ae89cc18 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -6366,8 +6366,8 @@ fn main() { $0V; }
 
             ```rust
             pub const V: i8 = {
-                let e = 123;
-                f(e)
+              let e = 123;
+              f(e)
             }
             ```
         "#]],
@@ -6393,7 +6393,7 @@ fn main() { $0V; }
 
             ```rust
             pub static V: i8 = {
-                let e = 123;
+              let e = 123;
             }
             ```
         "#]],
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 4c0a538f71..5400071c4b 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -39,7 +39,7 @@ fn benchmark_parser() {
     let tree = {
         let _b = bench("parsing");
         let p = SourceFile::parse(&data);
-        assert!(p.errors.is_none());
+        assert!(p.errors().is_empty());
         assert_eq!(p.tree().syntax.text_range().len(), 352474.into());
         p.tree()
     };
@@ -57,7 +57,7 @@ fn validation_tests() {
     dir_tests(&test_data_dir(), &["parser/validation"], "rast", |text, path| {
         let parse = SourceFile::parse(text);
         let errors = parse.errors();
-        assert_errors_are_present(errors, path);
+        assert_errors_are_present(&errors, path);
         parse.debug_dump()
     });
 }
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index a654366c62..ca3007d437 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -149,15 +149,15 @@ impl ChangeFixture {
         for entry in fixture {
             let text = if entry.text.contains(CURSOR_MARKER) {
                 if entry.text.contains(ESCAPED_CURSOR_MARKER) {
-                    entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER).into()
+                    entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER)
                 } else {
                     let (range_or_offset, text) = extract_range_or_offset(&entry.text);
                     assert!(file_position.is_none());
                     file_position = Some((file_id, range_or_offset));
-                    text.into()
+                    text
                 }
             } else {
-                entry.text.as_str().into()
+                entry.text.clone()
             };
 
             let meta = FileMeta::from_fixture(entry, current_source_root_kind);
@@ -195,10 +195,7 @@ impl ChangeFixture {
                 let prev = crates.insert(crate_name.clone(), crate_id);
                 assert!(prev.is_none(), "multiple crates with same name: {}", crate_name);
                 for dep in meta.deps {
-                    let prelude = match &meta.extern_prelude {
-                        Some(v) => v.contains(&dep),
-                        None => true,
-                    };
+                    let prelude = meta.extern_prelude.contains(&dep);
                     let dep = CrateName::normalize_dashes(&dep);
                     crate_deps.push((crate_name.clone(), dep, prelude))
                 }
@@ -209,7 +206,7 @@ impl ChangeFixture {
                 default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
             }
 
-            source_change.change_file(file_id, Some(text));
+            source_change.change_file(file_id, Some(text.into()));
             let path = VfsPath::new_virtual_path(meta.path);
             file_set.insert(file_id, path);
             files.push(file_id);
@@ -446,7 +443,7 @@ struct FileMeta {
     path: String,
     krate: Option<(String, CrateOrigin, Option<String>)>,
     deps: Vec<String>,
-    extern_prelude: Option<Vec<String>>,
+    extern_prelude: Vec<String>,
     cfg: CfgOptions,
     edition: Edition,
     env: Env,
@@ -476,7 +473,7 @@ impl FileMeta {
         Self {
             path: f.path,
             krate: f.krate.map(|it| parse_crate(it, current_source_root_kind, f.library)),
-            extern_prelude: f.extern_prelude,
+            extern_prelude: f.extern_prelude.unwrap_or_else(|| deps.clone()),
             deps,
             cfg,
             edition: f.edition.map_or(Edition::CURRENT, |v| Edition::from_str(&v).unwrap()),