]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide/src/hover.rs
Merge #11461
[rust.git] / crates / ide / src / hover.rs
index a01e272e5354b2a175287f8255629f7680fd0b50..0eba0b09ba6e2dfded2f179b785f18c7e1bcd5a0 100644 (file)
@@ -1,35 +1,27 @@
-use std::{collections::HashSet, iter, ops::ControlFlow};
+mod render;
+
+#[cfg(test)]
+mod tests;
+
+use std::iter;
 
 use either::Either;
-use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
+use hir::{HasSource, Semantics};
 use ide_db::{
-    base_db::{FileRange, SourceDatabase},
-    defs::{Definition, NameClass, NameRefClass},
-    helpers::{
-        generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
-        pick_best_token, try_resolve_derive_input_at, FamousDefs,
-    },
-    RootDatabase,
+    base_db::FileRange,
+    defs::{Definition, IdentClass},
+    helpers::{pick_best_token, FamousDefs},
+    FxIndexSet, RootDatabase,
 };
 use itertools::Itertools;
-use stdx::format_to;
-use syntax::{
-    algo, ast, display::fn_as_proc_macro_label, match_ast, AstNode, Direction, SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, TextSize, T,
-};
+use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T};
 
 use crate::{
-    display::{macro_label, TryToNav},
-    doc_links::{
-        doc_attributes, extract_definitions_from_docs, remove_links, resolve_doc_path_for_def,
-        rewrite_links,
-    },
-    markdown_remove::remove_markdown,
+    doc_links::token_as_doc_comment,
     markup::Markup,
     runnables::{runnable_fn, runnable_mod},
-    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
+    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
 };
-
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct HoverConfig {
     pub links_in_hover: bool,
@@ -62,7 +54,7 @@ fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Se
             .into_iter()
             .filter_map(|it| {
                 Some(HoverGotoTypeData {
-                    mod_path: render_path(
+                    mod_path: render::path(
                         db,
                         it.module(db)?,
                         it.name(db).map(|name| name.to_string()),
@@ -75,7 +67,7 @@ fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Se
     }
 }
 
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct HoverGotoTypeData {
     pub mod_path: String,
     pub nav: NavigationTarget,
@@ -99,184 +91,108 @@ pub(crate) fn hover(
     FileRange { file_id, range }: FileRange,
     config: &HoverConfig,
 ) -> Option<RangeInfo<HoverResult>> {
-    let sema = hir::Semantics::new(db);
+    let sema = &hir::Semantics::new(db);
     let file = sema.parse(file_id).syntax().clone();
 
     if !range.is_empty() {
-        return hover_ranged(&file, range, &sema, config);
+        return hover_ranged(&file, range, sema, config);
     }
     let offset = range.start();
 
-    let token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
+    let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
         T!['('] | T![')'] => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
     })?;
 
-    let mut seen = HashSet::default();
-
-    let mut fallback = None;
-    // attributes, require special machinery as they are mere ident tokens
+    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
+        cov_mark::hit!(no_highlight_on_comment_hover);
+        return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
+            let res = hover_for_definition(sema, file_id, def, &node, config)?;
+            Some(RangeInfo::new(range, res))
+        });
+    }
 
-    let descend_macros = sema.descend_into_macros_many(token.clone());
+    let descended = sema.descend_into_macros(original_token.clone());
 
-    for token in &descend_macros {
-        if token.kind() != COMMENT {
-            if let Some(attr) = token.ancestors().find_map(ast::Attr::cast) {
-                // lints
-                if let Some(res) = try_hover_for_lint(&attr, &token) {
-                    return Some(res);
-                // derives
-                } else {
-                    let def =
-                        try_resolve_derive_input_at(&sema, &attr, &token).map(Definition::Macro);
-                    if let Some(def) = def {
-                        if let Some(hover) = hover_for_definition(
-                            &sema,
-                            file_id,
-                            def,
-                            &token.parent().unwrap(),
-                            config,
-                        ) {
-                            return Some(RangeInfo::new(token.text_range(), hover));
-                        }
-                    }
-                }
-            }
-        }
+    // FIXME: Definition should include known lints and the like instead of having this special case here
+    let hovered_lint = descended.iter().find_map(|token| {
+        let attr = token.ancestors().find_map(ast::Attr::cast)?;
+        render::try_for_lint(&attr, token)
+    });
+    if let Some(res) = hovered_lint {
+        return Some(RangeInfo::new(original_token.text_range(), res));
     }
 
-    descend_macros
+    let result = descended
         .iter()
-        .filter_map(|token| match token.parent() {
-            Some(node) => {
-                match find_hover_result(&sema, file_id, offset, config, token, &node, &mut seen) {
-                    Some(res) => match res {
-                        ControlFlow::Break(inner) => Some(inner),
-                        ControlFlow::Continue(_) => {
-                            if fallback.is_none() {
-                                // FIXME we're only taking the first fallback into account that's not `None`
-                                fallback = hover_for_keyword(&sema, config, &token)
-                                    .or(type_hover(&sema, config, &token));
-                            }
-                            None
-                        }
-                    },
-                    None => None,
-                }
-            }
-            None => None,
+        .filter_map(|token| {
+            let node = token.parent()?;
+            let class = IdentClass::classify_token(sema, token)?;
+            Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
         })
-        // reduce all descends into a single `RangeInfo`
-        // that spans from the earliest start to the latest end (fishy/FIXME),
-        // concatenates all `Markup`s with `\n---\n`,
-        // and accumulates all actions into its `actions` vector.
-        .reduce(|mut acc, RangeInfo { range, mut info }| {
-            let start = acc.range.start().min(range.start());
-            let end = acc.range.end().max(range.end());
-
-            acc.range = TextRange::new(start, end);
-            acc.info.actions.append(&mut info.actions);
-            acc.info.markup = Markup::from(format!("{}\n---\n{}", acc.info.markup, info.markup));
+        .flatten()
+        .unique_by(|&(def, _)| def)
+        .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
+        .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
+            acc.actions.extend(actions);
+            acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup));
             acc
-        })
-        .or(fallback)
-}
+        });
 
