mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Refactor label & docs from ide::hover::render to ide-db::defs::Definition
To build the SymbolInformation::signature_documentation we need access to the “label” when building the TokenStaticData, preferably without any markdown markup. Therefore this refactors ide::hover::render::definition and its helper functions to give easier access to the label alone.
This commit is contained in:
parent
495a55689b
commit
b24914970f
2 changed files with 196 additions and 233 deletions
|
@ -7,17 +7,19 @@
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use hir::{
|
use hir::{
|
||||||
Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper,
|
Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate,
|
||||||
DocLinkDef, ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local,
|
DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam,
|
||||||
Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait,
|
HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution,
|
||||||
TraitAlias, TypeAlias, Variant, Visibility,
|
Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, Visibility,
|
||||||
};
|
};
|
||||||
use stdx::impl_from;
|
use stdx::{format_to, impl_from};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
|
match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::documentation::{Documentation, HasDocs};
|
||||||
|
use crate::famous_defs::FamousDefs;
|
||||||
use crate::RootDatabase;
|
use crate::RootDatabase;
|
||||||
|
|
||||||
// FIXME: a more precise name would probably be `Symbol`?
|
// FIXME: a more precise name would probably be `Symbol`?
|
||||||
|
@ -141,6 +143,125 @@ impl Definition {
|
||||||
};
|
};
|
||||||
Some(name)
|
Some(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn docs(
|
||||||
|
&self,
|
||||||
|
db: &RootDatabase,
|
||||||
|
famous_defs: Option<&FamousDefs<'_, '_>>,
|
||||||
|
) -> Option<Documentation> {
|
||||||
|
let docs = match self {
|
||||||
|
Definition::Macro(it) => it.docs(db),
|
||||||
|
Definition::Field(it) => it.docs(db),
|
||||||
|
Definition::Module(it) => it.docs(db),
|
||||||
|
Definition::Function(it) => it.docs(db),
|
||||||
|
Definition::Adt(it) => it.docs(db),
|
||||||
|
Definition::Variant(it) => it.docs(db),
|
||||||
|
Definition::Const(it) => it.docs(db),
|
||||||
|
Definition::Static(it) => it.docs(db),
|
||||||
|
Definition::Trait(it) => it.docs(db),
|
||||||
|
Definition::TraitAlias(it) => it.docs(db),
|
||||||
|
Definition::TypeAlias(it) => it.docs(db),
|
||||||
|
Definition::BuiltinType(it) => {
|
||||||
|
famous_defs.and_then(|fd| {
|
||||||
|
// std exposes prim_{} modules with docstrings on the root to document the builtins
|
||||||
|
let primitive_mod = format!("prim_{}", it.name().display(fd.0.db));
|
||||||
|
let doc_owner = find_std_module(fd, &primitive_mod)?;
|
||||||
|
doc_owner.docs(fd.0.db)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Definition::Local(_) => None,
|
||||||
|
Definition::SelfType(impl_def) => {
|
||||||
|
impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
|
||||||
|
}
|
||||||
|
Definition::GenericParam(_) => None,
|
||||||
|
Definition::Label(_) => None,
|
||||||
|
Definition::ExternCrateDecl(it) => it.docs(db),
|
||||||
|
|
||||||
|
Definition::BuiltinAttr(it) => {
|
||||||
|
let name = it.name(db);
|
||||||
|
let AttributeTemplate { word, list, name_value_str } = it.template(db)?;
|
||||||
|
let mut docs = "Valid forms are:".to_owned();
|
||||||
|
if word {
|
||||||
|
format_to!(docs, "\n - #\\[{}]", name);
|
||||||
|
}
|
||||||
|
if let Some(list) = list {
|
||||||
|
format_to!(docs, "\n - #\\[{}({})]", name, list);
|
||||||
|
}
|
||||||
|
if let Some(name_value_str) = name_value_str {
|
||||||
|
format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str);
|
||||||
|
}
|
||||||
|
Some(Documentation::new(docs.replace('*', "\\*")))
|
||||||
|
}
|
||||||
|
Definition::ToolModule(_) => None,
|
||||||
|
Definition::DeriveHelper(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
docs.or_else(|| {
|
||||||
|
// docs are missing, for assoc items of trait impls try to fall back to the docs of the
|
||||||
|
// original item of the trait
|
||||||
|
let assoc = self.as_assoc_item(db)?;
|
||||||
|
let trait_ = assoc.containing_trait_impl(db)?;
|
||||||
|
let name = Some(assoc.name(db)?);
|
||||||
|
let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
|
||||||
|
item.docs(db)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label(&self, db: &RootDatabase) -> Option<String> {
|
||||||
|
let label = match *self {
|
||||||
|
Definition::Macro(it) => it.display(db).to_string(),
|
||||||
|
Definition::Field(it) => it.display(db).to_string(),
|
||||||
|
Definition::Module(it) => it.display(db).to_string(),
|
||||||
|
Definition::Function(it) => it.display(db).to_string(),
|
||||||
|
Definition::Adt(it) => it.display(db).to_string(),
|
||||||
|
Definition::Variant(it) => it.display(db).to_string(),
|
||||||
|
Definition::Const(it) => it.display(db).to_string(),
|
||||||
|
Definition::Static(it) => it.display(db).to_string(),
|
||||||
|
Definition::Trait(it) => it.display(db).to_string(),
|
||||||
|
Definition::TraitAlias(it) => it.display(db).to_string(),
|
||||||
|
Definition::TypeAlias(it) => it.display(db).to_string(),
|
||||||
|
Definition::BuiltinType(it) => it.name().display(db).to_string(),
|
||||||
|
Definition::Local(it) => {
|
||||||
|
let ty = it.ty(db);
|
||||||
|
let ty = ty.display_truncated(db, None);
|
||||||
|
let is_mut = if it.is_mut(db) { "mut " } else { "" };
|
||||||
|
let desc = match it.primary_source(db).into_ident_pat() {
|
||||||
|
Some(ident) => {
|
||||||
|
let name = it.name(db);
|
||||||
|
let let_kw = if ident.syntax().parent().map_or(false, |p| {
|
||||||
|
p.kind() == SyntaxKind::LET_STMT || p.kind() == SyntaxKind::LET_EXPR
|
||||||
|
}) {
|
||||||
|
"let "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
format!("{let_kw}{is_mut}{}: {ty}", name.display(db))
|
||||||
|
}
|
||||||
|
None => format!("{is_mut}self: {ty}"),
|
||||||
|
};
|
||||||
|
desc
|
||||||
|
}
|
||||||
|
Definition::SelfType(impl_def) => {
|
||||||
|
impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))?
|
||||||
|
}
|
||||||
|
Definition::GenericParam(it) => it.display(db).to_string(),
|
||||||
|
Definition::Label(it) => it.name(db).display(db).to_string(),
|
||||||
|
Definition::ExternCrateDecl(it) => it.display(db).to_string(),
|
||||||
|
Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)),
|
||||||
|
Definition::ToolModule(it) => it.name(db).to_string(),
|
||||||
|
Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
|
||||||
|
};
|
||||||
|
Some(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
std_root_module.children(db).find(|module| {
|
||||||
|
module.name(db).map_or(false, |module| module.display(db).to_string() == name)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: IdentClass as a name no longer fits
|
// FIXME: IdentClass as a name no longer fits
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
//! Logic for rendering the different hover messages
|
//! Logic for rendering the different hover messages
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasSource, HirDisplay, Layout, LayoutError,
|
Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Semantics, TypeInfo,
|
||||||
Semantics, TypeInfo,
|
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::SourceDatabase,
|
base_db::SourceDatabase,
|
||||||
defs::Definition,
|
defs::Definition,
|
||||||
documentation::{Documentation, HasDocs},
|
documentation::HasDocs,
|
||||||
famous_defs::FamousDefs,
|
famous_defs::FamousDefs,
|
||||||
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||||
syntax_helpers::insert_whitespace_into_node,
|
syntax_helpers::insert_whitespace_into_node,
|
||||||
|
@ -20,9 +17,7 @@ use stdx::format_to;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo,
|
algo,
|
||||||
ast::{self, RecordPat},
|
ast::{self, RecordPat},
|
||||||
match_ast, AstNode, Direction,
|
match_ast, AstNode, Direction, SyntaxToken, T,
|
||||||
SyntaxKind::{LET_EXPR, LET_STMT},
|
|
||||||
SyntaxToken, T,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -393,48 +388,23 @@ pub(super) fn definition(
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
) -> Option<Markup> {
|
) -> Option<Markup> {
|
||||||
let mod_path = definition_mod_path(db, &def);
|
let mod_path = definition_mod_path(db, &def);
|
||||||
let (label, docs) = match def {
|
let label = def.label(db)?;
|
||||||
Definition::Macro(it) => label_and_docs(db, it),
|
let docs = def.docs(db, famous_defs);
|
||||||
Definition::Field(it) => label_and_layout_info_and_docs(
|
|
||||||
db,
|
let value = match def {
|
||||||
it,
|
Definition::Variant(it) => {
|
||||||
config,
|
if !it.parent_enum(db).is_data_carrying(db) {
|
||||||
|&it| it.layout(db),
|
match it.eval(db) {
|
||||||
|_| {
|
Ok(it) => {
|
||||||
let var_def = it.parent_def(db);
|
Some(if it >= 10 { format!("{it} ({it:#X})") } else { format!("{it}") })
|
||||||
match var_def {
|
|
||||||
hir::VariantDef::Struct(s) => {
|
|
||||||
Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it))
|
|
||||||
}
|
}
|
||||||
_ => None,
|
Err(_) => it.value(db).map(|it| format!("{it:?}")),
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
),
|
None
|
||||||
Definition::Module(it) => label_and_docs(db, it),
|
}
|
||||||
Definition::Function(it) => label_and_docs(db, it),
|
|
||||||
Definition::Adt(it) => {
|
|
||||||
label_and_layout_info_and_docs(db, it, config, |&it| it.layout(db), |_| None)
|
|
||||||
}
|
}
|
||||||
Definition::Variant(it) => label_value_and_layout_info_and_docs(
|
Definition::Const(it) => {
|
||||||
db,
|
|
||||||
it,
|
|
||||||
config,
|
|
||||||
|&it| {
|
|
||||||
if !it.parent_enum(db).is_data_carrying(db) {
|
|
||||||
match it.eval(db) {
|
|
||||||
Ok(it) => {
|
|
||||||
Some(if it >= 10 { format!("{it} ({it:#X})") } else { format!("{it}") })
|
|
||||||
}
|
|
||||||
Err(_) => it.value(db).map(|it| format!("{it:?}")),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|it| it.layout(db),
|
|
||||||
|layout| layout.enum_tag_size(),
|
|
||||||
),
|
|
||||||
Definition::Const(it) => label_value_and_docs(db, it, |it| {
|
|
||||||
let body = it.render_eval(db);
|
let body = it.render_eval(db);
|
||||||
match body {
|
match body {
|
||||||
Ok(it) => Some(it),
|
Ok(it) => Some(it),
|
||||||
|
@ -447,53 +417,59 @@ pub(super) fn definition(
|
||||||
Some(body.to_string())
|
Some(body.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
Definition::Static(it) => label_value_and_docs(db, it, |it| {
|
Definition::Static(it) => {
|
||||||
let source = it.source(db)?;
|
let source = it.source(db)?;
|
||||||
let mut body = source.value.body()?.syntax().clone();
|
let mut body = source.value.body()?.syntax().clone();
|
||||||
if source.file_id.is_macro() {
|
if source.file_id.is_macro() {
|
||||||
body = insert_whitespace_into_node::insert_ws_into(body);
|
body = insert_whitespace_into_node::insert_ws_into(body);
|
||||||
}
|
}
|
||||||
Some(body.to_string())
|
Some(body.to_string())
|
||||||
}),
|
|
||||||
Definition::Trait(it) => label_and_docs(db, it),
|
|
||||||
Definition::TraitAlias(it) => label_and_docs(db, it),
|
|
||||||
Definition::TypeAlias(it) => {
|
|
||||||
label_and_layout_info_and_docs(db, it, config, |&it| it.ty(db).layout(db), |_| None)
|
|
||||||
}
|
|
||||||
Definition::BuiltinType(it) => {
|
|
||||||
return famous_defs
|
|
||||||
.and_then(|fd| builtin(fd, it))
|
|
||||||
.or_else(|| Some(Markup::fenced_block(&it.name().display(db))))
|
|
||||||
}
|
|
||||||
Definition::Local(it) => return local(db, it, config),
|
|
||||||
Definition::SelfType(impl_def) => {
|
|
||||||
impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
|
|
||||||
}
|
|
||||||
Definition::GenericParam(it) => (it.display(db).to_string(), None),
|
|
||||||
Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db).display(db))),
|
|
||||||
Definition::ExternCrateDecl(it) => label_and_docs(db, it),
|
|
||||||
// FIXME: We should be able to show more info about these
|
|
||||||
Definition::BuiltinAttr(it) => return render_builtin_attr(db, it),
|
|
||||||
Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
|
|
||||||
Definition::DeriveHelper(it) => {
|
|
||||||
(format!("derive_helper {}", it.name(db).display(db)), None)
|
|
||||||
}
|
}
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let docs = docs
|
let layout_info = match def {
|
||||||
.filter(|_| config.documentation)
|
Definition::Field(it) => render_memory_layout(
|
||||||
.or_else(|| {
|
config.memory_layout,
|
||||||
// docs are missing, for assoc items of trait impls try to fall back to the docs of the
|
|| it.layout(db),
|
||||||
// original item of the trait
|
|_| {
|
||||||
let assoc = def.as_assoc_item(db)?;
|
let var_def = it.parent_def(db);
|
||||||
let trait_ = assoc.containing_trait_impl(db)?;
|
match var_def {
|
||||||
let name = Some(assoc.name(db)?);
|
hir::VariantDef::Struct(s) => {
|
||||||
let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
|
Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it))
|
||||||
item.docs(db)
|
}
|
||||||
})
|
_ => None,
|
||||||
.map(Into::into);
|
}
|
||||||
markup(docs, label, mod_path)
|
},
|
||||||
|
|_| None,
|
||||||
|
),
|
||||||
|
Definition::Adt(it) => {
|
||||||
|
render_memory_layout(config.memory_layout, || it.layout(db), |_| None, |_| None)
|
||||||
|
}
|
||||||
|
Definition::Variant(it) => render_memory_layout(
|
||||||
|
config.memory_layout,
|
||||||
|
|| it.layout(db),
|
||||||
|
|_| None,
|
||||||
|
|layout| layout.enum_tag_size(),
|
||||||
|
),
|
||||||
|
Definition::TypeAlias(it) => {
|
||||||
|
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
|
||||||
|
}
|
||||||
|
Definition::Local(it) => {
|
||||||
|
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let label = match (value, layout_info) {
|
||||||
|
(Some(value), Some(layout_info)) => format!("{label} = {value}{layout_info}"),
|
||||||
|
(Some(value), None) => format!("{label} = {value}"),
|
||||||
|
(None, Some(layout_info)) => format!("{label}{layout_info}"),
|
||||||
|
(None, None) => label,
|
||||||
|
};
|
||||||
|
|
||||||
|
markup(docs.map(Into::into), label, mod_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_info(
|
fn type_info(
|
||||||
|
@ -595,114 +571,16 @@ fn closure_ty(
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Markup> {
|
|
||||||
let name = attr.name(db);
|
|
||||||
let desc = format!("#[{name}]");
|
|
||||||
|
|
||||||
let AttributeTemplate { word, list, name_value_str } = match attr.template(db) {
|
|
||||||
Some(template) => template,
|
|
||||||
None => return Some(Markup::fenced_block(&attr.name(db))),
|
|
||||||
};
|
|
||||||
let mut docs = "Valid forms are:".to_owned();
|
|
||||||
if word {
|
|
||||||
format_to!(docs, "\n - #\\[{}]", name);
|
|
||||||
}
|
|
||||||
if let Some(list) = list {
|
|
||||||
format_to!(docs, "\n - #\\[{}({})]", name, list);
|
|
||||||
}
|
|
||||||
if let Some(name_value_str) = name_value_str {
|
|
||||||
format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str);
|
|
||||||
}
|
|
||||||
markup(Some(docs.replace('*', "\\*")), desc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<Documentation>)
|
|
||||||
where
|
|
||||||
D: HasDocs + HirDisplay,
|
|
||||||
{
|
|
||||||
let label = def.display(db).to_string();
|
|
||||||
let docs = def.docs(db);
|
|
||||||
(label, docs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label_and_layout_info_and_docs<D, E, E2>(
|
|
||||||
db: &RootDatabase,
|
|
||||||
def: D,
|
|
||||||
config: &HoverConfig,
|
|
||||||
layout_extractor: E,
|
|
||||||
layout_offset_extractor: E2,
|
|
||||||
) -> (String, Option<Documentation>)
|
|
||||||
where
|
|
||||||
D: HasDocs + HirDisplay,
|
|
||||||
E: Fn(&D) -> Result<Layout, LayoutError>,
|
|
||||||
E2: Fn(&Layout) -> Option<u64>,
|
|
||||||
{
|
|
||||||
let mut label = def.display(db).to_string();
|
|
||||||
if let Some(layout) = render_memory_layout(
|
|
||||||
config.memory_layout,
|
|
||||||
|| layout_extractor(&def),
|
|
||||||
layout_offset_extractor,
|
|
||||||
|_| None,
|
|
||||||
) {
|
|
||||||
format_to!(label, "{layout}");
|
|
||||||
}
|
|
||||||
let docs = def.docs(db);
|
|
||||||
(label, docs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label_value_and_layout_info_and_docs<D, E, E2, E3, V>(
|
|
||||||
db: &RootDatabase,
|
|
||||||
def: D,
|
|
||||||
config: &HoverConfig,
|
|
||||||
value_extractor: E,
|
|
||||||
layout_extractor: E2,
|
|
||||||
layout_tag_extractor: E3,
|
|
||||||
) -> (String, Option<Documentation>)
|
|
||||||
where
|
|
||||||
D: HasDocs + HirDisplay,
|
|
||||||
E: Fn(&D) -> Option<V>,
|
|
||||||
E2: Fn(&D) -> Result<Layout, LayoutError>,
|
|
||||||
E3: Fn(&Layout) -> Option<usize>,
|
|
||||||
V: Display,
|
|
||||||
{
|
|
||||||
let value = value_extractor(&def);
|
|
||||||
let mut label = match value {
|
|
||||||
Some(value) => format!("{} = {value}", def.display(db)),
|
|
||||||
None => def.display(db).to_string(),
|
|
||||||
};
|
|
||||||
if let Some(layout) = render_memory_layout(
|
|
||||||
config.memory_layout,
|
|
||||||
|| layout_extractor(&def),
|
|
||||||
|_| None,
|
|
||||||
layout_tag_extractor,
|
|
||||||
) {
|
|
||||||
format_to!(label, "{layout}");
|
|
||||||
}
|
|
||||||
let docs = def.docs(db);
|
|
||||||
(label, docs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label_value_and_docs<D, E, V>(
|
|
||||||
db: &RootDatabase,
|
|
||||||
def: D,
|
|
||||||
value_extractor: E,
|
|
||||||
) -> (String, Option<Documentation>)
|
|
||||||
where
|
|
||||||
D: HasDocs + HirDisplay,
|
|
||||||
E: Fn(&D) -> Option<V>,
|
|
||||||
V: Display,
|
|
||||||
{
|
|
||||||
let label = if let Some(value) = value_extractor(&def) {
|
|
||||||
format!("{} = {value}", def.display(db))
|
|
||||||
} else {
|
|
||||||
def.display(db).to_string()
|
|
||||||
};
|
|
||||||
let docs = def.docs(db);
|
|
||||||
(label, docs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
|
fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
|
||||||
if let Definition::GenericParam(_) = def {
|
if matches!(
|
||||||
|
def,
|
||||||
|
Definition::GenericParam(_)
|
||||||
|
| Definition::BuiltinType(_)
|
||||||
|
| Definition::Local(_)
|
||||||
|
| Definition::Label(_)
|
||||||
|
| Definition::BuiltinAttr(_)
|
||||||
|
| Definition::ToolModule(_)
|
||||||
|
) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
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)))
|
||||||
|
@ -724,14 +602,6 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Optio
|
||||||
Some(buf.into())
|
Some(buf.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn 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().display(famous_defs.0.db));
|
|
||||||
let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
|
|
||||||
let docs = doc_owner.docs(famous_defs.0.db)?;
|
|
||||||
markup(Some(docs.into()), builtin.name().display(famous_defs.0.db).to_string(), None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
|
fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
|
||||||
let db = famous_defs.0.db;
|
let db = famous_defs.0.db;
|
||||||
let std_crate = famous_defs.std()?;
|
let std_crate = famous_defs.std()?;
|
||||||
|
@ -741,34 +611,6 @@ fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Markup> {
|
|
||||||
let ty = it.ty(db);
|
|
||||||
let ty = ty.display_truncated(db, None);
|
|
||||||
let is_mut = if it.is_mut(db) { "mut " } else { "" };
|
|
||||||
let mut desc = match it.primary_source(db).into_ident_pat() {
|
|
||||||
Some(ident) => {
|
|
||||||
let name = it.name(db);
|
|
||||||
let let_kw = if ident
|
|
||||||
.syntax()
|
|
||||||
.parent()
|
|
||||||
.map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR)
|
|
||||||
{
|
|
||||||
"let "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
format!("{let_kw}{is_mut}{}: {ty}", name.display(db))
|
|
||||||
}
|
|
||||||
None => format!("{is_mut}self: {ty}"),
|
|
||||||
};
|
|
||||||
if let Some(layout) =
|
|
||||||
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
|
|
||||||
{
|
|
||||||
format_to!(desc, "{layout}");
|
|
||||||
}
|
|
||||||
markup(None, desc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_memory_layout(
|
fn render_memory_layout(
|
||||||
config: Option<MemoryLayoutHoverConfig>,
|
config: Option<MemoryLayoutHoverConfig>,
|
||||||
layout: impl FnOnce() -> Result<Layout, LayoutError>,
|
layout: impl FnOnce() -> Result<Layout, LayoutError>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue