]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide/src/hover.rs
Merge #7851
[rust.git] / crates / ide / src / hover.rs
index d2a0cfcd402e0ce48741e8a09924ab141a5d1903..a9454cfa317342c56225449c240640edd2df8259 100644 (file)
@@ -1,10 +1,11 @@
 use hir::{
-    Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module,
-    ModuleDef, ModuleSource, Semantics,
+    Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
+    HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
 };
-use ide_db::base_db::SourceDatabase;
 use ide_db::{
+    base_db::SourceDatabase,
     defs::{Definition, NameClass, NameRefClass},
+    helpers::FamousDefs,
     RootDatabase,
 };
 use itertools::Itertools;
 use test_utils::mark;
 
 use crate::{
-    display::{macro_label, ShortLabel, ToNav, TryToNav},
+    display::{macro_label, ShortLabel, TryToNav},
     doc_links::{remove_links, rewrite_links},
     markdown_remove::remove_markdown,
     markup::Markup,
-    runnables::runnable,
+    runnables::{runnable_fn, runnable_mod},
     FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
 };
 
@@ -31,19 +32,6 @@ pub struct HoverConfig {
     pub markdown: bool,
 }
 
-impl Default for HoverConfig {
-    fn default() -> Self {
-        Self {
-            implementations: true,
-            run: true,
-            debug: true,
-            goto_type_def: true,
-            links_in_hover: true,
-            markdown: true,
-        }
-    }
-}
-
 impl HoverConfig {
     pub const NO_ACTIONS: Self = Self {
         implementations: false,
@@ -70,7 +58,7 @@ pub fn runnable(&self) -> bool {
 #[derive(Debug, Clone)]
 pub enum HoverAction {
     Runnable(Runnable),
-    Implementaion(FilePosition),
+    Implementation(FilePosition),
     GoToType(Vec<HoverGotoTypeData>),
 }
 
@@ -107,7 +95,12 @@ pub(crate) fn hover(
     let node = token.parent();
     let definition = match_ast! {
         match node {
-            ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)),
+            // we don't use NameClass::referenced_or_defined here as we do not want to resolve
+            // field pattern shorthands to their definition
+            ast::Name(name) => NameClass::classify(&sema, &name).and_then(|class| match class {
+                NameClass::ConstReference(def) => Some(def),
+                def => def.defined(sema.db),
+            }),
             ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
             ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime)
                 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)),
@@ -115,15 +108,14 @@ pub(crate) fn hover(
         }
     };
     if let Some(definition) = definition {
-        if let Some(markup) = hover_for_definition(db, definition) {
-            let markup = if !markdown {
-                remove_markdown(&markup.as_str())
-            } else if links_in_hover {
-                rewrite_links(db, &markup.as_str(), &definition)
-            } else {
-                remove_links(&markup.as_str())
-            };
-            res.markup = Markup::from(markup);
+        let famous_defs = match &definition {
+            Definition::ModuleDef(ModuleDef::BuiltinType(_)) => {
+                Some(FamousDefs(&sema, sema.scope(&node).krate()))
+            }
+            _ => None,
+        };
+        if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref()) {
+            res.markup = process_markup(sema.db, definition, &markup, links_in_hover, markdown);
             if let Some(action) = show_implementations_action(db, definition) {
                 res.actions.push(action);
             }
@@ -145,18 +137,18 @@ pub(crate) fn hover(
         // don't highlight the entire parent node on comment hover
         return None;
     }
+    if let res @ Some(_) = hover_for_keyword(&sema, links_in_hover, markdown, &token) {
+        return res;
+    }
 
-    let node = token.ancestors().find(|n| {
-        ast::Expr::can_cast(n.kind())
-            || ast::Pat::can_cast(n.kind())
-            || ast::SelfParam::can_cast(n.kind())
-    })?;
+    let node = token
+        .ancestors()
+        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
 
     let ty = match_ast! {
         match node {
             ast::Expr(it) => sema.type_of_expr(&it)?,
             ast::Pat(it) => sema.type_of_pat(&it)?,
-            ast::SelfParam(self_param) => sema.type_of_self(&self_param)?,
             // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
             // (e.g expanding a builtin macro). So we give up here.
             ast::MacroCall(_it) => return None,
@@ -175,22 +167,19 @@ pub(crate) fn hover(
 
 fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
     fn to_action(nav_target: NavigationTarget) -> HoverAction {
-        HoverAction::Implementaion(FilePosition {
+        HoverAction::Implementation(FilePosition {
             file_id: nav_target.file_id,
             offset: nav_target.focus_or_full_range().start(),
         })
     }
 
-    match def {
-        Definition::ModuleDef(it) => match it {
-            ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
-            ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
-            _ => None,
-        },
+    let adt = match def {
+        Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
+        Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
+        Definition::SelfType(it) => it.target_ty(db).as_adt(),
         _ => None,
-    }
+    }?;
+    adt.try_to_nav(db).map(to_action)
 }
 
 fn runnable_action(
@@ -200,23 +189,16 @@ fn runnable_action(
 ) -> Option<HoverAction> {
     match def {
         Definition::ModuleDef(it) => match it {
-            ModuleDef::Module(it) => match it.definition_source(sema.db).value {
-                ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id)
-                    .map(|it| HoverAction::Runnable(it)),
-                _ => None,
-            },
-            ModuleDef::Function(it) => {
-                #[allow(deprecated)]
-                let src = it.source(sema.db)?;
+            ModuleDef::Module(it) => runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)),
+            ModuleDef::Function(func) => {
+                let src = func.source(sema.db)?;
                 if src.file_id != file_id.into() {
                     mark::hit!(hover_macro_generated_struct_fn_doc_comment);
                     mark::hit!(hover_macro_generated_struct_fn_doc_attr);
-
                     return None;
                 }
 
-                runnable(&sema, src.value.syntax().clone(), file_id)
-                    .map(|it| HoverAction::Runnable(it))
+                runnable_fn(&sema, func).map(HoverAction::Runnable)
             }
             _ => None,
         },
@@ -225,45 +207,46 @@ fn runnable_action(
 }
 
 fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
-    match def {
-        Definition::Local(it) => {
-            let mut targets: Vec<ModuleDef> = Vec::new();
-            let mut push_new_def = |item: ModuleDef| {
-                if !targets.contains(&item) {
-                    targets.push(item);
-                }
-            };
-
-            it.ty(db).walk(db, |t| {
-                if let Some(adt) = t.as_adt() {
-                    push_new_def(adt.into());
-                } else if let Some(trait_) = t.as_dyn_trait() {
-                    push_new_def(trait_.into());
-                } else if let Some(traits) = t.as_impl_traits(db) {
-                    traits.into_iter().for_each(|it| push_new_def(it.into()));
-                } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
-                    push_new_def(trait_.into());
-                }
-            });
-
-            let targets = targets
-                .into_iter()
-                .filter_map(|it| {
-                    Some(HoverGotoTypeData {
-                        mod_path: render_path(
-                            db,
-                            it.module(db)?,
-                            it.name(db).map(|name| name.to_string()),
-                        ),
-                        nav: it.try_to_nav(db)?,
-                    })
-                })
-                .collect();
-
-            Some(HoverAction::GoToType(targets))
+    let mut targets: Vec<ModuleDef> = Vec::new();
+    let mut push_new_def = |item: ModuleDef| {
+        if !targets.contains(&item) {
+            targets.push(item);
         }
-        _ => None,
+    };
+
+    if let Definition::GenericParam(GenericParam::TypeParam(it)) = def {
+        it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
+    } else {
+        let ty = match def {
+            Definition::Local(it) => it.ty(db),
+            Definition::GenericParam(GenericParam::ConstParam(it)) => it.ty(db),
+            _ => return None,
+        };
+
+        ty.walk(db, |t| {
+            if let Some(adt) = t.as_adt() {
+                push_new_def(adt.into());
+            } else if let Some(trait_) = t.as_dyn_trait() {
+                push_new_def(trait_.into());
+            } else if let Some(traits) = t.as_impl_traits(db) {
+                traits.into_iter().for_each(|it| push_new_def(it.into()));
+            } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
+                push_new_def(trait_.into());
+            }
+        });
     }
+
+    let targets = targets
+        .into_iter()
+        .filter_map(|it| {
+            Some(HoverGotoTypeData {
+                mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())),
+                nav: it.try_to_nav(db)?,
+            })
+        })
+        .collect();
+
+    Some(HoverAction::GoToType(targets))
 }
 
 fn hover_markup(
@@ -291,6 +274,24 @@ fn hover_markup(
     }
 }
 
+fn process_markup(
+    db: &RootDatabase,
+    def: Definition,
+    markup: &Markup,
+    links_in_hover: bool,
+    markdown: bool,
+) -> Markup {
+    let markup = markup.as_str();
+    let markup = if !markdown {
+        remove_markdown(markup)
+    } else if links_in_hover {
+        rewrite_links(db, markup, &def)
+    } else {
+        remove_links(markup)
+    };
+    Markup::from(markup)
+}
+
 fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
     match def {
         Definition::Field(f) => Some(f.parent_def(db).name(db)),
@@ -323,7 +324,11 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
     def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
 }
 
-fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
+fn hover_for_definition(
+    db: &RootDatabase,
+    def: Definition,
+    famous_defs: Option<&FamousDefs>,
+) -> Option<Markup> {
     let mod_path = definition_mod_path(db, &def);
     return match def {
         Definition::Macro(it) => {
@@ -331,7 +336,6 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
             from_def_source_labeled(db, it, Some(label), mod_path)
         }
         Definition::Field(def) => {
-            #[allow(deprecated)]
             let src = def.source(db)?.value;
             if let FieldSource::Named(it) = src {
                 from_def_source_labeled(db, def, it.short_label(), mod_path)
@@ -346,6 +350,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
                 match it.definition_source(db).value {
                     ModuleSource::Module(it) => it.short_label(),
                     ModuleSource::SourceFile(it) => it.short_label(),
+                    ModuleSource::BlockExpr(it) => it.short_label(),
                 },
                 mod_path,
             ),
@@ -358,7 +363,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
             ModuleDef::Static(it) => from_def_source(db, it, mod_path),
             ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
             ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
-            ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)),
+            ModuleDef::BuiltinType(it) => famous_defs
+                .and_then(|fd| hover_for_builtin(fd, it))
+                .or_else(|| Some(Markup::fenced_block(&it.name()))),
         },
         Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))),
         Definition::SelfType(impl_def) => {
@@ -369,11 +376,11 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
             })
         }
         Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