-fn find_hover_result(
-    sema: &Semantics<RootDatabase>,
-    file_id: FileId,
-    offset: TextSize,
-    config: &HoverConfig,
-    token: &SyntaxToken,
-    node: &SyntaxNode,
-    seen: &mut HashSet<Definition>,
-) -> Option<ControlFlow<RangeInfo<HoverResult>>> {
-    let mut range_override = None;
-
-    // intra-doc links and attributes are special cased
-    // so don't add them to the `seen` duplicate check
-    let mut add_to_seen_definitions = true;
-
-    let definition = find_definition(sema, node).next().or_else(|| {
-        // intra-doc links
-        // FIXME: move comment + attribute special cases somewhere else to simplify control flow,
-        // hopefully simplifying the return type of this function in the process
-        // (the `Break`/`Continue` distinction is needed to decide whether to use fallback hovers)
-        //
-        // FIXME: hovering the intra doc link to `Foo` not working:
-        //
-        // #[identity]
-        // trait Foo {
-        //    /// [`Foo`]
-        // fn foo() {}
-        if token.kind() == COMMENT {
-            add_to_seen_definitions = false;
-            cov_mark::hit!(no_highlight_on_comment_hover);
-            let (attributes, def) = doc_attributes(sema, node)?;
-            let (docs, doc_mapping) = attributes.docs_with_rangemap(sema.db)?;
-            let (idl_range, link, ns) = extract_definitions_from_docs(&docs).into_iter().find_map(
-                |(range, link, ns)| {
-                    let mapped = doc_mapping.map(range)?;
-                    (mapped.file_id == file_id.into() && mapped.value.contains(offset))
-                        .then(|| (mapped.value, link, ns))
-                },
-            )?;
-            range_override = Some(idl_range);
-            Some(match resolve_doc_path_for_def(sema.db, def, &link, ns)? {
-                Either::Left(it) => Definition::ModuleDef(it),
-                Either::Right(it) => Definition::Macro(it),
-            })
-        } else {
-            None
-        }
-    });
+    if result.is_none() {
+        // fallbacks, show keywords or types
 
-    if let Some(definition) = definition {
-        // skip duplicates
-        if seen.contains(&definition) {
-            return None;
+        let res = descended.iter().find_map(|token| render::keyword(sema, config, &token));
+        if let Some(res) = res {
+            return Some(RangeInfo::new(original_token.text_range(), res));
         }
-        if add_to_seen_definitions {
-            seen.insert(definition);
-        }
-        if let Some(res) = hover_for_definition(sema, file_id, definition, &node, config) {
-            let range = range_override.unwrap_or_else(|| sema.original_range(&node).range);
-            return Some(ControlFlow::Break(RangeInfo::new(range, res)));
+        let res = descended
+            .iter()
+            .find_map(|token| hover_type_fallback(sema, config, token, &original_token));
+        if let res @ Some(_) = res {
+            return res;
         }
     }
-
-    Some(ControlFlow::Continue(()))
+    result.map(|mut res: HoverResult| {
+        res.actions = dedupe_or_merge_hover_actions(res.actions);
+        RangeInfo::new(original_token.text_range(), res)
+    })
 }
 
-fn type_hover(
+pub(crate) fn hover_for_definition(
     sema: &Semantics<RootDatabase>,
+    file_id: FileId,
+    definition: Definition,
+    node: &SyntaxNode,
     config: &HoverConfig,
-    token: &SyntaxToken,
-) -> Option<RangeInfo<HoverResult>> {
-    if token.kind() == COMMENT {
-        return None;
-    }
-    let node = token
-        .ancestors()
-        .take_while(|it| !ast::Item::can_cast(it.kind()))
-        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
+) -> Option<HoverResult> {
+    let famous_defs = match &definition {
+        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node).krate())),
+        _ => None,
+    };
+    if let Some(markup) = render::definition(sema.db, definition, famous_defs.as_ref(), config) {
+        let mut res = HoverResult::default();
+        res.markup = render::process_markup(sema.db, definition, &markup, config);
+        if let Some(action) = show_implementations_action(sema.db, definition) {
+            res.actions.push(action);
+        }
 
-    let expr_or_pat = match_ast! {
-        match node {
-            ast::Expr(it) => Either::Left(it),
-            ast::Pat(it) => Either::Right(it),
-            // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
-            // (e.g expanding a builtin macro). So we give up here.
-            ast::MacroCall(_it) => return None,
-            _ => return None,
+        if let Some(action) = show_fn_references_action(sema.db, definition) {
+            res.actions.push(action);
         }
-    };
 
-    let res = hover_type_info(&sema, config, &expr_or_pat)?;
-    let range = sema.original_range(&node).range;
-    Some(RangeInfo::new(range, res))
+        if let Some(action) = runnable_action(sema, definition, file_id) {
+            res.actions.push(action);
+        }
+
+        if let Some(action) = goto_type_action_for_def(sema.db, definition) {
+            res.actions.push(action);
+        }
+        return Some(res);
+    }
+    None
 }
 
 fn hover_ranged(
@@ -285,6 +201,7 @@ fn hover_ranged(
     sema: &Semantics<RootDatabase>,
     config: &HoverConfig,
 ) -> Option<RangeInfo<HoverResult>> {
+    // FIXME: make this work in attributes
     let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| {
         match_ast! {
             match it {
@@ -295,15 +212,15 @@ fn hover_ranged(
         }
     })?;
     let res = match &expr_or_pat {
-        Either::Left(ast::Expr::TryExpr(try_expr)) => hover_try_expr(sema, config, try_expr),
+        Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr),
         Either::Left(ast::Expr::PrefixExpr(prefix_expr))
             if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
         {
-            hover_deref_expr(sema, config, prefix_expr)
+            render::deref_expr(sema, config, prefix_expr)
         }
         _ => None,
     };
-    let res = res.or_else(|| hover_type_info(sema, config, &expr_or_pat));
+    let res = res.or_else(|| render::type_info(sema, config, &expr_or_pat));
     res.map(|it| {
         let range = match expr_or_pat {
             Either::Left(it) => it.syntax().text_range(),
@@ -313,248 +230,34 @@ fn hover_ranged(
     })
 }
 
-fn hover_try_expr(
-    sema: &Semantics<RootDatabase>,
-    config: &HoverConfig,
-    try_expr: &ast::TryExpr,
-) -> Option<HoverResult> {
-    let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
-    let mut ancestors = try_expr.syntax().ancestors();
-    let mut body_ty = loop {
-        let next = ancestors.next()?;
-        break match_ast! {
-            match next {
-                ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
-                ast::Item(__) => return None,
-                ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
-                ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) {
-                    sema.type_of_expr(&effect.block_expr()?.into())?.original
-                } else {
-                    continue;
-                },
-                _ => continue,
-            }
-        };
-    };
-
-    if inner_ty == body_ty {
-        return None;
-    }
-
-    let mut inner_ty = inner_ty;
-    let mut s = "Try Target".to_owned();
-
-    let adts = inner_ty.as_adt().zip(body_ty.as_adt());
-    if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts {
-        let famous_defs = FamousDefs(sema, sema.scope(&try_expr.syntax()).krate());
-        // special case for two options, there is no value in showing them
-        if let Some(option_enum) = famous_defs.core_option_Option() {
-            if inner == option_enum && body == option_enum {
-                cov_mark::hit!(hover_try_expr_opt_opt);
-                return None;
-            }
-        }
-
-        // special case two results to show the error variants only
-        if let Some(result_enum) = famous_defs.core_result_Result() {
-            if inner == result_enum && body == result_enum {
-                let error_type_args =
-                    inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1));
-                if let Some((inner, body)) = error_type_args {
-                    inner_ty = inner;
-                    body_ty = body;
-                    s = "Try Error".to_owned();
-                }
-            }
-        }
-    }
-
-    let mut res = HoverResult::default();
-
-    let mut targets: Vec<hir::ModuleDef> = Vec::new();
-    let mut push_new_def = |item: hir::ModuleDef| {
-        if !targets.contains(&item) {
-            targets.push(item);
-        }
-    };
-    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
-    walk_and_push_ty(sema.db, &body_ty, &mut push_new_def);
-    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
-
-    let inner_ty = inner_ty.display(sema.db).to_string();
-    let body_ty = body_ty.display(sema.db).to_string();
-    let ty_len_max = inner_ty.len().max(body_ty.len());
-
-    let l = "Propagated as: ".len() - " Type: ".len();
-    let static_text_len_diff = l as isize - s.len() as isize;
-    let tpad = static_text_len_diff.max(0) as usize;
-    let ppad = static_text_len_diff.min(0).abs() as usize;
-
-    res.markup = format!(
-        "{bt_start}{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n{bt_end}",
-        s,
-        inner_ty,
-        body_ty,
-        pad0 = ty_len_max + tpad,
-        pad1 = ty_len_max + ppad,
-        bt_start = if config.markdown() { "```text\n" } else { "" },
-        bt_end = if config.markdown() { "```\n" } else { "" }
-    )
-    .into();
-    Some(res)
-}
-
-fn hover_deref_expr(
-    sema: &Semantics<RootDatabase>,
-    config: &HoverConfig,
-    deref_expr: &ast::PrefixExpr,
-) -> Option<HoverResult> {
-    let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
-    let TypeInfo { original, adjusted } =
-        sema.type_of_expr(&ast::Expr::from(deref_expr.clone()))?;
-
-    let mut res = HoverResult::default();
-    let mut targets: Vec<hir::ModuleDef> = Vec::new();
-    let mut push_new_def = |item: hir::ModuleDef| {
-        if !targets.contains(&item) {
-            targets.push(item);
-        }
-    };
-    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
-    walk_and_push_ty(sema.db, &original, &mut push_new_def);
-
-    res.markup = if let Some(adjusted_ty) = adjusted {
-        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
-        let original = original.display(sema.db).to_string();
-        let adjusted = adjusted_ty.display(sema.db).to_string();
-        let inner = inner_ty.display(sema.db).to_string();
-        let type_len = "To type: ".len();
-        let coerced_len = "Coerced to: ".len();
-        let deref_len = "Dereferenced from: ".len();
-        let max_len = (original.len() + type_len)
-            .max(adjusted.len() + coerced_len)
-            .max(inner.len() + deref_len);
-        format!(
-            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
-            inner,
-            original,
-            adjusted,
-            ipad = max_len - deref_len,
-            apad = max_len - type_len,
-            opad = max_len - coerced_len,
-            bt_start = if config.markdown() { "```text\n" } else { "" },
-            bt_end = if config.markdown() { "```\n" } else { "" }
-        )
-        .into()
-    } else {
-        let original = original.display(sema.db).to_string();
-        let inner = inner_ty.display(sema.db).to_string();
-        let type_len = "To type: ".len();
-        let deref_len = "Dereferenced from: ".len();
-        let max_len = (original.len() + type_len).max(inner.len() + deref_len);
-        format!(
-            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\n{bt_end}",
-            inner,
-            original,
-            ipad = max_len - deref_len,
-            apad = max_len - type_len,
-            bt_start = if config.markdown() { "```text\n" } else { "" },
-            bt_end = if config.markdown() { "```\n" } else { "" }
-        )
-        .into()
-    };
-    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
-
-    Some(res)
-}
-
-fn hover_type_info(
+fn hover_type_fallback(
     sema: &Semantics<RootDatabase>,
     config: &HoverConfig,
-    expr_or_pat: &Either<ast::Expr, ast::Pat>,
-) -> Option<HoverResult> {
-    let TypeInfo { original, adjusted } = match expr_or_pat {
-        Either::Left(expr) => sema.type_of_expr(expr)?,
-        Either::Right(pat) => sema.type_of_pat(pat)?,
-    };
-
-    let mut res = HoverResult::default();
-    let mut targets: Vec<hir::ModuleDef> = Vec::new();
-    let mut push_new_def = |item: hir::ModuleDef| {
-        if !targets.contains(&item) {
-            targets.push(item);
-        }
-    };
-    walk_and_push_ty(sema.db, &original, &mut push_new_def);
-
-    res.markup = if let Some(adjusted_ty) = adjusted {
-        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
-        let original = original.display(sema.db).to_string();
-        let adjusted = adjusted_ty.display(sema.db).to_string();
-        let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
-        format!(
-            "{bt_start}Type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
-            original,
-            adjusted,
-            apad = static_text_diff_len + adjusted.len().max(original.len()),
-            opad = original.len(),
-            bt_start = if config.markdown() { "```text\n" } else { "" },
-            bt_end = if config.markdown() { "```\n" } else { "" }
-        )
-        .into()
-    } else {
-        if config.markdown() {
-            Markup::fenced_block(&original.display(sema.db))
-        } else {
-            original.display(sema.db).to_string().into()
-        }
-    };
-    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
-    Some(res)
-}
+    token: &SyntaxToken,
+    original_token: &SyntaxToken,
+) -> Option<RangeInfo<HoverResult>> {
+    let node = token
+        .ancestors()
+        .take_while(|it| !ast::Item::can_cast(it.kind()))
+        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
 
-fn try_hover_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
-    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)
-            }
+    let expr_or_pat = match_ast! {
+        match node {
+            ast::Expr(it) => Either::Left(it),
+            ast::Pat(it) => Either::Right(it),
+            // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
+            // (e.g expanding a builtin macro). So we give up here.
+            ast::MacroCall(_it) => return None,
+            _ => return None,
         }
-        _ => 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()
-        },
-    ))
+    let res = render::type_info(sema, config, &expr_or_pat)?;
+    let range = sema
+        .original_range_opt(&node)
+        .map(|frange| frange.range)
+        .unwrap_or_else(|| original_token.text_range());
+    Some(RangeInfo::new(range, res))
 }
 
 fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
