Enable qualifier completions for derives

This commit is contained in:
Lukas Wirth 2022-03-10 21:56:19 +01:00
parent 2abe19e46a
commit b1ab5770c9
2 changed files with 123 additions and 83 deletions

View file

@ -1,79 +1,113 @@
//! Completion for derives
use hir::{HasAttrs, Macro};
use hir::{HasAttrs, ScopeDef};
use ide_db::SymbolKind;
use itertools::Itertools;
use syntax::SmolStr;
use crate::{
context::{CompletionContext, PathCompletionCtx, PathKind},
context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx},
item::CompletionItem,
Completions,
};
pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
match ctx.path_context {
// FIXME: Enable qualified completions
Some(PathCompletionCtx { kind: Some(PathKind::Derive), qualifier: None, .. }) => (),
let (qualifier, is_absolute_path) = match ctx.path_context {
Some(PathCompletionCtx {
kind: Some(PathKind::Derive),
ref qualifier,
is_absolute_path,
..
}) => (qualifier, is_absolute_path),
_ => return,
}
};
let core = ctx.famous_defs().core();
for (name, mac) in get_derives_in_scope(ctx) {
if ctx.existing_derives.contains(&mac) {
continue;
}
match qualifier {
Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
if *is_super_chain {
acc.add_keyword(ctx, "super::");
}
let name = name.to_smol_str();
let (label, lookup) = match (core, mac.module(ctx.db).krate()) {
// show derive dependencies for `core`/`std` derives
(Some(core), mac_krate) if core == mac_krate => {
if let Some(derive_completion) = DEFAULT_DERIVE_DEPENDENCIES
.iter()
.find(|derive_completion| derive_completion.label == name)
{
let mut components = vec![derive_completion.label];
components.extend(derive_completion.dependencies.iter().filter(
|&&dependency| {
!ctx.existing_derives
.iter()
.map(|it| it.name(ctx.db))
.any(|it| it.to_smol_str() == dependency)
},
));
let lookup = components.join(", ");
let label = Itertools::intersperse(components.into_iter().rev(), ", ");
(SmolStr::from_iter(label), Some(lookup))
} else {
(name, None)
let module = match resolution {
Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
_ => return,
};
for (name, def) in module.scope(ctx.db, ctx.module) {
let add_def = match def {
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
!ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db)
}
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
_ => false,
};
if add_def {
acc.add_resolution(ctx, name, def);
}
}
_ => (name, None),
};
return;
}
None if is_absolute_path => acc.add_crate_roots(ctx),
// only show modules in a fresh UseTree
None => {
ctx.process_all_names(&mut |name, def| {
let mac = match def {
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
if !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
{
mac
}
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => {
return acc.add_resolution(ctx, name, def);
}
_ => return,
};
let mut item = CompletionItem::new(SymbolKind::Derive, ctx.source_range(), label);
if let Some(docs) = mac.docs(ctx.db) {
item.documentation(docs);
match (core, mac.module(ctx.db).krate()) {
// show derive dependencies for `core`/`std` derives
(Some(core), mac_krate) if core == mac_krate && qualifier.is_none() => {}
_ => return acc.add_resolution(ctx, name, def),
};
let name_ = name.to_smol_str();
let find = DEFAULT_DERIVE_DEPENDENCIES
.iter()
.find(|derive_completion| derive_completion.label == name_);
match find {
Some(derive_completion) => {
let mut components = vec![derive_completion.label];
components.extend(derive_completion.dependencies.iter().filter(
|&&dependency| {
!ctx.existing_derives
.iter()
.map(|it| it.name(ctx.db))
.any(|it| it.to_smol_str() == dependency)
},
));
let lookup = components.join(", ");
let label = Itertools::intersperse(components.into_iter().rev(), ", ");
let mut item = CompletionItem::new(
SymbolKind::Derive,
ctx.source_range(),
SmolStr::from_iter(label),
);
if let Some(docs) = mac.docs(ctx.db) {
item.documentation(docs);
}
item.lookup_by(lookup);
item.add_to(acc);
}
None => acc.add_resolution(ctx, name, def),
}
});
acc.add_nameref_keywords(ctx);
}
if let Some(lookup) = lookup {
item.lookup_by(lookup);
}
item.add_to(acc);
}
}
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
let mut result = Vec::default();
ctx.process_all_names(&mut |name, scope_def| {
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) = scope_def {
if mac.kind(ctx.db) == hir::MacroKind::Derive {
result.push((name, mac));
}
}
});
result
}
struct DeriveDependencies {
label: &'static str,
dependencies: &'static [&'static str],

View file

@ -688,13 +688,17 @@ mod derive {
#[derive($0)] struct Test;
"#,
expect![[r#"
de Default
md core
de Default pub macro Default
de Clone, Copy
de PartialEq
de PartialEq pub macro PartialEq
de PartialEq, Eq
de PartialEq, Eq, PartialOrd, Ord
de Clone
de Clone pub macro Clone
de PartialEq, PartialOrd
kw self::
kw super::
kw crate::
"#]],
);
}
@ -707,12 +711,16 @@ mod derive {
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
"#,
expect![[r#"
de Default
md core
de Default pub macro Default
de Clone, Copy
de Eq
de Eq, PartialOrd, Ord
de Clone
de Clone pub macro Clone
de PartialOrd
kw self::
kw super::
kw crate::
"#]],
)
}
@ -725,36 +733,20 @@ mod derive {
#[derive($0 serde::Serialize, PartialEq)] struct Test;
"#,
expect![[r#"
de Default
md core
de Default pub macro Default
de Clone, Copy
de Eq
de Eq, PartialOrd, Ord
de Clone
de Clone pub macro Clone
de PartialOrd
kw self::
kw super::
kw crate::
"#]],
)
}
#[test]
fn derive_no_attrs() {
check_derive(
r#"
//- proc_macros: identity
//- minicore: derive
#[derive($0)] struct Test;
"#,
expect![[r#""#]],
);
check_derive(
r#"
//- proc_macros: identity
//- minicore: derive
#[derive(i$0)] struct Test;
"#,
expect![[r#""#]],
);
}
#[test]
fn derive_flyimport() {
check_derive(
@ -764,6 +756,11 @@ mod derive {
#[derive(der$0)] struct Test;
"#,
expect![[r#"
md proc_macros
md core
kw self::
kw super::
kw crate::
de DeriveIdentity (use proc_macros::DeriveIdentity) pub macro derive_identity
"#]],
);
@ -775,7 +772,12 @@ use proc_macros::DeriveIdentity;
#[derive(der$0)] struct Test;
"#,
expect![[r#"
de DeriveIdentity
de DeriveIdentity pub macro derive_identity
md proc_macros
md core
kw self::
kw super::
kw crate::
"#]],
);
}
@ -805,7 +807,9 @@ use proc_macros::DeriveIdentity;
//- minicore: derive, copy, clone
#[derive(proc_macros::$0)] struct Test;
"#,
expect![[r#""#]],
expect![[r#"
de DeriveIdentity pub macro derive_identity
"#]],
);
check_derive(
r#"
@ -813,7 +817,9 @@ use proc_macros::DeriveIdentity;
//- minicore: derive, copy, clone
#[derive(proc_macros::C$0)] struct Test;
"#,
expect![[r#""#]],
expect![[r#"
de DeriveIdentity pub macro derive_identity
"#]],
);
}
}