3519: Show mod path on hover r=matklad a=SomeoneToIgnore

Closes #1064

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
bors[bot] 2020-03-09 09:33:46 +00:00 committed by GitHub
commit 57c27f9139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 270 additions and 121 deletions

View File

@ -56,6 +56,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId {
crate_graph.add_crate_root( crate_graph.add_crate_root(
file_id, file_id,
Edition::Edition2018, Edition::Edition2018,
None,
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
); );
@ -98,8 +99,13 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
assert!(meta.path.starts_with(&source_root_prefix)); assert!(meta.path.starts_with(&source_root_prefix));
if let Some(krate) = meta.krate { if let Some(krate) = meta.krate {
let crate_id = let crate_id = crate_graph.add_crate_root(
crate_graph.add_crate_root(file_id, meta.edition, meta.cfg, Env::default()); file_id,
meta.edition,
Some(krate.clone()),
meta.cfg,
Env::default(),
);
let prev = crates.insert(krate.clone(), crate_id); let prev = crates.insert(krate.clone(), crate_id);
assert!(prev.is_none()); assert!(prev.is_none());
for dep in meta.deps { for dep in meta.deps {
@ -132,6 +138,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
crate_graph.add_crate_root( crate_graph.add_crate_root(
crate_root, crate_root,
Edition::Edition2018, Edition::Edition2018,
None,
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
); );

View File

@ -86,7 +86,7 @@ pub struct CrateId(pub u32);
pub struct CrateName(SmolStr); pub struct CrateName(SmolStr);
impl CrateName { impl CrateName {
/// Crates a crate name, checking for dashes in the string provided. /// Creates a crate name, checking for dashes in the string provided.
/// Dashes are not allowed in the crate names, /// Dashes are not allowed in the crate names,
/// hence the input string is returned as `Err` for those cases. /// hence the input string is returned as `Err` for those cases.
pub fn new(name: &str) -> Result<CrateName, &str> { pub fn new(name: &str) -> Result<CrateName, &str> {
@ -97,19 +97,23 @@ impl CrateName {
} }
} }
/// Crates a crate name, unconditionally replacing the dashes with underscores. /// Creates a crate name, unconditionally replacing the dashes with underscores.
pub fn normalize_dashes(name: &str) -> CrateName { pub fn normalize_dashes(name: &str) -> CrateName {
Self(SmolStr::new(name.replace('-', "_"))) Self(SmolStr::new(name.replace('-', "_")))
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct CrateData { pub struct CrateData {
file_id: FileId, pub root_file_id: FileId,
edition: Edition, pub edition: Edition,
/// The name to display to the end user.
/// This actual crate name can be different in a particular dependent crate
/// or may even be missing for some cases, such as a dummy crate for the code snippet.
pub display_name: Option<String>,
cfg_options: CfgOptions, cfg_options: CfgOptions,
env: Env, env: Env,
dependencies: Vec<Dependency>, pub dependencies: Vec<Dependency>,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -134,10 +138,11 @@ impl CrateGraph {
&mut self, &mut self,
file_id: FileId, file_id: FileId,
edition: Edition, edition: Edition,
display_name: Option<String>,
cfg_options: CfgOptions, cfg_options: CfgOptions,
env: Env, env: Env,
) -> CrateId { ) -> CrateId {
let data = CrateData::new(file_id, edition, cfg_options, env); let data = CrateData::new(file_id, edition, display_name, cfg_options, env);
let crate_id = CrateId(self.arena.len() as u32); let crate_id = CrateId(self.arena.len() as u32);
let prev = self.arena.insert(crate_id, data); let prev = self.arena.insert(crate_id, data);
assert!(prev.is_none()); assert!(prev.is_none());
@ -169,24 +174,17 @@ impl CrateGraph {
self.arena.keys().copied() self.arena.keys().copied()
} }
pub fn crate_root(&self, crate_id: CrateId) -> FileId { pub fn crate_data(&self, crate_id: &CrateId) -> &CrateData {
self.arena[&crate_id].file_id &self.arena[crate_id]
}
pub fn edition(&self, crate_id: CrateId) -> Edition {
self.arena[&crate_id].edition
} }
// FIXME: this only finds one crate with the given root; we could have multiple // FIXME: this only finds one crate with the given root; we could have multiple
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; let (&crate_id, _) =
self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?;
Some(crate_id) Some(crate_id)
} }
pub fn dependencies(&self, crate_id: CrateId) -> impl Iterator<Item = &Dependency> {
self.arena[&crate_id].dependencies.iter()
}
/// Extends this crate graph by adding a complete disjoint second crate /// Extends this crate graph by adding a complete disjoint second crate
/// graph. /// graph.
/// ///
@ -209,7 +207,7 @@ impl CrateGraph {
return false; return false;
} }
for dep in self.dependencies(from) { for dep in &self.crate_data(&from).dependencies {
let crate_id = dep.crate_id(); let crate_id = dep.crate_id();
if crate_id == target { if crate_id == target {
return true; return true;
@ -230,8 +228,21 @@ impl CrateId {
} }
impl CrateData { impl CrateData {
fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions, env: Env) -> CrateData { fn new(
CrateData { file_id, edition, dependencies: Vec::new(), cfg_options, env } root_file_id: FileId,
edition: Edition,
display_name: Option<String>,
cfg_options: CfgOptions,
env: Env,
) -> CrateData {
CrateData {
root_file_id,
edition,
display_name,
dependencies: Vec::new(),
cfg_options,
env,
}
} }
fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
@ -290,12 +301,27 @@ mod tests {
#[test] #[test]
fn it_should_panic_because_of_cycle_dependencies() { fn it_should_panic_because_of_cycle_dependencies() {
let mut graph = CrateGraph::default(); let mut graph = CrateGraph::default();
let crate1 = let crate1 = graph.add_crate_root(
graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); FileId(1u32),
let crate2 = Edition2018,
graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); None,
let crate3 = CfgOptions::default(),
graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default()); Env::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
Edition2018,
None,
CfgOptions::default(),
Env::default(),
);
let crate3 = graph.add_crate_root(
FileId(3u32),
Edition2018,
None,
CfgOptions::default(),
Env::default(),
);
assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
assert!(graph.add_dep(crate3, CrateName::new("crate1").unwrap(), crate1).is_err()); assert!(graph.add_dep(crate3, CrateName::new("crate1").unwrap(), crate1).is_err());
@ -304,12 +330,27 @@ mod tests {
#[test] #[test]
fn it_works() { fn it_works() {
let mut graph = CrateGraph::default(); let mut graph = CrateGraph::default();
let crate1 = let crate1 = graph.add_crate_root(
graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); FileId(1u32),
let crate2 = Edition2018,
graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); None,
let crate3 = CfgOptions::default(),
graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default()); Env::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
Edition2018,
None,
CfgOptions::default(),
Env::default(),
);
let crate3 = graph.add_crate_root(
FileId(3u32),
Edition2018,
None,
CfgOptions::default(),
Env::default(),
);
assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
} }
@ -317,16 +358,26 @@ mod tests {
#[test] #[test]
fn dashes_are_normalized() { fn dashes_are_normalized() {
let mut graph = CrateGraph::default(); let mut graph = CrateGraph::default();
let crate1 = let crate1 = graph.add_crate_root(
graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); FileId(1u32),
let crate2 = Edition2018,
graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); None,
CfgOptions::default(),
Env::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
Edition2018,
None,
CfgOptions::default(),
Env::default(),
);
assert!(graph assert!(graph
.add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
.is_ok()); .is_ok());
assert_eq!( assert_eq!(
graph.dependencies(crate1).collect::<Vec<_>>(), graph.crate_data(&crate1).dependencies,
vec![&Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }] vec![Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }]
); );
} }
} }

View File

@ -55,7 +55,9 @@ pub struct CrateDependency {
impl Crate { impl Crate {
pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> { pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> {
db.crate_graph() db.crate_graph()
.dependencies(self.id) .crate_data(&self.id)
.dependencies
.iter()
.map(|dep| { .map(|dep| {
let krate = Crate { id: dep.crate_id() }; let krate = Crate { id: dep.crate_id() };
let name = dep.as_name(); let name = dep.as_name();
@ -69,7 +71,9 @@ impl Crate {
let crate_graph = db.crate_graph(); let crate_graph = db.crate_graph();
crate_graph crate_graph
.iter() .iter()
.filter(|&krate| crate_graph.dependencies(krate).any(|it| it.crate_id == self.id)) .filter(|&krate| {
crate_graph.crate_data(&krate).dependencies.iter().any(|it| it.crate_id == self.id)
})
.map(|id| Crate { id }) .map(|id| Crate { id })
.collect() .collect()
} }
@ -80,12 +84,11 @@ impl Crate {
} }
pub fn root_file(self, db: &impl DefDatabase) -> FileId { pub fn root_file(self, db: &impl DefDatabase) -> FileId {
db.crate_graph().crate_root(self.id) db.crate_graph().crate_data(&self.id).root_file_id
} }
pub fn edition(self, db: &impl DefDatabase) -> Edition { pub fn edition(self, db: &impl DefDatabase) -> Edition {
let crate_graph = db.crate_graph(); db.crate_graph().crate_data(&self.id).edition
crate_graph.edition(self.id)
} }
pub fn all(db: &impl DefDatabase) -> Vec<Crate> { pub fn all(db: &impl DefDatabase) -> Vec<Crate> {
@ -496,6 +499,14 @@ impl Adt {
pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> { pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
Some(self.module(db).krate()) 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)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@ -523,6 +534,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<VariantData> { pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
match self { match self {
VariantDef::Struct(it) => it.variant_data(db), VariantDef::Struct(it) => it.variant_data(db),
@ -550,6 +569,14 @@ impl DefWithBody {
DefWithBody::Static(s) => s.module(db), DefWithBody::Static(s) => s.module(db),
} }
} }
pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View File

@ -176,7 +176,7 @@ fn find_importable_locations(
// directly (only through reexports in direct dependencies). // directly (only through reexports in direct dependencies).
for krate in Some(from.krate) for krate in Some(from.krate)
.into_iter() .into_iter()
.chain(crate_graph.dependencies(from.krate).map(|dep| dep.crate_id)) .chain(crate_graph.crate_data(&from.krate).dependencies.iter().map(|dep| dep.crate_id))
{ {
result.extend( result.extend(
importable_locations_in_crate(db, item, krate) importable_locations_in_crate(db, item, krate)

View File

@ -117,7 +117,9 @@ impl LangItems {
return Some(*target); return Some(*target);
} }
db.crate_graph() db.crate_graph()
.dependencies(start_crate) .crate_data(&start_crate)
.dependencies
.iter()
.find_map(|dep| db.lang_item(dep.crate_id, item.clone())) .find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
} }

View File

@ -179,8 +179,7 @@ impl CrateDefMap {
pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> {
let _p = profile("crate_def_map_query"); let _p = profile("crate_def_map_query");
let def_map = { let def_map = {
let crate_graph = db.crate_graph(); let edition = db.crate_graph().crate_data(&krate).edition;
let edition = crate_graph.edition(krate);
let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default(); let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default();
let root = modules.alloc(ModuleData::default()); let root = modules.alloc(ModuleData::default());
CrateDefMap { CrateDefMap {

View File

@ -34,7 +34,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
let crate_graph = db.crate_graph(); let crate_graph = db.crate_graph();
// populate external prelude // populate external prelude
for dep in crate_graph.dependencies(def_map.krate) { for dep in &crate_graph.crate_data(&def_map.krate).dependencies {
let dep_def_map = db.crate_def_map(dep.crate_id); let dep_def_map = db.crate_def_map(dep.crate_id);
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
def_map.extern_prelude.insert( def_map.extern_prelude.insert(
@ -128,8 +128,7 @@ where
DB: DefDatabase, DB: DefDatabase,
{ {
fn collect(&mut self) { fn collect(&mut self) {
let crate_graph = self.db.crate_graph(); let file_id = self.db.crate_graph().crate_data(&self.def_map.krate).root_file_id;
let file_id = crate_graph.crate_root(self.def_map.krate);
let raw_items = self.db.raw_items(file_id.into()); let raw_items = self.db.raw_items(file_id.into());
let module_id = self.def_map.root; let module_id = self.def_map.root;
self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
@ -955,7 +954,7 @@ mod tests {
let krate = db.test_crate(); let krate = db.test_crate();
let def_map = { let def_map = {
let edition = db.crate_graph().edition(krate); let edition = db.crate_graph().crate_data(&krate).edition;
let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default(); let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default();
let root = modules.alloc(ModuleData::default()); let root = modules.alloc(ModuleData::default());
CrateDefMap { CrateDefMap {

View File

@ -47,7 +47,7 @@ pub(crate) fn impls_for_trait_query(
// will only ever get called for a few crates near the root of the tree (the // will only ever get called for a few crates near the root of the tree (the
// ones the user is editing), so this may actually be a waste of memory. I'm // ones the user is editing), so this may actually be a waste of memory. I'm
// doing it like this mainly for simplicity for now. // doing it like this mainly for simplicity for now.
for dep in db.crate_graph().dependencies(krate) { for dep in &db.crate_graph().crate_data(&krate).dependencies {
impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter()); impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter());
} }
let crate_impl_defs = db.impls_in_crate(krate); let crate_impl_defs = db.impls_in_crate(krate);

View File

@ -68,17 +68,23 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
} }
pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { pub(crate) fn rust_code_markup<CODE: AsRef<str>>(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<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String pub(crate) fn rust_code_markup_with_doc<CODE, DOC>(
val: CODE,
doc: Option<DOC>,
mod_path: Option<String>,
) -> String
where where
CODE: AsRef<str>, CODE: AsRef<str>,
DOC: AsRef<str>, DOC: AsRef<str>,
{ {
let mod_path =
mod_path.filter(|path| !path.is_empty()).map(|path| path + "\n").unwrap_or_default();
if let Some(doc) = doc { 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 { } else {
format!("```rust\n{}\n```", val.as_ref()) format!("```rust\n{}{}\n```", mod_path, val.as_ref())
} }
} }

View File

@ -1,6 +1,10 @@
//! FIXME: write short doc here //! FIXME: write short doc here
use hir::{Adt, HasSource, HirDisplay, Semantics}; use hir::{
Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef,
ModuleSource, Semantics,
};
use ra_db::SourceDatabase;
use ra_ide_db::{ use ra_ide_db::{
defs::{classify_name, classify_name_ref, Definition}, defs::{classify_name, classify_name_ref, Definition},
RootDatabase, RootDatabase,
@ -16,6 +20,8 @@ use crate::{
display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
FilePosition, RangeInfo, FilePosition, RangeInfo,
}; };
use itertools::Itertools;
use std::iter::once;
/// Contains the results when hovering over an item /// Contains the results when hovering over an item
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -83,44 +89,86 @@ impl HoverResult {
} }
} }
fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { fn hover_text(
match (desc, docs) { docs: Option<String>,
(Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)), desc: Option<String>,
(None, Some(docs)) => Some(docs), mod_path: Option<String>,
) -> Option<String> {
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, _ => None,
} }
} }
fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
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<String> {
let mod_path = def.module(db).map(|module| {
once(db.crate_graph().crate_data(&module.krate().into()).display_name.clone())
.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)))
.flatten()
.join("::")
});
mod_path
}
fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
let mod_path = determine_mod_path(db, &def);
return match def { return match def {
Definition::Macro(it) => { Definition::Macro(it) => {
let src = it.source(db); 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) => { Definition::StructField(it) => {
let src = it.source(db); let src = it.source(db);
match src.value { match src.value {
hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), FieldSource::Named(it) => {
hover_text(it.doc_comment_text(), it.short_label(), mod_path)
}
_ => None, _ => None,
} }
} }
Definition::ModuleDef(it) => match it { Definition::ModuleDef(it) => match it {
hir::ModuleDef::Module(it) => match it.definition_source(db).value { ModuleDef::Module(it) => match it.definition_source(db).value {
hir::ModuleSource::Module(it) => { ModuleSource::Module(it) => {
hover_text(it.doc_comment_text(), it.short_label()) hover_text(it.doc_comment_text(), it.short_label(), mod_path)
} }
_ => None, _ => None,
}, },
hir::ModuleDef::Function(it) => from_def_source(db, it), ModuleDef::Function(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it), ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it), ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it), ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
hir::ModuleDef::EnumVariant(it) => from_def_source(db, it), ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::Const(it) => from_def_source(db, it), ModuleDef::Const(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::Static(it) => from_def_source(db, it), ModuleDef::Static(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::Trait(it) => from_def_source(db, it), ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), ModuleDef::BuiltinType(it) => Some(it.to_string()),
}, },
Definition::Local(it) => { Definition::Local(it) => {
Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string())) Some(rust_code_markup(it.ty(db).display_truncated(db, None).to_string()))
@ -131,13 +179,13 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
} }
}; };
fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String> fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String>
where where
D: HasSource<Ast = A>, D: HasSource<Ast = A>,
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
{ {
let src = def.source(db); 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 +393,7 @@ mod tests {
}; };
} }
"#, "#,
&["field_a: u32"], &["Foo\nfield_a: u32"],
); );
// Hovering over the field in the definition // Hovering over the field in the definition
@ -362,7 +410,7 @@ mod tests {
}; };
} }
"#, "#,
&["field_a: u32"], &["Foo\nfield_a: u32"],
); );
} }
@ -415,7 +463,7 @@ fn main() {
", ",
); );
let hover = analysis.hover(position).unwrap().unwrap(); 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( let (analysis, position) = single_file_with_position(
" "
@ -442,6 +490,7 @@ fn main() {
} }
"#, "#,
&[" &["
Option
None None
``` ```
@ -462,6 +511,7 @@ The None variant
} }
"#, "#,
&[" &["
Option
Some Some
``` ```
@ -528,21 +578,23 @@ fn func(foo: i32) { if true { <|>foo; }; }
fn test_hover_infer_associated_method_exact() { fn test_hover_infer_associated_method_exact() {
let (analysis, position) = single_file_with_position( let (analysis, position) = single_file_with_position(
" "
struct Thing { x: u32 } mod wrapper {
struct Thing { x: u32 }
impl Thing { impl Thing {
fn new() -> Thing { fn new() -> Thing {
Thing { x: 0 } Thing { x: 0 }
}
} }
} }
fn main() { fn main() {
let foo_test = Thing::new<|>(); let foo_test = wrapper::Thing::new<|>();
} }
", ",
); );
let hover = analysis.hover(position).unwrap().unwrap(); let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup_opt(hover.info.first()), Some("fn new() -> Thing")); assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing"));
assert_eq!(hover.info.is_exact(), true); assert_eq!(hover.info.is_exact(), true);
} }

View File

@ -211,7 +211,13 @@ impl Analysis {
// Default to enable test for single file. // Default to enable test for single file.
let mut cfg_options = CfgOptions::default(); let mut cfg_options = CfgOptions::default();
cfg_options.insert_atom("test".into()); cfg_options.insert_atom("test".into());
crate_graph.add_crate_root(file_id, Edition::Edition2018, cfg_options, Env::default()); crate_graph.add_crate_root(
file_id,
Edition::Edition2018,
None,
cfg_options,
Env::default(),
);
change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text)); change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text));
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
host.apply_change(change); host.apply_change(change);
@ -415,12 +421,12 @@ impl Analysis {
/// Returns the edition of the given crate. /// Returns the edition of the given crate.
pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> { pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> {
self.with_db(|db| db.crate_graph().edition(crate_id)) self.with_db(|db| db.crate_graph().crate_data(&crate_id).edition)
} }
/// Returns the root file of the given crate. /// Returns the root file of the given crate.
pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
self.with_db(|db| db.crate_graph().crate_root(crate_id)) self.with_db(|db| db.crate_graph().crate_data(&crate_id).root_file_id)
} }
/// Returns the set of possible targets to run for the current file. /// Returns the set of possible targets to run for the current file.

View File

@ -99,13 +99,19 @@ impl MockAnalysis {
root_crate = Some(crate_graph.add_crate_root( root_crate = Some(crate_graph.add_crate_root(
file_id, file_id,
Edition2018, Edition2018,
None,
cfg_options, cfg_options,
Env::default(), Env::default(),
)); ));
} else if path.ends_with("/lib.rs") { } else if path.ends_with("/lib.rs") {
let other_crate =
crate_graph.add_crate_root(file_id, Edition2018, cfg_options, Env::default());
let crate_name = path.parent().unwrap().file_name().unwrap(); let crate_name = path.parent().unwrap().file_name().unwrap();
let other_crate = crate_graph.add_crate_root(
file_id,
Edition2018,
Some(crate_name.to_owned()),
cfg_options,
Env::default(),
);
if let Some(root_crate) = root_crate { if let Some(root_crate) = root_crate {
crate_graph crate_graph
.add_dep(root_crate, CrateName::new(crate_name).unwrap(), other_crate) .add_dep(root_crate, CrateName::new(crate_name).unwrap(), other_crate)

View File

@ -133,6 +133,7 @@ mod tests {
let crate_id = crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
root_file, root_file,
Edition2018, Edition2018,
None,
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
); );

View File

@ -5,7 +5,7 @@ use std::{fmt, sync::Arc, time};
use ra_db::{ use ra_db::{
salsa::{Database, Durability, SweepStrategy}, salsa::{Database, Durability, SweepStrategy},
CrateGraph, CrateId, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, CrateGraph, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot,
SourceRootId, SourceRootId,
}; };
use ra_prof::{memory_usage, profile, Bytes}; use ra_prof::{memory_usage, profile, Bytes};
@ -88,10 +88,6 @@ impl AnalysisChange {
self.crate_graph = Some(graph); self.crate_graph = Some(graph);
} }
pub fn set_debug_crate_name(&mut self, crate_id: CrateId, name: String) {
self.debug_data.crate_names.insert(crate_id, name);
}
pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) { pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) {
self.debug_data.root_paths.insert(source_root_id, path); self.debug_data.root_paths.insert(source_root_id, path);
} }

View File

@ -131,12 +131,10 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub(crate) struct DebugData { pub(crate) struct DebugData {
pub(crate) root_paths: FxHashMap<SourceRootId, String>, pub(crate) root_paths: FxHashMap<SourceRootId, String>,
pub(crate) crate_names: FxHashMap<CrateId, String>,
} }
impl DebugData { impl DebugData {
pub(crate) fn merge(&mut self, other: DebugData) { pub(crate) fn merge(&mut self, other: DebugData) {
self.root_paths.extend(other.root_paths.into_iter()); self.root_paths.extend(other.root_paths.into_iter());
self.crate_names.extend(other.crate_names.into_iter());
} }
} }

View File

@ -14,7 +14,7 @@ use std::{
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use ra_cfg::CfgOptions; use ra_cfg::CfgOptions;
use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; use ra_db::{CrateGraph, CrateName, Edition, Env, FileId};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde_json::from_reader; use serde_json::from_reader;
@ -163,9 +163,8 @@ impl ProjectWorkspace {
&self, &self,
default_cfg_options: &CfgOptions, default_cfg_options: &CfgOptions,
load: &mut dyn FnMut(&Path) -> Option<FileId>, load: &mut dyn FnMut(&Path) -> Option<FileId>,
) -> (CrateGraph, FxHashMap<CrateId, String>) { ) -> CrateGraph {
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let mut names = FxHashMap::default();
match self { match self {
ProjectWorkspace::Json { project } => { ProjectWorkspace::Json { project } => {
let mut crates = FxHashMap::default(); let mut crates = FxHashMap::default();
@ -191,6 +190,8 @@ impl ProjectWorkspace {
crate_graph.add_crate_root( crate_graph.add_crate_root(
file_id, file_id,
edition, edition,
// FIXME json definitions can store the crate name
None,
cfg_options, cfg_options,
Env::default(), Env::default(),
), ),
@ -233,11 +234,11 @@ impl ProjectWorkspace {
let crate_id = crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
file_id, file_id,
Edition::Edition2018, Edition::Edition2018,
Some(krate.name(&sysroot).to_string()),
cfg_options, cfg_options,
Env::default(), Env::default(),
); );
sysroot_crates.insert(krate, crate_id); sysroot_crates.insert(krate, crate_id);
names.insert(crate_id, krate.name(&sysroot).to_string());
} }
} }
for from in sysroot.crates() { for from in sysroot.crates() {
@ -277,10 +278,10 @@ impl ProjectWorkspace {
let crate_id = crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
file_id, file_id,
edition, edition,
Some(pkg.name(&cargo).to_string()),
cfg_options, cfg_options,
Env::default(), Env::default(),
); );
names.insert(crate_id, pkg.name(&cargo).to_string());
if tgt.kind(&cargo) == TargetKind::Lib { if tgt.kind(&cargo) == TargetKind::Lib {
lib_tgt = Some(crate_id); lib_tgt = Some(crate_id);
pkg_to_lib_crate.insert(pkg, crate_id); pkg_to_lib_crate.insert(pkg, crate_id);
@ -381,7 +382,7 @@ impl ProjectWorkspace {
} }
} }
} }
(crate_graph, names) crate_graph
} }
pub fn workspace_root_for(&self, path: &Path) -> Option<&Path> { pub fn workspace_root_for(&self, path: &Path) -> Option<&Path> {

View File

@ -52,12 +52,11 @@ pub(crate) fn load_cargo(
opts opts
}; };
let (crate_graph, _crate_names) = let crate_graph = ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| {
ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| { let vfs_file = vfs.load(path);
let vfs_file = vfs.load(path); log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
log::debug!("vfs file {:?} -> {:?}", path, vfs_file); vfs_file.map(vfs_file_to_id)
vfs_file.map(vfs_file_to_id) });
});
log::debug!("crate graph: {:?}", crate_graph); log::debug!("crate graph: {:?}", crate_graph);
let source_roots = roots let source_roots = roots

View File

@ -123,13 +123,12 @@ impl WorldState {
let vfs_file = vfs.load(path); let vfs_file = vfs.load(path);
vfs_file.map(|f| FileId(f.0)) vfs_file.map(|f| FileId(f.0))
}; };
for ws in workspaces.iter() {
let (graph, crate_names) = ws.to_crate_graph(&default_cfg_options, &mut load); workspaces.iter().map(|ws| ws.to_crate_graph(&default_cfg_options, &mut load)).for_each(
let shift = crate_graph.extend(graph); |graph| {
for (crate_id, name) in crate_names { crate_graph.extend(graph);
change.set_debug_crate_name(crate_id.shift(shift), name) },
} );
}
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
// FIXME: Figure out the multi-workspace situation // FIXME: Figure out the multi-workspace situation