@@ -566,10 +269,8 @@ fn to_action(nav_target: NavigationTarget) -> HoverAction {
     }
 
     let adt = match def {
-        Definition::ModuleDef(hir::ModuleDef::Trait(it)) => {
-            return it.try_to_nav(db).map(to_action)
-        }
-        Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it),
+        Definition::Trait(it) => return it.try_to_nav(db).map(to_action),
+        Definition::Adt(it) => Some(it),
         Definition::SelfType(it) => it.self_ty(db).as_adt(),
         _ => None,
     }?;
@@ -578,14 +279,12 @@ fn to_action(nav_target: NavigationTarget) -> HoverAction {
 
 fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
     match def {
-        Definition::ModuleDef(hir::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(),
-                })
+        Definition::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,
     }
 }
@@ -596,20 +295,17 @@ fn runnable_action(
     file_id: FileId,
 ) -> Option<HoverAction> {
     match def {
-        Definition::ModuleDef(it) => match it {
-            hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
-            hir::ModuleDef::Function(func) => {
-                let src = func.source(sema.db)?;
-                if src.file_id != file_id.into() {
-                    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)
+        Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
+        Definition::Function(func) => {
+            let src = func.source(sema.db)?;
+            if src.file_id != file_id.into() {
+                cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
+                cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
+                return None;
             }
-            _ => None,
-        },
+
+            runnable_fn(sema, func).map(HoverAction::Runnable)
+        }
         _ => None,
     }
 }
@@ -629,6 +325,7 @@ fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option<HoverA
             Definition::Local(it) => it.ty(db),
             Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
             Definition::Field(field) => field.ty(db),
+            Definition::Function(function) => function.ret_type(db),
             _ => return None,
         };
 
@@ -649,4403 +346,49 @@ fn walk_and_push_ty(
         } 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()));
+            traits.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());
         }
     });
 }
 
-fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
-    let mut buf = String::new();
-
-    if let Some(mod_path) = mod_path {
-        if !mod_path.is_empty() {
-            format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
-        }
-    }
-    format_to!(buf, "```rust\n{}\n```", desc);
-
-    if let Some(doc) = docs {
-        format_to!(buf, "\n___\n\n{}", doc);
-    }
-    Some(buf.into())
-}
-
-fn process_markup(
-    db: &RootDatabase,
-    def: Definition,
-    markup: &Markup,
-    config: &HoverConfig,
-) -> Markup {
-    let markup = markup.as_str();
-    let markup = if !config.markdown() {
-        remove_markdown(markup)
-    } else if config.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)),
-        Definition::Local(l) => l.parent(db).name(db),
-        Definition::ModuleDef(md) => match md {
-            hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
-                hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
-                hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
-            },
-            hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
-            _ => None,
-        },
-        _ => None,
-    }
-    .map(|name| name.to_string())
-}
-
-fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
-    let crate_name =
-        db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
-    let module_path = module
-        .path_to_root(db)
-        .into_iter()
-        .rev()
-        .flat_map(|it| it.name(db).map(|name| name.to_string()));
-    crate_name.into_iter().chain(module_path).chain(item_name).join("::")
-}
-
-fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
-    if let Definition::GenericParam(_) = def {
-        return None;
-    }
-    def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
-}
+fn dedupe_or_merge_hover_actions(actions: Vec<HoverAction>) -> Vec<HoverAction> {
+    let mut deduped_actions = Vec::with_capacity(actions.len());
+    let mut go_to_type_targets = FxIndexSet::default();
 
-pub(crate) fn find_definition<'a>(
-    sema: &'a Semantics<RootDatabase>,
-    node: &SyntaxNode,
-) -> impl Iterator<Item = Definition> + 'a {
-    iter::once(node.clone()).flat_map(move |node| {
-        match_ast! {
-            match node {
-                ast::Name(name) => {
-                    let class = if let Some(x) = NameClass::classify(&sema, &name) {
-                        x
-                    } else {
-                        return vec![];
-                    };
-                    match class {
-                        NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
-                        NameClass::PatFieldShorthand { local_def, field_ref } => vec![Definition::Local(local_def), Definition::Field(field_ref)],
-                    }
-                },
-                ast::NameRef(name_ref) => {
-                    let class = if let Some(x) = NameRefClass::classify(sema, &name_ref) {
-                        x
-                    } else {
-                        return vec![];
-                    };
-                    match class {
-                        NameRefClass::Definition(def) => vec![def],
-                        NameRefClass::FieldShorthand { local_ref, field_ref } => {
-                            vec![Definition::Field(field_ref), Definition::Local(local_ref)]
-                        }
-                    }
-                },
-                ast::Lifetime(lifetime) => {
-                    (if let Some(x) = NameClass::classify_lifetime(&sema, &lifetime) {
-                        NameClass::defined(x)
-                    } else {
-                        NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
-                            NameRefClass::Definition(it) => Some(it),
-                            _ => None,
-                        })
-                    }).into_iter().collect()
-                },
-                _ => vec![],
+    let mut seen_implementation = false;
+    let mut seen_reference = false;
+    let mut seen_runnable = false;
+    for action in actions {
+        match action {
+            HoverAction::GoToType(targets) => {
+                go_to_type_targets.extend(targets);
             }
-        }
-    })
-}
-
-pub(crate) fn hover_for_definition(
-    sema: &Semantics<RootDatabase>,
-    file_id: FileId,
-    definition: Definition,
-    node: &SyntaxNode,
-    config: &HoverConfig,
-) -> Option<HoverResult> {
-    let famous_defs = match &definition {
-        Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
-            Some(FamousDefs(&sema, sema.scope(&node).krate()))
-        }
-        _ => None,
-    };
-    if let Some(markup) = markup_for_definition(sema.db, definition, famous_defs.as_ref(), config) {
-        let mut res = HoverResult::default();
-        res.markup = process_markup(sema.db, definition, &markup, config);
-        if let Some(action) = show_implementations_action(sema.db, definition) {
-            res.actions.push(action);
-        }
-
-        if let Some(action) = show_fn_references_action(sema.db, definition) {
-            res.actions.push(action);
-        }
-
-        if let Some(action) = runnable_action(&sema, definition, file_id) {
-            res.actions.push(action);
-        }
-
-        if let Some(action) = goto_type_action_for_def(sema.db, definition) {
-            res.actions.push(action);
-        }
-        return Some(res);
-    }
-    None
-}
-
-fn markup_for_definition(
-    db: &RootDatabase,
-    def: Definition,
-    famous_defs: Option<&FamousDefs>,
-    config: &HoverConfig,
-) -> Option<Markup> {
-    let mod_path = definition_mod_path(db, &def);
-    let (label, docs) = match def {
-        Definition::Macro(it) => (
-            match &it.source(db)?.value {
-                Either::Left(mac) => macro_label(mac),
-                Either::Right(mac_fn) => fn_as_proc_macro_label(mac_fn),
-            },
-            it.attrs(db).docs(),
-        ),
-        Definition::Field(def) => label_and_docs(db, def),
-        Definition::ModuleDef(it) => match it {
-            hir::ModuleDef::Module(it) => label_and_docs(db, it),
-            hir::ModuleDef::Function(it) => label_and_docs(db, it),
-            hir::ModuleDef::Adt(it) => label_and_docs(db, it),
-            hir::ModuleDef::Variant(it) => label_and_docs(db, it),
-            hir::ModuleDef::Const(it) => label_and_docs(db, it),
-            hir::ModuleDef::Static(it) => label_and_docs(db, it),
-            hir::ModuleDef::Trait(it) => label_and_docs(db, it),
-            hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it),
-            hir::ModuleDef::BuiltinType(it) => {
-                return famous_defs
-                    .and_then(|fd| hover_for_builtin(fd, it))
-                    .or_else(|| Some(Markup::fenced_block(&it.name())))
+            HoverAction::Implementation(..) => {
+                if !seen_implementation {
+                    seen_implementation = true;
+                    deduped_actions.push(action);
+                }
             }
-        },
-        Definition::Local(it) => return hover_for_local(it, db),
-        Definition::SelfType(impl_def) => {
-            impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
-        }
-        Definition::GenericParam(it) => label_and_docs(db, it),
-        Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
-    };
-
-    return hover_markup(
-        docs.filter(|_| config.documentation.is_some()).map(Into::into),
-        label,
-        mod_path,
-    );
-
-    fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
-    where
-        D: HasAttrs + HirDisplay,
-    {
-        let label = def.display(db).to_string();
-        let docs = def.attrs(db).docs();
-        (label, docs)
-    }
-}
-
-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, desc, None)
-}
-
-fn hover_for_keyword(
-    sema: &Semantics<RootDatabase>,
-    config: &HoverConfig,
-    token: &SyntaxToken,
-) -> Option<RangeInfo<HoverResult>> {
-    if !token.kind().is_keyword() || !config.documentation.is_some() {
-        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()), token.text().into(), None)?,
-        config,
-    );
-    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()), 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))
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::{expect, Expect};
-    use ide_db::base_db::{FileLoader, FileRange};
-    use syntax::TextRange;
-
-    use crate::{fixture, hover::HoverDocFormat, HoverConfig};
-
-    fn check_hover_no_result(ra_fixture: &str) {
-        let (analysis, position) = fixture::position(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: true,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
-            )
-            .unwrap();
-        assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap());
+            HoverAction::Reference(..) => {
+                if !seen_reference {
+                    seen_reference = true;
+                    deduped_actions.push(action);
+                }
+            }
+            HoverAction::Runnable(..) => {
+                if !seen_runnable {
+                    seen_runnable = true;
+                    deduped_actions.push(action);
+                }
+            }
+        };
     }
 
