Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #16179 - nicolas-guichard:scip/new_fields, r=Veykril
SCIP: populate new SymbolInformation fields Fixes #15919
bors 2024-01-03
parent d987137 · parent 73d9c77 · commit 0781832
-rw-r--r--crates/ide-db/src/defs.rs157
-rw-r--r--crates/ide/src/hover/render.rs292
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/moniker.rs246
-rw-r--r--crates/ide/src/static_index.rs12
-rw-r--r--crates/rust-analyzer/src/cli/scip.rs104
6 files changed, 498 insertions, 318 deletions
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index ded5d4e3db..410b830459 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<Definition> {
+ match self {
+ Definition::Local(it) => it.parent(db).try_into().ok(),
+ _ => None,
+ }
+ }
+
pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
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<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
@@ -662,3 +790,22 @@ impl From<DocLinkDef> for Definition {
}
}
}
+
+impl From<VariantDef> for Definition {
+ fn from(def: VariantDef) -> Self {
+ ModuleDef::from(def).into()
+ }
+}
+
+impl TryFrom<DefWithBody> for Definition {
+ type Error = ();
+ fn try_from(def: DefWithBody) -> Result<Self, Self::Error> {
+ 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 d0a02fd0db..ee2f15c5a6 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<Markup> {
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))))
+ _ => None,
+ };
+
+ 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::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::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::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)
+ Definition::Local(it) => {
+ render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| 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 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<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> {
- 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<String>, desc: String, mod_path: Option<String>) -> Optio
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> {
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<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(
config: Option<MemoryLayoutHoverConfig>,
layout: impl FnOnce() -> Result<Layout, LayoutError>,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 6ff16b9e2f..e5da1a24c8 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 8e8bb5e013..94ddd162de 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<SymbolInformationKind> 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 3724dc2822..47fe2472a5 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<FileRange>,
pub references: Vec<ReferenceData>,
pub moniker: Option<MonikerResult>,
+ pub display_name: Option<String>,
+ pub enclosing_moniker: Option<MonikerResult>,
+ pub signature: Option<String>,
+ 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 95c8798d43..c86b2c0ba4 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<TokenId> = HashSet::default();
let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
+ let mut tokens_to_enclosing_symbol: HashMap<TokenId, Option<String>> = 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<scip_types::Symbol> {
- 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<scip_types::Symbol> {
})
.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<scip_types::Symbol> {
.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;
}
}
@@ -360,6 +404,21 @@ pub mod module {
}
#[test]
+ fn symbol_for_trait_alias() {
+ check_symbol(
+ r#"
+//- /foo/lib.rs crate:[email protected],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(
r#"
@@ -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#",
+ );
+ }
}