Don't offer qualified path completions for buitlin derives

This commit is contained in:
Lukas Wirth 2022-03-10 21:22:13 +01:00
parent a8b76b632c
commit 2abe19e46a
6 changed files with 42 additions and 82 deletions

View File

@ -1811,6 +1811,10 @@ impl Macro {
pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
matches!(self.kind(db), MacroKind::Attr)
}
pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
matches!(self.kind(db), MacroKind::Derive)
}
}
impl HasVisibility for Macro {

View File

@ -1,32 +1,26 @@
//! Completion for derives
use hir::{HasAttrs, Macro, MacroKind};
use ide_db::{
imports::{import_assets::ImportAssets, insert_use::ImportScope},
SymbolKind,
};
use hir::{HasAttrs, Macro};
use ide_db::SymbolKind;
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{SmolStr, SyntaxKind};
use syntax::SmolStr;
use crate::{
completions::flyimport::compute_fuzzy_completion_order_key,
context::{CompletionContext, PathCompletionCtx, PathKind},
item::CompletionItem,
Completions, ImportEdit,
Completions,
};
pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
let attr = match (&ctx.path_context, ctx.attr.as_ref()) {
(Some(PathCompletionCtx { kind: Some(PathKind::Derive), .. }), Some(attr)) => attr,
match ctx.path_context {
// FIXME: Enable qualified completions
Some(PathCompletionCtx { kind: Some(PathKind::Derive), qualifier: None, .. }) => (),
_ => return,
};
}
let core = ctx.famous_defs().core();
let existing_derives: FxHashSet<_> =
ctx.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
for (name, mac) in get_derives_in_scope(ctx) {
if existing_derives.contains(&mac) {
if ctx.existing_derives.contains(&mac) {
continue;
}
@ -41,7 +35,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
let mut components = vec![derive_completion.label];
components.extend(derive_completion.dependencies.iter().filter(
|&&dependency| {
!existing_derives
!ctx.existing_derives
.iter()
.map(|it| it.name(ctx.db))
.any(|it| it.to_smol_str() == dependency)
@ -66,8 +60,6 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
}
item.add_to(acc);
}
flyimport_derive(acc, ctx);
}
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
@ -82,51 +74,6 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
result
}
fn flyimport_derive(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
if ctx.token.kind() != SyntaxKind::IDENT {
return None;
};
let potential_import_name = ctx.token.to_string();
let module = ctx.module?;
let parent = ctx.token.parent()?;
let user_input_lowercased = potential_import_name.to_lowercase();
let import_assets = ImportAssets::for_fuzzy_path(
module,
None,
potential_import_name,
&ctx.sema,
parent.clone(),
)?;
let import_scope = ImportScope::find_insert_use_container(&parent, &ctx.sema)?;
acc.add_all(
import_assets
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
.into_iter()
.filter_map(|import| match import.original_item {
hir::ItemInNs::Macros(mac) => Some((import, mac)),
_ => None,
})
.filter(|&(_, mac)| mac.kind(ctx.db) == MacroKind::Derive)
.filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
.sorted_by_key(|(import, _)| {
compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
})
.filter_map(|(import, mac)| {
let mut item = CompletionItem::new(
SymbolKind::Derive,
ctx.source_range(),
mac.name(ctx.db).to_smol_str(),
);
item.add_import(ImportEdit { import, scope: import_scope.clone() });
if let Some(docs) = mac.docs(ctx.db) {
item.documentation(docs);
}
Some(item.build())
}),
);
Some(())
}
struct DeriveDependencies {
label: &'static str,
dependencies: &'static [&'static str],

View File

@ -142,7 +142,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
)?;
let ns_filter = |import: &LocatedImport| {
let kind = match ctx.path_kind() {
let path_kind = match ctx.path_kind() {
Some(kind) => kind,
None => {
return match import.original_item {
@ -151,9 +151,9 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
}
}
};
match (kind, import.original_item) {
match (path_kind, import.original_item) {
// Aren't handled in flyimport
(PathKind::Vis { .. } | PathKind::Use | PathKind::Derive, _) => false,
(PathKind::Vis { .. } | PathKind::Use, _) => false,
// modules are always fair game
(_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
// and so are macros(except for attributes)
@ -173,6 +173,11 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
(PathKind::Attr { .. }, _) => false,
(PathKind::Derive, ItemInNs::Macros(mac)) => {
mac.is_derive(ctx.db) && !ctx.existing_derives.contains(&mac)
}
(PathKind::Derive, _) => false,
}
};

View File

@ -12,6 +12,7 @@ use ide_db::{
famous_defs::FamousDefs,
RootDatabase,
};
use rustc_hash::FxHashSet;
use syntax::{
algo::{find_node_at_offset, non_trivia_sibling},
ast::{self, AttrKind, HasName, NameOrNameRef},
@ -127,7 +128,6 @@ pub(crate) struct CompletionContext<'a> {
/// The parent function of the cursor position if it exists.
pub(super) function_def: Option<ast::Fn>,
pub(super) attr: Option<ast::Attr>,
/// The parent impl of the cursor position if it exists.
pub(super) impl_def: Option<ast::Impl>,
/// The NameLike under the cursor in the original file if it exists.
@ -143,6 +143,8 @@ pub(crate) struct CompletionContext<'a> {
pub(super) pattern_ctx: Option<PatternContext>,
pub(super) path_context: Option<PathCompletionCtx>,
pub(super) existing_derives: FxHashSet<hir::Macro>,
pub(super) locals: Vec<(Name, Local)>,
no_completion_required: bool,
@ -440,7 +442,6 @@ impl<'a> CompletionContext<'a> {
expected_name: None,
expected_type: None,
function_def: None,
attr: None,
impl_def: None,
name_syntax: None,
lifetime_ctx: None,
@ -453,6 +454,7 @@ impl<'a> CompletionContext<'a> {
locals,
incomplete_let: false,
no_completion_required: false,
existing_derives: Default::default(),
};
ctx.expand_and_fill(
original_file.syntax().clone(),
@ -746,11 +748,6 @@ impl<'a> CompletionContext<'a> {
(fn_is_prev && !inside_impl_trait_block) || for_is_prev2
};
self.attr = self
.sema
.token_ancestors_with_macros(self.token.clone())
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
.find_map(ast::Attr::cast);
self.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
self.incomplete_let =
@ -764,9 +761,21 @@ impl<'a> CompletionContext<'a> {
// Overwrite the path kind for derives
if let Some((original_file, file_with_fake_ident, offset)) = derive_ctx {
let attr = self
.sema
.token_ancestors_with_macros(self.token.clone())
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
.find_map(ast::Attr::cast);
if let Some(attr) = &attr {
self.existing_derives =
self.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
}
if let Some(ast::NameLike::NameRef(name_ref)) =
find_node_at_offset(&file_with_fake_ident, offset)
{
self.name_syntax =
find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
if let Some((path_ctx, _)) =
Self::classify_name_ref(&self.sema, &original_file, name_ref)
{

View File

@ -109,6 +109,7 @@ fn detail(sema: &Semantics<RootDatabase>, macro_: hir::Macro) -> Option<String>
let _ = sema.parse_or_expand(file_id);
let detail = match value {
Either::Left(node) => macro_label(&node),
// FIXME: this should render with the derive name, not the function name
Either::Right(node) => fn_as_proc_macro_label(&node),
};
Some(detail)

View File

@ -764,7 +764,7 @@ mod derive {
#[derive(der$0)] struct Test;
"#,
expect![[r#"
de DeriveIdentity (use proc_macros::DeriveIdentity)
de DeriveIdentity (use proc_macros::DeriveIdentity) pub macro derive_identity
"#]],
);
check_derive(
@ -805,10 +805,7 @@ use proc_macros::DeriveIdentity;
//- minicore: derive, copy, clone
#[derive(proc_macros::$0)] struct Test;
"#,
expect![[r#"
de Clone, Copy
de Clone
"#]],
expect![[r#""#]],
);
check_derive(
r#"
@ -816,10 +813,7 @@ use proc_macros::DeriveIdentity;
//- minicore: derive, copy, clone
#[derive(proc_macros::C$0)] struct Test;
"#,
expect![[r#"
de Clone, Copy
de Clone
"#]],
expect![[r#""#]],
);
}
}