]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide/src/hover.rs
clippy::redudant_borrow
[rust.git] / crates / ide / src / hover.rs
index a9454cfa317342c56225449c240640edd2df8259..b4b3b45b565a1c8ce2b9e49e14c25c591f66b55c 100644 (file)
@@ -1,21 +1,30 @@
+use either::Either;
 use hir::{
-    Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
-    HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
+    AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
+    ModuleDef, Semantics,
 };
 use ide_db::{
     base_db::SourceDatabase,
     defs::{Definition, NameClass, NameRefClass},
-    helpers::FamousDefs,
+    helpers::{
+        generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
+        FamousDefs,
+    },
     RootDatabase,
 };
 use itertools::Itertools;
 use stdx::format_to;
-use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
-use test_utils::mark;
+use syntax::{
+    algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, TokenAtOffset,
+    T,
+};
 
 use crate::{
-    display::{macro_label, ShortLabel, TryToNav},
-    doc_links::{remove_links, rewrite_links},
+    display::{macro_label, TryToNav},
+    doc_links::{
+        doc_attributes, extract_definitions_from_markdown, remove_links, resolve_doc_path_for_def,
+        rewrite_links,
+    },
     markdown_remove::remove_markdown,
     markup::Markup,
     runnables::{runnable_fn, runnable_mod},
@@ -25,6 +34,7 @@
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct HoverConfig {
     pub implementations: bool,
+    pub references: bool,
     pub run: bool,
     pub debug: bool,
     pub goto_type_def: bool,
@@ -35,6 +45,7 @@ pub struct HoverConfig {
 impl HoverConfig {
     pub const NO_ACTIONS: Self = Self {
         implementations: false,
+        references: false,
         run: false,
         debug: false,
         goto_type_def: false,
@@ -43,7 +54,7 @@ impl HoverConfig {
     };
 
     pub fn any(&self) -> bool {
-        self.implementations || self.runnable() || self.goto_type_def
+        self.implementations || self.references || self.runnable() || self.goto_type_def
     }
 
     pub fn none(&self) -> bool {
@@ -59,6 +70,7 @@ pub fn runnable(&self) -> bool {
 pub enum HoverAction {
     Runnable(Runnable),
     Implementation(FilePosition),
+    Reference(FilePosition),
     GoToType(Vec<HoverGotoTypeData>),
 }
 
@@ -79,6 +91,8 @@ pub struct HoverResult {
 //
 // Shows additional information, like type of an expression or documentation for definition when "focusing" code.
 // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
+//
+// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
 pub(crate) fn hover(
     db: &RootDatabase,
     position: FilePosition,
@@ -92,21 +106,49 @@ pub(crate) fn hover(
 
     let mut res = HoverResult::default();
 
-    let node = token.parent();
+    let node = token.parent()?;
+    let mut range = None;
     let definition = match_ast! {
         match node {
             // 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),
+                def => def.defined(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)),
-            _ => None,
+            ast::NameRef(name_ref) => {
+                NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(db))
+            },
+            ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else(
+                || NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(db)),
+                |d| d.defined(db),
+            ),
+
+            _ => {
+                if ast::Comment::cast(token.clone()).is_some() {
+                    cov_mark::hit!(no_highlight_on_comment_hover);
+                    let (attributes, def) = doc_attributes(&sema, &node)?;
+                    let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
+                    let (idl_range, link, ns) =
+                        extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| {
+                            let InFile { file_id, value: range } = doc_mapping.map(range.clone())?;
+                            if file_id == position.file_id.into() && range.contains(position.offset) {
+                                Some((range, link, ns))
+                            } else {
+                                None
+                            }
+                        })?;
+                    range = Some(idl_range);
+                    resolve_doc_path_for_def(db, def, &link, ns).map(Definition::ModuleDef)
+                } else if let res@Some(_) = try_hover_for_attribute(&token) {
+                    return res;
+                } else {
+                    None
+                }
+            },
         }
     };
+
     if let Some(definition) = definition {
         let famous_defs = match &definition {
             Definition::ModuleDef(ModuleDef::BuiltinType(_)) => {
@@ -120,6 +162,10 @@ pub(crate) fn hover(
                 res.actions.push(action);
             }
 
+            if let Some(action) = show_fn_references_action(db, definition) {
+                res.actions.push(action);
+            }
+
             if let Some(action) = runnable_action(&sema, definition, position.file_id) {
                 res.actions.push(action);
             }
@@ -128,15 +174,11 @@ pub(crate) fn hover(
                 res.actions.push(action);
             }
 
-            let range = sema.original_range(&node).range;
+            let range = range.unwrap_or_else(|| sema.original_range(&node).range);
             return Some(RangeInfo::new(range, res));
         }
     }
 
-    if token.kind() == syntax::SyntaxKind::COMMENT {
-        // 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;
     }
@@ -165,6 +207,51 @@ pub(crate) fn hover(
     Some(RangeInfo::new(range, res))
 }
 
+fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
+    let attr = token.ancestors().find_map(ast::Attr::cast)?;
+    let (path, tt) = attr.as_simple_call()?;
+    if !tt.syntax().text_range().contains(token.text_range().start()) {
+        return None;
+    }
+    let (is_clippy, lints) = match &*path {
+        "feature" => (false, FEATURES),
+        "allow" | "deny" | "forbid" | "warn" => {
+            let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev)
+                .filter(|t| t.kind() == T![:])
+                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
+                .filter(|t| t.kind() == T![:])
+                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
+                .map_or(false, |t| {
+                    t.kind() == T![ident] && t.into_token().map_or(false, |t| t.text() == "clippy")
+                });
+            if is_clippy {
+                (true, CLIPPY_LINTS)
+            } else {
+                (false, DEFAULT_LINTS)
+            }
+        }
+        _ => return None,
+    };
+
+    let tmp;
+    let needle = if is_clippy {
+        tmp = format!("clippy::{}", token.text());
+        &tmp
+    } else {
+        &*token.text()
+    };
+
+    let lint =
+        lints.binary_search_by_key(&needle, |lint| lint.label).ok().map(|idx| &lints[idx])?;
+    Some(RangeInfo::new(
+        token.text_range(),
+        HoverResult {
+            markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)),
+            ..Default::default()
+        },
+    ))
+}
+
 fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
     fn to_action(nav_target: NavigationTarget) -> HoverAction {
         HoverAction::Implementation(FilePosition {
@@ -176,12 +263,24 @@ fn to_action(nav_target: NavigationTarget) -> HoverAction {
     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(),
+        Definition::SelfType(it) => it.self_ty(db).as_adt(),
         _ => None,
     }?;
     adt.try_to_nav(db).map(to_action)
 }
 
+fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
+    match def {
+        Definition::ModuleDef(ModuleDef::Function(it)) => it.try_to_nav(db).map(|nav_target| {
+            HoverAction::Reference(FilePosition {
+                file_id: nav_target.file_id,
+                offset: nav_target.focus_or_full_range().start(),
+            })
+        }),
+        _ => None,
+    }
+}
+
 fn runnable_action(
     sema: &Semantics<RootDatabase>,
     def: Definition,
@@ -189,16 +288,16 @@ fn runnable_action(
 ) -> Option<HoverAction> {
     match def {
         Definition::ModuleDef(it) => match it {
-            ModuleDef::Module(it) => runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)),
+            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);
+                    cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
+                    cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
                     return None;
                 }
 
-                runnable_fn(&sema, func).map(HoverAction::Runnable)
+                runnable_fn(sema, func).map(HoverAction::Runnable)
             }
             _ => None,
         },
@@ -299,7 +398,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
         Definition::ModuleDef(md) => match md {
             ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
                 AssocItemContainer::Trait(t) => Some(t.name(db)),
-                AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
+                AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
             },
             ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
             _ => None,
@@ -331,65 +430,44 @@ fn hover_for_definition(
 ) -> Option<Markup> {
     let mod_path = definition_mod_path(db, &def);
     return match def {
-        Definition::Macro(it) => {
-            let label = macro_label(&it.source(db)?.value);
-            from_def_source_labeled(db, it, Some(label), mod_path)
-        }
-        Definition::Field(def) => {
-            let src = def.source(db)?.value;
-            if let FieldSource::Named(it) = src {
-                from_def_source_labeled(db, def, it.short_label(), mod_path)
-            } else {
+        Definition::Macro(it) => match &it.source(db)?.value {
+            Either::Left(mac) => {
+                let label = macro_label(mac);
+                from_def_source_labeled(db, it, Some(label), mod_path)
+            }
+            Either::Right(_) => {
+                // FIXME
                 None
             }
-        }
+        },
+        Definition::Field(def) => from_hir_fmt(db, def, mod_path),
         Definition::ModuleDef(it) => match it {
-            ModuleDef::Module(it) => from_def_source_labeled(
-                db,
-                it,
-                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,
-            ),
-            ModuleDef::Function(it) => from_def_source(db, it, mod_path),
-            ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
-            ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
-            ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
-            ModuleDef::Variant(it) => from_def_source(db, it, mod_path),
-            ModuleDef::Const(it) => from_def_source(db, it, mod_path),
-            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::Module(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Adt(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path),
+            ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path),
             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::Local(it) => hover_for_local(it, db),
         Definition::SelfType(impl_def) => {
-            impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
-                Adt::Struct(it) => from_def_source(db, it, mod_path),
-                Adt::Union(it) => from_def_source(db, it, mod_path),
-                Adt::Enum(it) => from_def_source(db, it, mod_path),
-            })
+            impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path))
         }
+        Definition::GenericParam(it) => from_hir_fmt(db, it, None),
         Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
-        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>
+    fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
     where
-        D: HasSource<Ast = A> + HasAttrs + Copy,
-        A: ShortLabel,
+        D: HasAttrs + HirDisplay,
     {
-        let short_label = def.source(db)?.value.short_label();
-        from_def_source_labeled(db, def, short_label, mod_path)
+        let label = def.display(db).to_string();
+        from_def_source_labeled(db, def, Some(label), mod_path)
     }
 
     fn from_def_source_labeled<D>(
@@ -406,6 +484,29 @@ fn from_def_source_labeled<D>(
     }
 }
 
+fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
+    let ty = it.ty(db);
+    let ty = ty.display(db);
+    let is_mut = if it.is_mut(db) { "mut " } else { "" };
+    let desc = match it.source(db).value {
+        Either::Left(ident) => {
+            let name = it.name(db).unwrap();
+            let let_kw = if ident
+                .syntax()
+                .parent()
+                .map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION)
+            {
+                "let "
+            } else {
+                ""
+            };
+            format!("{}{}{}: {}", let_kw, is_mut, name, ty)
+        }
+        Either::Right(_) => format!("{}self: {}", is_mut, ty),
+    };
+    hover_markup(None, Some(desc), None)
+}
+
 fn hover_for_keyword(
     sema: &Semantics<RootDatabase>,
     links_in_hover: bool,
@@ -415,7 +516,7 @@ fn hover_for_keyword(
     if !token.kind().is_keyword() {
         return None;
     }
-    let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()).krate());
+    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)?;
@@ -449,6 +550,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module>
 
 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 | T![self] | T![super] | T![crate] => 3,
