From 32f5276465266522ebc01b8417feeba99bf00f6f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 6 Mar 2020 01:02:14 +0200 Subject: [PATCH] Show mod path in hover tooltip --- crates/ra_hir/src/code_model.rs | 24 +++++++ crates/ra_ide/src/display.rs | 14 ++-- crates/ra_ide/src/hover.rs | 119 +++++++++++++++++++++++++------- crates/ra_ide_db/src/lib.rs | 4 ++ 4 files changed, 132 insertions(+), 29 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 2944926e6b..dca5f27b29 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -480,6 +480,14 @@ impl Adt { pub fn krate(self, db: &impl HirDatabase) -> Option { Some(self.module(db).krate()) } + + pub fn name(&self, db: &impl HirDatabase) -> Name { + match self { + Adt::Struct(s) => s.name(db), + Adt::Union(u) => u.name(db), + Adt::Enum(e) => e.name(db), + } + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -507,6 +515,14 @@ impl VariantDef { } } + pub fn name(&self, db: &impl HirDatabase) -> Name { + match self { + VariantDef::Struct(s) => s.name(db), + VariantDef::Union(u) => u.name(db), + VariantDef::EnumVariant(e) => e.name(db), + } + } + pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc { match self { VariantDef::Struct(it) => it.variant_data(db), @@ -534,6 +550,14 @@ impl DefWithBody { DefWithBody::Static(s) => s.module(db), } } + + pub fn name(self, db: &impl HirDatabase) -> Option { + match self { + DefWithBody::Function(f) => Some(f.name(db)), + DefWithBody::Static(s) => s.name(db), + DefWithBody::Const(c) => c.name(db), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 1c26a86974..eaeaaa2b40 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs @@ -68,17 +68,23 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String { } pub(crate) fn rust_code_markup>(val: CODE) -> String { - rust_code_markup_with_doc::<_, &str>(val, None) + rust_code_markup_with_doc::<_, &str>(val, None, None) } -pub(crate) fn rust_code_markup_with_doc(val: CODE, doc: Option) -> String +pub(crate) fn rust_code_markup_with_doc( + val: CODE, + doc: Option, + mod_path: Option, +) -> String where CODE: AsRef, DOC: AsRef, { + let mod_path = + mod_path.filter(|path| !path.is_empty()).map(|path| path + "\n").unwrap_or_default(); if let Some(doc) = doc { - format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref()) + format!("```rust\n{}{}\n```\n\n{}", mod_path, val.as_ref(), doc.as_ref()) } else { - format!("```rust\n{}\n```", val.as_ref()) + format!("```rust\n{}{}\n```", mod_path, val.as_ref()) } } diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index e9c6825570..da3b679433 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1,6 +1,8 @@ //! FIXME: write short doc here -use hir::{Adt, HasSource, HirDisplay, Semantics}; +use hir::{ + Adt, AsAssocItem, AssocItemContainer, HasSource, HirDisplay, ModuleDef, ModuleSource, Semantics, +}; use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition}, RootDatabase, @@ -16,6 +18,8 @@ use crate::{ display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, FilePosition, RangeInfo, }; +use itertools::Itertools; +use std::iter::once; /// Contains the results when hovering over an item #[derive(Debug, Clone)] @@ -83,44 +87,86 @@ impl HoverResult { } } -fn hover_text(docs: Option, desc: Option) -> Option { - match (desc, docs) { - (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), - (None, Some(docs)) => Some(docs), +fn hover_text( + docs: Option, + desc: Option, + mod_path: Option, +) -> Option { + match (desc, docs, mod_path) { + (Some(desc), docs, mod_path) => Some(rust_code_markup_with_doc(desc, docs, mod_path)), + (None, Some(docs), _) => Some(docs), _ => None, } } +fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option { + match def { + Definition::StructField(f) => Some(f.parent_def(db).name(db)), + Definition::Local(l) => l.parent(db).name(db), + Definition::ModuleDef(md) => match md { + ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { + AssocItemContainer::Trait(t) => Some(t.name(db)), + AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), + }, + ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)), + _ => None, + }, + Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), + _ => None, + } + .map(|name| name.to_string()) +} + +fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option { + let mod_path = def.module(db).map(|module| { + once(db.get_crate_original_name(&module.krate().into())) + .chain( + module + .path_to_root(db) + .into_iter() + .rev() + .map(|it| it.name(db).map(|name| name.to_string())), + ) + .chain(once(definition_owner_name(db, def))) + .filter_map(std::convert::identity) + .join("::") + }); + mod_path +} + fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option { + let mod_path = determine_mod_path(db, &def); return match def { Definition::Macro(it) => { let src = it.source(db); - hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value))) + hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) } Definition::StructField(it) => { let src = it.source(db); match src.value { - hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), + hir::FieldSource::Named(it) => { + hover_text(it.doc_comment_text(), it.short_label(), mod_path) + } _ => None, } } Definition::ModuleDef(it) => match it { - hir::ModuleDef::Module(it) => match it.definition_source(db).value { - hir::ModuleSource::Module(it) => { - hover_text(it.doc_comment_text(), it.short_label()) + ModuleDef::Module(it) => match it.definition_source(db).value { + ModuleSource::Module(it) => { + hover_text(it.doc_comment_text(), it.short_label(), mod_path) } _ => None, }, - hir::ModuleDef::Function(it) => from_def_source(db, it), - hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it), - hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it), - hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it), - hir::ModuleDef::EnumVariant(it) => from_def_source(db, it), - hir::ModuleDef::Const(it) => from_def_source(db, it), - hir::ModuleDef::Static(it) => from_def_source(db, it), - hir::ModuleDef::Trait(it) => from_def_source(db, it), - hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), - hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), + ModuleDef::Function(it) => from_def_source(db, it, mod_path), + ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), + ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), + ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), + ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path), + ModuleDef::Const(it) => from_def_source(db, it, mod_path), + ModuleDef::Static(it) => from_def_source(db, it, mod_path), + ModuleDef::Trait(it) => from_def_source(db, it, mod_path), + ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), + ModuleDef::BuiltinType(it) => Some(it.to_string()), }, Definition::Local(it) => { Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) @@ -131,13 +177,13 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option(db: &RootDatabase, def: D) -> Option + fn from_def_source(db: &RootDatabase, def: D, mod_path: Option) -> Option where D: HasSource, A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, { let src = def.source(db); - hover_text(src.value.doc_comment_text(), src.value.short_label()) + hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) } } @@ -345,7 +391,7 @@ mod tests { }; } "#, - &["field_a: u32"], + &["Foo\nfield_a: u32"], ); // Hovering over the field in the definition @@ -362,7 +408,7 @@ mod tests { }; } "#, - &["field_a: u32"], + &["Foo\nfield_a: u32"], ); } @@ -415,7 +461,7 @@ fn main() { ", ); let hover = analysis.hover(position).unwrap().unwrap(); - assert_eq!(trim_markup_opt(hover.info.first()), Some("Some")); + assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome")); let (analysis, position) = single_file_with_position( " @@ -442,6 +488,7 @@ fn main() { } "#, &[" +Option None ``` @@ -462,6 +509,7 @@ The None variant } "#, &[" +Option Some ``` @@ -815,4 +863,25 @@ fn func(foo: i32) { if true { <|>foo; }; } &["fn foo()\n```\n\n<- `\u{3000}` here"], ); } + + #[test] + fn zzz() { + check_hover_result( + " + //- /main.rs + mod vvv { + pub struct Test; + + impl Test { + pub fn whatever() {} + } + } + + fn main() { + vvv::Test::what<|>ever(); + } + ", + &["vvv::Test\npub fn whatever()"], + ); + } } diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 79f48c9e32..efa472c7d1 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -104,6 +104,10 @@ impl RootDatabase { db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); db } + + pub fn get_crate_original_name(&self, crate_id: &CrateId) -> Option { + self.debug_data.crate_names.get(crate_id).cloned() + } } impl salsa::ParallelDatabase for RootDatabase {