diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index ded5d4e3db5..410b8304592 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -7,17 +7,19 @@ use arrayvec::ArrayVec; use hir::{ - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, DocLinkDef, - ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, - Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, - TypeAlias, Variant, Visibility, + Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, + DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam, + HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, + Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, VariantDef, Visibility, }; -use stdx::impl_from; +use stdx::{format_to, impl_from}; use syntax::{ ast::{self, AstNode}, match_ast, SyntaxKind, SyntaxNode, SyntaxToken, }; +use crate::documentation::{Documentation, HasDocs}; +use crate::famous_defs::FamousDefs; use crate::RootDatabase; // FIXME: a more precise name would probably be `Symbol`? @@ -83,6 +85,13 @@ impl Definition { Some(module) } + pub fn enclosing_definition(&self, db: &RootDatabase) -> Option { + match self { + Definition::Local(it) => it.parent(db).try_into().ok(), + _ => None, + } + } + pub fn visibility(&self, db: &RootDatabase) -> Option { let vis = match self { Definition::Field(sf) => sf.visibility(db), @@ -134,6 +143,125 @@ impl Definition { }; Some(name) } + + pub fn docs( + &self, + db: &RootDatabase, + famous_defs: Option<&FamousDefs<'_, '_>>, + ) -> Option { + 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 { + 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 { + 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 @@ -662,3 +790,22 @@ impl From for Definition { } } } + +impl From for Definition { + fn from(def: VariantDef) -> Self { + ModuleDef::from(def).into() + } +} + +impl TryFrom for Definition { + type Error = (); + fn try_from(def: DefWithBody) -> Result { + match def { + DefWithBody::Function(it) => Ok(it.into()), + DefWithBody::Static(it) => Ok(it.into()), + DefWithBody::Const(it) => Ok(it.into()), + DefWithBody::Variant(it) => Ok(it.into()), + DefWithBody::InTypeConst(_) => Err(()), + } + } +} diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index d0a02fd0dba..ee2f15c5a6a 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -1,15 +1,12 @@ //! Logic for rendering the different hover messages -use std::fmt::Display; - use either::Either; use hir::{ - Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, - Semantics, TypeInfo, + Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Semantics, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, defs::Definition, - documentation::{Documentation, HasDocs}, + documentation::HasDocs, famous_defs::FamousDefs, generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, syntax_helpers::insert_whitespace_into_node, @@ -20,9 +17,7 @@ use stdx::format_to; use syntax::{ algo, ast::{self, RecordPat}, - match_ast, AstNode, Direction, - SyntaxKind::{LET_EXPR, LET_STMT}, - SyntaxToken, T, + match_ast, AstNode, Direction, SyntaxToken, T, }; use crate::{ @@ -393,48 +388,23 @@ pub(super) fn definition( config: &HoverConfig, ) -> Option { let mod_path = definition_mod_path(db, &def); - let (label, docs) = match def { - Definition::Macro(it) => label_and_docs(db, it), - Definition::Field(it) => label_and_layout_info_and_docs( - db, - it, - config, - |&it| it.layout(db), - |_| { - let var_def = it.parent_def(db); - match var_def { - hir::VariantDef::Struct(s) => { - Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) + let label = def.label(db)?; + let docs = def.docs(db, famous_defs); + + let value = match def { + Definition::Variant(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}") }) } - _ => None, + Err(_) => it.value(db).map(|it| format!("{it:?}")), } - }, - ), - 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) + } else { + None + } } - Definition::Variant(it) => label_value_and_layout_info_and_docs( - 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| { + Definition::Const(it) => { let body = it.render_eval(db); match body { Ok(it) => Some(it), @@ -447,53 +417,59 @@ pub(super) fn definition( Some(body.to_string()) } } - }), - Definition::Static(it) => label_value_and_docs(db, it, |it| { + } + Definition::Static(it) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); if source.file_id.is_macro() { body = insert_whitespace_into_node::insert_ws_into(body); } 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 - .filter(|_| config.documentation) - .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 = def.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) - }) - .map(Into::into); - markup(docs, label, mod_path) + let layout_info = match def { + Definition::Field(it) => render_memory_layout( + config.memory_layout, + || it.layout(db), + |_| { + let var_def = it.parent_def(db); + match var_def { + hir::VariantDef::Struct(s) => { + Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) + } + _ => None, + } + }, + |_| 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( @@ -595,114 +571,16 @@ fn closure_ty( Some(res) } -fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option { - 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(db: &RootDatabase, def: D) -> (String, Option) -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( - db: &RootDatabase, - def: D, - config: &HoverConfig, - layout_extractor: E, - layout_offset_extractor: E2, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Result, - E2: Fn(&Layout) -> Option, -{ - 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( - db: &RootDatabase, - def: D, - config: &HoverConfig, - value_extractor: E, - layout_extractor: E2, - layout_tag_extractor: E3, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Option, - E2: Fn(&D) -> Result, - E3: Fn(&Layout) -> Option, - 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( - db: &RootDatabase, - def: D, - value_extractor: E, -) -> (String, Option) -where - D: HasDocs + HirDisplay, - E: Fn(&D) -> Option, - 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 { - if let Definition::GenericParam(_) = def { + if matches!( + def, + Definition::GenericParam(_) + | Definition::BuiltinType(_) + | Definition::Local(_) + | Definition::Label(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) + ) { return None; } def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) @@ -724,14 +602,6 @@ fn markup(docs: Option, desc: String, mod_path: Option) -> Optio Some(buf.into()) } -fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option { - // 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 { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; @@ -741,34 +611,6 @@ fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option Option { - 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( config: Option, layout: impl FnOnce() -> Result, diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 6ff16b9e2f7..e5da1a24c84 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -99,7 +99,10 @@ pub use crate::{ }, join_lines::JoinLinesConfig, markup::Markup, - moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation}, + moniker::{ + MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation, + SymbolInformationKind, + }, move_item::Direction, navigation_target::{NavigationTarget, UpmappingResult}, prime_caches::ParallelPrimeCachesProgress, diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 8e8bb5e0139..94ddd162de4 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -1,7 +1,7 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{AsAssocItem, AssocItemContainer, Crate, DescendPreference, Semantics}; +use hir::{Adt, AsAssocItem, AssocItemContainer, Crate, DescendPreference, MacroKind, Semantics}; use ide_db::{ base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, defs::{Definition, IdentClass}, @@ -25,6 +25,62 @@ pub enum MonikerDescriptorKind { Meta, } +// Subset of scip_types::SymbolInformation::Kind +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SymbolInformationKind { + AssociatedType, + Attribute, + Constant, + Enum, + EnumMember, + Field, + Function, + Macro, + Method, + Module, + Parameter, + SelfParameter, + StaticMethod, + StaticVariable, + Struct, + Trait, + TraitMethod, + Type, + TypeAlias, + TypeParameter, + Union, + Variable, +} + +impl From for MonikerDescriptorKind { + fn from(value: SymbolInformationKind) -> Self { + match value { + SymbolInformationKind::AssociatedType => Self::TypeParameter, + SymbolInformationKind::Attribute => Self::Macro, + SymbolInformationKind::Constant => Self::Term, + SymbolInformationKind::Enum => Self::Type, + SymbolInformationKind::EnumMember => Self::Type, + SymbolInformationKind::Field => Self::Term, + SymbolInformationKind::Function => Self::Method, + SymbolInformationKind::Macro => Self::Macro, + SymbolInformationKind::Method => Self::Method, + SymbolInformationKind::Module => Self::Namespace, + SymbolInformationKind::Parameter => Self::Parameter, + SymbolInformationKind::SelfParameter => Self::Parameter, + SymbolInformationKind::StaticMethod => Self::Method, + SymbolInformationKind::StaticVariable => Self::Meta, + SymbolInformationKind::Struct => Self::Type, + SymbolInformationKind::Trait => Self::Type, + SymbolInformationKind::TraitMethod => Self::Method, + SymbolInformationKind::Type => Self::Type, + SymbolInformationKind::TypeAlias => Self::Type, + SymbolInformationKind::TypeParameter => Self::TypeParameter, + SymbolInformationKind::Union => Self::Type, + SymbolInformationKind::Variable => Self::Term, + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonikerDescriptor { pub name: String, @@ -112,6 +168,69 @@ pub(crate) fn moniker( Some(RangeInfo::new(original_token.text_range(), navs)) } +pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformationKind { + use SymbolInformationKind::*; + + match def { + Definition::Macro(it) => match it.kind(db) { + MacroKind::Declarative => Macro, + MacroKind::Derive => Attribute, + MacroKind::BuiltIn => Macro, + MacroKind::Attr => Attribute, + MacroKind::ProcMacro => Macro, + }, + Definition::Field(..) => Field, + Definition::Module(..) => Module, + Definition::Function(it) => { + if it.as_assoc_item(db).is_some() { + if it.has_self_param(db) { + if it.has_body(db) { + Method + } else { + TraitMethod + } + } else { + StaticMethod + } + } else { + Function + } + } + Definition::Adt(Adt::Struct(..)) => Struct, + Definition::Adt(Adt::Union(..)) => Union, + Definition::Adt(Adt::Enum(..)) => Enum, + Definition::Variant(..) => EnumMember, + Definition::Const(..) => Constant, + Definition::Static(..) => StaticVariable, + Definition::Trait(..) => Trait, + Definition::TraitAlias(..) => Trait, + Definition::TypeAlias(it) => { + if it.as_assoc_item(db).is_some() { + AssociatedType + } else { + TypeAlias + } + } + Definition::BuiltinType(..) => Type, + Definition::SelfType(..) => TypeAlias, + Definition::GenericParam(..) => TypeParameter, + Definition::Local(it) => { + if it.is_self(db) { + SelfParameter + } else if it.is_param(db) { + Parameter + } else { + Variable + } + } + Definition::Label(..) => Variable, // For lack of a better variant + Definition::DeriveHelper(..) => Attribute, + Definition::BuiltinAttr(..) => Attribute, + Definition::ToolModule(..) => Module, + Definition::ExternCrateDecl(..) => Module, + } +} + pub(crate) fn def_to_moniker( db: &RootDatabase, def: Definition, @@ -134,7 +253,7 @@ pub(crate) fn def_to_moniker( description.extend(module.path_to_root(db).into_iter().filter_map(|x| { Some(MonikerDescriptor { name: x.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, + desc: def_to_kind(db, x.into()).into(), }) })); @@ -147,7 +266,7 @@ pub(crate) fn def_to_moniker( // we have to include the trait name as part of the moniker for uniqueness. description.push(MonikerDescriptor { name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, trait_.into()).into(), }); } AssocItemContainer::Impl(impl_) => { @@ -156,14 +275,14 @@ pub(crate) fn def_to_moniker( if let Some(adt) = impl_.self_ty(db).as_adt() { description.push(MonikerDescriptor { name: adt.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, adt.into()).into(), }); } if let Some(trait_) = impl_.trait_(db) { description.push(MonikerDescriptor { name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, trait_.into()).into(), }); } } @@ -173,21 +292,26 @@ pub(crate) fn def_to_moniker( if let Definition::Field(it) = def { description.push(MonikerDescriptor { name: it.parent_def(db).name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, + desc: def_to_kind(db, it.parent_def(db).into()).into(), }); } // Qualify locals/parameters by their parent definition name. if let Definition::Local(it) = def { - let parent_name = it.parent(db).name(db); - if let Some(name) = parent_name { - description.push(MonikerDescriptor { - name: name.display(db).to_string(), - desc: MonikerDescriptorKind::Method, - }); + let parent = Definition::try_from(it.parent(db)).ok(); + if let Some(parent) = parent { + let parent_name = parent.name(db); + if let Some(name) = parent_name { + description.push(MonikerDescriptor { + name: name.display(db).to_string(), + desc: def_to_kind(db, parent).into(), + }); + } } } + let desc = def_to_kind(db, def).into(); + let name_desc = match def { // These are handled by top-level guard (for performance). Definition::GenericParam(_) @@ -201,67 +325,51 @@ pub(crate) fn def_to_moniker( return None; } - MonikerDescriptor { - name: local.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Parameter, - } + MonikerDescriptor { name: local.name(db).display(db).to_string(), desc } + } + Definition::Macro(m) => { + MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + } + Definition::Function(f) => { + MonikerDescriptor { name: f.name(db).display(db).to_string(), desc } + } + Definition::Variant(v) => { + MonikerDescriptor { name: v.name(db).display(db).to_string(), desc } + } + Definition::Const(c) => { + MonikerDescriptor { name: c.name(db)?.display(db).to_string(), desc } + } + Definition::Trait(trait_) => { + MonikerDescriptor { name: trait_.name(db).display(db).to_string(), desc } + } + Definition::TraitAlias(ta) => { + MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + } + Definition::TypeAlias(ta) => { + MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + } + Definition::Module(m) => { + MonikerDescriptor { name: m.name(db)?.display(db).to_string(), desc } + } + Definition::BuiltinType(b) => { + MonikerDescriptor { name: b.name().display(db).to_string(), desc } } - Definition::Macro(m) => MonikerDescriptor { - name: m.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Macro, - }, - Definition::Function(f) => MonikerDescriptor { - name: f.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Method, - }, - Definition::Variant(v) => MonikerDescriptor { - name: v.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Const(c) => MonikerDescriptor { - name: c.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Term, - }, - Definition::Trait(trait_) => MonikerDescriptor { - name: trait_.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::TraitAlias(ta) => MonikerDescriptor { - name: ta.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::TypeAlias(ta) => MonikerDescriptor { - name: ta.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::TypeParameter, - }, - Definition::Module(m) => MonikerDescriptor { - name: m.name(db)?.display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, - }, - Definition::BuiltinType(b) => MonikerDescriptor { - name: b.name().display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, Definition::SelfType(imp) => MonikerDescriptor { name: imp.self_ty(db).as_adt()?.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Field(it) => MonikerDescriptor { - name: it.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Term, - }, - Definition::Adt(adt) => MonikerDescriptor { - name: adt.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Type, - }, - Definition::Static(s) => MonikerDescriptor { - name: s.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Meta, - }, - Definition::ExternCrateDecl(m) => MonikerDescriptor { - name: m.name(db).display(db).to_string(), - desc: MonikerDescriptorKind::Namespace, + desc, }, + Definition::Field(it) => { + MonikerDescriptor { name: it.name(db).display(db).to_string(), desc } + } + Definition::Adt(adt) => { + MonikerDescriptor { name: adt.name(db).display(db).to_string(), desc } + } + Definition::Static(s) => { + MonikerDescriptor { name: s.name(db).display(db).to_string(), desc } + } + Definition::ExternCrateDecl(m) => { + MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + } }; description.push(name_desc); diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 3724dc28221..47fe2472a5e 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -17,7 +17,7 @@ use crate::navigation_target::UpmappingResult; use crate::{ hover::hover_for_definition, inlay_hints::AdjustmentHintsMode, - moniker::{def_to_moniker, MonikerResult}, + moniker::{def_to_kind, def_to_moniker, MonikerResult, SymbolInformationKind}, parent_module::crates_for, Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav, }; @@ -46,6 +46,10 @@ pub struct TokenStaticData { pub definition: Option, pub references: Vec, pub moniker: Option, + pub display_name: Option, + pub enclosing_moniker: Option, + pub signature: Option, + pub kind: SymbolInformationKind, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -172,6 +176,12 @@ impl StaticIndex<'_> { }), references: vec![], moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), + display_name: def.name(self.db).map(|name| name.display(self.db).to_string()), + enclosing_moniker: current_crate + .zip(def.enclosing_definition(self.db)) + .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)), + signature: def.label(self.db), + kind: def_to_kind(self.db, def), }); self.def_map.insert(def, it); it diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 95c8798d43c..c86b2c0ba40 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -7,8 +7,8 @@ use std::{ }; use ide::{ - LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId, - TokenStaticData, + LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, + SymbolInformationKind, TextRange, TokenId, }; use ide_db::LineIndexDatabase; use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; @@ -78,6 +78,7 @@ impl flags::Scip { let mut symbols_emitted: HashSet = HashSet::default(); let mut tokens_to_symbol: HashMap = HashMap::new(); + let mut tokens_to_enclosing_symbol: HashMap> = HashMap::new(); for StaticIndexedFile { file_id, tokens, .. } in si.files { let mut local_count = 0; @@ -109,10 +110,24 @@ impl flags::Scip { let symbol = tokens_to_symbol .entry(id) .or_insert_with(|| { - let symbol = token_to_symbol(token).unwrap_or_else(&mut new_local_symbol); + let symbol = token + .moniker + .as_ref() + .map(moniker_to_symbol) + .unwrap_or_else(&mut new_local_symbol); scip::symbol::format_symbol(symbol) }) .clone(); + let enclosing_symbol = tokens_to_enclosing_symbol + .entry(id) + .or_insert_with(|| { + token + .enclosing_moniker + .as_ref() + .map(moniker_to_symbol) + .map(scip::symbol::format_symbol) + }) + .clone(); let mut symbol_roles = Default::default(); @@ -128,15 +143,22 @@ impl flags::Scip { .map(|hover| hover.markup.as_str()) .filter(|it| !it.is_empty()) .map(|it| vec![it.to_owned()]); + let signature_documentation = + token.signature.clone().map(|text| scip_types::Document { + relative_path: relative_path.clone(), + language: "rust".to_string(), + text, + ..Default::default() + }); let symbol_info = scip_types::SymbolInformation { symbol: symbol.clone(), documentation: documentation.unwrap_or_default(), relationships: Vec::new(), special_fields: Default::default(), - kind: Default::default(), - display_name: String::new(), - signature_documentation: Default::default(), - enclosing_symbol: String::new(), + kind: symbol_kind(token.kind).into(), + display_name: token.display_name.clone().unwrap_or_default(), + signature_documentation: signature_documentation.into(), + enclosing_symbol: enclosing_symbol.unwrap_or_default(), }; symbols.push(symbol_info) @@ -228,14 +250,36 @@ fn new_descriptor(name: &str, suffix: scip_types::descriptor::Suffix) -> scip_ty } } -/// Loosely based on `def_to_moniker` -/// -/// Only returns a Symbol when it's a non-local symbol. -/// So if the visibility isn't outside of a document, then it will return None -fn token_to_symbol(token: &TokenStaticData) -> Option { - use scip_types::descriptor::Suffix::*; +fn symbol_kind(kind: SymbolInformationKind) -> scip_types::symbol_information::Kind { + use scip_types::symbol_information::Kind as ScipKind; + match kind { + SymbolInformationKind::AssociatedType => ScipKind::AssociatedType, + SymbolInformationKind::Attribute => ScipKind::Attribute, + SymbolInformationKind::Constant => ScipKind::Constant, + SymbolInformationKind::Enum => ScipKind::Enum, + SymbolInformationKind::EnumMember => ScipKind::EnumMember, + SymbolInformationKind::Field => ScipKind::Field, + SymbolInformationKind::Function => ScipKind::Function, + SymbolInformationKind::Macro => ScipKind::Macro, + SymbolInformationKind::Method => ScipKind::Method, + SymbolInformationKind::Module => ScipKind::Module, + SymbolInformationKind::Parameter => ScipKind::Parameter, + SymbolInformationKind::SelfParameter => ScipKind::SelfParameter, + SymbolInformationKind::StaticMethod => ScipKind::StaticMethod, + SymbolInformationKind::StaticVariable => ScipKind::StaticVariable, + SymbolInformationKind::Struct => ScipKind::Struct, + SymbolInformationKind::Trait => ScipKind::Trait, + SymbolInformationKind::TraitMethod => ScipKind::TraitMethod, + SymbolInformationKind::Type => ScipKind::Type, + SymbolInformationKind::TypeAlias => ScipKind::TypeAlias, + SymbolInformationKind::TypeParameter => ScipKind::TypeParameter, + SymbolInformationKind::Union => ScipKind::Union, + SymbolInformationKind::Variable => ScipKind::Variable, + } +} - let moniker = token.moniker.as_ref()?; +fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol { + use scip_types::descriptor::Suffix::*; let package_name = moniker.package_information.name.clone(); let version = moniker.package_information.version.clone(); @@ -260,7 +304,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { }) .collect(); - Some(scip_types::Symbol { + scip_types::Symbol { scheme: "rust-analyzer".into(), package: Some(scip_types::Package { manager: "cargo".to_string(), @@ -271,7 +315,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { .into(), descriptors, special_fields: Default::default(), - }) + } } #[cfg(test)] @@ -309,7 +353,7 @@ mod test { for &(range, id) in &file.tokens { if range.contains(offset - TextSize::from(1)) { let token = si.tokens.get(id).unwrap(); - found_symbol = token_to_symbol(token); + found_symbol = token.moniker.as_ref().map(moniker_to_symbol); break; } } @@ -359,6 +403,21 @@ pub mod module { ); } + #[test] + fn symbol_for_trait_alias() { + check_symbol( + r#" +//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library +#![feature(trait_alias)] +pub mod module { + pub trait MyTrait {} + pub trait MyTraitAlias$0 = MyTrait; +} +"#, + "rust-analyzer cargo foo 0.1.0 module/MyTraitAlias#", + ); + } + #[test] fn symbol_for_trait_constant() { check_symbol( @@ -525,4 +584,15 @@ pub mod example_mod { "rust-analyzer cargo main . foo/Bar#", ); } + + #[test] + fn symbol_for_for_type_alias() { + check_symbol( + r#" + //- /lib.rs crate:main + pub type MyTypeAlias$0 = u8; + "#, + "rust-analyzer cargo main . MyTypeAlias#", + ); + } }