@@ -575,7 +677,7 @@ fn main() {
                 *iter*
 
                 ```rust
-                Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
+                let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
                 ```
             "#]],
         );
@@ -647,7 +749,9 @@ pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
                 ```
 
                 ```rust
-                pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
+                pub fn foo<'a, T>(b: &'a T) -> &'a str
+                where
+                    T: AsRef<str>,
                 ```
             "#]],
         );
@@ -799,7 +903,7 @@ fn hover_const_static() {
                 ```
 
                 ```rust
-                const foo: u32 = 123
+                const foo: u32
                 ```
             "#]],
         );
@@ -832,7 +936,7 @@ fn main() {
                 *zz*
 
                 ```rust
-                Test<i32, u8>
+                let zz: Test<i32, u8>
                 ```
             "#]],
         );
@@ -855,7 +959,7 @@ enum Option<T> { Some(T) }
                 ```
 
                 ```rust
-                Some
+                Some(T)
                 ```
             "#]],
         );
@@ -871,7 +975,7 @@ enum Option<T> { Some(T) }
                 *bar*
 
                 ```rust
-                Option<i32>
+                let bar: Option<i32>
                 ```
             "#]],
         );
@@ -921,7 +1025,7 @@ fn main() {
                 ```
 
                 ```rust
-                Some
+                Some(T)
                 ```
 
                 ---
@@ -939,7 +1043,7 @@ fn hover_for_local_variable() {
                 *foo*
 
                 ```rust
-                i32
+                foo: i32
                 ```
             "#]],
         )
@@ -953,7 +1057,7 @@ fn hover_for_local_variable_pat() {
                 *foo*
 
                 ```rust
-                i32
+                foo: i32
                 ```
             "#]],
         )
@@ -967,7 +1071,7 @@ fn hover_local_var_edge() {
                 *foo*
 
                 ```rust
-                i32
+                foo: i32
                 ```
             "#]],
         )
@@ -981,7 +1085,7 @@ fn hover_for_param_edge() {
                 *foo*
 
                 ```rust
-                i32
+                foo: i32
                 ```
             "#]],
         )
@@ -1001,7 +1105,7 @@ fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
                 *_x*
 
                 ```rust
-                impl Deref<Target = u8> + DerefMut<Target = u8>
+                _x: impl Deref<Target = u8> + DerefMut<Target = u8>
                 ```
             "#]],
         )
@@ -1023,7 +1127,7 @@ fn new() -> Thing { Thing { x: 0 } }
                 *foo_test*
 
                 ```rust
-                Thing
+                let foo_test: Thing
                 ```
             "#]],
         )
@@ -1082,7 +1186,7 @@ fn main() {
                 ```
 
                 ```rust
-                const C: u32 = 1
+                const C: u32
                 ```
             "#]],
         )
@@ -1183,7 +1287,7 @@ fn y() {
                 *x*
 
                 ```rust
-                i32
+                let x: i32
                 ```
             "#]],
         )
@@ -1211,6 +1315,37 @@ macro_rules! foo
         )
     }
 
+    #[test]
+    fn test_hover_macro2_invocation() {
+        check(
+            r#"
+/// foo bar
+///
+/// foo bar baz
+macro foo() {}
+
+fn f() { fo$0o!(); }
+"#,
+            expect![[r#"
+                *foo*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                macro foo
+                ```
+
+                ---
+
+                foo bar
+
+                foo bar baz
+            "#]],
+        )
+    }
+
     #[test]
     fn test_hover_tuple_field() {
         check(
@@ -1260,7 +1395,7 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
                 *bar*
 
                 ```rust
-                u32
+                bar: u32
                 ```
             "#]],
         );
@@ -1278,7 +1413,7 @@ macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
                 *bar*
 
                 ```rust
-                u32
+                bar: u32
                 ```
             "#]],
         );