-    fn check(ra_fixture: &str, expect: Expect) {
-        let (analysis, position) = fixture::position(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: true,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
-            )
-            .unwrap()
-            .unwrap();
-
-        let content = analysis.db.file_text(position.file_id);
-        let hovered_element = &content[hover.range];
-
-        let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
-        expect.assert_eq(&actual)
+    if !go_to_type_targets.is_empty() {
+        deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect()));
     }
 
-    fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
-        let (analysis, position) = fixture::position(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: false,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
-            )
-            .unwrap()
-            .unwrap();
-
-        let content = analysis.db.file_text(position.file_id);
-        let hovered_element = &content[hover.range];
-
-        let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
-        expect.assert_eq(&actual)
-    }
-
-    fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
-        let (analysis, position) = fixture::position(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: true,
-                    documentation: Some(HoverDocFormat::PlainText),
-                },
-                FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
-            )
-            .unwrap()
-            .unwrap();
-
-        let content = analysis.db.file_text(position.file_id);
-        let hovered_element = &content[hover.range];
-
-        let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
-        expect.assert_eq(&actual)
-    }
-
-    fn check_actions(ra_fixture: &str, expect: Expect) {
-        let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: true,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                FileRange { file_id, range: position.range_or_empty() },
-            )
-            .unwrap()
-            .unwrap();
-        expect.assert_debug_eq(&hover.info.actions)
-    }
-
-    fn check_hover_range(ra_fixture: &str, expect: Expect) {
-        let (analysis, range) = fixture::range(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: false,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                range,
-            )
-            .unwrap()
-            .unwrap();
-        expect.assert_eq(hover.info.markup.as_str())
-    }
-
-    fn check_hover_range_no_results(ra_fixture: &str) {
-        let (analysis, range) = fixture::range(ra_fixture);
-        let hover = analysis
-            .hover(
-                &HoverConfig {
-                    links_in_hover: false,
-                    documentation: Some(HoverDocFormat::Markdown),
-                },
-                range,
-            )
-            .unwrap();
-        assert!(hover.is_none());
-    }
-
-    #[test]
-    fn hover_descend_macros_avoids_duplicates() {
-        check(
-            r#"
-macro_rules! dupe_use {
-    ($local:ident) => {
-        {
-            $local;
-            $local;
-        }
-    }
-}
-fn foo() {
-    let local = 0;
-    dupe_use!(local$0);
-}
-"#,
-            expect![[r#"
-            *local*
-
-            ```rust
-            let local: i32
-            ```
-        "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_all_macro_descends() {
-        check(
-            r#"
-macro_rules! m {
-    ($name:ident) => {
-        /// Outer
-        fn $name() {}
-
-        mod module {
-            /// Inner
-            fn $name() {}
-        }
-    };
-}
-
-m!(ab$0c);
-            "#,
-            expect![[r#"
-            *abc*
-
-            ```rust
-            test::module
-            ```
-
-            ```rust
-            fn abc()
-            ```
-
-            ---
-
-            Inner
-            ---
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            fn abc()
-            ```
-
-            ---
-
-            Outer
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_type_of_an_expression() {
-        check(
-            r#"
-pub fn foo() -> u32 { 1 }
-
-fn main() {
-    let foo_test = foo()$0;
-}
-"#,
-            expect![[r#"
-                *foo()*
-                ```rust
-                u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_remove_markdown_if_configured() {
-        check_hover_no_markdown(
-            r#"
-pub fn foo() -> u32 { 1 }
-
-fn main() {
-    let foo_test = foo()$0;
-}
-"#,
-            expect![[r#"
-                *foo()*
-                u32
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_long_type_of_an_expression() {
-        check(
-            r#"
-struct Scan<A, B, C> { a: A, b: B, c: C }
-struct Iter<I> { inner: I }
-enum Option<T> { Some(T), None }
-
-struct OtherStruct<T> { i: T }
-
-fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
-    Iter { inner: Scan { a, b, c } }
-}
-
-fn main() {
-    let num: i32 = 55;
-    let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
-        Option::Some(*memo + value)
-    };
-    let number = 5u32;
-    let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
-}
-"#,
-            expect![[r#"
-                *iter*
-
-                ```rust
-                let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_fn_signature() {
-        // Single file with result
-        check(
-            r#"
-pub fn foo() -> u32 { 1 }
-
-fn main() { let foo_test = fo$0o(); }
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub fn foo() -> u32
-                ```
-            "#]],
-        );
-
-        // Multiple candidates but results are ambiguous.
-        check(
-            r#"
-//- /a.rs
-pub fn foo() -> u32 { 1 }
-
-//- /b.rs
-pub fn foo() -> &str { "" }
-
-//- /c.rs
-pub fn foo(a: u32, b: u32) {}
-
-//- /main.rs
-mod a;
-mod b;
-mod c;
-
-fn main() { let foo_test = fo$0o(); }
-        "#,
-            expect![[r#"
-                *foo*
-                ```rust
-                {unknown}
-                ```
-            "#]],
-        );
-
-        // Use literal `crate` in path
-        check(
-            r#"
-pub struct X;
-
-fn foo() -> crate::X { X }
-
-fn main() { f$0oo(); }
-        "#,
-            expect![[r#"
-            *foo*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            fn foo() -> crate::X
-            ```
-        "#]],
-        );
-
-        // Check `super` in path
-        check(
-            r#"
-pub struct X;
-
-mod m { pub fn foo() -> super::X { super::X } }
-
-fn main() { m::f$0oo(); }
-        "#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test::m
-                ```
-
-                ```rust
-                pub fn foo() -> super::X
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_fn_signature_with_type_params() {
-        check(
-            r#"
-pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
-
-fn main() { let foo_test = fo$0o(); }
-        "#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub fn foo<'a, T>(b: &'a T) -> &'a str
-                where
-                    T: AsRef<str>,
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_fn_signature_on_fn_name() {
-        check(
-            r#"
-pub fn foo$0(a: u32, b: u32) -> u32 {}
-
-fn main() { }
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub fn foo(a: u32, b: u32) -> u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_fn_doc() {
-        check(
-            r#"
-/// # Example
-/// ```
-/// # use std::path::Path;
-/// #
-/// foo(Path::new("hello, world!"))
-/// ```
-pub fn foo$0(_: &Path) {}
-
-fn main() { }
-"#,
-            expect![[r##"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub fn foo(_: &Path)
-                ```
-
-                ---
-
-                # Example
-
-                ```
-                # use std::path::Path;
-                #
-                foo(Path::new("hello, world!"))
-                ```
-            "##]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_fn_doc_attr_raw_string() {
-        check(
-            r##"
-#[doc = r#"Raw string doc attr"#]
-pub fn foo$0(_: &Path) {}
-
-fn main() { }
-"##,
-            expect![[r##"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub fn foo(_: &Path)
-                ```
-
-                ---
-
-                Raw string doc attr
-            "##]],
-        );
-    }
-
-    #[test]
-    fn hover_shows_struct_field_info() {
-        // Hovering over the field when instantiating
-        check(
-            r#"
-struct Foo { field_a: u32 }
-
-fn main() {
-    let foo = Foo { field_a$0: 0, };
-}
-"#,
-            expect![[r#"
-                *field_a*
-
-                ```rust
-                test::Foo
-                ```
-
-                ```rust
-                field_a: u32
-                ```
-            "#]],
-        );
-
-        // Hovering over the field in the definition
-        check(
-            r#"
-struct Foo { field_a$0: u32 }
-
-fn main() {
-    let foo = Foo { field_a: 0 };
-}
-"#,
-            expect![[r#"
-                *field_a*
-
-                ```rust
-                test::Foo
-                ```
-
-                ```rust
-                field_a: u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_const_static() {
-        check(
-            r#"const foo$0: u32 = 123;"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                const foo: u32
-                ```
-            "#]],
-        );
-        check(
-            r#"static foo$0: u32 = 456;"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                static foo: u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_default_generic_types() {
-        check(
-            r#"
-struct Test<K, T = u8> { k: K, t: T }
-
-fn main() {
-    let zz$0 = Test { t: 23u8, k: 33 };
-}"#,
-            expect![[r#"
-                *zz*
-
-                ```rust
-                let zz: Test<i32, u8>
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_some() {
-        check(
-            r#"
-enum Option<T> { Some(T) }
-use Option::Some;
-
-fn main() { So$0me(12); }
-"#,
-            expect![[r#"
-                *Some*
-
-                ```rust
-                test::Option
-                ```
-
-                ```rust
-                Some(T)
-                ```
-            "#]],
-        );
-
-        check(
-            r#"
-enum Option<T> { Some(T) }
-use Option::Some;
-
-fn main() { let b$0ar = Some(12); }
-"#,
-            expect![[r#"
-                *bar*
-
-                ```rust
-                let bar: Option<i32>
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_enum_variant() {
-        check(
-            r#"
-enum Option<T> {
-    /// The None variant
-    Non$0e
-}
-"#,
-            expect![[r#"
-                *None*
-
-                ```rust
-                test::Option
-                ```
-
-                ```rust
-                None
-                ```
-
-                ---
-
-                The None variant
-            "#]],
-        );
-
-        check(
-            r#"
-enum Option<T> {
-    /// The Some variant
-    Some(T)
-}
-fn main() {
-    let s = Option::Som$0e(12);
-}
-"#,
-            expect![[r#"
-                *Some*
-
-                ```rust
-                test::Option
-                ```
-
-                ```rust
-                Some(T)
-                ```
-
-                ---
-
-                The Some variant
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_for_local_variable() {
-        check(
-            r#"fn func(foo: i32) { fo$0o; }"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                foo: i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_for_local_variable_pat() {
-        check(
-            r#"fn func(fo$0o: i32) {}"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                foo: i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_local_var_edge() {
-        check(
-            r#"fn func(foo: i32) { if true { $0foo; }; }"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                foo: i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_for_param_edge() {
-        check(
-            r#"fn func($0foo: i32) {}"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                foo: i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_for_param_with_multiple_traits() {
-        check(
-            r#"
-            //- minicore: sized
-            trait Deref {
-                type Target: ?Sized;
-            }
-            trait DerefMut {
-                type Target: ?Sized;
-            }
-            fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
-            expect![[r#"
-                *_x*
-
-                ```rust
-                _x: impl Deref<Target = u8> + DerefMut<Target = u8>
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_infer_associated_method_result() {
-        check(
-            r#"
-struct Thing { x: u32 }
-
-impl Thing {
-    fn new() -> Thing { Thing { x: 0 } }
-}
-
-fn main() { let foo_$0test = Thing::new(); }
-"#,
-            expect![[r#"
-                *foo_test*
-
-                ```rust
-                let foo_test: Thing
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_infer_associated_method_exact() {
-        check(
-            r#"
-mod wrapper {
-    struct Thing { x: u32 }
-
-    impl Thing {
-        fn new() -> Thing { Thing { x: 0 } }
-    }
-}
-
-fn main() { let foo_test = wrapper::Thing::new$0(); }
-"#,
-            expect![[r#"
-                *new*
-
-                ```rust
-                test::wrapper::Thing
-                ```
-
-                ```rust
-                fn new() -> Thing
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_infer_associated_const_in_pattern() {
-        check(
-            r#"
-struct X;
-impl X {
-    const C: u32 = 1;
-}
-
-fn main() {
-    match 1 {
-        X::C$0 => {},
-        2 => {},
-        _ => {}
-    };
-}
-"#,
-            expect![[r#"
-                *C*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                const C: u32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_self() {
-        check(
-            r#"
-struct Thing { x: u32 }
-impl Thing {
-    fn new() -> Self { Self$0 { x: 0 } }
-}
-"#,
-            expect![[r#"
-                *Self*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                struct Thing
-                ```
-            "#]],
-        );
-        check(
-            r#"
-struct Thing { x: u32 }
-impl Thing {
-    fn new() -> Self$0 { Self { x: 0 } }
-}
-"#,
-            expect![[r#"
-                *Self*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                struct Thing
-                ```
-            "#]],
-        );
-        check(
-            r#"
-enum Thing { A }
-impl Thing {
-    pub fn new() -> Self$0 { Thing::A }
-}
-"#,
-            expect![[r#"
-                *Self*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                enum Thing
-                ```
-            "#]],
-        );
-        check(
-            r#"
-        enum Thing { A }
-        impl Thing {
-            pub fn thing(a: Self$0) {}
-        }
-        "#,
-            expect![[r#"
-                *Self*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                enum Thing
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_shadowing_pat() {
-        check(
-            r#"
-fn x() {}
-
-fn y() {
-    let x = 0i32;
-    x$0;
-}
-"#,
-            expect![[r#"
-                *x*
-
-                ```rust
-                let x: i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_macro_invocation() {
-        check(
-            r#"
-macro_rules! foo { () => {} }
-
-fn f() { fo$0o!(); }
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                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(
-            r#"struct TS(String, i32$0);"#,
-            expect![[r#"
-                *i32*
-
-                ```rust
-                i32
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn test_hover_through_macro() {
-        check(
-            r#"
-macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
-fn foo() {}
-id! {
-    fn bar() { fo$0o(); }
-}
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn foo()
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_attr() {
-        check(
-            r#"
-//- proc_macros: identity
-#[proc_macros::identity]
-fn foo$0() {}
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn foo()
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_expr_in_macro() {
-        check(
-            r#"
-macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
-fn foo(bar:u32) { let a = id!(ba$0r); }
-"#,
-            expect![[r#"
-                *bar*
-
-                ```rust
-                bar: u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_expr_in_macro_recursive() {
-        check(
-            r#"
-macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
-macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
-fn foo(bar:u32) { let a = id!(ba$0r); }
-"#,
-            expect![[r#"
-                *bar*
-
-                ```rust
-                bar: u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_func_in_macro_recursive() {
-        check(
-            r#"
-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($0)] ); }
-"#,
-            expect![[r#"
-                *bar()*
-                ```rust
-                u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_literal_string_in_macro() {
-        check(
-            r#"
-macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
-fn foo() {
-    let mastered_for_itunes = "";
-    let _ = arr!("Tr$0acks", &mastered_for_itunes);
-}
-"#,
-            expect![[r#"
-                *"Tracks"*
-                ```rust
-                &str
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_assert_macro() {
-        check(
-            r#"
-#[rustc_builtin_macro]
-macro_rules! assert {}
-
-fn bar() -> bool { true }
-fn foo() {
-    assert!(ba$0r());
-}
-"#,
-            expect![[r#"
-                *bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn bar() -> bool
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_through_literal_string_in_builtin_macro() {
-        check_hover_no_result(
-            r#"
-            #[rustc_builtin_macro]
-            macro_rules! format {}
-
-            fn foo() {
-                format!("hel$0lo {}", 0);
-            }
-"#,
-        );
-    }
-
-    #[test]
-    fn test_hover_non_ascii_space_doc() {
-        check(
-            "
-/// <- `\u{3000}` here
-fn foo() { }
-
-fn bar() { fo$0o(); }
-",
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn foo()
-                ```
-
-                ---
-
-                \<- ` ` here
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_function_show_qualifiers() {
-        check(
-            r#"async fn foo$0() {}"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                async fn foo()
-                ```
-            "#]],
-        );
-        check(
-            r#"pub const unsafe fn foo$0() {}"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub const unsafe fn foo()
-                ```
-            "#]],
-        );
-        // Top level `pub(crate)` will be displayed as no visibility.
-        check(
-            r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test::m
-                ```
-
-                ```rust
-                pub(crate) async unsafe extern "C" fn foo()
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_trait_show_qualifiers() {
-        check_actions(
-            r"unsafe trait foo$0() {}",
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 13,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_extern_crate() {
-        check(
-            r#"
-//- /main.rs crate:main deps:std
-extern crate st$0d;
-//- /std/lib.rs crate:std
-//! Standard library for this test
-//!
-//! Printed?
-//! abc123
-"#,
-            expect![[r#"
-                *std*
-
-                ```rust
-                extern crate std
-                ```
-
-                ---
-
-                Standard library for this test
-
-                Printed?
-                abc123
-            "#]],
-        );
-        check(
-            r#"
-//- /main.rs crate:main deps:std
-extern crate std as ab$0c;
-//- /std/lib.rs crate:std
-//! Standard library for this test
-//!
-//! Printed?
-//! abc123
-"#,
-            expect![[r#"
-                *abc*
-
-                ```rust
-                extern crate std
-                ```
-
-                ---
-
-                Standard library for this test
-
-                Printed?
-                abc123
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_mod_with_same_name_as_function() {
-        check(
-            r#"
-use self::m$0y::Bar;
-mod my { pub struct Bar; }
-
-fn my() {}
-"#,
-            expect![[r#"
-                *my*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod my
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_struct_doc_comment() {
-        check(
-            r#"
-/// 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##"
-                *Bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                struct Bar
-                ```
-
-                ---
-
-                This is an example
-                multiline doc
-
-                # Example
-
-                ```
-                let five = 5;
-
-                assert_eq!(6, my_crate::add_one(5));
-                ```
-            "##]],
-        );
-    }
-
-    #[test]
-    fn test_hover_struct_doc_attr() {
-        check(
-            r#"
-#[doc = "bar docs"]
-struct Bar;
-
-fn foo() { let bar = Ba$0r; }
-"#,
-            expect![[r#"
-                *Bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                struct Bar
-                ```
-
-                ---
-
-                bar docs
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_struct_doc_attr_multiple_and_mixed() {
-        check(
-            r#"
-/// bar docs 0
-#[doc = "bar docs 1"]
-#[doc = "bar docs 2"]
-struct Bar;
-
-fn foo() { let bar = Ba$0r; }
-"#,
-            expect![[r#"
-                *Bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                struct Bar
-                ```
-
-                ---
-
-                bar docs 0
-                bar docs 1
-                bar docs 2
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_external_url() {
-        check(
-            r#"
-pub struct Foo;
-/// [external](https://www.google.com)
-pub struct B$0ar
-"#,
-            expect![[r#"
-                *Bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub struct Bar
-                ```
-
-                ---
-
-                [external](https://www.google.com)
-            "#]],
-        );
-    }
-
-    // Check that we don't rewrite links which we can't identify
-    #[test]
-    fn test_hover_unknown_target() {
-        check(
-            r#"
-pub struct Foo;
-/// [baz](Baz)
-pub struct B$0ar
-"#,
-            expect![[r#"
-                *Bar*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub struct Bar
-                ```
-
-                ---
-
-                [baz](Baz)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_no_links() {
-        check_hover_no_links(
-            r#"
-/// Test cases:
-/// case 1.  bare URL: https://www.example.com/
-/// case 2.  inline URL with title: [example](https://www.example.com/)
-/// 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.  reference: [example][example]
-/// case 8.  collapsed link: [example][]
-/// case 9.  shortcut link: [example]
-/// case 10. inline without URL: [example]()
-/// 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]()
-/// case 16. just escaped text: \[foo]
-/// case 17. inline link: [Foo](foo::Foo)
-///
-/// [`Result`]: ../../std/result/enum.Result.html
-/// [^example]: https://www.example.com/
-pub fn fo$0o() {}
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                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 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.  reference: example
-                case 8.  collapsed link: example
-                case 9.  shortcut link: example
-                case 10. inline without URL: example
-                case 11. reference: foo
-                case 12. reference: foo
-                case 13. collapsed link: foo
-                case 14. shortcut link: foo
-                case 15. inline without URL: foo
-                case 16. just escaped text: \[foo\]
-                case 17. inline link: Foo
-
-                [^example]: https://www.example.com/
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_macro_generated_struct_fn_doc_comment() {
-        cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
-
-        check(
-            r#"
-macro_rules! bar {
-    () => {
-        struct Bar;
-        impl Bar {
-            /// Do the foo
-            fn foo(&self) {}
-        }
-    }
-}
-
-bar!();
-
-fn foo() { let bar = Bar; bar.fo$0o(); }
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test::Bar
-                ```
-
-                ```rust
-                fn foo(&self)
-                ```
-
-                ---
-
-                Do the foo
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_macro_generated_struct_fn_doc_attr() {
-        cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
-
-        check(
-            r#"
-macro_rules! bar {
-    () => {
-        struct Bar;
-        impl Bar {
-            #[doc = "Do the foo"]
-            fn foo(&self) {}
-        }
-    }
-}
-
-bar!();
-
-fn foo() { let bar = Bar; bar.fo$0o(); }
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test::Bar
-                ```
-
-                ```rust
-                fn foo(&self)
-                ```
-
-                ---
-
-                Do the foo
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_trait_has_impl_action() {
-        check_actions(
-            r#"trait foo$0() {}"#,
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 6,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_struct_has_impl_action() {
-        check_actions(
-            r"struct foo$0() {}",
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 7,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_union_has_impl_action() {
-        check_actions(
-            r#"union foo$0() {}"#,
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 6,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_enum_has_impl_action() {
-        check_actions(
-            r"enum foo$0() { A, B }",
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 5,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[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_$0test() {}
-"#,
-            expect![[r#"
-                [
-                    Reference(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 11,
-                        },
-                    ),
-                    Runnable(
-                        Runnable {
-                            use_name_in_title: false,
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 0..24,
-                                focus_range: 11..19,
-                                name: "foo_test",
-                                kind: Function,
-                            },
-                            kind: Test {
-                                test_id: Path(
-                                    "foo_test",
-                                ),
-                                attr: TestAttr {
-                                    ignore: false,
-                                },
-                            },
-                            cfg: None,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_test_mod_has_action() {
-        check_actions(
-            r#"
-mod tests$0 {
-    #[test]
-    fn foo_test() {}
-}
-"#,
-            expect![[r#"
-                [
-                    Runnable(
-                        Runnable {
-                            use_name_in_title: false,
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 0..46,
-                                focus_range: 4..9,
-                                name: "tests",
-                                kind: Module,
-                                description: "mod tests",
-                            },
-                            kind: TestMod {
-                                path: "tests",
-                            },
-                            cfg: None,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_struct_has_goto_type_action() {
-        check_actions(
-            r#"
-struct S{ f1: u32 }
-
-fn main() { let s$0t = S{ f1:0 }; }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..19,
-                                    focus_range: 7..8,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_generic_struct_has_goto_type_actions() {
-        check_actions(
-            r#"
-struct Arg(u32);
-struct S<T>{ f1: T }
-
-fn main() { let s$0t = S{ f1:Arg(0) }; }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 17..37,
-                                    focus_range: 24..25,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::Arg",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..16,
-                                    focus_range: 7..10,
-                                    name: "Arg",
-                                    kind: Struct,
-                                    description: "struct Arg",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_generic_struct_has_flattened_goto_type_actions() {
-        check_actions(
-            r#"
-struct Arg(u32);
-struct S<T>{ f1: T }
-
-fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 17..37,
-                                    focus_range: 24..25,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::Arg",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..16,
-                                    focus_range: 7..10,
-                                    name: "Arg",
-                                    kind: Struct,
-                                    description: "struct Arg",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_tuple_has_goto_type_actions() {
-        check_actions(
-            r#"
-struct A(u32);
-struct B(u32);
-mod M {
-    pub struct C(u32);
-}
-
-fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::A",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..14,
-                                    focus_range: 7..8,
-                                    name: "A",
-                                    kind: Struct,
-                                    description: "struct A",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::B",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 15..29,
-                                    focus_range: 22..23,
-                                    name: "B",
-                                    kind: Struct,
-                                    description: "struct B",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::M::C",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 42..60,
-                                    focus_range: 53..54,
-                                    name: "C",
-                                    kind: Struct,
-                                    description: "pub struct C",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_return_impl_trait_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-fn foo() -> impl Foo {}
-
-fn main() { let s$0t = foo(); }
-"#,
-            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_generic_return_impl_trait_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo<T> {}
-struct S;
-fn foo() -> impl Foo<S> {}
-
-fn main() { let s$0t = foo(); }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..15,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 16..25,
-                                    focus_range: 23..24,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_return_impl_traits_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-trait Bar {}
-fn foo() -> impl Foo + Bar {}
-
-fn main() { let s$0t = foo(); }
-"#,
-            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",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::Bar",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 13..25,
-                                    focus_range: 19..22,
-                                    name: "Bar",
-                                    kind: Trait,
-                                    description: "trait Bar",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_generic_return_impl_traits_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo<T> {}
-trait Bar<T> {}
-struct S1 {}
-struct S2 {}
-
-fn foo() -> impl Foo<S1> + Bar<S2> {}
-
-fn main() { let s$0t = foo(); }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..15,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::Bar",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 16..31,
-                                    focus_range: 22..25,
-                                    name: "Bar",
-                                    kind: Trait,
-                                    description: "trait Bar<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S1",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 32..44,
-                                    focus_range: 39..41,
-                                    name: "S1",
-                                    kind: Struct,
-                                    description: "struct S1",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S2",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 45..57,
-                                    focus_range: 52..54,
-                                    name: "S2",
-                                    kind: Struct,
-                                    description: "struct S2",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_arg_impl_trait_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-fn foo(ar$0g: &impl Foo) {}
-"#,
-            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_arg_impl_traits_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-trait Bar<T> {}
-struct S{}
-
-fn foo(ar$0g: &impl Foo + Bar<S>) {}
-"#,
-            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",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::Bar",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 13..28,
-                                    focus_range: 19..22,
-                                    name: "Bar",
-                                    kind: Trait,
-                                    description: "trait Bar<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 29..39,
-                                    focus_range: 36..37,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_async_block_impl_trait_has_goto_type_action() {
-        check_actions(
-            r#"
-//- minicore: future
-struct S;
-fn foo() {
-    let fo$0o = async { S };
-}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "core::future::Future",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        1,
-                                    ),
-                                    full_range: 254..436,
-                                    focus_range: 293..299,
-                                    name: "Future",
-                                    kind: Trait,
-                                    description: "pub trait Future",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..9,
-                                    focus_range: 7..8,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo<T> {}
-struct S {}
-fn foo(ar$0g: &impl Foo<S>) {}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..15,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 16..27,
-                                    focus_range: 23..24,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_dyn_return_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-struct S;
-impl Foo for S {}
-
-struct B<T>{}
-fn foo() -> B<dyn Foo> {}
-
-fn main() { let s$0t = foo(); }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::B",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 42..55,
-                                    focus_range: 49..50,
-                                    name: "B",
-                                    kind: Struct,
-                                    description: "struct B<T>",
-                                },
-                            },
-                            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_dyn_arg_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-fn foo(ar$0g: &dyn Foo) {}
-"#,
-            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_generic_dyn_arg_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo<T> {}
-struct S {}
-fn foo(ar$0g: &dyn Foo<S>) {}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..15,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 16..27,
-                                    focus_range: 23..24,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_goto_type_action_links_order() {
-        check_actions(
-            r#"
-trait ImplTrait<T> {}
-trait DynTrait<T> {}
-struct B<T> {}
-struct S {}
-
-fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::ImplTrait",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..21,
-                                    focus_range: 6..15,
-                                    name: "ImplTrait",
-                                    kind: Trait,
-                                    description: "trait ImplTrait<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::B",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 43..57,
-                                    focus_range: 50..51,
-                                    name: "B",
-                                    kind: Struct,
-                                    description: "struct B<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::DynTrait",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 22..42,
-                                    focus_range: 28..36,
-                                    name: "DynTrait",
-                                    kind: Trait,
-                                    description: "trait DynTrait<T>",
-                                },
-                            },
-                            HoverGotoTypeData {
-                                mod_path: "test::S",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 58..69,
-                                    focus_range: 65..66,
-                                    name: "S",
-                                    kind: Struct,
-                                    description: "struct S",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_associated_type_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {
-    type Item;
-    fn get(self) -> Self::Item {}
-}
-
-struct Bar{}
-struct S{}
-
-impl Foo for S { type Item = Bar; }
-
-fn test() -> impl Foo { S {} }
-
-fn main() { let s$0t = test().get(); }
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..62,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[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(
-            r#"
-//- /lib.rs crate:name-with-dashes
-pub mod wrapper {
-    pub struct Thing { x: u32 }
-
-    impl Thing {
-        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$0(); }
-"#,
-            expect![[r#"
-            *new*
-
-            ```rust
-            name_with_dashes::wrapper::Thing
-            ```
-
-            ```rust
-            pub fn new() -> Thing
-            ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_field_pat_shorthand_ref_match_ergonomics() {
-        check(
-            r#"
-struct S {
-    f: i32,
-}
-
-fn main() {
-    let s = S { f: 0 };
-    let S { f$0 } = &s;
-}
-"#,
-            expect![[r#"
-                *f*
-
-                ```rust
-                f: &i32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_self_param_shows_type() {
-        check(
-            r#"
-struct Foo {}
-impl Foo {
-    fn bar(&sel$0f) {}
-}
-"#,
-            expect![[r#"
-                *self*
-
-                ```rust
-                self: &Foo
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_self_param_shows_type_for_arbitrary_self_type() {
-        check(
-            r#"
-struct Arc<T>(T);
-struct Foo {}
-impl Foo {
-    fn bar(sel$0f: Arc<Foo>) {}
-}
-"#,
-            expect![[r#"
-                *self*
-
-                ```rust
-                self: Arc<Foo>
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_doc_outer_inner() {
-        check(
-            r#"
-/// Be quick;
-mod Foo$0 {
-    //! time is mana
-
-    /// This comment belongs to the function
-    fn foo() {}
-}
-"#,
-            expect![[r#"
-                *Foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod Foo
-                ```
-
-                ---
-
-                Be quick;
-                time is mana
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_doc_outer_inner_attribue() {
-        check(
-            r#"
-#[doc = "Be quick;"]
-mod Foo$0 {
-    #![doc = "time is mana"]
-
-    #[doc = "This comment belongs to the function"]
-    fn foo() {}
-}
-"#,
-            expect![[r#"
-                *Foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod Foo
-                ```
-
-                ---
-
-                Be quick;
-                time is mana
-            "#]],
-        );
-    }
-
-    #[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() {
-    // no$0hover
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn hover_label() {
-        check(
-            r#"
-fn foo() {
-    'label$0: loop {}
-}
-"#,
-            expect![[r#"
-            *'label*
-
-            ```rust
-            'label
-            ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_lifetime() {
-        check(
-            r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
-            expect![[r#"
-            *'lifetime*
-
-            ```rust
-            'lifetime
-            ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_type_param() {
-        check(
-            r#"
-//- minicore: sized
-struct Foo<T>(T);
-trait TraitA {}
-trait TraitB {}
-impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T: TraitA + TraitB
-                ```
-            "#]],
-        );
-        check(
-            r#"
-//- minicore: sized
-struct Foo<T>(T);
-impl<T> Foo<T$0> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T
-                ```
-                "#]],
-        );
-        // lifetimes bounds arent being tracked yet
-        check(
-            r#"
-//- minicore: sized
-struct Foo<T>(T);
-impl<T: 'static> Foo<T$0> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T
-                ```
-                "#]],
-        );
-    }
-
-    #[test]
-    fn hover_type_param_sized_bounds() {
-        // implicit `: Sized` bound
-        check(
-            r#"
-//- minicore: sized
-trait Trait {}
-struct Foo<T>(T);
-impl<T: Trait> Foo<T$0> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T: Trait
-                ```
-            "#]],
-        );
-        check(
-            r#"
-//- minicore: sized
-trait Trait {}
-struct Foo<T>(T);
-impl<T: Trait + ?Sized> Foo<T$0> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T: Trait + ?Sized
-                ```
-            "#]],
-        );
-    }
-
-    mod type_param_sized_bounds {
-        use super::*;
-
-        #[test]
-        fn single_implicit() {
-            check(
-                r#"
-//- minicore: sized
-fn foo<T$0>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn single_explicit() {
-            check(
-                r#"
-//- minicore: sized
-fn foo<T$0: Sized>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn single_relaxed() {
-            check(
-                r#"
-//- minicore: sized
-fn foo<T$0: ?Sized>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T: ?Sized
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn multiple_implicit() {
-            check(
-                r#"
-//- minicore: sized
-trait Trait {}
-fn foo<T$0: Trait>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T: Trait
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn multiple_explicit() {
-            check(
-                r#"
-//- minicore: sized
-trait Trait {}
-fn foo<T$0: Trait + Sized>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T: Trait
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn multiple_relaxed() {
-            check(
-                r#"
-//- minicore: sized
-trait Trait {}
-fn foo<T$0: Trait + ?Sized>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T: Trait + ?Sized
-                    ```
-                "#]],
-            );
-        }
-
-        #[test]
-        fn mixed() {
-            check(
-                r#"
-//- minicore: sized
-fn foo<T$0: ?Sized + Sized + Sized>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T
-                    ```
-                "#]],
-            );
-            check(
-                r#"
-//- minicore: sized
-trait Trait {}
-fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
-"#,
-                expect![[r#"
-                    *T*
-
-                    ```rust
-                    T: Trait
-                    ```
-                "#]],
-            );
-        }
-    }
-
-    #[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
-                ```
-
-                ---
-
-                This is a doc
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_mod_def() {
-        check(
-            r#"
-//- /main.rs
-mod foo$0;
-//- /foo.rs
-//! For the horde!
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod 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
-                mod bar
-                ```
-
-                ---
-
-                But this should appear
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_keyword() {
-        check(
-            r#"
-//- /main.rs crate:main deps:std
-fn f() { retur$0n; }
-//- /libstd.rs crate:std
-/// Docs for return_keyword
-mod return_keyword {}
-"#,
-            expect![[r#"
-                *return*
-
-                ```rust
-                return
-                ```
-
-                ---
-
-                Docs for return_keyword
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_builtin() {
-        check(
-            r#"
-//- /main.rs crate:main deps:std
-cosnt _: &str$0 = ""; }
-
-//- /libstd.rs crate:std
-/// Docs for prim_str
-mod prim_str {}
-"#,
-            expect![[r#"
-                *str*
-
-                ```rust
-                str
-                ```
-
-                ---
-
-                Docs for prim_str
-            "#]],
-        );
-    }
-
-    #[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.
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_attr_path_qualifier() {
-        cov_mark::check!(name_ref_classify_attr_path_qualifier);
-        check(
-            r#"
-//- /foo.rs crate:foo
-
-//- /lib.rs crate:main.rs deps:foo
-#[fo$0o::bar()]
-struct Foo;
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                extern crate foo
-                ```
-            "#]],
-        )
-    }
-
-    #[test]
-    fn hover_rename() {
-        check(
-            r#"
-use self as foo$0;
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                extern crate test
-                ```
-            "#]],
-        );
-        check(
-            r#"
-mod bar {}
-use bar::{self as foo$0};
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                mod bar
-                ```
-            "#]],
-        );
-        check(
-            r#"
-mod bar {
-    use super as foo$0;
-}
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                extern crate test
-                ```
-            "#]],
-        );
-        check(
-            r#"
-use crate as foo$0;
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                extern crate test
-                ```
-            "#]],
-        );
-    }
-
-    // FIXME: wrong range in macros. `es! ` should be `Copy`
-    #[test]
-    fn hover_attribute_in_macro() {
-        check(
-            r#"
-macro_rules! identity {
-    ($struct:item) => {
-        $struct
-    };
-}
-#[rustc_builtin_macro]
-pub macro Copy {}
-identity!{
-    #[derive(Copy$0)]
-    struct Foo;
-}
-"#,
-            expect![[r#"
-                *es! *
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub macro Copy
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_derive_input() {
-        check(
-            r#"
-#[rustc_builtin_macro]
-pub macro Copy {}
-#[derive(Copy$0)]
-struct Foo;
-"#,
-            expect![[r#"
-                *Copy*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub macro Copy
-                ```
-            "#]],
-        );
-        check(
-            r#"
-mod foo {
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-}
-#[derive(foo::Copy$0)]
-struct Foo;
-"#,
-            expect![[r#"
-                *Copy*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                pub macro Copy
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_math() {
-        check_hover_range(
-            r#"
-fn f() { let expr = $01 + 2 * 3$0 }
-"#,
-            expect![[r#"
-            ```rust
-            i32
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f() { let expr = 1 $0+ 2 * $03 }
-"#,
-            expect![[r#"
-            ```rust
-            i32
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f() { let expr = 1 + $02 * 3$0 }
-"#,
-            expect![[r#"
-            ```rust
-            i32
-            ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_arrays() {
-        check_hover_range(
-            r#"
-fn f() { let expr = $0[1, 2, 3, 4]$0 }
-"#,
-            expect![[r#"
-            ```rust
-            [i32; 4]
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f() { let expr = [1, 2, $03, 4]$0 }
-"#,
-            expect![[r#"
-            ```rust
-            [i32; 4]
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f() { let expr = [1, 2, $03$0, 4] }
-"#,
-            expect![[r#"
-            ```rust
-            i32
-            ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_functions() {
-        check_hover_range(
-            r#"
-fn f<T>(a: &[T]) { }
-fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
-"#,
-            expect![[r#"
-            ```rust
-            fn f<i32>(&[i32])
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f<T>(a: &[T]) { }
-fn b() { f($0&[1, 2, 3, 4, 5]$0); }
-"#,
-            expect![[r#"
-            ```rust
-            &[i32; 5]
-            ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_shows_nothing_when_invalid() {
-        check_hover_range_no_results(
-            r#"
-fn f<T>(a: &[T]) { }
-fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
-"#,
-        );
-
-        check_hover_range_no_results(
-            r#"
-fn f<T>$0(a: &[T]) { }
-fn b() { f(&[1, 2, 3,$0 4, 5]); }
-"#,
-        );
-
-        check_hover_range_no_results(
-            r#"
-fn $0f() { let expr = [1, 2, 3, 4]$0 }
-"#,
-        );
-    }
-
-    #[test]
-    fn hover_range_shows_unit_for_statements() {
-        check_hover_range(
-            r#"
-fn f<T>(a: &[T]) { }
-fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
-"#,
-            expect![[r#"
-            ```rust
-            ()
-            ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn f() { let expr$0 = $0[1, 2, 3, 4] }
-"#,
-            expect![[r#"
-            ```rust
-            ()
-            ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_for_pat() {
-        check_hover_range(
-            r#"
-fn foo() {
-    let $0x$0 = 0;
-}
-"#,
-            expect![[r#"
-                ```rust
-                i32
-                ```"#]],
-        );
-
-        check_hover_range(
-            r#"
-fn foo() {
-    let $0x$0 = "";
-}
-"#,
-            expect![[r#"
-                ```rust
-                &str
-                ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_shows_coercions_if_applicable_expr() {
-        check_hover_range(
-            r#"
-fn foo() {
-    let x: &u32 = $0&&&&&0$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Type:       &&&&&u32
-                Coerced to:     &u32
-                ```
-            "#]],
-        );
-        check_hover_range(
-            r#"
-fn foo() {
-    let x: *const u32 = $0&0$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Type:             &u32
-                Coerced to: *const u32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_range_shows_type_actions() {
-        check_actions(
-            r#"
-struct Foo;
-fn foo() {
-    let x: &Foo = $0&&&&&Foo$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_try_expr_res() {
-        check_hover_range(
-            r#"
-//- minicore:result
-struct FooError;
-
-fn foo() -> Result<(), FooError> {
-    Ok($0Result::<(), FooError>::Ok(())?$0)
-}
-"#,
-            expect![[r#"
-                ```rust
-                ()
-                ```"#]],
-        );
-        check_hover_range(
-            r#"
-//- minicore:result
-struct FooError;
-struct BarError;
-
-fn foo() -> Result<(), FooError> {
-    Ok($0Result::<(), BarError>::Ok(())?$0)
-}
-"#,
-            expect![[r#"
-                ```text
-                Try Error Type: BarError
-                Propagated as:  FooError
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_try_expr() {
-        check_hover_range(
-            r#"
-struct NotResult<T, U>(T, U);
-struct Short;
-struct Looooong;
-
-fn foo() -> NotResult<(), Looooong> {
-    $0NotResult((), Short)?$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Try Target Type:    NotResult<(), Short>
-                Propagated as:   NotResult<(), Looooong>
-                ```
-            "#]],
-        );
-        check_hover_range(
-            r#"
-struct NotResult<T, U>(T, U);
-struct Short;
-struct Looooong;
-
-fn foo() -> NotResult<(), Short> {
-    $0NotResult((), Looooong)?$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Try Target Type: NotResult<(), Looooong>
-                Propagated as:      NotResult<(), Short>
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_try_expr_option() {
-        cov_mark::check!(hover_try_expr_opt_opt);
-        check_hover_range(
-            r#"
-//- minicore: option, try
-
-fn foo() -> Option<()> {
-    $0Some(0)?$0;
-    None
-}
-"#,
-            expect![[r#"
-                ```rust
-                <Option<i32> as Try>::Output
-                ```"#]],
-        );
-    }
-
-    #[test]
-    fn hover_deref_expr() {
-        check_hover_range(
-            r#"
-//- minicore: deref
-use core::ops::Deref;
-
-struct DerefExample<T> {
-    value: T
-}
-
-impl<T> Deref for DerefExample<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.value
-    }
-}
-
-fn foo() {
-    let x = DerefExample { value: 0 };
-    let y: i32 = $0*x$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Dereferenced from: DerefExample<i32>
-                To type:                         i32
-                ```
-            "#]],
-        );
-    }
-
-    #[test]
-    fn hover_deref_expr_with_coercion() {
-        check_hover_range(
-            r#"
-//- minicore: deref
-use core::ops::Deref;
-
-struct DerefExample<T> {
-    value: T
-}
-
-impl<T> Deref for DerefExample<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.value
-    }
-}
-
-fn foo() {
-    let x = DerefExample { value: &&&&&0 };
-    let y: &i32 = $0*x$0;
-}
-"#,
-            expect![[r#"
-                ```text
-                Dereferenced from: DerefExample<&&&&&i32>
-                To type:                         &&&&&i32
-                Coerced to:                          &i32
-                ```
-            "#]],
-        );
-    }
+    deduped_actions
 }