X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Fide%2Fsrc%2Fhover.rs;h=0eba0b09ba6e2dfded2f179b785f18c7e1bcd5a0;hb=0b53744f2d7e0694cd7207cca632fd6de1dc5bff;hp=2ebf46b56499d49cf1ed94e2003fdb78a672871b;hpb=f0da9406bcbde1bc727242b481d8de825e84f59a;p=rust.git diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2ebf46b5649..0eba0b09ba6 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -9,21 +9,19 @@ use hir::{HasSource, Semantics}; use ide_db::{ base_db::FileRange, - defs::Definition, + defs::{Definition, IdentClass}, helpers::{pick_best_token, FamousDefs}, - RootDatabase, + FxIndexSet, RootDatabase, }; use itertools::Itertools; use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T}; use crate::{ - display::TryToNav, 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, @@ -69,7 +67,7 @@ fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Se } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct HoverGotoTypeData { pub mod_path: String, pub nav: NavigationTarget, @@ -119,10 +117,11 @@ pub(crate) fn hover( let descended = sema.descend_into_macros(original_token.clone()); // FIXME: Definition should include known lints and the like instead of having this special case here - if let Some(res) = descended.iter().find_map(|token| { + 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)); } @@ -130,29 +129,36 @@ pub(crate) fn hover( .iter() .filter_map(|token| { let node = token.parent()?; - let defs = Definition::from_token(sema, token); - Some(defs.into_iter().zip(iter::once(node).cycle())) + let class = IdentClass::classify_token(sema, token)?; + Some(class.definitions().into_iter().zip(iter::once(node).cycle())) }) .flatten() .unique_by(|&(def, _)| def) .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) - .reduce(|mut acc, HoverResult { markup, actions }| { + .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { acc.actions.extend(actions); acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup)); acc }); + if result.is_none() { // fallbacks, show keywords or types - if let Some(res) = render::keyword(sema, config, &original_token) { + + 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 let res @ Some(_) = - descended.iter().find_map(|token| hover_type_fallback(sema, config, token)) - { + let res = descended + .iter() + .find_map(|token| hover_type_fallback(sema, config, token, &original_token)); + if let res @ Some(_) = res { return res; } } - result.map(|res| RangeInfo::new(original_token.text_range(), res)) + result.map(|mut res: HoverResult| { + res.actions = dedupe_or_merge_hover_actions(res.actions); + RangeInfo::new(original_token.text_range(), res) + }) } pub(crate) fn hover_for_definition( @@ -195,6 +201,7 @@ fn hover_ranged( sema: &Semantics, config: &HoverConfig, ) -> Option> { + // FIXME: make this work in attributes let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| { match_ast! { match it { @@ -227,6 +234,7 @@ fn hover_type_fallback( sema: &Semantics, config: &HoverConfig, token: &SyntaxToken, + original_token: &SyntaxToken, ) -> Option> { let node = token .ancestors() @@ -245,7 +253,10 @@ fn hover_type_fallback( }; let res = render::type_info(sema, config, &expr_or_pat)?; - let range = sema.original_range(&node).range; + let range = sema + .original_range_opt(&node) + .map(|frange| frange.range) + .unwrap_or_else(|| original_token.text_range()); Some(RangeInfo::new(range, res)) } @@ -335,9 +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 dedupe_or_merge_hover_actions(actions: Vec) -> Vec { + let mut deduped_actions = Vec::with_capacity(actions.len()); + let mut go_to_type_targets = FxIndexSet::default(); + + 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); + } + HoverAction::Implementation(..) => { + if !seen_implementation { + seen_implementation = true; + deduped_actions.push(action); + } + } + HoverAction::Reference(..) => { + if !seen_reference { + seen_reference = true; + deduped_actions.push(action); + } + } + HoverAction::Runnable(..) => { + if !seen_runnable { + seen_runnable = true; + deduped_actions.push(action); + } + } + }; + } + + if !go_to_type_targets.is_empty() { + deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect())); + } + + deduped_actions +}