@@ -1418,13 +1553,14 @@ async fn foo()
                 ```
             "#]],
         );
+        // Top level `pub(crate)` will be displayed as no visibility.
         check(
-            r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
+            r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
             expect![[r#"
                 *foo*
 
                 ```rust
-                test
+                test::m
                 ```
 
                 ```rust
@@ -1466,11 +1602,18 @@ fn test_hover_extern_crate() {
 //! abc123
             "#,
             expect![[r#"
-            *std*
-            Standard library for this test
+                *std*
+
+                ```rust
+                extern crate std
+                ```
+
+                ---
+
+                Standard library for this test
 
-            Printed?
-            abc123
+                Printed?
+                abc123
             "#]],
         );
         check(
@@ -1484,11 +1627,18 @@ fn test_hover_extern_crate() {
 //! abc123
             "#,
             expect![[r#"
-            *abc*
-            Standard library for this test
+                *abc*
+
+                ```rust
+                extern crate std
+                ```
 
-            Printed?
-            abc123
+                ---
+
+                Standard library for this test
+
+                Printed?
+                abc123
             "#]],
         );
     }
@@ -1520,12 +1670,21 @@ mod my
     fn test_hover_struct_doc_comment() {
         check(
             r#"
-/// bar docs
+/// This is an example
+/// multiline doc
+///
+/// # Example
+///
+/// ```
+/// let five = 5;
+///
+/// assert_eq!(6, my_crate::add_one(5));
+/// ```
 struct Bar;
 
 fn foo() { let bar = Ba$0r; }
 "#,
-            expect![[r#"
+            expect![[r##"
                 *Bar*
 
                 ```rust
@@ -1538,8 +1697,17 @@ struct Bar
 
                 ---
 
-                bar docs
-            "#]],
+                This is an example
+                multiline doc
+
+                # Example
+
+                ```
+                let five = 5;
+
+                assert_eq!(6, my_crate::add_one(5));
+                ```
+            "##]],
         );
     }
 
@@ -1998,7 +2166,7 @@ enum E {
                 ```
 
                 ```rust
-                V
+                V { field: i32 }
                 ```
 
                 ---
@@ -2101,7 +2269,7 @@ pub fn foo()
 
     #[test]
     fn test_hover_macro_generated_struct_fn_doc_comment() {
-        mark::check!(hover_macro_generated_struct_fn_doc_comment);
+        cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
 
         check(
             r#"
@@ -2139,7 +2307,7 @@ fn foo(&self)
 
     #[test]
     fn test_hover_macro_generated_struct_fn_doc_attr() {
-        mark::check!(hover_macro_generated_struct_fn_doc_attr);
+        cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
 
         check(
             r#"
@@ -2279,6 +2447,14 @@ fn foo_$0test() {}
 "#,
             expect![[r#"
                 [
+                    Reference(
+                        FilePosition {
+                            file_id: FileId(
+                                0,
+                            ),
+                            offset: 11,
+                        },
+                    ),
                     Runnable(
                         Runnable {
                             nav: NavigationTarget {
@@ -2394,7 +2570,7 @@ struct S<T>{ f1: T }
                                     focus_range: 24..25,
                                     name: "S",
                                     kind: Struct,
-                                    description: "struct S",
+                                    description: "struct S<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2440,7 +2616,7 @@ struct S<T>{ f1: T }
                                     focus_range: 24..25,
                                     name: "S",
                                     kind: Struct,
-                                    description: "struct S",
+                                    description: "struct S<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2582,7 +2758,7 @@ fn foo() -> impl Foo<S> {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo",
+                                    description: "trait Foo<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2679,7 +2855,7 @@ fn foo() -> impl Foo<S1> + Bar<S2> {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo",
+                                    description: "trait Foo<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2692,7 +2868,7 @@ fn foo() -> impl Foo<S1> + Bar<S2> {}
                                     focus_range: 22..25,
                                     name: "Bar",
                                     kind: Trait,
-                                    description: "trait Bar",
+                                    description: "trait Bar<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2796,7 +2972,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
                                     focus_range: 19..22,
                                     name: "Bar",
                                     kind: Trait,
-                                    description: "trait Bar",
+                                    description: "trait Bar<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2893,7 +3069,7 @@ fn foo(ar$0g: &impl Foo<S>) {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo",
+                                    description: "trait Foo<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -2943,7 +3119,7 @@ fn foo() -> B<dyn Foo> {}
                                     focus_range: 49..50,
                                     name: "B",
                                     kind: Struct,
-                                    description: "struct B",
+                                    description: "struct B<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3019,7 +3195,7 @@ fn foo(ar$0g: &dyn Foo<S>) {}
                                     focus_range: 6..9,
                                     name: "Foo",
                                     kind: Trait,
-                                    description: "trait Foo",
+                                    description: "trait Foo<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3067,7 +3243,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 6..15,
                                     name: "ImplTrait",
                                     kind: Trait,
-                                    description: "trait ImplTrait",
+                                    description: "trait ImplTrait<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3080,7 +3256,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 50..51,
                                     name: "B",
                                     kind: Struct,
-                                    description: "struct B",
+                                    description: "struct B<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3093,7 +3269,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
                                     focus_range: 28..36,
                                     name: "DynTrait",
                                     kind: Trait,
-                                    description: "trait DynTrait",
+                                    description: "trait DynTrait<T>",
                                 },
                             },
                             HoverGotoTypeData {
@@ -3303,7 +3479,7 @@ fn main() {
                 *f*
 
                 ```rust
-                &i32
+                f: &i32
                 ```
             "#]],
         );
@@ -3322,7 +3498,7 @@ fn bar(&sel$0f) {}
                 *self*
 
                 ```rust
-                &Foo
+                self: &Foo
                 ```
             "#]],
         );
@@ -3342,7 +3518,7 @@ fn bar(sel$0f: Arc<Foo>) {}
                 *self*
 
                 ```rust
-                Arc<Foo>
+                self: Arc<Foo>
                 ```
             "#]],
         );
@@ -3410,8 +3586,43 @@ mod Foo
         );
     }
 
+    #[test]
+    fn hover_doc_block_style_indentend() {
+        check(
+            r#"
+/**
+    foo
+    ```rust
+    let x = 3;
+    ```
+*/
+fn foo$0() {}
+"#,
+            expect![[r#"
+                *foo*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                fn foo()
+                ```
+
+                ---
+
+                foo
+
+                ```rust
+                let x = 3;
+                ```
+            "#]],
+        );
+    }
+
     #[test]
     fn hover_comments_dont_highlight_parent() {
+        cov_mark::check!(no_highlight_on_comment_hover);
         check_hover_no_result(
             r#"
 fn no_hover() {
@@ -3538,7 +3749,7 @@ fn foo() {
                 ```
 
                 ```rust
-                const FOO: usize = 3
+                const FOO: usize
                 ```
 
                 ---
@@ -3559,6 +3770,17 @@ fn hover_mod_def() {
 "#,
             expect![[r#"
                 *foo*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                mod foo
+                ```
+
+                ---
+
                 For the horde!
             "#]],
         );
@@ -3583,7 +3805,7 @@ pub mod bar {}
                 ```
 
                 ```rust
-                pub mod bar
+                mod bar
                 ```
 
                 ---
@@ -3634,4 +3856,273 @@ fn hover_builtin() {
             "#]],
         );
     }
+
+    #[test]
+    fn hover_macro_expanded_function() {
+        check(
+            r#"
+struct S<'a, T>(&'a T);
+trait Clone {}
+macro_rules! foo {
+    () => {
+        fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
+            't: 't + 't,
+            for<'a> T: Clone + 'a
+        { 0 as _ }
+    };
+}
+
+foo!();
+
+fn main() {
+    bar$0;
+}
+"#,
+            expect![[r#"
+                *bar*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
+                where
+                    T: Clone + 't,
+                    't: 't + 't,
+                    for<'a> T: Clone + 'a,
+                ```
+            "#]],
+        )
+    }
+
+    #[test]
+    fn hover_intra_doc_links() {
+        check(
+            r#"
+
+pub mod theitem {
+    /// This is the item. Cool!
+    pub struct TheItem;
+}
+
+/// Gives you a [`TheItem$0`].
+///
+/// [`TheItem`]: theitem::TheItem
+pub fn gimme() -> theitem::TheItem {
+    theitem::TheItem
+}
+"#,
+            expect![[r#"
+                *[`TheItem`]*
+
+                ```rust
+                test::theitem
+                ```
+
+                ```rust
+                pub struct TheItem
+                ```
+
+                ---
+
+                This is the item. Cool!
+            "#]],
+        );
+    }
+
+    #[test]
+    fn hover_generic_assoc() {
+        check(
+            r#"
+fn foo<T: A>() where T::Assoc$0: {}
+
+trait A {
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+        check(
+            r#"
+fn foo<T: A>() {
+    let _: <T>::Assoc$0;
+}
+
+trait A {
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+        check(
+            r#"
+trait A where
+    Self::Assoc$0: ,
+{
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+    }
+
+    #[test]
+    fn string_shadowed_with_inner_items() {
+        check(
+            r#"
+//- /main.rs crate:main deps:alloc
+
+/// Custom `String` type.
+struct String;
+
+fn f() {
+    let _: String$0;
+
+    fn inner() {}
+}
+
+//- /alloc.rs crate:alloc
+#[prelude_import]
+pub use string::*;
+
+mod string {
+    /// This is `alloc::String`.
+    pub struct String;
+}
+            "#,
+            expect![[r#"
+                *String*
+
+                ```rust
+                main
+                ```
+
+                ```rust
+                struct String
+                ```
+
+                ---
+
+                Custom `String` type.
+            "#]],
+        )
+    }
+
+    #[test]
+    fn function_doesnt_shadow_crate_in_use_tree() {
+        check(
+            r#"
+//- /main.rs crate:main deps:foo
+use foo$0::{foo};
+
+//- /foo.rs crate:foo
+pub fn foo() {}
+"#,
+            expect![[r#"
+                *foo*
+
+                ```rust
+                extern crate foo
+                ```
+            "#]],
+        )
+    }
+
+    #[test]
+    fn hover_feature() {
+        check(
+            r#"#![feature(box_syntax$0)]"#,
+            expect![[r##"
+                *box_syntax*
+                ```
+                box_syntax
+                ```
+                ___
+
+                # `box_syntax`
+
+                The tracking issue for this feature is: [#49733]
+
+                [#49733]: https://github.com/rust-lang/rust/issues/49733
+
+                See also [`box_patterns`](box-patterns.md)
+
+                ------------------------
+
+                Currently the only stable way to create a `Box` is via the `Box::new` method.
+                Also it is not possible in stable Rust to destructure a `Box` in a match
+                pattern. The unstable `box` keyword can be used to create a `Box`. An example
+                usage would be:
+
+                ```rust
+                #![feature(box_syntax)]
+
+                fn main() {
+                    let b = box 5;
+                }
+                ```
+
+            "##]],
+        )
+    }
+
+    #[test]
+    fn hover_lint() {
+        check(
+            r#"#![allow(arithmetic_overflow$0)]"#,
+            expect![[r#"
+                *arithmetic_overflow*
+                ```
+                arithmetic_overflow
+                ```
+                ___
+
+                arithmetic operation overflows
+            "#]],
+        )
+    }
+
+    #[test]
+    fn hover_clippy_lint() {
+        check(
+            r#"#![allow(clippy::almost_swapped$0)]"#,
+            expect![[r#"
+                *almost_swapped*
+                ```
+                clippy::almost_swapped
+                ```
+                ___
+
+                Checks for `foo = bar; bar = foo` sequences.
+            "#]],
+        )
+    }
 }