Infallible definition hovers

This commit is contained in:
Lukas Wirth 2024-02-19 18:00:50 +01:00
parent 2223b4fa71
commit a822291a02
5 changed files with 135 additions and 38 deletions

View file

@ -213,8 +213,8 @@ impl Definition {
}) })
} }
pub fn label(&self, db: &RootDatabase) -> Option<String> { pub fn label(&self, db: &RootDatabase) -> String {
let label = match *self { match *self {
Definition::Macro(it) => it.display(db).to_string(), Definition::Macro(it) => it.display(db).to_string(),
Definition::Field(it) => it.display(db).to_string(), Definition::Field(it) => it.display(db).to_string(),
Definition::TupleField(it) => it.display(db).to_string(), Definition::TupleField(it) => it.display(db).to_string(),
@ -241,7 +241,11 @@ impl Definition {
} }
} }
Definition::SelfType(impl_def) => { Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))? let self_ty = &impl_def.self_ty(db);
match self_ty.as_adt() {
Some(it) => it.display(db).to_string(),
None => self_ty.display(db).to_string(),
}
} }
Definition::GenericParam(it) => it.display(db).to_string(), Definition::GenericParam(it) => it.display(db).to_string(),
Definition::Label(it) => it.name(db).display(db).to_string(), Definition::Label(it) => it.name(db).display(db).to_string(),
@ -249,8 +253,7 @@ impl Definition {
Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)), Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)),
Definition::ToolModule(it) => it.name(db).to_string(), Definition::ToolModule(it) => it.name(db).to_string(),
Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
}; }
Some(label)
} }
} }

View file