-        Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
-        Definition::TypeParam(_) | Definition::ConstParam(_) => {
-            // FIXME: Hover for generic param
-            None
-        }
+        Definition::GenericParam(it) => match it {
+            GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
+            GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
+            GenericParam::ConstParam(it) => from_def_source(db, it, None),
+        },
     };
 
     fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -381,7 +388,6 @@ fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) ->
         D: HasSource<Ast = A> + HasAttrs + Copy,
         A: ShortLabel,
     {
-        #[allow(deprecated)]
         let short_label = def.source(db)?.value.short_label();
         from_def_source_labeled(db, def, short_label, mod_path)
     }
@@ -400,11 +406,52 @@ fn from_def_source_labeled<D>(
     }
 }
 
+fn hover_for_keyword(
+    sema: &Semantics<RootDatabase>,
+    links_in_hover: bool,
+    markdown: bool,
+    token: &SyntaxToken,
+) -> Option<RangeInfo<HoverResult>> {
+    if !token.kind().is_keyword() {
+        return None;
+    }
+    let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()).krate());
+    // std exposes {}_keyword modules with docstrings on the root to document keywords
+    let keyword_mod = format!("{}_keyword", token.text());
+    let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
+    let docs = doc_owner.attrs(sema.db).docs()?;
+    let markup = process_markup(
+        sema.db,
+        Definition::ModuleDef(doc_owner.into()),
+        &hover_markup(Some(docs.into()), Some(token.text().into()), None)?,
+        links_in_hover,
+        markdown,
+    );
+    Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
+}
+
+fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Option<Markup> {
+    // std exposes prim_{} modules with docstrings on the root to document the builtins
+    let primitive_mod = format!("prim_{}", builtin.name());
+    let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
+    let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
+    hover_markup(Some(docs.into()), Some(builtin.name().to_string()), None)
+}
+
+fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> {
+    let db = famous_defs.0.db;
+    let std_crate = famous_defs.std()?;
+    let std_root_module = std_crate.root_module(db);
+    std_root_module
+        .children(db)
+        .find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
+}
+
 fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
     return tokens.max_by_key(priority);
     fn priority(n: &SyntaxToken) -> usize {
         match n.kind() {
-            IDENT | INT_NUMBER | LIFETIME_IDENT => 3,
+            IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
             T!['('] | T![')'] => 2,
             kind if kind.is_trivia() => 0,
             _ => 1,
@@ -472,7 +519,7 @@ fn hover_shows_type_of_an_expression() {
 pub fn foo() -> u32 { 1 }
 
 fn main() {
-    let foo_test = foo()<|>;
+    let foo_test = foo()$0;
 }
 "#,
             expect![[r#"
@@ -491,7 +538,7 @@ fn hover_remove_markdown_if_configured() {
 pub fn foo() -> u32 { 1 }
 
 fn main() {
-    let foo_test = foo()<|>;
+    let foo_test = foo()$0;
 }
 "#,
             expect![[r#"
@@ -521,7 +568,7 @@ fn main() {
         Option::Some(*memo + value)
     };
     let number = 5u32;
-    let mut iter<|> = scan(OtherStruct { i: num }, closure, number);
+    let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
 }
 "#,
             expect![[r#"
@@ -541,7 +588,7 @@ fn hover_shows_fn_signature() {
             r#"
 pub fn foo() -> u32 { 1 }
 
-fn main() { let foo_test = fo<|>o(); }
+fn main() { let foo_test = fo$0o(); }
 "#,
             expect![[r#"
                 *foo*
@@ -573,7 +620,7 @@ pub fn foo(a: u32, b: u32) {}
 mod b;
 mod c;
 
-fn main() { let foo_test = fo<|>o(); }
+fn main() { let foo_test = fo$0o(); }
         "#,
             expect![[r#"
                 *foo*
@@ -590,7 +637,7 @@ fn hover_shows_fn_signature_with_type_params() {
             r#"
 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
 
-fn main() { let foo_test = fo<|>o(); }
+fn main() { let foo_test = fo$0o(); }
         "#,
             expect![[r#"
                 *foo*
@@ -610,7 +657,7 @@ pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
     fn hover_shows_fn_signature_on_fn_name() {
         check(
             r#"
-pub fn foo<|>(a: u32, b: u32) -> u32 {}
+pub fn foo$0(a: u32, b: u32) -> u32 {}
 
 fn main() { }
 "#,
@@ -638,7 +685,7 @@ fn hover_shows_fn_doc() {
 /// #
 /// foo(Path::new("hello, world!"))
 /// ```
-pub fn foo<|>(_: &Path) {}
+pub fn foo$0(_: &Path) {}
 
 fn main() { }
 "#,
@@ -671,7 +718,7 @@ fn hover_shows_fn_doc_attr_raw_string() {
         check(
             r##"
 #[doc = r#"Raw string doc attr"#]
-pub fn foo<|>(_: &Path) {}
+pub fn foo$0(_: &Path) {}
 
 fn main() { }
 "##,
@@ -701,7 +748,7 @@ fn hover_shows_struct_field_info() {
 struct Foo { field_a: u32 }
 
 fn main() {
-    let foo = Foo { field_a<|>: 0, };
+    let foo = Foo { field_a$0: 0, };
 }
 "#,
             expect![[r#"
@@ -720,7 +767,7 @@ fn main() {
         // Hovering over the field in the definition
         check(
             r#"
-struct Foo { field_a<|>: u32 }
+struct Foo { field_a$0: u32 }
 
 fn main() {
     let foo = Foo { field_a: 0 };
@@ -743,7 +790,7 @@ fn main() {
     #[test]
     fn hover_const_static() {
         check(
-            r#"const foo<|>: u32 = 123;"#,
+            r#"const foo$0: u32 = 123;"#,
             expect![[r#"
                 *foo*
 
@@ -757,7 +804,7 @@ fn hover_const_static() {
             "#]],
         );
         check(
-            r#"static foo<|>: u32 = 456;"#,
+            r#"static foo$0: u32 = 456;"#,
             expect![[r#"
                 *foo*
 
@@ -779,7 +826,7 @@ fn hover_default_generic_types() {
 struct Test<K, T = u8> { k: K, t: T }
 
 fn main() {
-    let zz<|> = Test { t: 23u8, k: 33 };
+    let zz$0 = Test { t: 23u8, k: 33 };
 }"#,
             expect![[r#"
                 *zz*
@@ -798,7 +845,7 @@ fn hover_some() {
 enum Option<T> { Some(T) }
 use Option::Some;
 
-fn main() { So<|>me(12); }
+fn main() { So$0me(12); }
 "#,
             expect![[r#"
                 *Some*
@@ -818,7 +865,7 @@ enum Option<T> { Some(T) }
 enum Option<T> { Some(T) }
 use Option::Some;
 
-fn main() { let b<|>ar = Some(12); }
+fn main() { let b$0ar = Some(12); }
 "#,
             expect![[r#"
                 *bar*
@@ -836,7 +883,7 @@ fn hover_enum_variant() {
             r#"
 enum Option<T> {
     /// The None variant
-    Non<|>e
+    Non$0e
 }
 "#,
             expect![[r#"
@@ -863,7 +910,7 @@ enum Option<T> {
     Some(T)
 }
 fn main() {
-    let s = Option::Som<|>e(12);
+    let s = Option::Som$0e(12);
 }
 "#,
             expect![[r#"
@@ -887,7 +934,7 @@ fn main() {
     #[test]
     fn hover_for_local_variable() {
         check(
-            r#"fn func(foo: i32) { fo<|>o; }"#,
+            r#"fn func(foo: i32) { fo$0o; }"#,
             expect![[r#"
                 *foo*
 
@@ -901,7 +948,7 @@ fn hover_for_local_variable() {
     #[test]
     fn hover_for_local_variable_pat() {
         check(
-            r#"fn func(fo<|>o: i32) {}"#,
+            r#"fn func(fo$0o: i32) {}"#,
             expect![[r#"
                 *foo*
 
@@ -915,7 +962,7 @@ fn hover_for_local_variable_pat() {
     #[test]
     fn hover_local_var_edge() {
         check(
-            r#"fn func(foo: i32) { if true { <|>foo; }; }"#,
+            r#"fn func(foo: i32) { if true { $0foo; }; }"#,
             expect![[r#"
                 *foo*
 
@@ -929,7 +976,7 @@ fn hover_local_var_edge() {
     #[test]
     fn hover_for_param_edge() {
         check(
-            r#"fn func(<|>foo: i32) {}"#,
+            r#"fn func($0foo: i32) {}"#,
             expect![[r#"
                 *foo*
 
@@ -949,7 +996,7 @@ fn hover_for_param_with_multiple_traits() {
             trait DerefMut {
                 type Target: ?Sized;
             }
-            fn f(_x<|>: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
+            fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
             expect![[r#"
                 *_x*
 
@@ -970,7 +1017,7 @@ impl Thing {
     fn new() -> Thing { Thing { x: 0 } }
 }
 
-fn main() { let foo_<|>test = Thing::new(); }
+fn main() { let foo_$0test = Thing::new(); }
             "#,
             expect![[r#"
                 *foo_test*
@@ -994,7 +1041,7 @@ fn new() -> Thing { Thing { x: 0 } }
     }
 }
 
-fn main() { let foo_test = wrapper::Thing::new<|>(); }
+fn main() { let foo_test = wrapper::Thing::new$0(); }
 "#,
             expect![[r#"
                 *new*
@@ -1021,7 +1068,7 @@ impl X {
 
 fn main() {
     match 1 {
-        X::C<|> => {},
+        X::C$0 => {},
         2 => {},
         _ => {}
     };
@@ -1047,7 +1094,7 @@ fn test_hover_self() {
             r#"
 struct Thing { x: u32 }
 impl Thing {
-    fn new() -> Self { Self<|> { x: 0 } }
+    fn new() -> Self { Self$0 { x: 0 } }
 }
 "#,
             expect![[r#"
@@ -1066,7 +1113,7 @@ struct Thing
             r#"
 struct Thing { x: u32 }
 impl Thing {
-    fn new() -> Self<|> { Self { x: 0 } }
+    fn new() -> Self$0 { Self { x: 0 } }
 }
 "#,
             expect![[r#"
@@ -1085,7 +1132,7 @@ struct Thing
             r#"
 enum Thing { A }
 impl Thing {
-    pub fn new() -> Self<|> { Thing::A }
+    pub fn new() -> Self$0 { Thing::A }
 }
 "#,
             expect![[r#"
@@ -1104,7 +1151,7 @@ enum Thing
             r#"
         enum Thing { A }
         impl Thing {
-            pub fn thing(a: Self<|>) {}
+            pub fn thing(a: Self$0) {}
         }
         "#,
             expect![[r#"
@@ -1129,7 +1176,7 @@ fn x() {}
 
 fn y() {
     let x = 0i32;
-    x<|>;
+    x$0;
 }
 "#,
             expect![[r#"
@@ -1148,7 +1195,7 @@ fn test_hover_macro_invocation() {
             r#"
 macro_rules! foo { () => {} }
 
-fn f() { fo<|>o!(); }
+fn f() { fo$0o!(); }
 "#,
             expect![[r#"
                 *foo*
@@ -1167,7 +1214,7 @@ macro_rules! foo
     #[test]
     fn test_hover_tuple_field() {
         check(
-            r#"struct TS(String, i32<|>);"#,
+            r#"struct TS(String, i32$0);"#,
             expect![[r#"
                 *i32*
 
@@ -1185,7 +1232,7 @@ fn test_hover_through_macro() {
 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 fn foo() {}
 id! {
-    fn bar() { fo<|>o(); }
+    fn bar() { fo$0o(); }
 }
 "#,
             expect![[r#"
@@ -1207,7 +1254,7 @@ fn test_hover_through_expr_in_macro() {
         check(
             r#"
 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
-fn foo(bar:u32) { let a = id!(ba<|>r); }
+fn foo(bar:u32) { let a = id!(ba$0r); }
 "#,
             expect![[r#"
                 *bar*
@@ -1225,7 +1272,7 @@ fn test_hover_through_expr_in_macro_recursive() {
             r#"
 macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
-fn foo(bar:u32) { let a = id!(ba<|>r); }
+fn foo(bar:u32) { let a = id!(ba$0r); }
 "#,
             expect![[r#"
                 *bar*
@@ -1244,7 +1291,7 @@ fn test_hover_through_func_in_macro_recursive() {
 macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
 fn bar() -> u32 { 0 }
-fn foo() { let a = id!([0u32, bar(<|>)] ); }
+fn foo() { let a = id!([0u32, bar($0)] ); }
 "#,
             expect![[r#"
                 *bar()*
@@ -1262,7 +1309,7 @@ fn test_hover_through_literal_string_in_macro() {
 macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
 fn foo() {
     let mastered_for_itunes = "";
-    let _ = arr!("Tr<|>acks", &mastered_for_itunes);
+    let _ = arr!("Tr$0acks", &mastered_for_itunes);
 }
 "#,
             expect![[r#"
@@ -1283,7 +1330,7 @@ macro_rules! assert {}
 
 fn bar() -> bool { true }
 fn foo() {
-    assert!(ba<|>r());
+    assert!(ba$0r());
 }
 "#,
             expect![[r#"
@@ -1308,7 +1355,7 @@ fn test_hover_through_literal_string_in_builtin_macro() {
             macro_rules! format {}
 
             fn foo() {
-                format!("hel<|>lo {}", 0);
+                format!("hel$0lo {}", 0);
             }
             "#,
         );
@@ -1321,7 +1368,7 @@ fn test_hover_non_ascii_space_doc() {
 /// <- `\u{3000}` here
 fn foo() { }
 
-fn bar() { fo<|>o(); }
+fn bar() { fo$0o(); }
 ",
             expect![[r#"
                 *foo*
@@ -1344,7 +1391,7 @@ fn foo()
     #[test]
     fn test_hover_function_show_qualifiers() {
         check(
-            r#"async fn foo<|>() {}"#,
+            r#"async fn foo$0() {}"#,
             expect![[r#"
                 *foo*
 
@@ -1358,7 +1405,7 @@ async fn foo()
             "#]],
         );
         check(
-            r#"pub const unsafe fn foo<|>() {}"#,
+            r#"pub const unsafe fn foo$0() {}"#,
             expect![[r#"
                 *foo*
 
@@ -1372,7 +1419,7 @@ async fn foo()
             "#]],
         );
         check(
-            r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
+            r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
             expect![[r#"
                 *foo*
 
@@ -1390,10 +1437,10 @@ async fn foo()
     #[test]
     fn test_hover_trait_show_qualifiers() {
         check_actions(
-            r"unsafe trait foo<|>() {}",
+            r"unsafe trait foo$0() {}",
             expect![[r#"
                 [
-                    Implementaion(
+                    Implementation(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -1411,7 +1458,7 @@ fn test_hover_extern_crate() {
         check(
             r#"
 //- /main.rs crate:main deps:std
-extern crate st<|>d;
+extern crate st$0d;
 //- /std/lib.rs crate:std
 //! Standard library for this test
 //!
@@ -1429,7 +1476,7 @@ fn test_hover_extern_crate() {
         check(
             r#"
 //- /main.rs crate:main deps:std
-extern crate std as ab<|>c;
+extern crate std as ab$0c;
 //- /std/lib.rs crate:std
 //! Standard library for this test
 //!
@@ -1450,7 +1497,7 @@ fn test_hover_extern_crate() {
     fn test_hover_mod_with_same_name_as_function() {
         check(
             r#"
-use self::m<|>y::Bar;
+use self::m$0y::Bar;
 mod my { pub struct Bar; }
 
 fn my() {}
@@ -1476,7 +1523,7 @@ fn test_hover_struct_doc_comment() {
 /// bar docs
 struct Bar;
 
-fn foo() { let bar = Ba<|>r; }
+fn foo() { let bar = Ba$0r; }
 "#,
             expect![[r#"
                 *Bar*
@@ -1503,7 +1550,7 @@ fn test_hover_struct_doc_attr() {
 #[doc = "bar docs"]
 struct Bar;
 
-fn foo() { let bar = Ba<|>r; }
+fn foo() { let bar = Ba$0r; }
 "#,
             expect![[r#"
                 *Bar*
@@ -1532,7 +1579,7 @@ fn test_hover_struct_doc_attr_multiple_and_mixed() {
 #[doc = "bar docs 2"]
 struct Bar;
 
-fn foo() { let bar = Ba<|>r; }
+fn foo() { let bar = Ba$0r; }
 "#,
             expect![[r#"
                 *Bar*
@@ -1560,7 +1607,7 @@ fn test_hover_path_link() {
             r#"
 pub struct Foo;
 /// [Foo](struct.Foo.html)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1586,7 +1633,7 @@ fn test_hover_path_link_no_strip() {
             r#"
 pub struct Foo;
 /// [struct Foo](struct.Foo.html)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1614,7 +1661,7 @@ fn test_hover_path_link_field() {
 pub struct Foo;
 pub struct Bar {
     /// [Foo](struct.Foo.html)
-    fie<|>ld: ()
+    fie$0ld: ()
 }
 "#,
             expect![[r#"
@@ -1643,7 +1690,7 @@ pub mod foo {
     pub struct Foo;
 }
 /// [Foo](foo::Foo)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1673,7 +1720,7 @@ pub mod foo {
     pub struct Foo;
 }
 /// [Foo](foo::Foo)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1699,7 +1746,7 @@ fn test_hover_intra_link_shortlink() {
             r#"
 pub struct Foo;
 /// [Foo]
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1725,7 +1772,7 @@ fn test_hover_intra_link_shortlink_code() {
             r#"
 pub struct Foo;
 /// [`Foo`]
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1752,7 +1799,7 @@ fn test_hover_intra_link_namespaced() {
 pub struct Foo;
 fn Foo() {}
 /// [Foo()]
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1778,7 +1825,7 @@ fn test_hover_intra_link_shortlink_namspaced_code() {
             r#"
 pub struct Foo;
 /// [`struct Foo`]
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1804,7 +1851,7 @@ fn test_hover_intra_link_shortlink_namspaced_code_with_at() {
             r#"
 pub struct Foo;
 /// [`struct@Foo`]
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1832,7 +1879,7 @@ fn test_hover_intra_link_reference() {
 /// [my Foo][foo]
 ///
 /// [foo]: Foo
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1851,6 +1898,35 @@ pub struct Bar
             "#]],
         );
     }
+    #[test]
+    fn test_hover_intra_link_reference_to_trait_method() {
+        check(
+            r#"
+pub trait Foo {
+    fn buzz() -> usize;
+}
+/// [Foo][buzz]
+///
+/// [buzz]: Foo::buzz
+pub struct B$0ar
+"#,
+            expect![[r#"
+                *Bar*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                pub struct Bar
+                ```
+
+                ---
+
+                [Foo](https://docs.rs/test/*/test/trait.Foo.html#tymethod.buzz)
+            "#]],
+        );
+    }
 
     #[test]
     fn test_hover_external_url() {
@@ -1858,7 +1934,7 @@ fn test_hover_external_url() {
             r#"
 pub struct Foo;
 /// [external](https://www.google.com)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1885,7 +1961,7 @@ fn test_hover_unknown_target() {
             r#"
 pub struct Foo;
 /// [baz](Baz)
-pub struct B<|>ar
+pub struct B$0ar
 "#,
             expect![[r#"
                 *Bar*
@@ -1911,7 +1987,7 @@ fn test_doc_links_enum_variant() {
             r#"
 enum E {
     /// [E]
-    V<|> { field: i32 }
+    V$0 { field: i32 }
 }
 "#,
             expect![[r#"
@@ -1938,7 +2014,7 @@ fn test_doc_links_field() {
             r#"
 struct S {
     /// [`S`]
-    field<|>: i32
+    field$0: i32
 }
 "#,
             expect![[r#"
@@ -1966,16 +2042,16 @@ fn test_hover_no_links() {
 /// Test cases:
 /// case 1.  bare URL: https://www.example.com/
 /// case 2.  inline URL with title: [example](https://www.example.com/)
-/// case 3.  code refrence: [`Result`]
-/// case 4.  code refrence but miss footnote: [`String`]
+/// case 3.  code reference: [`Result`]
+/// case 4.  code reference but miss footnote: [`String`]
 /// case 5.  autolink: <http://www.example.com/>
 /// case 6.  email address: <test@example.com>
-/// case 7.  refrence: [example][example]
+/// case 7.  reference: [example][example]
 /// case 8.  collapsed link: [example][]
 /// case 9.  shortcut link: [example]
 /// case 10. inline without URL: [example]()
-/// case 11. refrence: [foo][foo]
-/// case 12. refrence: [foo][bar]
+/// case 11. reference: [foo][foo]
+/// case 12. reference: [foo][bar]
 /// case 13. collapsed link: [foo][]
 /// case 14. shortcut link: [foo]
 /// case 15. inline without URL: [foo]()
@@ -1984,7 +2060,7 @@ fn test_hover_no_links() {
 ///
 /// [`Result`]: ../../std/result/enum.Result.html
 /// [^example]: https://www.example.com/
-pub fn fo<|>o() {}
+pub fn fo$0o() {}
 "#,
             expect![[r#"
                 *foo*
@@ -2002,16 +2078,16 @@ pub fn foo()
                 Test cases:
                 case 1.  bare URL: https://www.example.com/
                 case 2.  inline URL with title: [example](https://www.example.com/)
-                case 3.  code refrence: `Result`
-                case 4.  code refrence but miss footnote: `String`
+                case 3.  code reference: `Result`
+                case 4.  code reference but miss footnote: `String`
                 case 5.  autolink: http://www.example.com/
                 case 6.  email address: test@example.com
-                case 7.  refrence: example
+                case 7.  reference: example
                 case 8.  collapsed link: example
                 case 9.  shortcut link: example
                 case 10. inline without URL: example
-                case 11. refrence: foo
-                case 12. refrence: foo
+                case 11. reference: foo
+                case 12. reference: foo
                 case 13. collapsed link: foo
                 case 14. shortcut link: foo
                 case 15. inline without URL: foo
@@ -2041,7 +2117,7 @@ fn foo(&self) {}
 
 bar!();
 
-fn foo() { let bar = Bar; bar.fo<|>o(); }
+fn foo() { let bar = Bar; bar.fo$0o(); }
 "#,
             expect![[r#"
                 *foo*
@@ -2079,7 +2155,7 @@ fn foo(&self) {}
 
 bar!();
 
-fn foo() { let bar = Bar; bar.fo<|>o(); }
+fn foo() { let bar = Bar; bar.fo$0o(); }
 "#,
             expect![[r#"
                 *foo*
@@ -2102,10 +2178,10 @@ fn foo(&self)
     #[test]
     fn test_hover_trait_has_impl_action() {
         check_actions(
-            r#"trait foo<|>() {}"#,
+            r#"trait foo$0() {}"#,
             expect![[r#"
                 [
-                    Implementaion(
+                    Implementation(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2121,10 +2197,10 @@ fn test_hover_trait_has_impl_action() {
     #[test]
     fn test_hover_struct_has_impl_action() {
         check_actions(
-            r"struct foo<|>() {}",
+            r"struct foo$0() {}",
             expect![[r#"
                 [
-                    Implementaion(
+                    Implementation(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2140,10 +2216,10 @@ fn test_hover_struct_has_impl_action() {
     #[test]
     fn test_hover_union_has_impl_action() {
         check_actions(
-            r#"union foo<|>() {}"#,
+            r#"union foo$0() {}"#,
             expect![[r#"
                 [
-                    Implementaion(
+                    Implementation(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2159,10 +2235,10 @@ fn test_hover_union_has_impl_action() {
     #[test]
     fn test_hover_enum_has_impl_action() {
         check_actions(
-            r"enum foo<|>() { A, B }",
+            r"enum foo$0() { A, B }",
             expect![[r#"
                 [
-                    Implementaion(
+                    Implementation(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2175,12 +2251,31 @@ fn test_hover_enum_has_impl_action() {
         );
     }
 
+    #[test]
+    fn test_hover_self_has_impl_action() {
+        check_actions(
+            r#"struct foo where Self$0:;"#,
+            expect![[r#"
+                [
+                    Implementation(
+                        FilePosition {
+                            file_id: FileId(
+                                0,
+                            ),
+                            offset: 7,
+                        },
+                    ),
+                ]
+            "#]],
+        );
+    }
+
     #[test]
     fn test_hover_test_has_action() {
         check_actions(
             r#"
 #[test]
-fn foo_<|>test() {}
+fn foo_$0test() {}
 "#,
             expect![[r#"
                 [
@@ -2215,7 +2310,7 @@ fn foo_<|>test() {}
     fn test_hover_test_mod_has_action() {
         check_actions(
             r#"
-mod tests<|> {
+mod tests$0 {
     #[test]
     fn foo_test() {}
 }
@@ -2250,7 +2345,7 @@ fn test_hover_struct_has_goto_type_action() {
             r#"
 struct S{ f1: u32 }
 
-fn main() { let s<|>t = S{ f1:0 }; }
+fn main() { let s$0t = S{ f1:0 }; }
             "#,
             expect![[r#"
                 [
@@ -2283,7 +2378,7 @@ fn test_hover_generic_struct_has_goto_type_actions() {
 struct Arg(u32);
 struct S<T>{ f1: T }
 
-fn main() { let s<|>t = S{ f1:Arg(0) }; }
+fn main() { let s$0t = S{ f1:Arg(0) }; }
 "#,
             expect![[r#"
                 [
@@ -2329,7 +2424,7 @@ fn test_hover_generic_struct_has_flattened_goto_type_actions() {
 struct Arg(u32);
 struct S<T>{ f1: T }
 
-fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
+fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
             "#,
             expect![[r#"
                 [
@@ -2378,7 +2473,7 @@ mod M {
     pub struct C(u32);
 }
 
-fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
+fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
 "#,
             expect![[r#"
                 [
@@ -2437,7 +2532,7 @@ fn test_hover_return_impl_trait_has_goto_type_action() {
 trait Foo {}
 fn foo() -> impl Foo {}
 
-fn main() { let s<|>t = foo(); }
+fn main() { let s$0t = foo(); }
 "#,
             expect![[r#"
                 [
@@ -2471,7 +2566,7 @@ trait Foo<T> {}
 struct S;
 fn foo() -> impl Foo<S> {}
 
-fn main() { let s<|>t = foo(); }
+fn main() { let s$0t = foo(); }
 "#,
             expect![[r#"
                 [
@@ -2518,7 +2613,7 @@ trait Foo {}
 trait Bar {}
 fn foo() -> impl Foo + Bar {}
 
-fn main() { let s<|>t = foo(); }
+fn main() { let s$0t = foo(); }
             "#,
             expect![[r#"
                 [
@@ -2568,7 +2663,7 @@ struct S2 {}
 
 fn foo() -> impl Foo<S1> + Bar<S2> {}
 
-fn main() { let s<|>t = foo(); }
+fn main() { let s$0t = foo(); }
 "#,
             expect![[r#"
                 [
@@ -2638,7 +2733,7 @@ fn test_hover_arg_impl_trait_has_goto_type_action() {
         check_actions(
             r#"
 trait Foo {}
-fn foo(ar<|>g: &impl Foo) {}
+fn foo(ar$0g: &impl Foo) {}
 "#,
             expect![[r#"
                 [
@@ -2672,7 +2767,7 @@ trait Foo {}
 trait Bar<T> {}
 struct S{}
 
-fn foo(ar<|>g: &impl Foo + Bar<S>) {}
+fn foo(ar$0g: &impl Foo + Bar<S>) {}
 "#,
             expect![[r#"
                 [
@@ -2730,7 +2825,7 @@ fn test_hover_async_block_impl_trait_has_goto_type_action() {
             r#"
 struct S;
 fn foo() {
-    let fo<|>o = async { S };
+    let fo$0o = async { S };
 }
 
 #[prelude_import] use future::*;
@@ -2782,7 +2877,7 @@ fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
             r#"
 trait Foo<T> {}
 struct S {}
-fn foo(ar<|>g: &impl Foo<S>) {}
+fn foo(ar$0g: &impl Foo<S>) {}
 "#,
             expect![[r#"
                 [
@@ -2832,7 +2927,7 @@ impl Foo for S {}
 struct B<T>{}
 fn foo() -> B<dyn Foo> {}
 
-fn main() { let s<|>t = foo(); }
+fn main() { let s$0t = foo(); }
 "#,
             expect![[r#"
                 [
@@ -2876,7 +2971,7 @@ fn test_hover_dyn_arg_has_goto_type_action() {
         check_actions(
             r#"
 trait Foo {}
-fn foo(ar<|>g: &dyn Foo) {}
+fn foo(ar$0g: &dyn Foo) {}
 "#,
             expect![[r#"
                 [
@@ -2908,7 +3003,7 @@ fn test_hover_generic_dyn_arg_has_goto_type_action() {
             r#"
 trait Foo<T> {}
 struct S {}
-fn foo(ar<|>g: &dyn Foo<S>) {}
+fn foo(ar$0g: &dyn Foo<S>) {}
 "#,
             expect![[r#"
                 [
@@ -2956,7 +3051,7 @@ trait DynTrait<T> {}
 struct B<T> {}
 struct S {}
 
-fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
+fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
             "#,
             expect![[r#"
                 [
@@ -3037,7 +3132,7 @@ struct S{}
 
 fn test() -> impl Foo { S {} }
 
-fn main() { let s<|>t = test().get(); }
+fn main() { let s$0t = test().get(); }
 "#,
             expect![[r#"
                 [
@@ -3063,6 +3158,104 @@ fn test() -> impl Foo { S {} }
         );
     }
 
+    #[test]
+    fn test_hover_const_param_has_goto_type_action() {
+        check_actions(
+            r#"
+struct Bar;
+struct Foo<const BAR: Bar>;
+
+impl<const BAR: Bar> Foo<BAR$0> {}
+"#,
+            expect![[r#"
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Bar",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..11,
+                                    focus_range: 7..10,
+                                    name: "Bar",
+                                    kind: Struct,
+                                    description: "struct Bar",
+                                },
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_hover_type_param_has_goto_type_action() {
+        check_actions(
+            r#"
+trait Foo {}
+
+fn foo<T: Foo>(t: T$0){}
+"#,
+            expect![[r#"
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Foo",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..12,
+                                    focus_range: 6..9,
+                                    name: "Foo",
+                                    kind: Trait,
+                                    description: "trait Foo",
+                                },
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_hover_self_has_go_to_type() {
+        check_actions(
+            r#"
+struct Foo;
+impl Foo {
+    fn foo(&self$0) {}
+}
+"#,
+            expect![[r#"
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Foo",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..11,
+                                    focus_range: 7..10,
+                                    name: "Foo",
+                                    kind: Struct,
+                                    description: "struct Foo",
+                                },
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
     #[test]
     fn hover_displays_normalized_crate_names() {
         check(
@@ -3077,7 +3270,7 @@ pub fn new() -> Thing { Thing { x: 0 } }
 }
 
 //- /main.rs crate:main deps:name-with-dashes
-fn main() { let foo_test = name_with_dashes::wrapper::Thing::new<|>(); }
+fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
 "#,
             expect![[r#"
             *new*
@@ -3103,7 +3296,7 @@ struct S {
 
 fn main() {
     let s = S { f: 0 };
-    let S { f<|> } = &s;
+    let S { f$0 } = &s;
 }
 "#,
             expect![[r#"
@@ -3122,11 +3315,12 @@ fn hover_self_param_shows_type() {
             r#"
 struct Foo {}
 impl Foo {
-    fn bar(&sel<|>f) {}
+    fn bar(&sel$0f) {}
 }
 "#,
             expect![[r#"
-                *&self*
+                *self*
+
                 ```rust
                 &Foo
                 ```
@@ -3141,11 +3335,12 @@ fn hover_self_param_shows_type_for_arbitrary_self_type() {
 struct Arc<T>(T);
 struct Foo {}
 impl Foo {
-    fn bar(sel<|>f: Arc<Foo>) {}
+    fn bar(sel$0f: Arc<Foo>) {}
 }
 "#,
             expect![[r#"
-                *self: Arc<Foo>*
+                *self*
+
                 ```rust
                 Arc<Foo>
                 ```
@@ -3158,7 +3353,7 @@ fn hover_doc_outer_inner() {
         check(
             r#"
 /// Be quick;
-mod Foo<|> {
+mod Foo$0 {
     //! time is mana
 
     /// This comment belongs to the function
@@ -3189,7 +3384,7 @@ fn hover_doc_outer_inner_attribue() {
         check(
             r#"
 #[doc = "Be quick;"]
-mod Foo<|> {
+mod Foo$0 {
     #![doc = "time is mana"]
 
     #[doc = "This comment belongs to the function"]
@@ -3220,7 +3415,7 @@ fn hover_comments_dont_highlight_parent() {
         check_hover_no_result(
             r#"
 fn no_hover() {
-    // no<|>hover
+    // no$0hover
 }
 "#,
         );
@@ -3231,7 +3426,7 @@ fn hover_label() {
         check(
             r#"
 fn foo() {
-    'label<|>: loop {}
+    'label$0: loop {}
 }
 "#,
             expect![[r#"
@@ -3247,7 +3442,7 @@ fn foo() {
     #[test]
     fn hover_lifetime() {
         check(
-            r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#,
+            r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
             expect![[r#"
             *'lifetime*
 
@@ -3257,4 +3452,186 @@ fn hover_lifetime() {
             "#]],
         );
     }
+
+    #[test]
+    fn hover_type_param() {
+        check(
+            r#"
+struct Foo<T>(T);
+trait Copy {}
+trait Clone {}
+trait Sized {}
+impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
+"#,
+            expect![[r#"
+                *T*
+
+                ```rust
+                T: Copy + Clone + Sized
+                ```
+            "#]],
+        );
+        check(
+            r#"
+struct Foo<T>(T);
+impl<T> Foo<T$0> {}
+"#,
+            expect![[r#"
+                *T*
+
+                ```rust
+                T
+                ```
+                "#]],
+        );
+        // lifetimes bounds arent being tracked yet
+        check(
+            r#"
+struct Foo<T>(T);
+impl<T: 'static> Foo<T$0> {}
+"#,
+            expect![[r#"
+                *T*
+
+                ```rust
+                T
+                ```
+                "#]],
+        );
+    }
+
+    #[test]
+    fn hover_const_param() {
+        check(
+            r#"
+struct Foo<const LEN: usize>;
+impl<const LEN: usize> Foo<LEN$0> {}
+"#,
+            expect![[r#"
+                *LEN*
+
+                ```rust
+                const LEN: usize
+                ```
+            "#]],
+        );
+    }
+
+    #[test]
+    fn hover_const_pat() {
+        check(
+            r#"
+/// This is a doc
+const FOO: usize = 3;
+fn foo() {
+    match 5 {
+        FOO$0 => (),
+        _ => ()
+    }
+}
+"#,
+            expect![[r#"
+                *FOO*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                const FOO: usize = 3
+                ```
+
+                ---
+
+                This is a doc
+            "#]],
+        );
+    }
+
+    #[test]
+    fn hover_mod_def() {
+        check(
+            r#"
+//- /main.rs
+mod foo$0;
+//- /foo.rs
+//! For the horde!
+"#,
+            expect![[r#"
+                *foo*
+                For the horde!
+            "#]],
+        );
+    }
+
+    #[test]
+    fn hover_self_in_use() {
+        check(
+            r#"
+//! This should not appear
+mod foo {
+    /// But this should appear
+    pub mod bar {}
+}
+use foo::bar::{self$0};
+"#,
+            expect![[r#"
+                *self*
+
+                ```rust
+                test::foo
+                ```
+
+                ```rust
+                pub mod bar
+                ```
+
+                ---
+
+                But this should appear
+            "#]],
+        )
+    }
+
+    #[test]
+    fn hover_keyword() {
+        let ra_fixture = r#"//- /main.rs crate:main deps:std
+fn f() { retur$0n; }"#;
+        let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE);
+        check(
+            &fixture,
+            expect![[r#"
+                *return*
+
+                ```rust
+                return
+                ```
+
+                ---
+
+                Docs for return_keyword
+            "#]],
+        );
+    }
+
+    #[test]
+    fn hover_builtin() {
+        let ra_fixture = r#"//- /main.rs crate:main deps:std
+cosnt _: &str$0 = ""; }"#;
+        let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE);
+        check(
+            &fixture,
+            expect![[r#"
+                *str*
+
+                ```rust
+                str
+                ```
+
+                ---
+
+                Docs for prim_str
+            "#]],
+        );
+    }
 }