1 //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
4 use hir
::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics}
;
6 base_db
::{CrateOrigin, FilePosition, LangCrateOrigin}
,
7 defs
::{Definition, IdentClass}
,
8 helpers
::pick_best_token
,
11 use itertools
::Itertools
;
12 use syntax
::{AstNode, SyntaxKind::*, T}
;
14 use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo}
;
16 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17 pub enum MonikerDescriptorKind
{
28 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
29 pub struct MonikerDescriptor
{
31 pub desc
: MonikerDescriptorKind
,
34 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
35 pub struct MonikerIdentifier
{
36 pub crate_name
: String
,
37 pub description
: Vec
<MonikerDescriptor
>,
40 impl ToString
for MonikerIdentifier
{
41 fn to_string(&self) -> String
{
43 MonikerIdentifier { description, crate_name }
=> {
47 description
.iter().map(|x
| x
.name
.to_string()).join("::")
54 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55 pub enum MonikerKind
{
60 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
61 pub struct MonikerResult
{
62 pub identifier
: MonikerIdentifier
,
63 pub kind
: MonikerKind
,
64 pub package_information
: PackageInformation
,
68 pub fn from_def(db
: &RootDatabase
, def
: Definition
, from_crate
: Crate
) -> Option
<Self> {
69 def_to_moniker(db
, def
, from_crate
)
73 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
74 pub struct PackageInformation
{
76 pub repo
: Option
<String
>,
77 pub version
: Option
<String
>,
80 pub(crate) fn moniker(
82 FilePosition { file_id, offset }
: FilePosition
,
83 ) -> Option
<RangeInfo
<Vec
<MonikerResult
>>> {
84 let sema
= &Semantics
::new(db
);
85 let file
= sema
.parse(file_id
).syntax().clone();
86 let current_crate
: hir
::Crate
= crates_for(db
, file_id
).pop()?
.into();
87 let original_token
= pick_best_token(file
.token_at_offset(offset
), |kind
| match kind
{
96 kind
if kind
.is_trivia() => 0,
99 if let Some(doc_comment
) = token_as_doc_comment(&original_token
) {
100 return doc_comment
.get_definition_with_descend_at(sema
, offset
, |def
, _
, _
| {
101 let m
= def_to_moniker(db
, def
, current_crate
)?
;
102 Some(RangeInfo
::new(original_token
.text_range(), vec
![m
]))
106 .descend_into_macros(original_token
.clone())
108 .filter_map(|token
| {
109 IdentClass
::classify_token(sema
, &token
).map(IdentClass
::definitions_no_ops
).map(|it
| {
110 it
.into_iter().flat_map(|def
| def_to_moniker(sema
.db
, def
, current_crate
))
115 .collect
::<Vec
<_
>>();
116 Some(RangeInfo
::new(original_token
.text_range(), navs
))
119 pub(crate) fn def_to_moniker(
123 ) -> Option
<MonikerResult
> {
126 Definition
::GenericParam(_
)
127 | Definition
::Label(_
)
128 | Definition
::DeriveHelper(_
)
129 | Definition
::BuiltinAttr(_
)
130 | Definition
::ToolModule(_
)
135 let module
= def
.module(db
)?
;
136 let krate
= module
.krate();
137 let mut description
= vec
![];
138 description
.extend(module
.path_to_root(db
).into_iter().filter_map(|x
| {
139 Some(MonikerDescriptor { name: x.name(db)?, desc: MonikerDescriptorKind::Namespace }
)
142 // Handle associated items within a trait
143 if let Some(assoc
) = def
.as_assoc_item(db
) {
144 let container
= assoc
.container(db
);
146 AssocItemContainer
::Trait(trait_
) => {
147 // Because different traits can have functions with the same name,
148 // we have to include the trait name as part of the moniker for uniqueness.
149 description
.push(MonikerDescriptor
{
150 name
: trait_
.name(db
),
151 desc
: MonikerDescriptorKind
::Type
,
154 AssocItemContainer
::Impl(impl_
) => {
155 // Because a struct can implement multiple traits, for implementations
156 // we add both the struct name and the trait name to the path
157 if let Some(adt
) = impl_
.self_ty(db
).as_adt() {
158 description
.push(MonikerDescriptor
{
160 desc
: MonikerDescriptorKind
::Type
,
164 if let Some(trait_
) = impl_
.trait_(db
) {
165 description
.push(MonikerDescriptor
{
166 name
: trait_
.name(db
),
167 desc
: MonikerDescriptorKind
::Type
,
174 if let Definition
::Field(it
) = def
{
175 description
.push(MonikerDescriptor
{
176 name
: it
.parent_def(db
).name(db
),
177 desc
: MonikerDescriptorKind
::Type
,
181 let name_desc
= match def
{
182 // These are handled by top-level guard (for performance).
183 Definition
::GenericParam(_
)
184 | Definition
::Label(_
)
185 | Definition
::DeriveHelper(_
)
186 | Definition
::BuiltinAttr(_
)
187 | Definition
::ToolModule(_
) => return None
,
189 Definition
::Local(local
) => {
190 if !local
.is_param(db
) {
194 MonikerDescriptor { name: local.name(db), desc: MonikerDescriptorKind::Parameter }
196 Definition
::Macro(m
) => {
197 MonikerDescriptor { name: m.name(db), desc: MonikerDescriptorKind::Macro }
199 Definition
::Function(f
) => {
200 MonikerDescriptor { name: f.name(db), desc: MonikerDescriptorKind::Method }
202 Definition
::Variant(v
) => {
203 MonikerDescriptor { name: v.name(db), desc: MonikerDescriptorKind::Type }
205 Definition
::Const(c
) => {
206 MonikerDescriptor { name: c.name(db)?, desc: MonikerDescriptorKind::Term }
208 Definition
::Trait(trait_
) => {
209 MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type }
211 Definition
::TypeAlias(ta
) => {
212 MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter }
214 Definition
::Module(m
) => {
215 MonikerDescriptor { name: m.name(db)?, desc: MonikerDescriptorKind::Namespace }
217 Definition
::BuiltinType(b
) => {
218 MonikerDescriptor { name: b.name(), desc: MonikerDescriptorKind::Type }
220 Definition
::SelfType(imp
) => MonikerDescriptor
{
221 name
: imp
.self_ty(db
).as_adt()?
.name(db
),
222 desc
: MonikerDescriptorKind
::Type
,
224 Definition
::Field(it
) => {
225 MonikerDescriptor { name: it.name(db), desc: MonikerDescriptorKind::Term }
227 Definition
::Adt(adt
) => {
228 MonikerDescriptor { name: adt.name(db), desc: MonikerDescriptorKind::Type }
230 Definition
::Static(s
) => {
231 MonikerDescriptor { name: s.name(db), desc: MonikerDescriptorKind::Meta }
235 description
.push(name_desc
);
238 identifier
: MonikerIdentifier
{
239 crate_name
: krate
.display_name(db
)?
.crate_name().to_string(),
242 kind
: if krate
== from_crate { MonikerKind::Export }
else { MonikerKind::Import }
,
243 package_information
: {
244 let (name
, repo
, version
) = match krate
.origin(db
) {
245 CrateOrigin
::CratesIo { repo, name }
=> (
246 name
.unwrap_or(krate
.display_name(db
)?
.canonical_name().to_string()),
250 CrateOrigin
::Lang(lang
) => (
251 krate
.display_name(db
)?
.canonical_name().to_string(),
252 Some("https://github.com/rust-lang/rust/".to_string()),
254 LangCrateOrigin
::Other
=> {
255 "https://github.com/rust-lang/rust/library/".into()
257 lang
=> format
!("https://github.com/rust-lang/rust/library/{lang}",),
261 PackageInformation { name, repo, version }
270 use super::MonikerKind
;
273 fn no_moniker(ra_fixture
: &str) {
274 let (analysis
, position
) = fixture
::position(ra_fixture
);
275 if let Some(x
) = analysis
.moniker(position
).unwrap() {
276 assert_eq
!(x
.info
.len(), 0, "Moniker founded but no moniker expected: {:?}", x
);
281 fn check_moniker(ra_fixture
: &str, identifier
: &str, package
: &str, kind
: MonikerKind
) {
282 let (analysis
, position
) = fixture
::position(ra_fixture
);
283 let x
= analysis
.moniker(position
).unwrap().expect("no moniker found").info
;
284 assert_eq
!(x
.len(), 1);
285 let x
= x
.into_iter().next().unwrap();
286 assert_eq
!(identifier
, x
.identifier
.to_string());
287 assert_eq
!(package
, format
!("{:?}", x
.package_information
));
288 assert_eq
!(kind
, x
.kind
);
295 //- /lib.rs crate:main deps:foo
296 use foo::module::func;
300 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
306 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
311 //- /lib.rs crate:main deps:foo
312 use foo::module::func;
316 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
322 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
328 fn moniker_for_trait() {
331 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
338 "foo::module::MyTrait::func",
339 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
345 fn moniker_for_trait_constant() {
348 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
351 const MY_CONST$0: u8;
355 "foo::module::MyTrait::MY_CONST",
356 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
362 fn moniker_for_trait_type() {
365 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
372 "foo::module::MyTrait::MyType",
373 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
379 fn moniker_for_trait_impl_function() {
382 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
390 impl MyTrait for MyStruct {
395 "foo::module::MyStruct::MyTrait::func",
396 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
402 fn moniker_for_field() {
405 //- /lib.rs crate:main deps:foo
408 let x = St { a$0: 2 };
410 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
416 r
#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
422 fn no_moniker_for_local() {
425 //- /lib.rs crate:main deps:foo
426 use foo::module::func;
430 //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git