@ -147,7 +147,7 @@ fn hover_simple(
if let Some(doc_comment) = token_as_doc_comment(&original_token) { if let Some(doc_comment) = token_as_doc_comment(&original_token) {
cov_mark::hit!(no_highlight_on_comment_hover); cov_mark::hit!(no_highlight_on_comment_hover);
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| { return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
let res = hover_for_definition(sema, file_id, def, &node, config)?; let res = hover_for_definition(sema, file_id, def, &node, config);
Some(RangeInfo::new(range, res)) Some(RangeInfo::new(range, res))
}); });
} }
@ -161,7 +161,7 @@ fn hover_simple(
Definition::from(resolution?), Definition::from(resolution?),
&original_token.parent()?, &original_token.parent()?,
config, config,
)?; );
return Some(RangeInfo::new(range, res)); return Some(RangeInfo::new(range, res));
} }
@ -215,7 +215,7 @@ fn hover_simple(
}) })
.flatten() .flatten()
.unique_by(|&(def, _)| def) .unique_by(|&(def, _)| def)
.filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) .map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
acc.actions.extend(actions); acc.actions.extend(actions);
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup)); acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
@ -373,9 +373,9 @@ pub(crate) fn hover_for_definition(
def: Definition, def: Definition,
scope_node: &SyntaxNode, scope_node: &SyntaxNode,
config: &HoverConfig, config: &HoverConfig,
) -> Option<HoverResult> { ) -> HoverResult {
let famous_defs = match &def { let famous_defs = match &def {
Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())), Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
_ => None, _ => None,
}; };
@ -396,7 +396,7 @@ pub(crate) fn hover_for_definition(
}; };
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config).map(|markup| { let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
HoverResult { HoverResult {
markup: render::process_markup(sema.db, def, &markup, config), markup: render::process_markup(sema.db, def, &markup, config),
actions: [ actions: [
@ -409,7 +409,6 @@ pub(crate) fn hover_for_definition(
.flatten() .flatten()
.collect(), .collect(),
} }
})
} }
fn notable_traits( fn notable_traits(

View file

@ -264,7 +264,7 @@ pub(super) fn keyword(
let markup = process_markup( let markup = process_markup(
sema.db, sema.db,
Definition::Module(doc_owner), Definition::Module(doc_owner),
&markup(Some(docs.into()), description, None)?, &markup(Some(docs.into()), description, None),
config, config,
); );
Some(HoverResult { markup, actions }) Some(HoverResult { markup, actions })
@ -396,11 +396,11 @@ pub(super) fn definition(
famous_defs: Option<&FamousDefs<'_, '_>>, famous_defs: Option<&FamousDefs<'_, '_>>,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)], notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
config: &HoverConfig, config: &HoverConfig,
) -> Option<Markup> { ) -> Markup {
let mod_path = definition_mod_path(db, &def); let mod_path = definition_mod_path(db, &def);
let label = def.label(db)?; let label = def.label(db);
let docs = def.docs(db, famous_defs); let docs = def.docs(db, famous_defs);
let value = match def { let value = (|| match def {
Definition::Variant(it) => { Definition::Variant(it) => {
if !it.parent_enum(db).is_data_carrying(db) { if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) { match it.eval(db) {
@ -436,7 +436,7 @@ pub(super) fn definition(
Some(body.to_string()) Some(body.to_string())
} }
_ => None, _ => None,
}; })();
let layout_info = match def { let layout_info = match def {
Definition::Field(it) => render_memory_layout( Definition::Field(it) => render_memory_layout(
@ -683,7 +683,7 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
} }
fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> { fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup {
let mut buf = String::new(); let mut buf = String::new();
if let Some(mod_path) = mod_path { if let Some(mod_path) = mod_path {
@ -696,7 +696,7 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Optio
if let Some(doc) = docs { if let Some(doc) = docs {
format_to!(buf, "\n___\n\n{}", doc); format_to!(buf, "\n___\n\n{}", doc);
} }
Some(buf.into()) buf.into()
} }
fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> { fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {

View file

@ -1279,11 +1279,11 @@ impl Thing {
); );
check( check(
r#" r#"
enum Thing { A } enum Thing { A }
impl Thing { impl Thing {
pub fn thing(a: Self$0) {} pub fn thing(a: Self$0) {}
} }
"#, "#,
expect![[r#" expect![[r#"
*Self* *Self*
@ -1298,6 +1298,42 @@ impl Thing {
``` ```
"#]], "#]],
); );
check(
r#"
impl usize {
pub fn thing(a: Self$0) {}
}
"#,
expect![[r#"
*Self*
```rust
test
```
```rust
usize
```
"#]],
);
check(
r#"
impl fn() -> usize {
pub fn thing(a: Self$0) {}
}
"#,
expect![[r#"
*Self*
```rust
test
```
```rust
fn() -> usize
```
"#]],
);
} }
#[test] #[test]
@ -7201,6 +7237,65 @@ impl Iterator for S {
); );
} }
#[test]
fn extern_items() {
check(
r#"
extern "C" {
static STATIC$0: ();
}
"#,
expect![[r#"
*STATIC*
```rust
test
```
```rust
static STATIC: ()
```
"#]],
);
check(
r#"
extern "C" {
fn fun$0();
}
"#,
expect![[r#"
*fun*
```rust
test
```
```rust
unsafe fn fun()
```
"#]],
);
check(
r#"
extern "C" {
type Ty$0;
}
"#,
expect![[r#"
*Ty*
```rust
test
```
```rust
// size = 0, align = 1
type Ty
```
"#]],
);
}
#[test] #[test]
fn notable_ranged() { fn notable_ranged() {
check_hover_range( check_hover_range(

View file

@ -186,7 +186,7 @@ impl StaticIndex<'_> {
} else { } else {
let it = self.tokens.insert(TokenStaticData { let it = self.tokens.insert(TokenStaticData {
documentation: documentation_for_definition(&sema, def, &node), documentation: documentation_for_definition(&sema, def, &node),
hover: hover_for_definition(&sema, file_id, def, &node, &hover_config), hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)),
definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| { definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
FileRange { file_id: it.file_id, range: it.focus_or_full_range() } FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
}), }),
@ -196,7 +196,7 @@ impl StaticIndex<'_> {
enclosing_moniker: current_crate enclosing_moniker: current_crate
.zip(def.enclosing_definition(self.db)) .zip(def.enclosing_definition(self.db))
.and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)), .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)),
signature: def.label(self.db), signature: Some(def.label(self.db)),
kind: def_to_kind(self.db, def), kind: def_to_kind(self.db, def),
}); });
self.def_map.insert(def, it); self.def_map.insert(def, it);