Repository: rust-analyzer/rust-analyzer
Pull request #11662 (2022-03-08 20:13:32)

fix: extract_module selection inside impl
Should close: #11508 

From issue:
Concern 1: Seems to be fixed in latest `rust-analyzer` build
Concern 2 and 3: Should be fixed by this PR
Concern 4: Got fixed in #11472 

Points to note:

- Here I have seperated use items and other items, this is becuase the new `impl` block which we will be creating cannot contain use items as immediate children. As they are the only one item that can be generated by our assist, so seperating them helps in handling their inclusion in new `impl` block inside new `module`

- There's also a new method added which helps in removing remaning left over indentation after removing `impl` or other `item`


Patch:
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 59603c6112..7e83819a4f 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -149,7 +149,6 @@ fn resolve_doc_path(
     };
 
     let modpath = {
-        // FIXME: this is not how we should get a mod path here
         let ast_path = ast::SourceFile::parse(&format!("type T = {};", link))
             .syntax_node()
             .descendants()
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 1d8c984d11..6f93f8ac94 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -102,7 +102,7 @@ use smallvec::SmallVec;
 use stdx::impl_from;
 use syntax::{
     ast::{self, HasName},
-    AstNode, SyntaxNode,
+    match_ast, AstNode, SyntaxNode,
 };
 
 use crate::{db::HirDatabase, InFile};
@@ -132,10 +132,13 @@ impl SourceToDefCtx<'_, '_> {
 
     pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
         let _p = profile::span("module_to_def");
-        let parent_declaration = src
-            .syntax()
-            .ancestors_with_macros_skip_attr_item(self.db.upcast())
-            .find_map(|it| it.map(ast::Module::cast).transpose());
+        let parent_declaration =
+            src.syntax().ancestors_with_macros_skip_attr_item(self.db.upcast()).skip(1).find_map(
+                |it| {
+                    let m = ast::Module::cast(it.value.clone())?;
+                    Some(it.with_value(m))
+                },
+            );
 
         let parent_module = match parent_declaration {
             Some(parent_declaration) => self.module_to_def(parent_declaration),
@@ -147,7 +150,7 @@ impl SourceToDefCtx<'_, '_> {
 
         let child_name = src.value.name()?.as_name();
         let def_map = parent_module.def_map(self.db.upcast());
-        let &child_id = def_map[parent_module.local_id].children.get(&child_name)?;
+        let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
         Some(def_map.module_id(child_id))
     }
 
@@ -334,7 +337,7 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
-        for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()) {
+        for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()).skip(1) {
             if let Some(res) = self.container_to_def(container) {
                 return Some(res);
             }
@@ -345,62 +348,70 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> {
-        let cont = if let Some(item) = ast::Item::cast(container.value.clone()) {
-            match item {
-                ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(),
-                ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
-                ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
-                ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
-                ast::Item::TypeAlias(it) => {
-                    self.type_alias_to_def(container.with_value(it))?.into()
-                }
-                ast::Item::Struct(it) => {
+        let cont = match_ast! {
+            match (container.value) {
+                ast::Module(it) => {
+                    let def = self.module_to_def(container.with_value(it))?;
+                    def.into()
+                },
+                ast::Trait(it) => {
+                    let def = self.trait_to_def(container.with_value(it))?;
+                    def.into()
+                },
+                ast::Impl(it) => {
+                    let def = self.impl_to_def(container.with_value(it))?;
+                    def.into()
+                },
+                ast::Fn(it) => {
+                    let def = self.fn_to_def(container.with_value(it))?;
+                    DefWithBodyId::from(def).into()
+                },
+                ast::Struct(it) => {
                     let def = self.struct_to_def(container.with_value(it))?;
                     VariantId::from(def).into()
-                }
-                ast::Item::Union(it) => {
+                },
+                ast::Enum(it) => {
+                    let def = self.enum_to_def(container.with_value(it))?;
+                    def.into()
+                },
+                ast::Union(it) => {
                     let def = self.union_to_def(container.with_value(it))?;
                     VariantId::from(def).into()
-                }
-                ast::Item::Fn(it) => {
-                    let def = self.fn_to_def(container.with_value(it))?;
-                    DefWithBodyId::from(def).into()
-                }
-                ast::Item::Static(it) => {
+                },
+                ast::Static(it) => {
                     let def = self.static_to_def(container.with_value(it))?;
                     DefWithBodyId::from(def).into()
-                }
-                ast::Item::Const(it) => {
+                },
+                ast::Const(it) => {
                     let def = self.const_to_def(container.with_value(it))?;
                     DefWithBodyId::from(def).into()
-                }
+                },
+                ast::TypeAlias(it) => {
+                    let def = self.type_alias_to_def(container.with_value(it))?;
+                    def.into()
+                },
+                ast::Variant(it) => {
+                    let def = self.enum_variant_to_def(container.with_value(it))?;
+                    VariantId::from(def).into()
+                },
                 _ => return None,
             }
-        } else {
-            let it = ast::Variant::cast(container.value)?;
-            let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
-            VariantId::from(def).into()
         };
         Some(cont)
     }
 
     fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
-        let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast());
-        for InFile { file_id, value } in ancestors {
-            let item = match ast::Item::cast(value) {
-                Some(it) => it,
-                None => continue,
-            };
-            let res: GenericDefId = match item {
-                ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::Struct(it) => self.struct_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::Enum(it) => self.enum_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::Trait(it) => self.trait_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::TypeAlias(it) => {
-                    self.type_alias_to_def(InFile::new(file_id, it))?.into()
+        for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()).skip(1) {
+            let res: GenericDefId = match_ast! {
+                match (container.value) {
+                    ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
+                    ast::Struct(it) => self.struct_to_def(container.with_value(it))?.into(),
+                    ast::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
+                    ast::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
+                    ast::TypeAlias(it) => self.type_alias_to_def(container.with_value(it))?.into(),
+                    ast::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
+                    _ => continue,
                 }
-                ast::Item::Impl(it) => self.impl_to_def(InFile::new(file_id, it))?.into(),
-                _ => continue,
             };
             return Some(res);
         }
@@ -408,17 +419,14 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
-        let ancestors = src.ancestors_with_macros_skip_attr_item(self.db.upcast());
-        for InFile { file_id, value } in ancestors {
-            let item = match ast::Item::cast(value) {
-                Some(it) => it,
-                None => continue,
-            };
-            let res: DefWithBodyId = match item {
-                ast::Item::Const(it) => self.const_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::Static(it) => self.static_to_def(InFile::new(file_id, it))?.into(),
-                ast::Item::Fn(it) => self.fn_to_def(InFile::new(file_id, it))?.into(),
-                _ => continue,
+        for container in src.ancestors_with_macros_skip_attr_item(self.db.upcast()).skip(1) {
+            let res: DefWithBodyId = match_ast! {
+                match (container.value) {
+                    ast::Const(it) => self.const_to_def(container.with_value(it))?.into(),
+                    ast::Static(it) => self.static_to_def(container.with_value(it))?.into(),
+                    ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
+                    _ => continue,
+                }
             };
             return Some(res);
         }
diff --git a/crates/hir_expand/src/builtin_fn_macro.rs b/crates/hir_expand/src/builtin_fn_macro.rs
index f69742971e..da76b6b080 100644
--- a/crates/hir_expand/src/builtin_fn_macro.rs
+++ b/crates/hir_expand/src/builtin_fn_macro.rs
@@ -4,10 +4,7 @@ use base_db::{AnchoredPath, Edition, FileId};
 use cfg::CfgExpr;
 use either::Either;
 use mbe::{parse_exprs_with_sep, parse_to_token_tree};
-use syntax::{
-    ast::{self, AstToken},
-    SmolStr,
-};
+use syntax::ast::{self, AstToken};
 
 use crate::{
     db::AstDatabase, name, quote, AstId, CrateId, ExpandError, ExpandResult, MacroCallId,
@@ -133,9 +130,6 @@ register_builtin! {
     (option_env, OptionEnv) => option_env_expand
 }
 
-const DOLLAR_CRATE: tt::Ident =
-    tt::Ident { text: SmolStr::new_inline("$crate"), id: tt::TokenId::unspecified() };
-
 fn module_path_expand(
     _db: &dyn AstDatabase,
     _id: MacroCallId,
@@ -208,6 +202,7 @@ fn assert_expand(
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
+    let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
     let args = parse_exprs_with_sep(tt, ',');
     let expanded = match &*args {
         [cond, panic_args @ ..] => {
@@ -223,7 +218,7 @@ fn assert_expand(
             let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
             quote! {{
                 if !#cond {
-                    #DOLLAR_CRATE::panic!(##panic_args);
+                    #krate::panic!(##panic_args);
                 }
             }}
         }
@@ -298,13 +293,15 @@ fn asm_expand(
     // We expand all assembly snippets to `format_args!` invocations to get format syntax
     // highlighting for them.
 
+    let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
+
     let mut literals = Vec::new();
     for tt in tt.token_trees.chunks(2) {
         match tt {
             [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
             | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', id: _, spacing: _ }))] =>
             {
-                let krate = DOLLAR_CRATE.clone();
+                let krate = krate.clone();
                 literals.push(quote!(#krate::format_args!(#lit);));
             }
             _ => break,
@@ -346,10 +343,11 @@ fn panic_expand(
 ) -> ExpandResult<tt::Subtree> {
     let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
     // Expand to a macro call `$crate::panic::panic_{edition}`
+    let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
     let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
-        quote!(#DOLLAR_CRATE::panic::panic_2021!)
+        quote!(#krate::panic::panic_2021!)
     } else {
-        quote!(#DOLLAR_CRATE::panic::panic_2015!)
+        quote!(#krate::panic::panic_2015!)
     };
 
     // Pass the original arguments
@@ -364,10 +362,11 @@ fn unreachable_expand(
 ) -> ExpandResult<tt::Subtree> {
     let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
     // Expand to a macro call `$crate::panic::unreachable_{edition}`
+    let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
     let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
-        quote!(#DOLLAR_CRATE::panic::unreachable_2021!)
+        quote!(#krate::panic::unreachable_2021!)
     } else {
-        quote!(#DOLLAR_CRATE::panic::unreachable_2015!)
+        quote!(#krate::panic::unreachable_2015!)
     };
 
     // Pass the original arguments
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 99cb493f32..bdb01ca170 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -712,7 +712,7 @@ impl<'a> InFile<&'a SyntaxNode> {
         self,
         db: &dyn db::AstDatabase,
     ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
-        let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
+        iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
             Some(parent) => Some(node.with_value(parent)),
             None => {
                 let parent_node = node.file_id.call_node(db)?;
@@ -724,8 +724,7 @@ impl<'a> InFile<&'a SyntaxNode> {
                     Some(parent_node)
                 }
             }
-        };
-        iter::successors(succ(&self.cloned()), succ)
+        })
     }
 
     /// Falls back to the macro call range if the node cannot be mapped up fully.
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 14464426bf..7bb6b24a23 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -1,6 +1,6 @@
 use hir::Semantics;
 use ide_db::{
-    helpers::pick_best_token, syntax_helpers::insert_whitespace_into_node::insert_ws_into,
+    helpers::{insert_whitespace_into_node::insert_ws_into, pick_best_token},
     RootDatabase,
 };
 use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T};
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index ba999524d6..66126c8d55 100755
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -1,4 +1,4 @@
-use ide_db::syntax_helpers::node_ext::vis_eq;
+use ide_db::helpers::node_ext::vis_eq;
 use rustc_hash::FxHashSet;
 
 use syntax::{
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index baa015354f..5724090e63 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -2,9 +2,10 @@ use hir::Semantics;
 use ide_db::{
     base_db::{FileId, FilePosition},
     defs::{Definition, IdentClass},
-    helpers::pick_best_token,
+    helpers::{
+        for_each_break_and_continue_expr, for_each_tail_expr, node_ext::walk_expr, pick_best_token,
+    },
     search::{FileReference, ReferenceCategory, SearchScope},
-    syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr},
     RootDatabase,
 };
 use rustc_hash::FxHashSet;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 4a762ad1f8..30d0d34358 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -10,8 +10,7 @@ use hir::{HasSource, Semantics};
 use ide_db::{
     base_db::FileRange,
     defs::{Definition, IdentClass},
-    famous_defs::FamousDefs,
-    helpers::pick_best_token,
+    helpers::{pick_best_token, FamousDefs},
     FxIndexSet, RootDatabase,
 };
 use itertools::Itertools;
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index c298065f4e..f8ac43bbdd 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -6,8 +6,10 @@ use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Seman
 use ide_db::{
     base_db::SourceDatabase,
     defs::Definition,
-    famous_defs::FamousDefs,
-    generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
+    helpers::{
+        generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
+        FamousDefs,
+    },
     RootDatabase,
 };
 use itertools::Itertools;
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 8ecc5567b4..2ca756cbe0 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,11 +1,11 @@
 use either::Either;
 use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
-use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
+use ide_db::{base_db::FileRange, helpers::FamousDefs, RootDatabase};
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{self, AstNode, HasArgList, HasName, UnaryOp},
-    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, TextRange, T,
+    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
 };
 
 use crate::FileId;
@@ -58,7 +58,6 @@ pub struct InlayHint {
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
     file_id: FileId,
-    range_limit: Option<FileRange>,
     config: &InlayHintsConfig,
 ) -> Vec<InlayHint> {
     let _p = profile::span("inlay_hints");
@@ -66,50 +65,25 @@ pub(crate) fn inlay_hints(
     let file = sema.parse(file_id);
     let file = file.syntax();
 
-    let mut hints = Vec::new();
-
-    if let Some(range_limit) = range_limit {
-        let range_limit = range_limit.range;
-        match file.covering_element(range_limit) {
-            NodeOrToken::Token(_) => return hints,
-            NodeOrToken::Node(n) => {
-                for node in n
-                    .descendants()
-                    .filter(|descendant| range_limit.contains_range(descendant.text_range()))
-                {
-                    get_hints(&mut hints, &sema, config, node);
-                }
-            }
-        }
-    } else {
-        for node in file.descendants() {
-            get_hints(&mut hints, &sema, config, node);
-        }
-    }
+    let mut res = Vec::new();
 
-    hints
-}
-
-fn get_hints(
-    hints: &mut Vec<InlayHint>,
-    sema: &Semantics<RootDatabase>,
-    config: &InlayHintsConfig,
-    node: SyntaxNode,
-) {
-    if let Some(expr) = ast::Expr::cast(node.clone()) {
-        get_chaining_hints(hints, sema, config, &expr);
-        match expr {
-            ast::Expr::CallExpr(it) => {
-                get_param_name_hints(hints, sema, config, ast::Expr::from(it));
-            }
-            ast::Expr::MethodCallExpr(it) => {
-                get_param_name_hints(hints, sema, config, ast::Expr::from(it));
+    for node in file.descendants() {
+        if let Some(expr) = ast::Expr::cast(node.clone()) {
+            get_chaining_hints(&mut res, &sema, config, &expr);
+            match expr {
+                ast::Expr::CallExpr(it) => {
+                    get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
+                }
+                ast::Expr::MethodCallExpr(it) => {
+                    get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
+                }
+                _ => (),
             }
-            _ => (),
+        } else if let Some(it) = ast::IdentPat::cast(node.clone()) {
+            get_bind_pat_hints(&mut res, &sema, config, &it);
         }
-    } else if let Some(it) = ast::IdentPat::cast(node) {
-        get_bind_pat_hints(hints, sema, config, &it);
     }
+    res
 }
 
 fn get_chaining_hints(
@@ -567,8 +541,6 @@ fn get_callable(
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
-    use ide_db::base_db::FileRange;
-    use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
     use crate::{fixture, inlay_hints::InlayHintsConfig};
@@ -632,7 +604,7 @@ mod tests {
     fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
-        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
+        let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
         let actual =
             inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
         assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
@@ -641,7 +613,7 @@ mod tests {
     #[track_caller]
     fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
         let (analysis, file_id) = fixture::file(ra_fixture);
-        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
+        let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
         expect.assert_debug_eq(&inlay_hints)
     }
 
@@ -1073,55 +1045,6 @@ fn main() {
         )
     }
 
-    #[test]
-    fn check_hint_range_limit() {
-        let fixture = r#"
-        //- minicore: fn, sized
-        fn foo() -> impl Fn() { loop {} }
-        fn foo1() -> impl Fn(f64) { loop {} }
-        fn foo2() -> impl Fn(f64, f64) { loop {} }
-        fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
-        fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
-        fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
-        fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
-        fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
-
-        fn main() {
-            let foo = foo();
-            let foo = foo1();
-            let foo = foo2();
-            let foo = foo3();
-             // ^^^ impl Fn(f64, f64) -> u32
-            let foo = foo4();
-             // ^^^ &dyn Fn(f64, f64) -> u32
-            let foo = foo5();
-            let foo = foo6();
-            let foo = foo7();
-        }
-        "#;
-        let (analysis, file_id) = fixture::file(fixture);
-        let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
-        let inlay_hints = analysis
-            .inlay_hints(
-                &InlayHintsConfig {
-                    parameter_hints: false,
-                    type_hints: true,
-                    chaining_hints: false,
-                    hide_named_constructor_hints: false,
-                    max_length: None,
-                },
-                file_id,
-                Some(FileRange {
-                    file_id,
-                    range: TextRange::new(TextSize::from(500), TextSize::from(600)),
-                }),
-            )
-            .unwrap();
-        let actual =
-            inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
-        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
-    }
-
     #[test]
     fn fn_hints_ptr_rpit_fn_parentheses() {
         check_types(
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 00ff9ed31b..54c0b5e704 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -1,5 +1,5 @@
 use ide_assists::utils::extract_trivial_expression;
-use ide_db::syntax_helpers::node_ext::expr_as_name_ref;
+use ide_db::helpers::node_ext::expr_as_name_ref;
 use itertools::Itertools;
 use syntax::{
     ast::{self, AstNode, AstToken, IsString},
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 1acaaaccf0..4028b0bc72 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -358,9 +358,8 @@ impl Analysis {
         &self,
         config: &InlayHintsConfig,
         file_id: FileId,
-        range: Option<FileRange>,
     ) -> Cancellable<Vec<InlayHint>> {
-        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
+        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config))
     }
 
     /// Returns the set of folding ranges.
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 31d85c60e7..fb94342a78 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -112,7 +112,6 @@ impl StaticIndex<'_> {
                     max_length: Some(25),
                 },
                 file_id,
-                None,
             )
             .unwrap();
         // hovers
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index 2d5f5f00e1..c74b9f56db 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -1,6 +1,6 @@
 //! Syntax highlighting for format macro strings.
 use ide_db::{
-    syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
+    helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
     SymbolKind,
 };
 use syntax::{ast, TextRange};
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index eeec8dcba8..b98fa1ab39 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,7 +3,7 @@
 use hir::{AsAssocItem, HasVisibility, Semantics};
 use ide_db::{
     defs::{Definition, IdentClass, NameClass, NameRefClass},
-    famous_defs::FamousDefs,
+    helpers::FamousDefs,
     RootDatabase, SymbolKind,
 };
 use rustc_hash::FxHashMap;
@@ -123,12 +123,12 @@ fn punctuation(sema: &Semantics<RootDatabase>, token: SyntaxToken, kind: SyntaxK
             }
             .into()
         }
-        (T![+] | T![-] | T![*] | T![/] | T![%], BIN_EXPR) => HlOperator::Arithmetic.into(),
-        (T![+=] | T![-=] | T![*=] | T![/=] | T![%=], BIN_EXPR) => {
+        (T![+] | T![-] | T![*] | T![/], BIN_EXPR) => HlOperator::Arithmetic.into(),
+        (T![+=] | T![-=] | T![*=] | T![/=], BIN_EXPR) => {
             Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable
         }
-        (T![|] | T![&] | T![!] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(),
-        (T![|=] | T![&=] | T![^=] | T![>>=] | T![<<=], BIN_EXPR) => {
+        (T![|] | T![&] | T![!] | T![^], BIN_EXPR) => HlOperator::Bitwise.into(),
+        (T![|=] | T![&=] | T![^=], BIN_EXPR) => {
             Highlight::from(HlOperator::Bitwise) | HlMod::Mutable
         }
         (T![&&] | T![||], BIN_EXPR) => HlOperator::Logical.into(),
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 7ac1200a4a..774934a249 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -5,7 +5,8 @@ use std::mem;
 use either::Either;
 use hir::{InFile, Semantics};
 use ide_db::{
-    active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
+    active_parameter::ActiveParameter, defs::Definition, helpers::rust_doc::is_rust_fence,
+    SymbolKind,
 };
 use syntax::{
     ast::{self, AstNode, IsString, QuoteOffsets},
diff --git a/crates/ide_assists/src/assist_config.rs b/crates/ide_assists/src/assist_config.rs
index d4d148c774..9cabf037c0 100644
--- a/crates/ide_assists/src/assist_config.rs
+++ b/crates/ide_assists/src/assist_config.rs
@@ -4,7 +4,7 @@
 //! module, and we use to statically check that we only produce snippet
 //! assists if we are allowed to.
 
-use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
+use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
 
 use crate::AssistKind;
 
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index fd46aa2479..1181adb8d5 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -5,7 +5,7 @@ use std::mem;
 use hir::Semantics;
 use ide_db::{
     base_db::{AnchoredPathBuf, FileId, FileRange},
-    SnippetCap,
+    helpers::SnippetCap,
 };
 use ide_db::{
     label::Label,
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 11f12773e8..945edfd999 100644
--- a/crates/ide_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide_assists/src/handlers/add_explicit_type.rs
@@ -1,5 +1,5 @@
 use hir::HirDisplay;
-use ide_db::syntax_helpers::node_ext::walk_ty;
+use ide_db::helpers::node_ext::walk_ty;
 use syntax::ast::{self, AstNode, LetStmt, Param};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
index c82caa3704..3105b28911 100644
--- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
@@ -1,7 +1,5 @@
 use hir::HasSource;
-use ide_db::{
-    syntax_helpers::insert_whitespace_into_node::insert_ws_into, traits::resolve_target_trait,
-};
+use ide_db::{helpers::insert_whitespace_into_node::insert_ws_into, traits::resolve_target_trait};
 use syntax::ast::{self, make, AstNode};
 
 use crate::{
diff --git a/crates/ide_assists/src/handlers/add_missing_match_arms.rs b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
index 9b6a1ad169..ec8fbb4974 100644
--- a/crates/ide_assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
@@ -2,8 +2,8 @@ use std::iter::{self, Peekable};
 
 use either::Either;
 use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
+use ide_db::helpers::{mod_path_to_ast, FamousDefs};
 use ide_db::RootDatabase;
-use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
 use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
 
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 5a2809a1cf..9c0233b028 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -1,9 +1,7 @@
-use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::{
-        import_assets::{ImportAssets, ImportCandidate},
-        insert_use::{insert_use, ImportScope},
-    },
+use ide_db::helpers::{
+    import_assets::{ImportAssets, ImportCandidate},
+    insert_use::{insert_use, ImportScope},
+    mod_path_to_ast,
 };
 use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
 
diff --git a/crates/ide_assists/src/handlers/convert_bool_then.rs b/crates/ide_assists/src/handlers/convert_bool_then.rs
index daec28999e..274718e6ea 100644
--- a/crates/ide_assists/src/handlers/convert_bool_then.rs
+++ b/crates/ide_assists/src/handlers/convert_bool_then.rs
@@ -1,8 +1,9 @@
 use hir::{known, AsAssocItem, Semantics};
 use ide_db::{
-    famous_defs::FamousDefs,
-    syntax_helpers::node_ext::{
-        block_as_lone_tail, for_each_tail_expr, is_pattern_cond, preorder_expr,
+    helpers::{
+        for_each_tail_expr,
+        node_ext::{block_as_lone_tail, is_pattern_cond, preorder_expr},
+        FamousDefs,
     },
     RootDatabase,
 };
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs
index 9185501a62..7f27b507ba 100644
--- a/crates/ide_assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs
@@ -1,4 +1,7 @@
-use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait};
+use ide_db::{
+    helpers::{mod_path_to_ast, FamousDefs},
+    traits::resolve_target_trait,
+};
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index bb75cb5c95..4a4ad984db 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -1,5 +1,5 @@
 use hir::known;
-use ide_db::famous_defs::FamousDefs;
+use ide_db::helpers::FamousDefs;
 use stdx::format_to;
 use syntax::{
     ast::{self, edit_in_place::Indent, make, HasArgList, HasLoopBody},
diff --git a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
index a7c43413d2..193d1cdfb2 100644
--- a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
+++ b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
@@ -1,6 +1,6 @@
 use std::iter::once;
 
-use ide_db::syntax_helpers::node_ext::{is_pattern_cond, single_let};
+use ide_db::helpers::node_ext::{is_pattern_cond, single_let};
 use syntax::{
     ast::{
         self,
diff --git a/crates/ide_assists/src/handlers/convert_while_to_loop.rs b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
index 345d0c2063..0fa2dcfbde 100644
--- a/crates/ide_assists/src/handlers/convert_while_to_loop.rs
+++ b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
@@ -1,6 +1,6 @@
 use std::iter::once;
 
-use ide_db::syntax_helpers::node_ext::is_pattern_cond;
+use ide_db::helpers::node_ext::is_pattern_cond;
 use syntax::{
     ast::{
         self,
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 5f86957ba2..e80dce0c45 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -5,11 +5,13 @@ use either::Either;
 use hir::{HirDisplay, InFile, Local, ModuleDef, Semantics, TypeInfo};
 use ide_db::{
     defs::{Definition, NameRefClass},
-    famous_defs::FamousDefs,
-    helpers::mod_path_to_ast,
-    imports::insert_use::{insert_use, ImportScope},
+    helpers::{
+        insert_use::{insert_use, ImportScope},
+        mod_path_to_ast,
+        node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr},
+        FamousDefs,
+    },
     search::{FileReference, ReferenceCategory, SearchScope},
-    syntax_helpers::node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr},
     FxIndexSet, RootDatabase,
 };
 use itertools::Itertools;
diff --git a/crates/ide_assists/src/handlers/extract_module.rs b/crates/ide_assists/src/handlers/extract_module.rs
index 880617dd38..08bfd10dc7 100644
--- a/crates/ide_assists/src/handlers/extract_module.rs
+++ b/crates/ide_assists/src/handlers/extract_module.rs
@@ -7,6 +7,7 @@ use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
     search::{FileReference, SearchScope},
 };
+use parser::SyntaxKind::WHITESPACE;
 use stdx::format_to;
 use syntax::{
     algo::find_node_at_range,
@@ -59,6 +60,20 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<(
         syntax::NodeOrToken::Token(t) => t.parent()?,
     };
 
+    //If the selection is inside impl block, we need to place new module outside impl block,
+    //as impl blocks cannot contain modules
+
+    let mut impl_parent: Option<ast::Impl> = None;
+    let mut impl_child_count: usize = 0;
+    if let Some(parent_assoc_list) = node.parent() {
+        if let Some(parent_impl) = parent_assoc_list.parent() {
+            if let Some(impl_) = ast::Impl::cast(parent_impl) {
+                impl_child_count = parent_assoc_list.children().count();
+                impl_parent = Some(impl_);
+            }
+        }
+    }
+
     let mut curr_parent_module: Option<ast::Module> = None;
     if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
         curr_parent_module = ast::Module::cast(mod_syn_opt);
@@ -98,18 +113,55 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<(
         "Extract Module",
         module.text_range,
         |builder| {
-            let _ = &module;
+            let mut body_items: Vec<String> = Vec::new();
+            let mut items_to_be_processed: Vec<ast::Item> = module.body_items.clone();
+            let mut new_item_indent = old_item_indent + 1;
 
-            let mut body_items = Vec::new();
-            let new_item_indent = old_item_indent + 1;
-            for item in module.body_items {
+            if impl_parent.is_some() {
+                new_item_indent = old_item_indent + 2;
+            } else {
+                items_to_be_processed = [module.use_items.clone(), items_to_be_processed].concat();
+            }
+
+            for item in items_to_be_processed {
                 let item = item.indent(IndentLevel(1));
                 let mut indented_item = String::new();
                 format_to!(indented_item, "{}{}", new_item_indent, item.to_string());
                 body_items.push(indented_item);
             }
 
-            let body = body_items.join("\n\n");
+            let mut body = body_items.join("\n\n");
+
+            if let Some(impl_) = &impl_parent {
+                let mut impl_body_def = String::new();
+
+                if let Some(self_ty) = impl_.self_ty() {
+                    format_to!(
+                        impl_body_def,
+                        "{}impl {} {{\n{}\n{}}}",
+                        old_item_indent + 1,
+                        self_ty.to_string(),
+                        body,
+                        old_item_indent + 1
+                    );
+
+                    body = impl_body_def;
+
+                    // Add the import for enum/struct corresponding to given impl block
+                    if let Some(_) = module.make_use_stmt_of_node_with_super(self_ty.syntax()) {
+                        for item in module.use_items {
+                            let mut indented_item = String::new();
+                            format_to!(
+                                indented_item,
+                                "{}{}",
+                                old_item_indent + 1,
+                                item.to_string()
+                            );
+                            body = format!("{}\n\n{}", indented_item, body);
+                        }
+                    }
+                }
+            }
 
             let mut module_def = String::new();
 
@@ -135,7 +187,29 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<(
             for import_path_text_range in import_paths_to_be_removed {
                 builder.delete(import_path_text_range);
             }
-            builder.replace(module.text_range, module_def)
+
+            if let Some(impl_) = impl_parent {
+                let node_to_be_removed;
+
+                // Remove complete impl block if it has only one child (as such it will be empty
+                // after deleting that child)
+                if impl_child_count == 1 {
+                    node_to_be_removed = impl_.syntax()
+                } else {
+                    //Remove selected node
+                    node_to_be_removed = &node;
+                }
+
+                builder.delete(node_to_be_removed.text_range());
+                // Remove preceding indentation from node
+                if let Some(range) = indent_range_before_given_node(&node_to_be_removed) {
+                    builder.delete(range);
+                }
+
+                builder.insert(impl_.syntax().text_range().end(), format!("\n\n{}", module_def));
+            } else {
+                builder.replace(module.text_range, module_def)
+            }
         },
     )
 }
@@ -144,16 +218,24 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<(
 struct Module {
     text_range: TextRange,
     name: String,
-    body_items: Vec<ast::Item>,
+    body_items: Vec<ast::Item>, // All items except use items
+    use_items: Vec<ast::Item>, // Use items are kept separately as they help when the selection is inside an impl block, we can directly take these items and keep them outside generated impl block inside generated module
 }
 
 fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
+    let mut use_items = vec![];
+
     let mut body_items: Vec<ast::Item> = node
         .children()
         .filter_map(|child| {
-            if let Some(item) = ast::Item::cast(child) {
-                if selection_range.contains_range(item.syntax().text_range()) {
-                    return Some(item);
+            if selection_range.contains_range(child.text_range()) {
+                let child_kind = child.kind();
+                if let Some(item) = ast::Item::cast(child) {
+                    if ast::Use::can_cast(child_kind) {
+                        use_items.push(item);
+                    } else {
+                        return Some(item);
+                    }
                 }
                 return None;
             }
@@ -165,7 +247,7 @@ fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Modul
         body_items.push(node_item);
     }
 
-    Some(Module { text_range: selection_range, name: "modname".to_string(), body_items })
+    Some(Module { text_range: selection_range, name: "modname".to_string(), body_items, use_items })
 }
 
 impl Module {
@@ -543,23 +625,27 @@ impl Module {
             let use_ =
                 make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
             if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
-                self.body_items.insert(0, item);
+                self.use_items.insert(0, item);
             }
         }
 
         import_path_to_be_removed
     }
 
-    fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) {
+    fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> Option<ast::Item> {
         let super_path = make::ext::ident_path("super");
         let node_path = make::ext::ident_path(&node_syntax.to_string());
         let use_ = make::use_(
             None,
             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
         );
+
         if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
-            self.body_items.insert(0, item);
+            self.use_items.insert(0, item.clone());
+            return Some(item);
         }
+
+        return None;
     }
 
     fn process_use_stmt_for_import_resolve(
@@ -859,6 +945,14 @@ fn compare_hir_and_ast_module(
     return Some(());
 }
 
+fn indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange> {
+    let x = node.siblings_with_tokens(syntax::Direction::Prev).find(|x| {
+        return x.kind() == WHITESPACE;
+    })?;
+
+    return Some(x.text_range());
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -1435,4 +1529,63 @@ mod modname {
             ",
         )
     }
+
+    #[test]
+    fn test_if_inside_impl_block_generate_module_outside() {
+        check_assist(
+            extract_module,
+            r"
+            struct A {}
+
+            impl A {
+$0fn foo() {}$0
+                fn bar() {}
+            }
+        ",
+            r"
+            struct A {}
+
+            impl A {
+                fn bar() {}
+            }
+
+mod modname {
+    use super::A;
+
+    impl A {
+        pub(crate) fn foo() {}
+    }
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() {
+        check_assist(
+            extract_module,
+            r"
+            struct A {}
+            struct B {}
+
+            impl A {
+$0fn foo(x: B) {}$0
+            }
+        ",
+            r"
+            struct A {}
+            struct B {}
+
+mod modname {
+    use super::B;
+
+    use super::A;
+
+    impl A {
+        pub(crate) fn foo(x: B) {}
+    }
+}
+        ",
+        )
+    }
 }
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 4b597837aa..1cdd4187af 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -4,8 +4,10 @@ use either::Either;
 use hir::{Module, ModuleDef, Name, Variant};
 use ide_db::{
     defs::Definition,
-    helpers::mod_path_to_ast,
-    imports::insert_use::{insert_use, ImportScope, InsertUseConfig},
+    helpers::{
+        insert_use::{insert_use, ImportScope, InsertUseConfig},
+        mod_path_to_ast,
+    },
     search::FileReference,
     RootDatabase,
 };
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs
index f664aa6dbf..d7ad62782f 100644
--- a/crates/ide_assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide_assists/src/handlers/extract_type_alias.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use ide_db::syntax_helpers::node_ext::walk_ty;
+use ide_db::helpers::node_ext::walk_ty;
 use itertools::Itertools;
 use syntax::{
     ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index 4745ac24e9..e67789a662 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,4 +1,4 @@
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use ide_db::{helpers::FamousDefs, RootDatabase};
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 669fb28d10..6f158ceb99 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -1,4 +1,4 @@
-use ide_db::famous_defs::FamousDefs;
+use ide_db::helpers::FamousDefs;
 use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
index 4328c54c09..2208c23c15 100644
--- a/crates/ide_assists/src/handlers/generate_deref.rs
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use ide_db::{helpers::FamousDefs, RootDatabase};
 use syntax::{
     ast::{self, HasName},
     AstNode, SyntaxNode,
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index ee8de5a20e..96b751f099 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,4 +1,5 @@
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use ide_db::helpers::FamousDefs;
+use ide_db::RootDatabase;
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index c06498a4c9..ac33d56858 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -1,11 +1,12 @@
 use rustc_hash::{FxHashMap, FxHashSet};
 
 use hir::{HasSource, HirDisplay, Module, Semantics, TypeInfo};
+use ide_db::helpers::FamousDefs;
 use ide_db::{
     base_db::FileId,
     defs::{Definition, NameRefClass},
-    famous_defs::FamousDefs,
-    RootDatabase, SnippetCap,
+    helpers::SnippetCap,
+    RootDatabase,
 };
 use stdx::to_lower_snake_case;
 use syntax::{
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index c6e979c072..653e448cbb 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -1,4 +1,4 @@
-use ide_db::famous_defs::FamousDefs;
+use ide_db::helpers::FamousDefs;
 use stdx::{format_to, to_lower_snake_case};
 use syntax::ast::{self, AstNode, HasName, HasVisibility};
 
diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs
index 5e9f561806..d88e3fdcd3 100644
--- a/crates/ide_assists/src/handlers/inline_call.rs
+++ b/crates/ide_assists/src/handlers/inline_call.rs
@@ -4,10 +4,9 @@ use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
 use ide_db::{
     base_db::{FileId, FileRange},
     defs::Definition,
-    imports::insert_use::remove_path_if_in_use_stmt,
+    helpers::{insert_use::remove_path_if_in_use_stmt, node_ext::expr_as_name_ref},
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    syntax_helpers::node_ext::expr_as_name_ref,
     RootDatabase,
 };
 use itertools::{izip, Itertools};
diff --git a/crates/ide_assists/src/handlers/invert_if.rs b/crates/ide_assists/src/handlers/invert_if.rs
index 6eed59c9ea..46f11f4af3 100644
--- a/crates/ide_assists/src/handlers/invert_if.rs
+++ b/crates/ide_assists/src/handlers/invert_if.rs
@@ -1,4 +1,4 @@
-use ide_db::syntax_helpers::node_ext::is_pattern_cond;
+use ide_db::helpers::node_ext::is_pattern_cond;
 use syntax::{
     ast::{self, AstNode},
     T,
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index e35c962a3f..68aa741fac 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -1,4 +1,4 @@
-use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
+use ide_db::helpers::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
 use syntax::{algo::neighbor, ast, ted, AstNode};
 
 use crate::{
diff --git a/crates/ide_assists/src/handlers/promote_local_to_const.rs b/crates/ide_assists/src/handlers/promote_local_to_const.rs
index 58cee8eafb..879247d37e 100644
--- a/crates/ide_assists/src/handlers/promote_local_to_const.rs
+++ b/crates/ide_assists/src/handlers/promote_local_to_const.rs
@@ -2,7 +2,7 @@ use hir::{HirDisplay, ModuleDef, PathResolution, Semantics};
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
-    syntax_helpers::node_ext::preorder_expr,
+    helpers::node_ext::preorder_expr,
     RootDatabase,
 };
 use stdx::to_upper_snake_case;
diff --git a/crates/ide_assists/src/handlers/qualify_method_call.rs b/crates/ide_assists/src/handlers/qualify_method_call.rs
index 61c16aa044..43878879ed 100644
--- a/crates/ide_assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide_assists/src/handlers/qualify_method_call.rs
@@ -1,7 +1,7 @@
 use hir::{ItemInNs, ModuleDef};
 use ide_db::{
     assists::{AssistId, AssistKind},
-    imports::import_assets::item_for_path_search,
+    helpers::import_assets::item_for_path_search,
 };
 use syntax::{ast, AstNode};
 
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 5deb60f57b..ae29068bd7 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -1,11 +1,11 @@
 use std::iter;
 
 use hir::AsAssocItem;
-use ide_db::RootDatabase;
-use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::import_assets::{ImportCandidate, LocatedImport},
+use ide_db::helpers::{
+    import_assets::{ImportCandidate, LocatedImport},
+    mod_path_to_ast,
 };
+use ide_db::RootDatabase;
 use syntax::{
     ast,
     ast::{make, HasArgList},
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 0d0bd7071f..27f2960c7e 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -1,7 +1,9 @@
 use hir::{InFile, ModuleDef};
 use ide_db::{
-    helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator,
-    syntax_helpers::insert_whitespace_into_node::insert_ws_into,
+    helpers::{
+        import_assets::NameToImport, insert_whitespace_into_node::insert_ws_into, mod_path_to_ast,
+    },
+    items_locator,
 };
 use itertools::Itertools;
 use syntax::{
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
index 1c403eafe3..b594c64c41 100644
--- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
@@ -3,7 +3,7 @@ use std::iter::{self, successors};
 use either::Either;
 use ide_db::{
     defs::NameClass,
-    syntax_helpers::node_ext::{is_pattern_cond, single_let},
+    helpers::node_ext::{is_pattern_cond, single_let},
     ty_filter::TryEnum,
     RootDatabase,
 };
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 50134db8a1..71c674a8dd 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,7 +1,7 @@
 use hir::AsAssocItem;
-use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::insert_use::{insert_use, ImportScope},
+use ide_db::helpers::{
+    insert_use::{insert_use, ImportScope},
+    mod_path_to_ast,
 };
 use syntax::{
     ast::{self, make},
diff --git a/crates/ide_assists/src/handlers/unwrap_result_return_type.rs b/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
index b890462389..82499d77c3 100644
--- a/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
+++ b/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
@@ -1,7 +1,4 @@
-use ide_db::{
-    famous_defs::FamousDefs,
-    syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
-};
+use ide_db::helpers::{for_each_tail_expr, node_ext::walk_expr, FamousDefs};
 use itertools::Itertools;
 use syntax::{
     ast::{self, Expr},
diff --git a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
index 972d4765bb..c510a5f965 100644
--- a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
+++ b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
@@ -1,9 +1,6 @@
 use std::iter;
 
-use ide_db::{
-    famous_defs::FamousDefs,
-    syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
-};
+use ide_db::helpers::{for_each_tail_expr, node_ext::walk_expr, FamousDefs};
 use syntax::{
     ast::{self, make, Expr},
     match_ast, AstNode,
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 42317ea4da..116f150ef2 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -6,7 +6,9 @@ use itertools::Itertools;
 
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{db::HirDatabase, HirDisplay, Semantics};
-use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
+use ide_db::{
+    helpers::FamousDefs, helpers::SnippetCap, path_transform::PathTransform, RootDatabase,
+};
 use stdx::format_to;
 use syntax::{
     ast::{
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index eb287847be..cb45d9de03 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -3,10 +3,12 @@
 //! This module uses a bit of static metadata to provide completions for builtin-in attributes and lints.
 
 use ide_db::{
-    generated::lints::{
-        Lint, CLIPPY_LINTS, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, FEATURES, RUSTDOC_LINTS,
+    helpers::{
+        generated_lints::{
+            Lint, CLIPPY_LINTS, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, FEATURES, RUSTDOC_LINTS,
+        },
+        parse_tt_as_comma_sep_paths,
     },
-    syntax_helpers::node_ext::parse_tt_as_comma_sep_paths,
     SymbolKind,
 };
 use itertools::Itertools;
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index cbd0050085..29fe096e13 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -1,7 +1,7 @@
 //! Completion for derives
 use hir::{HasAttrs, MacroDef, MacroKind};
 use ide_db::{
-    imports::{import_assets::ImportAssets, insert_use::ImportScope},
+    helpers::{import_assets::ImportAssets, insert_use::ImportScope},
     SymbolKind,
 };
 use itertools::Itertools;
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
index 8991d657e8..e2477423a2 100644
--- a/crates/ide_completion/src/completions/attribute/lint.rs
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -1,5 +1,5 @@
 //! Completion for lints
-use ide_db::{generated::lints::Lint, SymbolKind};
+use ide_db::{helpers::generated_lints::Lint, SymbolKind};
 use syntax::{ast, T};
 
 use crate::{context::CompletionContext, item::CompletionItem, Completions};
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 0a06e09bac..723abd62ae 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,6 +1,6 @@
 //! See [`import_on_the_fly`].
 use hir::ItemInNs;
-use ide_db::imports::{
+use ide_db::helpers::{
     import_assets::{ImportAssets, ImportCandidate, LocatedImport},
     insert_use::ImportScope,
 };
diff --git a/crates/ide_completion/src/completions/format_string.rs b/crates/ide_completion/src/completions/format_string.rs
index f0c994f6b6..87052d020a 100644
--- a/crates/ide_completion/src/completions/format_string.rs
+++ b/crates/ide_completion/src/completions/format_string.rs
@@ -1,6 +1,6 @@
 //! Completes identifiers in format string literals.
 
-use ide_db::syntax_helpers::format_string::is_format_string;
+use ide_db::helpers::format_string::is_format_string;
 use itertools::Itertools;
 use syntax::{ast, AstToken, TextRange, TextSize};
 
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 23d4310aa9..e8e0c7ea9f 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -3,7 +3,10 @@
 mod format_like;
 
 use hir::{Documentation, HasAttrs};
-use ide_db::{imports::insert_use::ImportScope, ty_filter::TryEnum, SnippetCap};
+use ide_db::{
+    helpers::{insert_use::ImportScope, SnippetCap},
+    ty_filter::TryEnum,
+};
 use syntax::{
     ast::{self, AstNode, AstToken},
     SyntaxKind::{EXPR_STMT, STMT_LIST},
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs
index b5ef87b881..8098045b1e 100644
--- a/crates/ide_completion/src/completions/postfix/format_like.rs
+++ b/crates/ide_completion/src/completions/postfix/format_like.rs
@@ -16,7 +16,7 @@
 //
 // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
 
-use ide_db::SnippetCap;
+use ide_db::helpers::SnippetCap;
 use syntax::ast::{self, AstToken};
 
 use crate::{
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index e4c4899477..9a2b9c2fa4 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -1,7 +1,7 @@
 //! This file provides snippet completions, like `pd` => `eprintln!(...)`.
 
 use hir::Documentation;
-use ide_db::{imports::insert_use::ImportScope, SnippetCap};
+use ide_db::helpers::{insert_use::ImportScope, SnippetCap};
 use syntax::T;
 
 use crate::{
diff --git a/crates/ide_completion/src/config.rs b/crates/ide_completion/src/config.rs
index 302836dd1e..c4e91e7283 100644
--- a/crates/ide_completion/src/config.rs
+++ b/crates/ide_completion/src/config.rs
@@ -4,7 +4,7 @@
 //! module, and we use to statically check that we only produce snippet
 //! completions if we are allowed to.
 
-use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
+use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
 
 use crate::snippet::Snippet;
 
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index da80224dd8..c4e145ffcb 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -9,7 +9,7 @@ use hir::{
 use ide_db::{
     active_parameter::ActiveParameter,
     base_db::{FilePosition, SourceDatabase},
-    famous_defs::FamousDefs,
+    helpers::FamousDefs,
     RootDatabase,
 };
 use syntax::{
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 4b9f7d17c3..32b14764a1 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -4,12 +4,12 @@ use std::fmt;
 
 use hir::{Documentation, Mutability};
 use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::{
+    helpers::{
         import_assets::LocatedImport,
         insert_use::{self, ImportScope, InsertUseConfig},
+        mod_path_to_ast, SnippetCap,
     },
-    SnippetCap, SymbolKind,
+    SymbolKind,
 };
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 3225a0bc9f..9f6f6592de 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -14,10 +14,10 @@ mod snippet;
 use completions::flyimport::position_for_import;
 use ide_db::{
     base_db::FilePosition,
-    helpers::mod_path_to_ast,
-    imports::{
+    helpers::{
         import_assets::NameToImport,
         insert_use::{self, ImportScope},
+        mod_path_to_ast,
     },
     items_locator, RootDatabase,
 };
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 1836f80bfb..d5618f1474 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -12,7 +12,10 @@ pub(crate) mod struct_literal;
 mod builder_ext;
 
 use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
-use ide_db::{helpers::item_name, RootDatabase, SnippetCap, SymbolKind};
+use ide_db::{
+    helpers::{item_name, SnippetCap},
+    RootDatabase, SymbolKind,
+};
 use syntax::{SmolStr, SyntaxKind, TextRange};
 
 use crate::{
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index c2d51b1252..68e29246d7 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -1,7 +1,7 @@
 //! Renderer for patterns.
 
 use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
-use ide_db::SnippetCap;
+use ide_db::helpers::SnippetCap;
 use itertools::Itertools;
 use syntax::SmolStr;
 
diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs
index 3bc94fa782..a3d4bcf29e 100644
--- a/crates/ide_completion/src/render/struct_literal.rs
+++ b/crates/ide_completion/src/render/struct_literal.rs
@@ -1,7 +1,7 @@
 //! Renderer for `struct` literal.
 
 use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
-use ide_db::SnippetCap;
+use ide_db::helpers::SnippetCap;
 use itertools::Itertools;
 use syntax::SmolStr;
 
diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs
index 05b066a0a9..3a4f713333 100644
--- a/crates/ide_completion/src/snippet.rs
+++ b/crates/ide_completion/src/snippet.rs
@@ -102,7 +102,7 @@ use std::ops::Deref;
 // }
 // ----
 
-use ide_db::imports::{import_assets::LocatedImport, insert_use::ImportScope};
+use ide_db::helpers::{import_assets::LocatedImport, insert_use::ImportScope};
 use itertools::Itertools;
 use syntax::{ast, AstNode, GreenNode, SyntaxNode};
 
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index c83193580f..9d05db4a77 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -150,9 +150,9 @@ impl IdentClass {
         sema: &Semantics<RootDatabase>,
         lifetime: &ast::Lifetime,
     ) -> Option<IdentClass> {
-        NameRefClass::classify_lifetime(sema, &lifetime)
-            .map(IdentClass::NameRefClass)
-            .or_else(|| NameClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameClass))
+        NameClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameClass).or_else(|| {
+            NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)
+        })
     }
 
     pub fn definitions(self) -> ArrayVec<Definition, 2> {
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 1e3d68b321..4a14a7f849 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -1,15 +1,28 @@
-//! Random assortment of ide helpers for high-level ide features that don't fit in any other module.
+//! A module with ide helpers for high-level ide features.
+pub mod famous_defs;
+pub mod generated_lints;
+pub mod import_assets;
+pub mod insert_use;
+pub mod merge_imports;
+pub mod insert_whitespace_into_node;
+pub mod node_ext;
+pub mod rust_doc;
+pub mod format_string;
 
 use std::collections::VecDeque;
 
 use base_db::FileId;
 use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
+use itertools::Itertools;
 use syntax::{
-    ast::{self, make},
-    AstToken, SyntaxKind, SyntaxToken, TokenAtOffset,
+    ast::{self, make, HasLoopBody},
+    AstNode, AstToken, Preorder, RustLanguage, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
+    T,
 };
 
-use crate::{defs::Definition, generated, RootDatabase};
+use crate::{defs::Definition, RootDatabase};
+
+pub use self::famous_defs::FamousDefs;
 
 pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
     match item {
@@ -78,16 +91,216 @@ pub fn visit_file_defs(
     module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SnippetCap {
+    _private: (),
+}
+
+impl SnippetCap {
+    pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
+        if allow_snippets {
+            Some(SnippetCap { _private: () })
+        } else {
+            None
+        }
+    }
+}
+
+/// Calls `cb` on each expression inside `expr` that is at "tail position".
+/// Does not walk into `break` or `return` expressions.
+/// Note that modifying the tree while iterating it will cause undefined iteration which might
+/// potentially results in an out of bounds panic.
+pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
+    match expr {
+        ast::Expr::BlockExpr(b) => {
+            match b.modifier() {
+                Some(
+                    ast::BlockModifier::Async(_)
+                    | ast::BlockModifier::Try(_)
+                    | ast::BlockModifier::Const(_),
+                ) => return cb(expr),
+
+                Some(ast::BlockModifier::Label(label)) => {
+                    for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
+                        cb(&ast::Expr::BreakExpr(b))
+                    });
+                }
+                Some(ast::BlockModifier::Unsafe(_)) => (),
+                None => (),
+            }
+            if let Some(stmt_list) = b.stmt_list() {
+                if let Some(e) = stmt_list.tail_expr() {
+                    for_each_tail_expr(&e, cb);
+                }
+            }
+        }
+        ast::Expr::IfExpr(if_) => {
+            let mut if_ = if_.clone();
+            loop {
+                if let Some(block) = if_.then_branch() {
+                    for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
+                }
+                match if_.else_branch() {
+                    Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
+                    Some(ast::ElseBranch::Block(block)) => {
+                        for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
+                        break;
+                    }
+                    None => break,
+                }
+            }
+        }
+        ast::Expr::LoopExpr(l) => {
+            for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
+                cb(&ast::Expr::BreakExpr(b))
+            })
+        }
+        ast::Expr::MatchExpr(m) => {
+            if let Some(arms) = m.match_arm_list() {
+                arms.arms().filter_map(|arm| arm.expr()).for_each(|e| for_each_tail_expr(&e, cb));
+            }
+        }
+        ast::Expr::ArrayExpr(_)
+        | ast::Expr::AwaitExpr(_)
+        | ast::Expr::BinExpr(_)
+        | ast::Expr::BoxExpr(_)
+        | ast::Expr::BreakExpr(_)
+        | ast::Expr::CallExpr(_)
+        | ast::Expr::CastExpr(_)
+        | ast::Expr::ClosureExpr(_)
+        | ast::Expr::ContinueExpr(_)
+        | ast::Expr::FieldExpr(_)
+        | ast::Expr::ForExpr(_)
+        | ast::Expr::IndexExpr(_)
+        | ast::Expr::Literal(_)
+        | ast::Expr::MacroCall(_)
+        | ast::Expr::MacroStmts(_)
+        | ast::Expr::MethodCallExpr(_)
+        | ast::Expr::ParenExpr(_)
+        | ast::Expr::PathExpr(_)
+        | ast::Expr::PrefixExpr(_)
+        | ast::Expr::RangeExpr(_)
+        | ast::Expr::RecordExpr(_)
+        | ast::Expr::RefExpr(_)
+        | ast::Expr::ReturnExpr(_)
+        | ast::Expr::TryExpr(_)
+        | ast::Expr::TupleExpr(_)
+        | ast::Expr::WhileExpr(_)
+        | ast::Expr::LetExpr(_)
+        | ast::Expr::UnderscoreExpr(_)
+        | ast::Expr::YieldExpr(_) => cb(expr),
+    }
+}
+
+pub fn for_each_break_and_continue_expr(
+    label: Option<ast::Label>,
+    body: Option<ast::StmtList>,
+    cb: &mut dyn FnMut(ast::Expr),
+) {
+    let label = label.and_then(|lbl| lbl.lifetime());
+    if let Some(b) = body {
+        let tree_depth_iterator = TreeWithDepthIterator::new(b);
+        for (expr, depth) in tree_depth_iterator {
+            match expr {
+                ast::Expr::BreakExpr(b)
+                    if (depth == 0 && b.lifetime().is_none())
+                        || eq_label_lt(&label, &b.lifetime()) =>
+                {
+                    cb(ast::Expr::BreakExpr(b));
+                }
+                ast::Expr::ContinueExpr(c)
+                    if (depth == 0 && c.lifetime().is_none())
+                        || eq_label_lt(&label, &c.lifetime()) =>
+                {
+                    cb(ast::Expr::ContinueExpr(c));
+                }
+                _ => (),
+            }
+        }
+    }
+}
+
+fn for_each_break_expr(
+    label: Option<ast::Label>,
+    body: Option<ast::StmtList>,
+    cb: &mut dyn FnMut(ast::BreakExpr),
+) {
+    let label = label.and_then(|lbl| lbl.lifetime());
+    if let Some(b) = body {
+        let tree_depth_iterator = TreeWithDepthIterator::new(b);
+        for (expr, depth) in tree_depth_iterator {
+            match expr {
+                ast::Expr::BreakExpr(b)
+                    if (depth == 0 && b.lifetime().is_none())
+                        || eq_label_lt(&label, &b.lifetime()) =>
+                {
+                    cb(b);
+                }
+                _ => (),
+            }
+        }
+    }
+}
+
+fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
+    lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
+}
+
+struct TreeWithDepthIterator {
+    preorder: Preorder<RustLanguage>,
+    depth: u32,
+}
+
+impl TreeWithDepthIterator {
+    fn new(body: ast::StmtList) -> Self {
+        let preorder = body.syntax().preorder();
+        Self { preorder, depth: 0 }
+    }
+}
+
+impl<'a> Iterator for TreeWithDepthIterator {
+    type Item = (ast::Expr, u32);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        while let Some(event) = self.preorder.find_map(|ev| match ev {
+            WalkEvent::Enter(it) => ast::Expr::cast(it).map(WalkEvent::Enter),
+            WalkEvent::Leave(it) => ast::Expr::cast(it).map(WalkEvent::Leave),
+        }) {
+            match event {
+                WalkEvent::Enter(
+                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
+                ) => {
+                    self.depth += 1;
+                }
+                WalkEvent::Leave(
+                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
+                ) => {
+                    self.depth -= 1;
+                }
+                WalkEvent::Enter(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
+                    self.depth += 1;
+                }
+                WalkEvent::Leave(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
+                    self.depth -= 1;
+                }
+                WalkEvent::Enter(expr) => return Some((expr, self.depth)),
+                _ => (),
+            }
+        }
+        None
+    }
+}
+
 /// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
 pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
     if lint == lint_is {
         return true;
     }
 
-    if let Some(group) = generated::lints::DEFAULT_LINT_GROUPS
+    if let Some(group) = generated_lints::DEFAULT_LINT_GROUPS
         .iter()
-        .chain(generated::lints::CLIPPY_LINT_GROUPS.iter())
-        .chain(generated::lints::RUSTDOC_LINT_GROUPS.iter())
+        .chain(generated_lints::CLIPPY_LINT_GROUPS.iter())
+        .chain(generated_lints::RUSTDOC_LINT_GROUPS.iter())
         .find(|&check| check.lint.label == lint_is)
     {
         group.children.contains(&lint)
@@ -95,3 +308,30 @@ pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
         false
     }
 }
+
+/// Parses the input token tree as comma separated plain paths.
+pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
+    let r_paren = input.r_paren_token();
+    let tokens =
+        input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
+            // seeing a keyword means the attribute is unclosed so stop parsing here
+            Some(tok) if tok.kind().is_keyword() => None,
+            // don't include the right token tree parenthesis if it exists
+            tok @ Some(_) if tok == r_paren => None,
+            // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
+            None => None,
+            Some(tok) => Some(tok),
+        });
+    let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
+    let paths = input_expressions
+        .into_iter()
+        .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
+        .filter_map(|mut tokens| {
+            syntax::hacks::parse_expr_from_str(&tokens.join("")).and_then(|expr| match expr {
+                ast::Expr::PathExpr(it) => it.path(),
+                _ => None,
+            })
+        })
+        .collect();
+    Some(paths)
+}
diff --git a/crates/ide_db/src/famous_defs.rs b/crates/ide_db/src/helpers/famous_defs.rs
similarity index 100%
rename from crates/ide_db/src/famous_defs.rs
rename to crates/ide_db/src/helpers/famous_defs.rs
diff --git a/crates/ide_db/src/syntax_helpers/format_string.rs b/crates/ide_db/src/helpers/format_string.rs
similarity index 100%
rename from crates/ide_db/src/syntax_helpers/format_string.rs
rename to crates/ide_db/src/helpers/format_string.rs
diff --git a/crates/ide_db/src/generated/lints.rs b/crates/ide_db/src/helpers/generated_lints.rs
similarity index 100%
rename from crates/ide_db/src/generated/lints.rs
rename to crates/ide_db/src/helpers/generated_lints.rs
diff --git a/crates/ide_db/src/imports/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
similarity index 99%
rename from crates/ide_db/src/imports/import_assets.rs
rename to crates/ide_db/src/helpers/import_assets.rs
index 3c63f65fce..d91627e0a9 100644
--- a/crates/ide_db/src/imports/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -12,11 +12,12 @@ use syntax::{
 };
 
 use crate::{
-    helpers::item_name,
     items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
     RootDatabase,
 };
 
+use super::item_name;
+
 /// A candidate for import, derived during various IDE activities:
 /// * completion with imports on the fly proposals
 /// * completion edit resolve requests
diff --git a/crates/ide_db/src/imports/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
similarity index 99%
rename from crates/ide_db/src/imports/insert_use.rs
rename to crates/ide_db/src/helpers/insert_use.rs
index 9e39c26b45..efb704b253 100644
--- a/crates/ide_db/src/imports/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -12,7 +12,7 @@ use syntax::{
 };
 
 use crate::{
-    imports::merge_imports::{
+    helpers::merge_imports::{
         common_prefix, eq_attrs, eq_visibility, try_merge_imports, use_tree_path_cmp, MergeBehavior,
     },
     RootDatabase,
diff --git a/crates/ide_db/src/imports/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
similarity index 100%
rename from crates/ide_db/src/imports/insert_use/tests.rs
rename to crates/ide_db/src/helpers/insert_use/tests.rs
diff --git a/crates/ide_db/src/syntax_helpers/insert_whitespace_into_node.rs b/crates/ide_db/src/helpers/insert_whitespace_into_node.rs
similarity index 100%
rename from crates/ide_db/src/syntax_helpers/insert_whitespace_into_node.rs
rename to crates/ide_db/src/helpers/insert_whitespace_into_node.rs
diff --git a/crates/ide_db/src/imports/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
similarity index 99%
rename from crates/ide_db/src/imports/merge_imports.rs
rename to crates/ide_db/src/helpers/merge_imports.rs
index 71859b7fc7..dfaf578cb1 100644
--- a/crates/ide_db/src/imports/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -7,7 +7,7 @@ use syntax::{
     ted,
 };
 
-use crate::syntax_helpers::node_ext::vis_eq;
+use crate::helpers::node_ext::vis_eq;
 
 /// What type of merges are allowed.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/crates/ide_db/src/syntax_helpers/node_ext.rs b/crates/ide_db/src/helpers/node_ext.rs
similarity index 54%
rename from crates/ide_db/src/syntax_helpers/node_ext.rs
rename to crates/ide_db/src/helpers/node_ext.rs
index 115d83c6e2..5df3ed1366 100644
--- a/crates/ide_db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide_db/src/helpers/node_ext.rs
@@ -1,9 +1,7 @@
 //! Various helper functions to work with SyntaxNodes.
-use itertools::Itertools;
-use parser::T;
 use syntax::{
-    ast::{self, HasLoopBody, PathSegmentKind, VisibilityKind},
-    AstNode, Preorder, RustLanguage, WalkEvent,
+    ast::{self, PathSegmentKind, VisibilityKind},
+    AstNode, WalkEvent,
 };
 
 pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
@@ -244,215 +242,3 @@ pub fn is_pattern_cond(expr: ast::Expr) -> bool {
         _ => false,
     }
 }
-
-/// Calls `cb` on each expression inside `expr` that is at "tail position".
-/// Does not walk into `break` or `return` expressions.
-/// Note that modifying the tree while iterating it will cause undefined iteration which might
-/// potentially results in an out of bounds panic.
-pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
-    match expr {
-        ast::Expr::BlockExpr(b) => {
-            match b.modifier() {
-                Some(
-                    ast::BlockModifier::Async(_)
-                    | ast::BlockModifier::Try(_)
-                    | ast::BlockModifier::Const(_),
-                ) => return cb(expr),
-
-                Some(ast::BlockModifier::Label(label)) => {
-                    for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
-                        cb(&ast::Expr::BreakExpr(b))
-                    });
-                }
-                Some(ast::BlockModifier::Unsafe(_)) => (),
-                None => (),
-            }
-            if let Some(stmt_list) = b.stmt_list() {
-                if let Some(e) = stmt_list.tail_expr() {
-                    for_each_tail_expr(&e, cb);
-                }
-            }
-        }
-        ast::Expr::IfExpr(if_) => {
-            let mut if_ = if_.clone();
-            loop {
-                if let Some(block) = if_.then_branch() {
-                    for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
-                }
-                match if_.else_branch() {
-                    Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
-                    Some(ast::ElseBranch::Block(block)) => {
-                        for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
-                        break;
-                    }
-                    None => break,
-                }
-            }
-        }
-        ast::Expr::LoopExpr(l) => {
-            for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
-                cb(&ast::Expr::BreakExpr(b))
-            })
-        }
-        ast::Expr::MatchExpr(m) => {
-            if let Some(arms) = m.match_arm_list() {
-                arms.arms().filter_map(|arm| arm.expr()).for_each(|e| for_each_tail_expr(&e, cb));
-            }
-        }
-        ast::Expr::ArrayExpr(_)
-        | ast::Expr::AwaitExpr(_)
-        | ast::Expr::BinExpr(_)
-        | ast::Expr::BoxExpr(_)
-        | ast::Expr::BreakExpr(_)
-        | ast::Expr::CallExpr(_)
-        | ast::Expr::CastExpr(_)
-        | ast::Expr::ClosureExpr(_)
-        | ast::Expr::ContinueExpr(_)
-        | ast::Expr::FieldExpr(_)
-        | ast::Expr::ForExpr(_)
-        | ast::Expr::IndexExpr(_)
-        | ast::Expr::Literal(_)
-        | ast::Expr::MacroCall(_)
-        | ast::Expr::MacroStmts(_)
-        | ast::Expr::MethodCallExpr(_)
-        | ast::Expr::ParenExpr(_)
-        | ast::Expr::PathExpr(_)
-        | ast::Expr::PrefixExpr(_)
-        | ast::Expr::RangeExpr(_)
-        | ast::Expr::RecordExpr(_)
-        | ast::Expr::RefExpr(_)
-        | ast::Expr::ReturnExpr(_)
-        | ast::Expr::TryExpr(_)
-        | ast::Expr::TupleExpr(_)
-        | ast::Expr::WhileExpr(_)
-        | ast::Expr::LetExpr(_)
-        | ast::Expr::UnderscoreExpr(_)
-        | ast::Expr::YieldExpr(_) => cb(expr),
-    }
-}
-
-pub fn for_each_break_and_continue_expr(
-    label: Option<ast::Label>,
-    body: Option<ast::StmtList>,
-    cb: &mut dyn FnMut(ast::Expr),
-) {
-    let label = label.and_then(|lbl| lbl.lifetime());
-    if let Some(b) = body {
-        let tree_depth_iterator = TreeWithDepthIterator::new(b);
-        for (expr, depth) in tree_depth_iterator {
-            match expr {
-                ast::Expr::BreakExpr(b)
-                    if (depth == 0 && b.lifetime().is_none())
-                        || eq_label_lt(&label, &b.lifetime()) =>
-                {
-                    cb(ast::Expr::BreakExpr(b));
-                }
-                ast::Expr::ContinueExpr(c)
-                    if (depth == 0 && c.lifetime().is_none())
-                        || eq_label_lt(&label, &c.lifetime()) =>
-                {
-                    cb(ast::Expr::ContinueExpr(c));
-                }
-                _ => (),
-            }
-        }
-    }
-}
-
-fn for_each_break_expr(
-    label: Option<ast::Label>,
-    body: Option<ast::StmtList>,
-    cb: &mut dyn FnMut(ast::BreakExpr),
-) {
-    let label = label.and_then(|lbl| lbl.lifetime());
-    if let Some(b) = body {
-        let tree_depth_iterator = TreeWithDepthIterator::new(b);
-        for (expr, depth) in tree_depth_iterator {
-            match expr {
-                ast::Expr::BreakExpr(b)
-                    if (depth == 0 && b.lifetime().is_none())
-                        || eq_label_lt(&label, &b.lifetime()) =>
-                {
-                    cb(b);
-                }
-                _ => (),
-            }
-        }
-    }
-}
-
-fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
-    lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
-}
-
-struct TreeWithDepthIterator {
-    preorder: Preorder<RustLanguage>,
-    depth: u32,
-}
-
-impl TreeWithDepthIterator {
-    fn new(body: ast::StmtList) -> Self {
-        let preorder = body.syntax().preorder();
-        Self { preorder, depth: 0 }
-    }
-}
-
-impl<'a> Iterator for TreeWithDepthIterator {
-    type Item = (ast::Expr, u32);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        while let Some(event) = self.preorder.find_map(|ev| match ev {
-            WalkEvent::Enter(it) => ast::Expr::cast(it).map(WalkEvent::Enter),
-            WalkEvent::Leave(it) => ast::Expr::cast(it).map(WalkEvent::Leave),
-        }) {
-            match event {
-                WalkEvent::Enter(
-                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
-                ) => {
-                    self.depth += 1;
-                }
-                WalkEvent::Leave(
-                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
-                ) => {
-                    self.depth -= 1;
-                }
-                WalkEvent::Enter(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
-                    self.depth += 1;
-                }
-                WalkEvent::Leave(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
-                    self.depth -= 1;
-                }
-                WalkEvent::Enter(expr) => return Some((expr, self.depth)),
-                _ => (),
-            }
-        }
-        None
-    }
-}
-
-/// Parses the input token tree as comma separated plain paths.
-pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
-    let r_paren = input.r_paren_token();
-    let tokens =
-        input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
-            // seeing a keyword means the attribute is unclosed so stop parsing here
-            Some(tok) if tok.kind().is_keyword() => None,
-            // don't include the right token tree parenthesis if it exists
-            tok @ Some(_) if tok == r_paren => None,
-            // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
-            None => None,
-            Some(tok) => Some(tok),
-        });
-    let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
-    let paths = input_expressions
-        .into_iter()
-        .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
-        .filter_map(|mut tokens| {
-            syntax::hacks::parse_expr_from_str(&tokens.join("")).and_then(|expr| match expr {
-                ast::Expr::PathExpr(it) => it.path(),
-                _ => None,
-            })
-        })
-        .collect();
-    Some(paths)
-}
diff --git a/crates/ide_db/src/rust_doc.rs b/crates/ide_db/src/helpers/rust_doc.rs
similarity index 100%
rename from crates/ide_db/src/rust_doc.rs
rename to crates/ide_db/src/helpers/rust_doc.rs
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs
index 891b7c8e92..db38a48783 100644
--- a/crates/ide_db/src/items_locator.rs
+++ b/crates/ide_db/src/items_locator.rs
@@ -13,7 +13,7 @@ use syntax::{ast, AstNode, SyntaxKind::NAME};
 
 use crate::{
     defs::{Definition, NameClass},
-    imports::import_assets::NameToImport,
+    helpers::import_assets::NameToImport,
     symbol_index, RootDatabase,
 };
 
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index b11b70d127..3f64c0a124 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -4,38 +4,21 @@
 
 mod apply_change;
 
-pub mod active_parameter;
 pub mod assists;
-pub mod defs;
-pub mod famous_defs;
-pub mod helpers;
-pub mod items_locator;
 pub mod label;
 pub mod line_index;
-pub mod path_transform;
-pub mod rename;
-pub mod rust_doc;
-pub mod search;
-pub mod source_change;
 pub mod symbol_index;
-pub mod traits;
+pub mod defs;
+pub mod items_locator;
+pub mod source_change;
 pub mod ty_filter;
+pub mod traits;
+pub mod helpers;
+pub mod path_transform;
 
-pub mod imports {
-    pub mod import_assets;
-    pub mod insert_use;
-    pub mod merge_imports;
-}
-
-pub mod generated {
-    pub mod lints;
-}
-
-pub mod syntax_helpers {
-    pub mod node_ext;
-    pub mod insert_whitespace_into_node;
-    pub mod format_string;
-}
+pub mod search;
+pub mod rename;
+pub mod active_parameter;
 
 use std::{fmt, mem::ManuallyDrop, sync::Arc};
 
@@ -59,14 +42,14 @@ pub type FxIndexMap<K, V> =
     indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
 
 #[salsa::database(
-    base_db::SourceDatabaseExtStorage,
     base_db::SourceDatabaseStorage,
+    base_db::SourceDatabaseExtStorage,
+    LineIndexDatabaseStorage,
+    symbol_index::SymbolsDatabaseStorage,
+    hir::db::InternDatabaseStorage,
     hir::db::AstDatabaseStorage,
     hir::db::DefDatabaseStorage,
-    hir::db::HirDatabaseStorage,
-    hir::db::InternDatabaseStorage,
-    LineIndexDatabaseStorage,
-    symbol_index::SymbolsDatabaseStorage
+    hir::db::HirDatabaseStorage
 )]
 pub struct RootDatabase {
     // We use `ManuallyDrop` here because every codegen unit that contains a
@@ -78,7 +61,9 @@ pub struct RootDatabase {
 
 impl Drop for RootDatabase {
     fn drop(&mut self) {
-        unsafe { ManuallyDrop::drop(&mut self.storage) };
+        unsafe {
+            ManuallyDrop::drop(&mut self.storage);
+        }
     }
 }
 
@@ -132,7 +117,7 @@ impl RootDatabase {
         db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
         db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
         db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
-        db.set_enable_proc_attr_macros(false);
+        db.set_enable_proc_attr_macros(Default::default());
         db.update_lru_capacity(lru_capacity);
         db
     }
@@ -219,21 +204,6 @@ impl From<FileSymbolKind> for SymbolKind {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct SnippetCap {
-    _private: (),
-}
-
-impl SnippetCap {
-    pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
-        if allow_snippets {
-            Some(SnippetCap { _private: () })
-        } else {
-            None
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     mod sourcegen_lints;
diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs
index 68ad07ee83..35e1757eae 100644
--- a/crates/ide_db/src/line_index.rs
+++ b/crates/ide_db/src/line_index.rs
@@ -1,6 +1,6 @@
 //! `LineIndex` maps flat `TextSize` offsets into `(Line, Column)`
 //! representation.
-use std::{iter, mem};
+use std::iter;
 
 use rustc_hash::FxHashMap;
 use syntax::{TextRange, TextSize};
@@ -59,7 +59,8 @@ impl LineIndex {
         let mut utf16_chars = Vec::new();
 
         let mut newlines = vec![0.into()];
-        let mut curr_row @ mut curr_col = 0.into();
+        let mut curr_row = 0.into();
+        let mut curr_col = 0.into();
         let mut line = 0;
         for c in text.chars() {
             let c_len = TextSize::of(c);
@@ -69,7 +70,8 @@ impl LineIndex {
 
                 // Save any utf-16 characters seen in the previous line
                 if !utf16_chars.is_empty() {
-                    utf16_lines.insert(line, mem::take(&mut utf16_chars));
+                    utf16_lines.insert(line, utf16_chars);
+                    utf16_chars = Vec::new();
                 }
 
                 // Prepare for processing the next line
@@ -163,138 +165,4 @@ impl LineIndex {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_line_index() {
-        let text = "hello\nworld";
-        let table = [
-            (00, 0, 0),
-            (01, 0, 1),
-            (05, 0, 5),
-            (06, 1, 0),
-            (07, 1, 1),
-            (08, 1, 2),
-            (10, 1, 4),
-            (11, 1, 5),
-            (12, 1, 6),
-        ];
-
-        let index = LineIndex::new(text);
-        for &(offset, line, col) in &table {
-            assert_eq!(index.line_col(offset.into()), LineCol { line, col });
-        }
-
-        let text = "\nhello\nworld";
-        let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)];
-        let index = LineIndex::new(text);
-        for &(offset, line, col) in &table {
-            assert_eq!(index.line_col(offset.into()), LineCol { line, col });
-        }
-    }
-
-    #[test]
-    fn test_char_len() {
-        assert_eq!('メ'.len_utf8(), 3);
-        assert_eq!('メ'.len_utf16(), 1);
-    }
-
-    #[test]
-    fn test_empty_index() {
-        let col_index = LineIndex::new(
-            "
-const C: char = 'x';
-",
-        );
-        assert_eq!(col_index.utf16_lines.len(), 0);
-    }
-
-    #[test]
-    fn test_single_char() {
-        let col_index = LineIndex::new(
-            "
-const C: char = 'メ';
-",
-        );
-
-        assert_eq!(col_index.utf16_lines.len(), 1);
-        assert_eq!(col_index.utf16_lines[&1].len(), 1);
-        assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
-
-        // UTF-8 to UTF-16, no changes
-        assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
-
-        // UTF-8 to UTF-16
-        assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
-
-        // UTF-16 to UTF-8, no changes
-        assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
-
-        // UTF-16 to UTF-8
-        assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
-
-        let col_index = LineIndex::new("a𐐏b");
-        assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
-    }
-
-    #[test]
-    fn test_string() {
-        let col_index = LineIndex::new(
-            "
-const C: char = \"メ メ\";
-",
-        );
-
-        assert_eq!(col_index.utf16_lines.len(), 1);
-        assert_eq!(col_index.utf16_lines[&1].len(), 2);
-        assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
-        assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
-
-        // UTF-8 to UTF-16
-        assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
-
-        assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
-        assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
-
-        assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
-
-        // UTF-16 to UTF-8
-        assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
-
-        // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
-        assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
-        assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
-        assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
-
-        assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
-    }
-
-    #[test]
-    fn test_splitlines() {
-        fn r(lo: u32, hi: u32) -> TextRange {
-            TextRange::new(lo.into(), hi.into())
-        }
-
-        let text = "a\nbb\nccc\n";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
-        let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
-        assert_eq!(actual, expected);
-
-        let text = "";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
-        let expected = vec![];
-        assert_eq!(actual, expected);
-
-        let text = "\n";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
-        let expected = vec![r(0, 1)];
-        assert_eq!(actual, expected)
-    }
-}
+mod tests;
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs
index 13234a817b..a44fe04e74 100644
--- a/crates/ide_db/src/rename.rs
+++ b/crates/ide_db/src/rename.rs
@@ -10,7 +10,7 @@
 //!
 //! Another can of worms are macros:
 //!
-//! ```ignore
+//! ```
 //! macro_rules! m { () => { fn f() {} } }
 //! m!();
 //! fn main() {
@@ -34,9 +34,9 @@ use text_edit::{TextEdit, TextEditBuilder};
 
 use crate::{
     defs::Definition,
+    helpers::node_ext::expr_as_name_ref,
     search::FileReference,
     source_change::{FileSystemEdit, SourceChange},
-    syntax_helpers::node_ext::expr_as_name_ref,
     RootDatabase,
 };
 
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs
index c8cb1a26a8..def7a8acaa 100644
--- a/crates/ide_db/src/traits.rs
+++ b/crates/ide_db/src/traits.rs
@@ -77,147 +77,4 @@ pub fn get_missing_assoc_items(
 }
 
 #[cfg(test)]
-mod tests {
-    use base_db::{fixture::ChangeFixture, FilePosition};
-    use expect_test::{expect, Expect};
-    use hir::Semantics;
-    use syntax::ast::{self, AstNode};
-
-    use crate::RootDatabase;
-
-    /// Creates analysis from a multi-file fixture, returns positions marked with $0.
-    pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
-        let change_fixture = ChangeFixture::parse(ra_fixture);
-        let mut database = RootDatabase::default();
-        database.apply_change(change_fixture.change);
-        let (file_id, range_or_offset) =
-            change_fixture.file_position.expect("expected a marker ($0)");
-        let offset = range_or_offset.expect_offset();
-        (database, FilePosition { file_id, offset })
-    }
-
-    fn check_trait(ra_fixture: &str, expect: Expect) {
-        let (db, position) = position(ra_fixture);
-        let sema = Semantics::new(&db);
-        let file = sema.parse(position.file_id);
-        let impl_block: ast::Impl =
-            sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
-        let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
-        let actual = match trait_ {
-            Some(trait_) => trait_.name(&db).to_string(),
-            None => String::new(),
-        };
-        expect.assert_eq(&actual);
-    }
-
-    fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
-        let (db, position) = position(ra_fixture);
-        let sema = Semantics::new(&db);
-        let file = sema.parse(position.file_id);
-        let impl_block: ast::Impl =
-            sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
-        let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
-        let actual = items
-            .into_iter()
-            .map(|item| item.name(&db).unwrap().to_string())
-            .collect::<Vec<_>>()
-            .join("\n");
-        expect.assert_eq(&actual);
-    }
-
-    #[test]
-    fn resolve_trait() {
-        check_trait(
-            r#"
-pub trait Foo {
-    fn bar();
-}
-impl Foo for u8 {
-    $0
-}
-            "#,
-            expect![["Foo"]],
-        );
-        check_trait(
-            r#"
-pub trait Foo {
-    fn bar();
-}
-impl Foo for u8 {
-    fn bar() {
-        fn baz() {
-            $0
-        }
-        baz();
-    }
-}
-            "#,
-            expect![["Foo"]],
-        );
-        check_trait(
-            r#"
-pub trait Foo {
-    fn bar();
-}
-pub struct Bar;
-impl Bar {
-    $0
-}
-            "#,
-            expect![[""]],
-        );
-    }
-
-    #[test]
-    fn missing_assoc_items() {
-        check_missing_assoc(
-            r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    $0
-}"#,
-            expect![[r#"
-                FOO
-                bar"#]],
-        );
-
-        check_missing_assoc(
-            r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    const FOO: u8 = 10;
-    $0
-}"#,
-            expect![[r#"
-                bar"#]],
-        );
-
-        check_missing_assoc(
-            r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    const FOO: u8 = 10;
-    fn bar() {$0}
-}"#,
-            expect![[r#""#]],
-        );
-
-        check_missing_assoc(
-            r#"
-pub struct Foo;
-impl Foo {
-    fn bar() {$0}
-}"#,
-            expect![[r#""#]],
-        );
-    }
-}
+mod tests;
diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index 8b3c22fffc..186bfc3d58 100644
--- a/crates/ide_diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -3,7 +3,7 @@ use hir::{
     db::{AstDatabase, HirDatabase},
     known, AssocItem, HirDisplay, InFile, Type,
 };
-use ide_db::{assists::Assist, famous_defs::FamousDefs, source_change::SourceChange};
+use ide_db::{assists::Assist, helpers::FamousDefs, source_change::SourceChange};
 use rustc_hash::FxHashMap;
 use stdx::format_to;
 use syntax::{
diff --git a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
index d5635ba8ba..74a7265464 100644
--- a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
@@ -1,7 +1,5 @@
 use hir::{db::AstDatabase, TypeInfo};
-use ide_db::{
-    assists::Assist, source_change::SourceChange, syntax_helpers::node_ext::for_each_tail_expr,
-};
+use ide_db::{assists::Assist, helpers::for_each_tail_expr, source_change::SourceChange};
 use syntax::AstNode;
 use text_edit::TextEdit;
 
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index dc6cf61f79..457399a618 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -115,7 +115,6 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         experimental: Some(json!({
             "externalDocs": true,
             "hoverRange": true,
-            "inlayHints": true,
             "joinLines": true,
             "matchingBrace": true,
             "moveItem": true,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1194fd9faf..af779ee000 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -14,8 +14,8 @@ use ide::{
     AssistConfig, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, HighlightRelatedConfig,
     HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig, Snippet, SnippetScope,
 };
-use ide_db::{
-    imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
+use ide_db::helpers::{
+    insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
     SnippetCap,
 };
 use lsp_types::{ClientCapabilities, MarkupKind};
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 249e861f9b..b45fbe698c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1318,22 +1318,11 @@ pub(crate) fn handle_inlay_hints(
     params: InlayHintsParams,
 ) -> Result<Vec<InlayHint>> {
     let _p = profile::span("handle_inlay_hints");
-    let document_uri = &params.text_document.uri;
-    let file_id = from_proto::file_id(&snap, document_uri)?;
+    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
-    let range = params
-        .range
-        .map(|range| {
-            from_proto::file_range(
-                &snap,
-                TextDocumentIdentifier::new(document_uri.to_owned()),
-                range,
-            )
-        })
-        .transpose()?;
     Ok(snap
         .analysis
-        .inlay_hints(&snap.config.inlay_hints(), file_id, range)?
+        .inlay_hints(&snap.config.inlay_hints(), file_id)?
         .into_iter()
         .map(|it| to_proto::inlay_hint(&line_index, it))
         .collect())
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index b1f8958e92..a910a910bb 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -13,8 +13,8 @@
 use std::sync::Arc;
 
 use ide::{Change, CompletionConfig, FilePosition, TextSize};
-use ide_db::{
-    imports::insert_use::{ImportGranularity, InsertUseConfig},
+use ide_db::helpers::{
+    insert_use::{ImportGranularity, InsertUseConfig},
     SnippetCap,
 };
 use project_model::CargoConfig;
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 846f151304..ea98d09935 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -233,34 +233,27 @@ pub enum InlayHints {}
 impl Request for InlayHints {
     type Params = InlayHintsParams;
     type Result = Vec<InlayHint>;
-    const METHOD: &'static str = "experimental/inlayHints";
+    const METHOD: &'static str = "rust-analyzer/inlayHints";
 }
 
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 pub struct InlayHintsParams {
     pub text_document: TextDocumentIdentifier,
-    pub range: Option<lsp_types::Range>,
 }
 
-#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize)]
-#[serde(transparent)]
-pub struct InlayHintKind(u8);
-
-impl InlayHintKind {
-    pub const TYPE: InlayHintKind = InlayHintKind(1);
-    pub const PARAMETER: InlayHintKind = InlayHintKind(2);
+#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
+pub enum InlayKind {
+    TypeHint,
+    ParameterHint,
+    ChainingHint,
 }
 
 #[derive(Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
 pub struct InlayHint {
+    pub range: Range,
+    pub kind: InlayKind,
     pub label: String,
-    pub position: Position,
-    pub kind: Option<InlayHintKind>,
-    pub tooltip: Option<String>,
-    pub padding_left: Option<bool>,
-    pub padding_right: Option<bool>,
 }
 
 pub enum Ssr {}
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index e1ff0f0178..59c904f86e 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -1,5 +1,5 @@
 //! Transforms markdown
-use ide_db::rust_doc::is_rust_fence;
+use ide_db::helpers::rust_doc::is_rust_fence;
 
 const RUSTDOC_FENCE: &str = "```";
 
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 7809d24dd6..4a2b3a1b47 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -415,33 +415,13 @@ pub(crate) fn signature_help(
 
 pub(crate) fn inlay_hint(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint {
     lsp_ext::InlayHint {
-        label: match inlay_hint.kind {
-            InlayKind::ParameterHint => format!("{}:", inlay_hint.label),
-            InlayKind::TypeHint => format!(": {}", inlay_hint.label),
-            InlayKind::ChainingHint => inlay_hint.label.to_string(),
-        },
-        position: match inlay_hint.kind {
-            InlayKind::ParameterHint => position(line_index, inlay_hint.range.start()),
-            InlayKind::TypeHint | InlayKind::ChainingHint => {
-                position(line_index, inlay_hint.range.end())
-            }
-        },
+        label: inlay_hint.label.to_string(),
+        range: range(line_index, inlay_hint.range),
         kind: match inlay_hint.kind {
-            InlayKind::ParameterHint => Some(lsp_ext::InlayHintKind::PARAMETER),
-            InlayKind::TypeHint => Some(lsp_ext::InlayHintKind::TYPE),
-            InlayKind::ChainingHint => None,
+            InlayKind::ParameterHint => lsp_ext::InlayKind::ParameterHint,
+            InlayKind::TypeHint => lsp_ext::InlayKind::TypeHint,
+            InlayKind::ChainingHint => lsp_ext::InlayKind::ChainingHint,
         },
-        tooltip: None,
-        padding_left: Some(match inlay_hint.kind {
-            InlayKind::TypeHint => false,
-            InlayKind::ParameterHint => false,
-            InlayKind::ChainingHint => true,
-        }),
-        padding_right: Some(match inlay_hint.kind {
-            InlayKind::TypeHint => false,
-            InlayKind::ParameterHint => true,
-            InlayKind::ChainingHint => false,
-        }),
     }
 }
 
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 9f1c7fe0a3..85df1188a8 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: e32fdde032ff6ebc
+lsp_ext.rs hash: 5b53b92c9f9d6650
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -562,11 +562,11 @@ Expands macro call at a given position.
 
 ## Inlay Hints
 
-**Method:** `experimental/inlayHints`
+**Method:** `rust-analyzer/inlayHints`
 
 This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types.
 Generally, the client should re-query inlay hints after every modification.
-Until it gets upstreamed, this follows the VS Code API.
+Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one.
 Upstream issues: https://github.com/microsoft/language-server-protocol/issues/956 , https://github.com/rust-analyzer/rust-analyzer/issues/2797
 
 **Request:**
@@ -581,12 +581,9 @@ interface InlayHintsParams {
 
 ```typescript
 interface InlayHint {
-    position: Position;
-    label: string | InlayHintLabelPart[];
-    tooltip?: string | MarkdownString | undefined;
-    kind?: InlayHintKind;
-    paddingLeft?: boolean;
-    paddingRight?: boolean;
+    kind: "TypeHint" | "ParameterHint" | "ChainingHint",
+    range: Range,
+    label: string,
 }
 ```
 
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index e8386607a0..3578c0d78a 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -473,7 +473,7 @@ You can follow instructions for installing <<rust-analyzer-language-server-binar
 == Troubleshooting
 
 Start with looking at the rust-analyzer version.
-Try **Rust Analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
+Try **Rust Analyzer: Show RA Version** in VS Code and `rust-analyzer --version` in the command line.
 If the date is more than a week ago, it's better to update rust-analyzer version.
 
 The next thing to check would be panic messages in rust-analyzer's log.
diff --git a/editors/code/.gitignore b/editors/code/.gitignore
index 2c975a947e..3acb6b3f62 100644
--- a/editors/code/.gitignore
+++ b/editors/code/.gitignore
@@ -3,5 +3,3 @@ node_modules
 server
 .vscode-test/
 *.vsix
-bundle
-vscode.proposed.d.ts
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index d2015b3bce..1f0c97ad27 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -11,34 +11,34 @@
             "dependencies": {
                 "d3": "^7.3.0",
                 "d3-graphviz": "^4.0.0",
-                "vscode-languageclient": "8.0.0-next.12"
+                "vscode-languageclient": "8.0.0-next.8"
             },
             "devDependencies": {
                 "@types/node": "~14.17.5",
-                "@types/vscode": "~1.65.0",
+                "@types/vscode": "~1.63.0",
                 "@typescript-eslint/eslint-plugin": "^5.10.0",
                 "@typescript-eslint/parser": "^5.10.0",
                 "@vscode/test-electron": "^2.1.1",
                 "esbuild": "^0.14.12",
-                "eslint": "^8.10.0",
+                "eslint": "^8.7.0",
                 "tslib": "^2.3.0",
                 "typescript": "^4.5.5",
                 "typescript-formatter": "^7.2.2",
-                "vsce": "^2.6.7"
+                "vsce": "^2.6.3"
             },
             "engines": {
-                "vscode": "^1.65.0"
+                "vscode": "^1.63.0"
             }
         },
         "node_modules/@eslint/eslintrc": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz",
-            "integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==",
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
+            "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==",
             "dev": true,
             "dependencies": {
                 "ajv": "^6.12.4",
                 "debug": "^4.3.2",
-                "espree": "^9.3.1",
+                "espree": "^9.2.0",
                 "globals": "^13.9.0",
                 "ignore": "^4.0.6",
                 "import-fresh": "^3.2.1",
@@ -141,9 +141,9 @@
             "dev": true
         },
         "node_modules/@types/vscode": {
-            "version": "1.65.0",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz",
-            "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==",
+            "version": "1.63.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.63.1.tgz",
+            "integrity": "sha512-Z+ZqjRcnGfHP86dvx/BtSwWyZPKQ/LBdmAVImY82TphyjOw2KgTKcp7Nx92oNwCTsHzlshwexAG/WiY2JuUm3g==",
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
@@ -1514,60 +1514,39 @@
             }
         },
         "node_modules/esbuild": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz",
-            "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.12.tgz",
+            "integrity": "sha512-o1vQkG+eSDLkWDqWfR8v6eI+byGAUkbRs30eAJcJxUFp3dwMGWR0tAjtam1Bb1RSS2j+4kAUFiuJTnW3J4CYcw==",
             "dev": true,
             "hasInstallScript": true,
             "bin": {
                 "esbuild": "bin/esbuild"
             },
-            "engines": {
-                "node": ">=12"
-            },
             "optionalDependencies": {
-                "esbuild-android-64": "0.14.25",
-                "esbuild-android-arm64": "0.14.25",
-                "esbuild-darwin-64": "0.14.25",
-                "esbuild-darwin-arm64": "0.14.25",
-                "esbuild-freebsd-64": "0.14.25",
-                "esbuild-freebsd-arm64": "0.14.25",
-                "esbuild-linux-32": "0.14.25",
-                "esbuild-linux-64": "0.14.25",
-                "esbuild-linux-arm": "0.14.25",
-                "esbuild-linux-arm64": "0.14.25",
-                "esbuild-linux-mips64le": "0.14.25",
-                "esbuild-linux-ppc64le": "0.14.25",
-                "esbuild-linux-riscv64": "0.14.25",
-                "esbuild-linux-s390x": "0.14.25",
-                "esbuild-netbsd-64": "0.14.25",
-                "esbuild-openbsd-64": "0.14.25",
-                "esbuild-sunos-64": "0.14.25",
-                "esbuild-windows-32": "0.14.25",
-                "esbuild-windows-64": "0.14.25",
-                "esbuild-windows-arm64": "0.14.25"
-            }
-        },
-        "node_modules/esbuild-android-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz",
-            "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==",
-            "cpu": [
-                "x64"
-            ],
-            "dev": true,
-            "optional": true,
-            "os": [
-                "android"
-            ],
-            "engines": {
-                "node": ">=12"
+                "esbuild-android-arm64": "0.14.12",
+                "esbuild-darwin-64": "0.14.12",
+                "esbuild-darwin-arm64": "0.14.12",
+                "esbuild-freebsd-64": "0.14.12",
+                "esbuild-freebsd-arm64": "0.14.12",
+                "esbuild-linux-32": "0.14.12",
+                "esbuild-linux-64": "0.14.12",
+                "esbuild-linux-arm": "0.14.12",
+                "esbuild-linux-arm64": "0.14.12",
+                "esbuild-linux-mips64le": "0.14.12",
+                "esbuild-linux-ppc64le": "0.14.12",
+                "esbuild-linux-s390x": "0.14.12",
+                "esbuild-netbsd-64": "0.14.12",
+                "esbuild-openbsd-64": "0.14.12",
+                "esbuild-sunos-64": "0.14.12",
+                "esbuild-windows-32": "0.14.12",
+                "esbuild-windows-64": "0.14.12",
+                "esbuild-windows-arm64": "0.14.12"
             }
         },
         "node_modules/esbuild-android-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz",
-            "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.12.tgz",
+            "integrity": "sha512-eO4JHwnTeJq1/xC9K0FdHNEYztwT0HaWHnOzR5kXKwJxHatxDNZ+lCHOSxMzh9uVSmnA8YwdSiXPWbwTlWZVrw==",
             "cpu": [
                 "arm64"
             ],
@@ -1575,15 +1554,12 @@
             "optional": true,
             "os": [
                 "android"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-darwin-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz",
-            "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.12.tgz",
+            "integrity": "sha512-LyZ81assnJWhq2IxKEVipwddKlXLTubbz/IObyKOm5cWS9jQCpuwQey2PpzroWSiy7QLGV8XCGWY5b8U8fsmWA==",
             "cpu": [
                 "x64"
             ],
@@ -1591,15 +1567,12 @@
             "optional": true,
             "os": [
                 "darwin"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-darwin-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz",
-            "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.12.tgz",
+            "integrity": "sha512-jj27iSbDS4KlftN1PHHNiTrtXPQIk11J/qpQiQLwKJpeEMNeJUBfQlS7X7dXgFFMxV0rNtcRl8AimEFl+qEMRQ==",
             "cpu": [
                 "arm64"
             ],
@@ -1607,15 +1580,12 @@
             "optional": true,
             "os": [
                 "darwin"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-freebsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz",
-            "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.12.tgz",
+            "integrity": "sha512-RnTty09bA8Ts/eWnrJsYiE2dFM6ZseKYQ/7QCM5QYphU6GbifooO9oGjc/UE3Sg8R58yZVO15vnIV0i+kTgDOw==",
             "cpu": [
                 "x64"
             ],
@@ -1623,15 +1593,12 @@
             "optional": true,
             "os": [
                 "freebsd"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-freebsd-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz",
-            "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.12.tgz",
+            "integrity": "sha512-AvAQoEgsHE53hucgoVWdHnXJBl0r9W/7eUCaBvpcgYu3W/EbPZ26VnZwfSXLpk0Pf3t7o6SRwrU+KDTKPscDTw==",
             "cpu": [
                 "arm64"
             ],
@@ -1639,15 +1606,12 @@
             "optional": true,
             "os": [
                 "freebsd"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-32": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz",
-            "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.12.tgz",
+            "integrity": "sha512-na4I5i2c9ACPuglfYmrnJ6qGQnFJb59dFjyFk5OHTCtoKCq3lXbGHrvYa+3sYlOrRax1kYuRDRGse7YsDLbr3Q==",
             "cpu": [
                 "ia32"
             ],
@@ -1655,15 +1619,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz",
-            "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.12.tgz",
+            "integrity": "sha512-ObPoYGakJLx/RldQsFQiwsQ7N9YbQ4LLazHtpKx34bjqFjhqO5JiHPVAJYCmAtci3cJMsZ5DtEFXvijytTBz1g==",
             "cpu": [
                 "x64"
             ],
@@ -1671,15 +1632,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-arm": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz",
-            "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.12.tgz",
+            "integrity": "sha512-tD4q/zVUeYkThGehYAJQElo80+ysxvq5vpd2QvykDp4hvIidEUJu2hf+NzG5OuMJSQJmAeAWPrkFOXN+6di9cA==",
             "cpu": [
                 "arm"
             ],
@@ -1687,15 +1645,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz",
-            "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.12.tgz",
+            "integrity": "sha512-i1/ikCl9gG9yx6QuI+8yJMk9XHUu8ekIQOo6cex2pDqXY5KVHSXDTAT4FDWOd5YXQ1QTjneBAQHcKGft4pd6PQ==",
             "cpu": [
                 "arm64"
             ],
@@ -1703,15 +1658,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-mips64le": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz",
-            "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.12.tgz",
+            "integrity": "sha512-+/a6/tiKUCENep8ryUR75Jba4znG51Sb75OzKT6phZFEkB7fao4+GZD39Zxx3EaaA5OC10MsJPjJMFrn0dMusg==",
             "cpu": [
                 "mips64el"
             ],
@@ -1719,15 +1671,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-ppc64le": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz",
-            "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.12.tgz",
+            "integrity": "sha512-SD7e2VLza/cEU2qKuD18Ibt1V0h3TUuerC1Mp3jRJ4RRGXWAyUt4gUpqKSiB7R0rHe6LWECdLbeVFAuGEntCeA==",
             "cpu": [
                 "ppc64"
             ],
@@ -1735,31 +1684,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/esbuild-linux-riscv64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz",
-            "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==",
-            "cpu": [
-                "riscv64"
-            ],
-            "dev": true,
-            "optional": true,
-            "os": [
-                "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-linux-s390x": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz",
-            "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.12.tgz",
+            "integrity": "sha512-KZmjYgAvYUpPBG0v6xv8qCngbfcRKC2AdYx3H3j3VqJfICgjt5XYsyG7ntWdc8Rdw9jZxr9sni6othy2Rp/T+A==",
             "cpu": [
                 "s390x"
             ],
@@ -1767,15 +1697,12 @@
             "optional": true,
             "os": [
                 "linux"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-netbsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz",
-            "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.12.tgz",
+            "integrity": "sha512-dG+hbCIJC65fHqzkTEYbrPSYG3m8pEaI9A1VDtqHfV13Oiw9/tua1odd47iwoWvTyurErb49wanHsIAKb8/2oQ==",
             "cpu": [
                 "x64"
             ],
@@ -1783,15 +1710,12 @@
             "optional": true,
             "os": [
                 "netbsd"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-openbsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz",
-            "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.12.tgz",
+            "integrity": "sha512-W3SwxnMjJR3HtBD0aij5WPd0ow2bRB5BsW6FjhN7FgwDBQ+jgniFs1dq54HOkjQ2qBJrt8JvPDFAxacWjdD6Jw==",
             "cpu": [
                 "x64"
             ],
@@ -1799,15 +1723,12 @@
             "optional": true,
             "os": [
                 "openbsd"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-sunos-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz",
-            "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.12.tgz",
+            "integrity": "sha512-jU/IcTFwvUtt21wOmqKJrevyHQ5XRfiCdFbPie4wsYr8VFcPZZsz18A9lcoI8gZdrF/8pBdD0V+L2UuUY0KsGg==",
             "cpu": [
                 "x64"
             ],
@@ -1815,15 +1736,12 @@
             "optional": true,
             "os": [
                 "sunos"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-windows-32": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz",
-            "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.12.tgz",
+            "integrity": "sha512-6luae9cmTB0rSPMCQFWMgf0SLNZ9hxusoS0poVEUHJf3n8bW6wgdyLE2xfYcEcXPMsjAt2e71/etkpqlFxeuYg==",
             "cpu": [
                 "ia32"
             ],
@@ -1831,15 +1749,12 @@
             "optional": true,
             "os": [
                 "win32"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-windows-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz",
-            "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.12.tgz",
+            "integrity": "sha512-CdCXvME/7s0uMt+4rYd8d5roHJJ5k2VDOzWaOMWExjroet+nSSZngfLpxI5St+28lXLeBorUxeBS+p1qcfEDfw==",
             "cpu": [
                 "x64"
             ],
@@ -1847,15 +1762,12 @@
             "optional": true,
             "os": [
                 "win32"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/esbuild-windows-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz",
-            "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.12.tgz",
+            "integrity": "sha512-vNuLQh/MpYDepK0GNpEWHy0Kn7Jf3Shz/Xetf8hUIc31jgCR1qbLVLDf3ckQdanD2U430YZupOGtEZKRwno79w==",
             "cpu": [
                 "arm64"
             ],
@@ -1863,10 +1775,7 @@
             "optional": true,
             "os": [
                 "win32"
-            ],
-            "engines": {
-                "node": ">=12"
-            }
+            ]
         },
         "node_modules/escape-string-regexp": {
             "version": "4.0.0",
@@ -1881,12 +1790,12 @@
             }
         },
         "node_modules/eslint": {
-            "version": "8.10.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz",
-            "integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==",
+            "version": "8.7.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz",
+            "integrity": "sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==",
             "dev": true,
             "dependencies": {
-                "@eslint/eslintrc": "^1.2.0",
+                "@eslint/eslintrc": "^1.0.5",
                 "@humanwhocodes/config-array": "^0.9.2",
                 "ajv": "^6.10.0",
                 "chalk": "^4.0.0",
@@ -1894,10 +1803,10 @@
                 "debug": "^4.3.2",
                 "doctrine": "^3.0.0",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^7.1.1",
+                "eslint-scope": "^7.1.0",
                 "eslint-utils": "^3.0.0",
-                "eslint-visitor-keys": "^3.3.0",
-                "espree": "^9.3.1",
+                "eslint-visitor-keys": "^3.2.0",
+                "espree": "^9.3.0",
                 "esquery": "^1.4.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
@@ -1973,18 +1882,18 @@
             }
         },
         "node_modules/eslint-visitor-keys": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
-            "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz",
+            "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==",
             "dev": true,
             "engines": {
                 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
             }
         },
         "node_modules/eslint/node_modules/eslint-scope": {
-            "version": "7.1.1",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
-            "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+            "version": "7.1.0",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz",
+            "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==",
             "dev": true,
             "dependencies": {
                 "esrecurse": "^4.3.0",
@@ -2004,14 +1913,14 @@
             }
         },
         "node_modules/espree": {
-            "version": "9.3.1",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
-            "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
+            "version": "9.3.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz",
+            "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==",
             "dev": true,
             "dependencies": {
                 "acorn": "^8.7.0",
                 "acorn-jsx": "^5.3.1",
-                "eslint-visitor-keys": "^3.3.0"
+                "eslint-visitor-keys": "^3.1.0"
             },
             "engines": {
                 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -2334,9 +2243,9 @@
             }
         },
         "node_modules/globals": {
-            "version": "13.12.1",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz",
-            "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==",
+            "version": "13.12.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
+            "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
             "dev": true,
             "dependencies": {
                 "type-fest": "^0.20.2"
@@ -3855,39 +3764,39 @@
             }
         },
         "node_modules/vscode-jsonrpc": {
-            "version": "8.0.0-next.6",
-            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.6.tgz",
-            "integrity": "sha512-6Ld3RYjygn5Ih7CkAtcAwiDQC+rakj2O+PnASfNyYv3sLmm44eJpEKzuPUN30Iy2UB09AZg8T6LBKWTJTEJDVw==",
+            "version": "8.0.0-next.5",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.5.tgz",
+            "integrity": "sha512-owRllqcFTnz5rXxcbmHPFGmpFmLqj9Z1V3Dzrv+s8ejOHLIT62Pyb5Uqzyl2/in2VP22DmzErPgZwrxjLCIKiQ==",
             "engines": {
                 "node": ">=14.0.0"
             }
         },
         "node_modules/vscode-languageclient": {
-            "version": "8.0.0-next.12",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.12.tgz",
-            "integrity": "sha512-4+kr1BQcoh+sA5/4XJDJXrQXGQ5Yz/x+WpsVGGzK/TOB7RwQ63ooxG6Ej7i/+aOQM4/QdmcYWmipDtG7vqcOiw==",
+            "version": "8.0.0-next.8",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.8.tgz",
+            "integrity": "sha512-CBdYRIVqqlRmZ2YBeTk0S2QMtsL8ZJfbddlfvERmRPXW4Pimr7Nk+mYq16F/k3HbrO9Xt+RAFP1t6FIIbmuUGw==",
             "dependencies": {
                 "minimatch": "^3.0.4",
                 "semver": "^7.3.5",
-                "vscode-languageserver-protocol": "3.17.0-next.14"
+                "vscode-languageserver-protocol": "3.17.0-next.12"
             },
             "engines": {
                 "vscode": "^1.63.0"
             }
         },
         "node_modules/vscode-languageserver-protocol": {
-            "version": "3.17.0-next.14",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.14.tgz",
-            "integrity": "sha512-iangobY8dL6sFZkOx4OhRPJM9gN0I1caUsOVR+MnPozsqQUtwMXmbIcfaIf0Akp0pd3KhJDPf/tdwRX68QGeeA==",
+            "version": "3.17.0-next.12",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.12.tgz",
+            "integrity": "sha512-VLRcWKOpCXcx9UrqrS+NSF6pNxV498VGYGW+eyp9a79/F9ElUq3wdG6acXYlEfpWHuIxpm6MXps8FU88wqIgTg==",
             "dependencies": {
-                "vscode-jsonrpc": "8.0.0-next.6",
-                "vscode-languageserver-types": "3.17.0-next.7"
+                "vscode-jsonrpc": "8.0.0-next.5",
+                "vscode-languageserver-types": "3.17.0-next.6"
             }
         },
         "node_modules/vscode-languageserver-types": {
-            "version": "3.17.0-next.7",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.7.tgz",
-            "integrity": "sha512-KH4zdG1qBXxoso61ChgpeoZYyHGJo8bV7Jv4I+fwQ1Ryy59JAxoZ9GAbhR5TeeafHctLcg6RFvY3m8Jqfu17cg=="
+            "version": "3.17.0-next.6",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.6.tgz",
+            "integrity": "sha512-rHYeCotiabJHgvIYzWjV8g0dHCxyOQtcryTv1Xa1horaQ4jx2V+rjLBstc6zMpCyrnZcjorwEcAvGBDCd6wudw=="
         },
         "node_modules/which": {
             "version": "2.0.2",
@@ -3977,14 +3886,14 @@
     },
     "dependencies": {
         "@eslint/eslintrc": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz",
-            "integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==",
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
+            "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==",
             "dev": true,
             "requires": {
                 "ajv": "^6.12.4",
                 "debug": "^4.3.2",
-                "espree": "^9.3.1",
+                "espree": "^9.2.0",
                 "globals": "^13.9.0",
                 "ignore": "^4.0.6",
                 "import-fresh": "^3.2.1",
@@ -4068,9 +3977,9 @@
             "dev": true
         },
         "@types/vscode": {
-            "version": "1.65.0",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz",
-            "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==",
+            "version": "1.63.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.63.1.tgz",
+            "integrity": "sha512-Z+ZqjRcnGfHP86dvx/BtSwWyZPKQ/LBdmAVImY82TphyjOw2KgTKcp7Nx92oNwCTsHzlshwexAG/WiY2JuUm3g==",
             "dev": true
         },
         "@typescript-eslint/eslint-plugin": {
@@ -5068,170 +4977,154 @@
             "dev": true
         },
         "esbuild": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz",
-            "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==",
-            "dev": true,
-            "requires": {
-                "esbuild-android-64": "0.14.25",
-                "esbuild-android-arm64": "0.14.25",
-                "esbuild-darwin-64": "0.14.25",
-                "esbuild-darwin-arm64": "0.14.25",
-                "esbuild-freebsd-64": "0.14.25",
-                "esbuild-freebsd-arm64": "0.14.25",
-                "esbuild-linux-32": "0.14.25",
-                "esbuild-linux-64": "0.14.25",
-                "esbuild-linux-arm": "0.14.25",
-                "esbuild-linux-arm64": "0.14.25",
-                "esbuild-linux-mips64le": "0.14.25",
-                "esbuild-linux-ppc64le": "0.14.25",
-                "esbuild-linux-riscv64": "0.14.25",
-                "esbuild-linux-s390x": "0.14.25",
-                "esbuild-netbsd-64": "0.14.25",
-                "esbuild-openbsd-64": "0.14.25",
-                "esbuild-sunos-64": "0.14.25",
-                "esbuild-windows-32": "0.14.25",
-                "esbuild-windows-64": "0.14.25",
-                "esbuild-windows-arm64": "0.14.25"
-            }
-        },
-        "esbuild-android-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz",
-            "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==",
-            "dev": true,
-            "optional": true
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.12.tgz",
+            "integrity": "sha512-o1vQkG+eSDLkWDqWfR8v6eI+byGAUkbRs30eAJcJxUFp3dwMGWR0tAjtam1Bb1RSS2j+4kAUFiuJTnW3J4CYcw==",
+            "dev": true,
+            "requires": {
+                "esbuild-android-arm64": "0.14.12",
+                "esbuild-darwin-64": "0.14.12",
+                "esbuild-darwin-arm64": "0.14.12",
+                "esbuild-freebsd-64": "0.14.12",
+                "esbuild-freebsd-arm64": "0.14.12",
+                "esbuild-linux-32": "0.14.12",
+                "esbuild-linux-64": "0.14.12",
+                "esbuild-linux-arm": "0.14.12",
+                "esbuild-linux-arm64": "0.14.12",
+                "esbuild-linux-mips64le": "0.14.12",
+                "esbuild-linux-ppc64le": "0.14.12",
+                "esbuild-linux-s390x": "0.14.12",
+                "esbuild-netbsd-64": "0.14.12",
+                "esbuild-openbsd-64": "0.14.12",
+                "esbuild-sunos-64": "0.14.12",
+                "esbuild-windows-32": "0.14.12",
+                "esbuild-windows-64": "0.14.12",
+                "esbuild-windows-arm64": "0.14.12"
+            }
         },
         "esbuild-android-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz",
-            "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.12.tgz",
+            "integrity": "sha512-eO4JHwnTeJq1/xC9K0FdHNEYztwT0HaWHnOzR5kXKwJxHatxDNZ+lCHOSxMzh9uVSmnA8YwdSiXPWbwTlWZVrw==",
             "dev": true,
             "optional": true
         },
         "esbuild-darwin-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz",
-            "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.12.tgz",
+            "integrity": "sha512-LyZ81assnJWhq2IxKEVipwddKlXLTubbz/IObyKOm5cWS9jQCpuwQey2PpzroWSiy7QLGV8XCGWY5b8U8fsmWA==",
             "dev": true,
             "optional": true
         },
         "esbuild-darwin-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz",
-            "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.12.tgz",
+            "integrity": "sha512-jj27iSbDS4KlftN1PHHNiTrtXPQIk11J/qpQiQLwKJpeEMNeJUBfQlS7X7dXgFFMxV0rNtcRl8AimEFl+qEMRQ==",
             "dev": true,
             "optional": true
         },
         "esbuild-freebsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz",
-            "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.12.tgz",
+            "integrity": "sha512-RnTty09bA8Ts/eWnrJsYiE2dFM6ZseKYQ/7QCM5QYphU6GbifooO9oGjc/UE3Sg8R58yZVO15vnIV0i+kTgDOw==",
             "dev": true,
             "optional": true
         },
         "esbuild-freebsd-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz",
-            "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.12.tgz",
+            "integrity": "sha512-AvAQoEgsHE53hucgoVWdHnXJBl0r9W/7eUCaBvpcgYu3W/EbPZ26VnZwfSXLpk0Pf3t7o6SRwrU+KDTKPscDTw==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-32": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz",
-            "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.12.tgz",
+            "integrity": "sha512-na4I5i2c9ACPuglfYmrnJ6qGQnFJb59dFjyFk5OHTCtoKCq3lXbGHrvYa+3sYlOrRax1kYuRDRGse7YsDLbr3Q==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz",
-            "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.12.tgz",
+            "integrity": "sha512-ObPoYGakJLx/RldQsFQiwsQ7N9YbQ4LLazHtpKx34bjqFjhqO5JiHPVAJYCmAtci3cJMsZ5DtEFXvijytTBz1g==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-arm": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz",
-            "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.12.tgz",
+            "integrity": "sha512-tD4q/zVUeYkThGehYAJQElo80+ysxvq5vpd2QvykDp4hvIidEUJu2hf+NzG5OuMJSQJmAeAWPrkFOXN+6di9cA==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz",
-            "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.12.tgz",
+            "integrity": "sha512-i1/ikCl9gG9yx6QuI+8yJMk9XHUu8ekIQOo6cex2pDqXY5KVHSXDTAT4FDWOd5YXQ1QTjneBAQHcKGft4pd6PQ==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-mips64le": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz",
-            "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.12.tgz",
+            "integrity": "sha512-+/a6/tiKUCENep8ryUR75Jba4znG51Sb75OzKT6phZFEkB7fao4+GZD39Zxx3EaaA5OC10MsJPjJMFrn0dMusg==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-ppc64le": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz",
-            "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==",
-            "dev": true,
-            "optional": true
-        },
-        "esbuild-linux-riscv64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz",
-            "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.12.tgz",
+            "integrity": "sha512-SD7e2VLza/cEU2qKuD18Ibt1V0h3TUuerC1Mp3jRJ4RRGXWAyUt4gUpqKSiB7R0rHe6LWECdLbeVFAuGEntCeA==",
             "dev": true,
             "optional": true
         },
         "esbuild-linux-s390x": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz",
-            "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.12.tgz",
+            "integrity": "sha512-KZmjYgAvYUpPBG0v6xv8qCngbfcRKC2AdYx3H3j3VqJfICgjt5XYsyG7ntWdc8Rdw9jZxr9sni6othy2Rp/T+A==",
             "dev": true,
             "optional": true
         },
         "esbuild-netbsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz",
-            "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.12.tgz",
+            "integrity": "sha512-dG+hbCIJC65fHqzkTEYbrPSYG3m8pEaI9A1VDtqHfV13Oiw9/tua1odd47iwoWvTyurErb49wanHsIAKb8/2oQ==",
             "dev": true,
             "optional": true
         },
         "esbuild-openbsd-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz",
-            "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.12.tgz",
+            "integrity": "sha512-W3SwxnMjJR3HtBD0aij5WPd0ow2bRB5BsW6FjhN7FgwDBQ+jgniFs1dq54HOkjQ2qBJrt8JvPDFAxacWjdD6Jw==",
             "dev": true,
             "optional": true
         },
         "esbuild-sunos-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz",
-            "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.12.tgz",
+            "integrity": "sha512-jU/IcTFwvUtt21wOmqKJrevyHQ5XRfiCdFbPie4wsYr8VFcPZZsz18A9lcoI8gZdrF/8pBdD0V+L2UuUY0KsGg==",
             "dev": true,
             "optional": true
         },
         "esbuild-windows-32": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz",
-            "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.12.tgz",
+            "integrity": "sha512-6luae9cmTB0rSPMCQFWMgf0SLNZ9hxusoS0poVEUHJf3n8bW6wgdyLE2xfYcEcXPMsjAt2e71/etkpqlFxeuYg==",
             "dev": true,
             "optional": true
         },
         "esbuild-windows-64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz",
-            "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.12.tgz",
+            "integrity": "sha512-CdCXvME/7s0uMt+4rYd8d5roHJJ5k2VDOzWaOMWExjroet+nSSZngfLpxI5St+28lXLeBorUxeBS+p1qcfEDfw==",
             "dev": true,
             "optional": true
         },
         "esbuild-windows-arm64": {
-            "version": "0.14.25",
-            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz",
-            "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==",
+            "version": "0.14.12",
+            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.12.tgz",
+            "integrity": "sha512-vNuLQh/MpYDepK0GNpEWHy0Kn7Jf3Shz/Xetf8hUIc31jgCR1qbLVLDf3ckQdanD2U430YZupOGtEZKRwno79w==",
             "dev": true,
             "optional": true
         },
@@ -5242,12 +5135,12 @@
             "dev": true
         },
         "eslint": {
-            "version": "8.10.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz",
-            "integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==",
+            "version": "8.7.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz",
+            "integrity": "sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w==",
             "dev": true,
             "requires": {
-                "@eslint/eslintrc": "^1.2.0",
+                "@eslint/eslintrc": "^1.0.5",
                 "@humanwhocodes/config-array": "^0.9.2",
                 "ajv": "^6.10.0",
                 "chalk": "^4.0.0",
@@ -5255,10 +5148,10 @@
                 "debug": "^4.3.2",
                 "doctrine": "^3.0.0",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^7.1.1",
+                "eslint-scope": "^7.1.0",
                 "eslint-utils": "^3.0.0",
-                "eslint-visitor-keys": "^3.3.0",
-                "espree": "^9.3.1",
+                "eslint-visitor-keys": "^3.2.0",
+                "espree": "^9.3.0",
                 "esquery": "^1.4.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
@@ -5285,9 +5178,9 @@
             },
             "dependencies": {
                 "eslint-scope": {
-                    "version": "7.1.1",
-                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
-                    "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+                    "version": "7.1.0",
+                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz",
+                    "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==",
                     "dev": true,
                     "requires": {
                         "esrecurse": "^4.3.0",
@@ -5330,20 +5223,20 @@
             }
         },
         "eslint-visitor-keys": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
-            "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz",
+            "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==",
             "dev": true
         },
         "espree": {
-            "version": "9.3.1",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
-            "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
+            "version": "9.3.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz",
+            "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==",
             "dev": true,
             "requires": {
                 "acorn": "^8.7.0",
                 "acorn-jsx": "^5.3.1",
-                "eslint-visitor-keys": "^3.3.0"
+                "eslint-visitor-keys": "^3.1.0"
             }
         },
         "esquery": {
@@ -5613,9 +5506,9 @@
             }
         },
         "globals": {
-            "version": "13.12.1",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz",
-            "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==",
+            "version": "13.12.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
+            "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
             "dev": true,
             "requires": {
                 "type-fest": "^0.20.2"
@@ -6778,33 +6671,33 @@
             }
         },
         "vscode-jsonrpc": {
-            "version": "8.0.0-next.6",
-            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.6.tgz",
-            "integrity": "sha512-6Ld3RYjygn5Ih7CkAtcAwiDQC+rakj2O+PnASfNyYv3sLmm44eJpEKzuPUN30Iy2UB09AZg8T6LBKWTJTEJDVw=="
+            "version": "8.0.0-next.5",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.5.tgz",
+            "integrity": "sha512-owRllqcFTnz5rXxcbmHPFGmpFmLqj9Z1V3Dzrv+s8ejOHLIT62Pyb5Uqzyl2/in2VP22DmzErPgZwrxjLCIKiQ=="
         },
         "vscode-languageclient": {
-            "version": "8.0.0-next.12",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.12.tgz",
-            "integrity": "sha512-4+kr1BQcoh+sA5/4XJDJXrQXGQ5Yz/x+WpsVGGzK/TOB7RwQ63ooxG6Ej7i/+aOQM4/QdmcYWmipDtG7vqcOiw==",
+            "version": "8.0.0-next.8",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.8.tgz",
+            "integrity": "sha512-CBdYRIVqqlRmZ2YBeTk0S2QMtsL8ZJfbddlfvERmRPXW4Pimr7Nk+mYq16F/k3HbrO9Xt+RAFP1t6FIIbmuUGw==",
             "requires": {
                 "minimatch": "^3.0.4",
                 "semver": "^7.3.5",
-                "vscode-languageserver-protocol": "3.17.0-next.14"
+                "vscode-languageserver-protocol": "3.17.0-next.12"
             }
         },
         "vscode-languageserver-protocol": {
-            "version": "3.17.0-next.14",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.14.tgz",
-            "integrity": "sha512-iangobY8dL6sFZkOx4OhRPJM9gN0I1caUsOVR+MnPozsqQUtwMXmbIcfaIf0Akp0pd3KhJDPf/tdwRX68QGeeA==",
+            "version": "3.17.0-next.12",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.12.tgz",
+            "integrity": "sha512-VLRcWKOpCXcx9UrqrS+NSF6pNxV498VGYGW+eyp9a79/F9ElUq3wdG6acXYlEfpWHuIxpm6MXps8FU88wqIgTg==",
             "requires": {
-                "vscode-jsonrpc": "8.0.0-next.6",
-                "vscode-languageserver-types": "3.17.0-next.7"
+                "vscode-jsonrpc": "8.0.0-next.5",
+                "vscode-languageserver-types": "3.17.0-next.6"
             }
         },
         "vscode-languageserver-types": {
-            "version": "3.17.0-next.7",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.7.tgz",
-            "integrity": "sha512-KH4zdG1qBXxoso61ChgpeoZYyHGJo8bV7Jv4I+fwQ1Ryy59JAxoZ9GAbhR5TeeafHctLcg6RFvY3m8Jqfu17cg=="
+            "version": "3.17.0-next.6",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.6.tgz",
+            "integrity": "sha512-rHYeCotiabJHgvIYzWjV8g0dHCxyOQtcryTv1Xa1horaQ4jx2V+rjLBstc6zMpCyrnZcjorwEcAvGBDCd6wudw=="
         },
         "which": {
             "version": "2.0.2",
diff --git a/editors/code/package.json b/editors/code/package.json
index c94a09f084..4843ea8421 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -21,9 +21,9 @@
         "Programming Languages"
     ],
     "engines": {
-        "vscode": "^1.65.0"
+        "vscode": "^1.63.0"
     },
-    "enabledApiProposals": [],
+    "enableProposedApi": true,
     "scripts": {
         "vscode:prepublish": "npm run build-base -- --minify",
         "package": "vsce package -o rust-analyzer.vsix",
@@ -36,18 +36,18 @@
         "test": "node ./out/tests/runTests.js"
     },
     "dependencies": {
-        "vscode-languageclient": "8.0.0-next.12",
+        "vscode-languageclient": "8.0.0-next.8",
         "d3": "^7.3.0",
         "d3-graphviz": "^4.0.0"
     },
     "devDependencies": {
         "@types/node": "~14.17.5",
-        "@types/vscode": "~1.65.0",
+        "@types/vscode": "~1.63.0",
         "@typescript-eslint/eslint-plugin": "^5.10.0",
         "@typescript-eslint/parser": "^5.10.0",
         "@vscode/test-electron": "^2.1.1",
         "esbuild": "^0.14.12",
-        "eslint": "^8.10.0",
+        "eslint": "^8.7.0",
         "tslib": "^2.3.0",
         "typescript": "^4.5.5",
         "typescript-formatter": "^7.2.2",
@@ -298,6 +298,11 @@
                     "default": true,
                     "description": "Whether to show inlay hints."
                 },
+                "rust-analyzer.inlayHints.smallerHints": {
+                    "type": "boolean",
+                    "default": true,
+                    "description": "Whether inlay hints font size should be smaller than editor's font size."
+                },
                 "rust-analyzer.server.path": {
                     "type": [
                         "null",
@@ -1078,6 +1083,78 @@
             }
         ],
         "colors": [
+            {
+                "id": "rust_analyzer.inlayHints.foreground",
+                "description": "Foreground color of inlay hints (is overriden by more specific rust_analyzer.inlayHints.foreground.* configurations)",
+                "defaults": {
+                    "dark": "#A0A0A0F0",
+                    "light": "#747474",
+                    "highContrast": "#BEBEBE"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.background",
+                "description": "Background color of inlay hints (is overriden by more specific rust_analyzer.inlayHints.background.* configurations)",
+                "defaults": {
+                    "dark": "#11223300",
+                    "light": "#11223300",
+                    "highContrast": "#11223300"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.foreground.typeHints",
+                "description": "Foreground color of inlay type hints for variables (overrides rust_analyzer.inlayHints.foreground)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.foreground",
+                    "light": "rust_analyzer.inlayHints.foreground",
+                    "highContrast": "rust_analyzer.inlayHints.foreground"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.foreground.chainingHints",
+                "description": "Foreground color of inlay type hints for method chains (overrides rust_analyzer.inlayHints.foreground)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.foreground",
+                    "light": "rust_analyzer.inlayHints.foreground",
+                    "highContrast": "rust_analyzer.inlayHints.foreground"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.foreground.parameterHints",
+                "description": "Foreground color of function parameter name inlay hints at the call site (overrides rust_analyzer.inlayHints.foreground)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.foreground",
+                    "light": "rust_analyzer.inlayHints.foreground",
+                    "highContrast": "rust_analyzer.inlayHints.foreground"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.background.typeHints",
+                "description": "Background color of inlay type hints for variables (overrides rust_analyzer.inlayHints.background)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.background",
+                    "light": "rust_analyzer.inlayHints.background",
+                    "highContrast": "rust_analyzer.inlayHints.background"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.background.chainingHints",
+                "description": "Background color of inlay type hints for method chains (overrides rust_analyzer.inlayHints.background)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.background",
+                    "light": "rust_analyzer.inlayHints.background",
+                    "highContrast": "rust_analyzer.inlayHints.background"
+                }
+            },
+            {
+                "id": "rust_analyzer.inlayHints.background.parameterHints",
+                "description": "Background color of function parameter name inlay hints at the call site (overrides rust_analyzer.inlayHints.background)",
+                "defaults": {
+                    "dark": "rust_analyzer.inlayHints.background",
+                    "light": "rust_analyzer.inlayHints.background",
+                    "highContrast": "rust_analyzer.inlayHints.background"
+                }
+            },
             {
                 "id": "rust_analyzer.syntaxTreeBorder",
                 "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 441370a677..c23d6f7384 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -1,54 +1,267 @@
+import * as lc from "vscode-languageclient";
 import * as vscode from 'vscode';
 import * as ra from './lsp_ext';
 
 import { Ctx, Disposable } from './ctx';
-import { sendRequestWithRetry, isRustDocument } from './util';
+import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util';
+
+interface InlayHintStyle {
+    decorationType: vscode.TextEditorDecorationType;
+    toDecoration(hint: ra.InlayHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions;
+};
+
+interface InlayHintsStyles {
+    typeHints: InlayHintStyle;
+    paramHints: InlayHintStyle;
+    chainingHints: InlayHintStyle;
+}
+
 
 export function activateInlayHints(ctx: Ctx) {
     const maybeUpdater = {
-        hintsProvider: null as Disposable | null,
-        updateHintsEventEmitter: new vscode.EventEmitter<void>(),
-
+        updater: null as null | HintsUpdater,
         async onConfigChange() {
-            this.dispose();
-
             const anyEnabled = ctx.config.inlayHints.typeHints
                 || ctx.config.inlayHints.parameterHints
                 || ctx.config.inlayHints.chainingHints;
             const enabled = ctx.config.inlayHints.enable && anyEnabled;
-            if (!enabled) return;
-
-            const event = this.updateHintsEventEmitter.event;
-            this.hintsProvider = vscode.languages.registerInlayHintsProvider({ scheme: 'file', language: 'rust' }, new class implements vscode.InlayHintsProvider {
-                onDidChangeInlayHints = event;
-                async provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise<vscode.InlayHint[]> {
-                    const request = { textDocument: { uri: document.uri.toString() }, range: { start: range.start, end: range.end } };
-                    const hints = await sendRequestWithRetry(ctx.client, ra.inlayHints, request, token).catch(_ => null);
-                    if (hints == null) {
-                        return [];
-                    } else {
-                        return hints;
-                    }
-                }
-            });
-        },
 
-        onDidChangeTextDocument({ contentChanges, document }: vscode.TextDocumentChangeEvent) {
-            if (contentChanges.length === 0 || !isRustDocument(document)) return;
-            this.updateHintsEventEmitter.fire();
-        },
+            if (!enabled) return this.dispose();
 
-        dispose() {
-            this.hintsProvider?.dispose();
-            this.hintsProvider = null;
-            this.updateHintsEventEmitter.dispose();
+            await sleep(100);
+            if (this.updater) {
+                this.updater.updateInlayHintsStyles();
+                this.updater.syncCacheAndRenderHints();
+            } else {
+                this.updater = new HintsUpdater(ctx);
+            }
         },
+        dispose() {
+            this.updater?.dispose();
+            this.updater = null;
+        }
     };
 
     ctx.pushCleanup(maybeUpdater);
 
-    vscode.workspace.onDidChangeConfiguration(maybeUpdater.onConfigChange, maybeUpdater, ctx.subscriptions);
-    vscode.workspace.onDidChangeTextDocument(maybeUpdater.onDidChangeTextDocument, maybeUpdater, ctx.subscriptions);
+    vscode.workspace.onDidChangeConfiguration(
+        maybeUpdater.onConfigChange, maybeUpdater, ctx.subscriptions
+    );
 
     maybeUpdater.onConfigChange().catch(console.error);
 }
+
+function createHintStyle(hintKind: "type" | "parameter" | "chaining", smallerHints: boolean): InlayHintStyle {
+    // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature
+    // between code and type hints
+    const [pos, render] = ({
+        type: ["after", (label: string) => `\u{200c}: ${label}`],
+        parameter: ["before", (label: string) => `${label}: `],
+        chaining: ["after", (label: string) => `\u{200c}: ${label}`],
+    } as const)[hintKind];
+
+    const fg = new vscode.ThemeColor(`rust_analyzer.inlayHints.foreground.${hintKind}Hints`);
+    const bg = new vscode.ThemeColor(`rust_analyzer.inlayHints.background.${hintKind}Hints`);
+    return {
+        decorationType: vscode.window.createTextEditorDecorationType({
+            [pos]: {
+                color: fg,
+                backgroundColor: bg,
+                fontStyle: "normal",
+                fontWeight: "normal",
+                textDecoration: smallerHints ? ";font-size:smaller" : "none",
+            },
+        }),
+        toDecoration(hint: ra.InlayHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions {
+            return {
+                range: conv.asRange(hint.range),
+                renderOptions: { [pos]: { contentText: render(hint.label) } }
+            };
+        }
+    };
+}
+
+const smallHintsStyles = {
+    typeHints: createHintStyle("type", true),
+    paramHints: createHintStyle("parameter", true),
+    chainingHints: createHintStyle("chaining", true),
+};
+
+const biggerHintsStyles = {
+    typeHints: createHintStyle("type", false),
+    paramHints: createHintStyle("parameter", false),
+    chainingHints: createHintStyle("chaining", false),
+};
+
+class HintsUpdater implements Disposable {
+    private sourceFiles = new Map<string, RustSourceFile>(); // map Uri -> RustSourceFile
+    private readonly disposables: Disposable[] = [];
+    private pendingDisposeDecorations: undefined | InlayHintsStyles = undefined;
+    private inlayHintsStyles!: InlayHintsStyles;
+
+    constructor(private readonly ctx: Ctx) {
+        vscode.window.onDidChangeVisibleTextEditors(
+            this.onDidChangeVisibleTextEditors,
+            this,
+            this.disposables
+        );
+
+        vscode.workspace.onDidChangeTextDocument(
+            this.onDidChangeTextDocument,
+            this,
+            this.disposables
+        );
+
+        // Set up initial cache shape
+        ctx.visibleRustEditors.forEach(editor => this.sourceFiles.set(
+            editor.document.uri.toString(),
+            {
+                document: editor.document,
+                inlaysRequest: null,
+                cachedDecorations: null
+            }
+        ));
+
+        this.updateInlayHintsStyles();
+        this.syncCacheAndRenderHints();
+    }
+
+    dispose() {
+        this.sourceFiles.forEach(file => file.inlaysRequest?.cancel());
+        this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [], chaining: [] }));
+        this.disposables.forEach(d => d.dispose());
+    }
+
+    onDidChangeTextDocument({ contentChanges, document }: vscode.TextDocumentChangeEvent) {
+        if (contentChanges.length === 0 || !isRustDocument(document)) return;
+        this.syncCacheAndRenderHints();
+    }
+
+    updateInlayHintsStyles() {
+        const inlayHintsStyles = this.ctx.config.inlayHints.smallerHints ? smallHintsStyles : biggerHintsStyles;
+
+        if (inlayHintsStyles !== this.inlayHintsStyles) {
+            this.pendingDisposeDecorations = this.inlayHintsStyles;
+            this.inlayHintsStyles = inlayHintsStyles;
+        }
+    }
+
+    syncCacheAndRenderHints() {
+        this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => {
+            if (!hints) return;
+
+            file.cachedDecorations = this.hintsToDecorations(hints);
+
+            for (const editor of this.ctx.visibleRustEditors) {
+                if (editor.document.uri.toString() === uri) {
+                    this.renderDecorations(editor, file.cachedDecorations);
+                }
+            }
+        }));
+    }
+
+    onDidChangeVisibleTextEditors() {
+        const newSourceFiles = new Map<string, RustSourceFile>();
+
+        // Rerendering all, even up-to-date editors for simplicity
+        this.ctx.visibleRustEditors.forEach(async editor => {
+            const uri = editor.document.uri.toString();
+            const file = this.sourceFiles.get(uri) ?? {
+                document: editor.document,
+                inlaysRequest: null,
+                cachedDecorations: null
+            };
+            newSourceFiles.set(uri, file);
+
+            // No text documents changed, so we may try to use the cache
+            if (!file.cachedDecorations) {
+                const hints = await this.fetchHints(file);
+                if (!hints) return;
+
+                file.cachedDecorations = this.hintsToDecorations(hints);
+            }
+
+            this.renderDecorations(editor, file.cachedDecorations);
+        });
+
+        // Cancel requests for no longer visible (disposed) source files
+        this.sourceFiles.forEach((file, uri) => {
+            if (!newSourceFiles.has(uri)) file.inlaysRequest?.cancel();
+        });
+
+        this.sourceFiles = newSourceFiles;
+    }
+
+    private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) {
+        const { typeHints, paramHints, chainingHints } = this.inlayHintsStyles;
+        if (this.pendingDisposeDecorations !== undefined) {
+            const { typeHints, paramHints, chainingHints } = this.pendingDisposeDecorations;
+            editor.setDecorations(typeHints.decorationType, []);
+            editor.setDecorations(paramHints.decorationType, []);
+            editor.setDecorations(chainingHints.decorationType, []);
+        }
+        editor.setDecorations(typeHints.decorationType, decorations.type);
+        editor.setDecorations(paramHints.decorationType, decorations.param);
+        editor.setDecorations(chainingHints.decorationType, decorations.chaining);
+    }
+
+    private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations {
+        const { typeHints, paramHints, chainingHints } = this.inlayHintsStyles;
+        const decorations: InlaysDecorations = { type: [], param: [], chaining: [] };
+        const conv = this.ctx.client.protocol2CodeConverter;
+
+        for (const hint of hints) {
+            switch (hint.kind) {
+                case ra.InlayHint.Kind.TypeHint: {
+                    decorations.type.push(typeHints.toDecoration(hint, conv));
+                    continue;
+                }
+                case ra.InlayHint.Kind.ParamHint: {
+                    decorations.param.push(paramHints.toDecoration(hint, conv));
+                    continue;
+                }
+                case ra.InlayHint.Kind.ChainingHint: {
+                    decorations.chaining.push(chainingHints.toDecoration(hint, conv));
+                    continue;
+                }
+            }
+        }
+        return decorations;
+    }
+
+    private async fetchHints(file: RustSourceFile): Promise<null | ra.InlayHint[]> {
+        file.inlaysRequest?.cancel();
+
+        const tokenSource = new vscode.CancellationTokenSource();
+        file.inlaysRequest = tokenSource;
+
+        const request = { textDocument: { uri: file.document.uri.toString() } };
+
+        return sendRequestWithRetry(this.ctx.client, ra.inlayHints, request, tokenSource.token)
+            .catch(_ => null)
+            .finally(() => {
+                if (file.inlaysRequest === tokenSource) {
+                    file.inlaysRequest = null;
+                }
+            });
+    }
+}
+
+interface InlaysDecorations {
+    type: vscode.DecorationOptions[];
+    param: vscode.DecorationOptions[];
+    chaining: vscode.DecorationOptions[];
+}
+
+interface RustSourceFile {
+    /**
+     * Source of the token to cancel in-flight inlay hints request if any.
+     */
+    inlaysRequest: null | vscode.CancellationTokenSource;
+    /**
+     * Last applied decorations.
+     */
+    cachedDecorations: null | InlaysDecorations;
+
+    document: RustDocument;
+}
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 9493a03481..9248bd1b6f 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -2,7 +2,6 @@
  * This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations.
  */
 
-import { InlayHint } from "vscode";
 import * as lc from "vscode-languageclient";
 
 export interface AnalyzerStatusParams {
@@ -100,11 +99,26 @@ export interface TestInfo {
 
 export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>("rust-analyzer/relatedTests");
 
+export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint;
+
+export namespace InlayHint {
+    export const enum Kind {
+        TypeHint = "TypeHint",
+        ParamHint = "ParameterHint",
+        ChainingHint = "ChainingHint",
+    }
+    interface Common {
+        range: lc.Range;
+        label: string;
+    }
+    export type TypeHint = Common & { kind: Kind.TypeHint };
+    export type ParamHint = Common & { kind: Kind.ParamHint };
+    export type ChainingHint = Common & { kind: Kind.ChainingHint };
+}
 export interface InlayHintsParams {
     textDocument: lc.TextDocumentIdentifier;
-    range: lc.Range;
 }
-export const inlayHints = new lc.RequestType<InlayHintsParams, InlayHint[], void>("experimental/inlayHints");
+export const inlayHints = new lc.RequestType<InlayHintsParams, InlayHint[], void>("rust-analyzer/inlayHints");
 
 export interface SsrParams {
     query: string;
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 985829880c..30909f53b2 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -55,7 +55,7 @@ fn dist_client(version: &str, release_tag: &str, target: &Target) -> Result<()>
         .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
         .replace(r#""$generated-start": {},"#, "")
         .replace(",\n                \"$generated-end\": {}", "")
-        .replace(r#""enabledApiProposals": [],"#, r#""#);
+        .replace(r#""enableProposedApi": true,"#, r#""#);
     patch.commit()?;
 
     Ok(())


Test patch:
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
deleted file mode 100644
index 46220993e6..0000000000
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ /dev/null
@@ -1,57 +0,0 @@
-
-<style>
-body                { margin: 0; }
-pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
-
-.lifetime           { color: #DFAF8F; font-style: italic; }
-.label              { color: #DFAF8F; font-style: italic; }
-.comment            { color: #7F9F7F; }
-.documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
-.injected           { opacity: 0.65 ; }
-.struct, .enum      { color: #7CB8BB; }
-.enum_variant       { color: #BDE0F3; }
-.string_literal     { color: #CC9393; }
-.field              { color: #94BFF3; }
-.function           { color: #93E0E3; }
-.function.unsafe    { color: #BC8383; }
-.trait.unsafe       { color: #BC8383; }
-.operator.unsafe    { color: #BC8383; }
-.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe     { color: #BC8383; font-weight: bold; }
-.parameter          { color: #94BFF3; }
-.text               { color: #DCDCCC; }
-.type               { color: #7CB8BB; }
-.builtin_type       { color: #8CD0D3; }
-.type_param         { color: #DFAF8F; }
-.attribute          { color: #94BFF3; }
-.numeric_literal    { color: #BFEBBF; }
-.bool_literal       { color: #BFE6EB; }
-.macro              { color: #94BFF3; }
-.derive             { color: #94BFF3; font-style: italic; }
-.module             { color: #AFD8AF; }
-.value_param        { color: #DCDCCC; }
-.variable           { color: #DCDCCC; }
-.format_specifier   { color: #CC696B; }
-.mutable            { text-decoration: underline; }
-.escape_sequence    { color: #94BFF3; }
-.keyword            { color: #F0DFAF; font-weight: bold; }
-.control            { font-style: italic; }
-.reference          { font-style: italic; font-weight: bold; }
-
-.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
-</style>
-<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">&gt;&gt;</span> <span class="numeric_literal">1</span> <span class="bitwise">&lt;&lt;</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">a</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="arithmetic mutable">+=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="arithmetic mutable">-=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="arithmetic mutable">*=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="arithmetic mutable">/=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="arithmetic mutable">%=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="bitwise mutable">|=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="bitwise mutable">&=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="bitwise mutable">^=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="bitwise mutable">&gt;&gt;=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-    <span class="variable mutable">a</span> <span class="bitwise mutable">&lt;&lt;=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
-<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index efd03c2823..0af743431b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -841,30 +841,6 @@ fn foo() {
     );
 }
 
-#[test]
-fn test_operators() {
-    check_highlighting(
-        r##"
-fn main() {
-    1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1;
-    let mut a = 0;
-    a += 1;
-    a -= 1;
-    a *= 1;
-    a /= 1;
-    a %= 1;
-    a |= 1;
-    a &= 1;
-    a ^= 1;
-    a >>= 1;
-    a <<= 1;
-}
-"##,
-        expect_file!["./test_data/highlight_operators.html"],
-        false,
-    );
-}
-
 #[test]
 fn test_rainbow_highlighting() {
     check_highlighting(
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 09260c12ed..08947e4ecd 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -5,9 +5,12 @@ use expect_test::expect;
 use hir::{db::DefDatabase, Semantics};
 use ide_db::{
     base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
-    imports::insert_use::{ImportGranularity, InsertUseConfig},
+    helpers::{
+        insert_use::{ImportGranularity, InsertUseConfig},
+        SnippetCap,
+    },
     source_change::FileSystemEdit,
-    RootDatabase, SnippetCap,
+    RootDatabase,
 };
 use stdx::{format_to, trim_indent};
 use syntax::TextRange;
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index eedc37e2a6..45c7c58dc0 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -27,8 +27,11 @@ use std::mem;
 use hir::{db::DefDatabase, PrefixKind, Semantics};
 use ide_db::{
     base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
-    imports::insert_use::{ImportGranularity, InsertUseConfig},
-    RootDatabase, SnippetCap,
+    helpers::{
+        insert_use::{ImportGranularity, InsertUseConfig},
+        SnippetCap,
+    },
+    RootDatabase,
 };
 use itertools::Itertools;
 use stdx::{format_to, trim_indent};
diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs
new file mode 100644
index 0000000000..09f3bca626
--- /dev/null
+++ b/crates/ide_db/src/line_index/tests.rs
@@ -0,0 +1,133 @@
+use super::*;
+
+#[test]
+fn test_line_index() {
+    let text = "hello\nworld";
+    let table = [
+        (00, 0, 0),
+        (01, 0, 1),
+        (05, 0, 5),
+        (06, 1, 0),
+        (07, 1, 1),
+        (08, 1, 2),
+        (10, 1, 4),
+        (11, 1, 5),
+        (12, 1, 6),
+    ];
+
+    let index = LineIndex::new(text);
+    for &(offset, line, col) in &table {
+        assert_eq!(index.line_col(offset.into()), LineCol { line, col });
+    }
+
+    let text = "\nhello\nworld";
+    let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)];
+    let index = LineIndex::new(text);
+    for &(offset, line, col) in &table {
+        assert_eq!(index.line_col(offset.into()), LineCol { line, col });
+    }
+}
+
+#[test]
+fn test_char_len() {
+    assert_eq!('メ'.len_utf8(), 3);
+    assert_eq!('メ'.len_utf16(), 1);
+}
+
+#[test]
+fn test_empty_index() {
+    let col_index = LineIndex::new(
+        "
+const C: char = 'x';
+",
+    );
+    assert_eq!(col_index.utf16_lines.len(), 0);
+}
+
+#[test]
+fn test_single_char() {
+    let col_index = LineIndex::new(
+        "
+const C: char = 'メ';
+",
+    );
+
+    assert_eq!(col_index.utf16_lines.len(), 1);
+    assert_eq!(col_index.utf16_lines[&1].len(), 1);
+    assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
+
+    // UTF-8 to UTF-16, no changes
+    assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
+
+    // UTF-8 to UTF-16
+    assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
+
+    // UTF-16 to UTF-8, no changes
+    assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
+
+    // UTF-16 to UTF-8
+    assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
+
+    let col_index = LineIndex::new("a𐐏b");
+    assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
+}
+
+#[test]
+fn test_string() {
+    let col_index = LineIndex::new(
+        "
+const C: char = \"メ メ\";
+",
+    );
+
+    assert_eq!(col_index.utf16_lines.len(), 1);
+    assert_eq!(col_index.utf16_lines[&1].len(), 2);
+    assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
+    assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
+
+    // UTF-8 to UTF-16
+    assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
+
+    assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
+    assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
+
+    assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
+
+    // UTF-16 to UTF-8
+    assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
+
+    // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
+    assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
+    assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
+    assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
+
+    assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
+}
+
+#[test]
+fn test_splitlines() {
+    fn r(lo: u32, hi: u32) -> TextRange {
+        TextRange::new(lo.into(), hi.into())
+    }
+
+    let text = "a\nbb\nccc\n";
+    let line_index = LineIndex::new(text);
+
+    let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
+    let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
+    assert_eq!(actual, expected);
+
+    let text = "";
+    let line_index = LineIndex::new(text);
+
+    let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
+    let expected = vec![];
+    assert_eq!(actual, expected);
+
+    let text = "\n";
+    let line_index = LineIndex::new(text);
+
+    let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
+    let expected = vec![r(0, 1)];
+    assert_eq!(actual, expected)
+}
diff --git a/crates/ide_db/src/tests/sourcegen_lints.rs b/crates/ide_db/src/tests/sourcegen_lints.rs
index 44f8f21795..9e2b8b9683 100644
--- a/crates/ide_db/src/tests/sourcegen_lints.rs
+++ b/crates/ide_db/src/tests/sourcegen_lints.rs
@@ -44,7 +44,7 @@ pub struct LintGroup {
 
     let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));
 
-    let destination = project_root().join("crates/ide_db/src/generated/lints.rs");
+    let destination = project_root().join("crates/ide_db/src/helpers/generated_lints.rs");
     sourcegen::ensure_file_contents(destination.as_path(), &contents);
 }
 
diff --git a/crates/ide_db/src/traits/tests.rs b/crates/ide_db/src/traits/tests.rs
new file mode 100644
index 0000000000..de994407c7
--- /dev/null
+++ b/crates/ide_db/src/traits/tests.rs
@@ -0,0 +1,141 @@
+use base_db::{fixture::ChangeFixture, FilePosition};
+use expect_test::{expect, Expect};
+use hir::Semantics;
+use syntax::ast::{self, AstNode};
+
+use crate::RootDatabase;
+
+/// Creates analysis from a multi-file fixture, returns positions marked with $0.
+pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let mut database = RootDatabase::default();
+    database.apply_change(change_fixture.change);
+    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
+    let offset = range_or_offset.expect_offset();
+    (database, FilePosition { file_id, offset })
+}
+
+fn check_trait(ra_fixture: &str, expect: Expect) {
+    let (db, position) = position(ra_fixture);
+    let sema = Semantics::new(&db);
+    let file = sema.parse(position.file_id);
+    let impl_block: ast::Impl =
+        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
+    let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
+    let actual = match trait_ {
+        Some(trait_) => trait_.name(&db).to_string(),
+        None => String::new(),
+    };
+    expect.assert_eq(&actual);
+}
+
+fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
+    let (db, position) = position(ra_fixture);
+    let sema = Semantics::new(&db);
+    let file = sema.parse(position.file_id);
+    let impl_block: ast::Impl =
+        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
+    let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
+    let actual = items
+        .into_iter()
+        .map(|item| item.name(&db).unwrap().to_string())
+        .collect::<Vec<_>>()
+        .join("\n");
+    expect.assert_eq(&actual);
+}
+
+#[test]
+fn resolve_trait() {
+    check_trait(
+        r#"
+pub trait Foo {
+    fn bar();
+}
+impl Foo for u8 {
+    $0
+}
+            "#,
+        expect![["Foo"]],
+    );
+    check_trait(
+        r#"
+pub trait Foo {
+    fn bar();
+}
+impl Foo for u8 {
+    fn bar() {
+        fn baz() {
+            $0
+        }
+        baz();
+    }
+}
+            "#,
+        expect![["Foo"]],
+    );
+    check_trait(
+        r#"
+pub trait Foo {
+    fn bar();
+}
+pub struct Bar;
+impl Bar {
+    $0
+}
+            "#,
+        expect![[""]],
+    );
+}
+
+#[test]
+fn missing_assoc_items() {
+    check_missing_assoc(
+        r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    $0
+}"#,
+        expect![[r#"
+                FOO
+                bar"#]],
+    );
+
+    check_missing_assoc(
+        r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    const FOO: u8 = 10;
+    $0
+}"#,
+        expect![[r#"
+                bar"#]],
+    );
+
+    check_missing_assoc(
+        r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    const FOO: u8 = 10;
+    fn bar() {$0}
+}"#,
+        expect![[r#""#]],
+    );
+
+    check_missing_assoc(
+        r#"
+pub struct Foo;
+impl Foo {
+    fn bar() {$0}
+}"#,
+        expect![[r#""#]],
+    );
+}
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 2b51e7fecb..37be41754e 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -188,7 +188,7 @@ https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-
 fn deny_clippy(path: &Path, text: &str) {
     let ignore = &[
         // The documentation in string literals may contain anything for its own purposes
-        "ide_db/src/generated/lints.rs",
+        "ide_db/src/helpers/generated_lints.rs",
         // The tests test clippy lint hovers
         "ide/src/hover/tests.rs",
         // The tests test clippy lint completions
@@ -279,7 +279,7 @@ fn check_todo(path: &Path, text: &str) {
         // `ast::make`.
         "ast/make.rs",
         // The documentation in string literals may contain anything for its own purposes
-        "ide_db/src/generated/lints.rs",
+        "ide_db/src/helpers/generated_lints.rs",
         "ide_assists/src/utils/gen_trait_fn_body.rs",
         "ide_assists/src/tests/generated.rs",
         // The tests for missing fields
@@ -315,7 +315,7 @@ fn check_dbg(path: &Path, text: &str) {
         "ide_completion/src/tests/proc_macros.rs",
         // The documentation in string literals may contain anything for its own purposes
         "ide_completion/src/lib.rs",
-        "ide_db/src/generated/lints.rs",
+        "ide_db/src/helpers/generated_lints.rs",
         // test for doc test for remove_dbg
         "src/tests/generated.rs",
     ];