mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Don't offer qualified path completions for buitlin derives
This commit is contained in:
parent
a8b76b632c
commit
2abe19e46a
6 changed files with 42 additions and 82 deletions
|
@ -1811,6 +1811,10 @@ impl Macro {
|
||||||
pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
|
pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
|
||||||
matches!(self.kind(db), MacroKind::Attr)
|
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 {
|
impl HasVisibility for Macro {
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
//! Completion for derives
|
//! Completion for derives
|
||||||
use hir::{HasAttrs, Macro, MacroKind};
|
use hir::{HasAttrs, Macro};
|
||||||
use ide_db::{
|
use ide_db::SymbolKind;
|
||||||
imports::{import_assets::ImportAssets, insert_use::ImportScope},
|
|
||||||
SymbolKind,
|
|
||||||
};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
use syntax::SmolStr;
|
||||||
use syntax::{SmolStr, SyntaxKind};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::flyimport::compute_fuzzy_completion_order_key,
|
|
||||||
context::{CompletionContext, PathCompletionCtx, PathKind},
|
context::{CompletionContext, PathCompletionCtx, PathKind},
|
||||||
item::CompletionItem,
|
item::CompletionItem,
|
||||||
Completions, ImportEdit,
|
Completions,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
|
pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
let attr = match (&ctx.path_context, ctx.attr.as_ref()) {
|
match ctx.path_context {
|
||||||
(Some(PathCompletionCtx { kind: Some(PathKind::Derive), .. }), Some(attr)) => attr,
|
// FIXME: Enable qualified completions
|
||||||
|
Some(PathCompletionCtx { kind: Some(PathKind::Derive), qualifier: None, .. }) => (),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
}
|
||||||
|
|
||||||
let core = ctx.famous_defs().core();
|
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) {
|
for (name, mac) in get_derives_in_scope(ctx) {
|
||||||
if existing_derives.contains(&mac) {
|
if ctx.existing_derives.contains(&mac) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +35,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
let mut components = vec![derive_completion.label];
|
let mut components = vec![derive_completion.label];
|
||||||
components.extend(derive_completion.dependencies.iter().filter(
|
components.extend(derive_completion.dependencies.iter().filter(
|
||||||
|&&dependency| {
|
|&&dependency| {
|
||||||
!existing_derives
|
!ctx.existing_derives
|
||||||
.iter()
|
.iter()
|
||||||
.map(|it| it.name(ctx.db))
|
.map(|it| it.name(ctx.db))
|
||||||
.any(|it| it.to_smol_str() == dependency)
|
.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);
|
item.add_to(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
flyimport_derive(acc, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
|
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
|
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 {
|
struct DeriveDependencies {
|
||||||
label: &'static str,
|
label: &'static str,
|
||||||
dependencies: &'static [&'static str],
|
dependencies: &'static [&'static str],
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let ns_filter = |import: &LocatedImport| {
|
let ns_filter = |import: &LocatedImport| {
|
||||||
let kind = match ctx.path_kind() {
|
let path_kind = match ctx.path_kind() {
|
||||||
Some(kind) => kind,
|
Some(kind) => kind,
|
||||||
None => {
|
None => {
|
||||||
return match import.original_item {
|
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
|
// Aren't handled in flyimport
|
||||||
(PathKind::Vis { .. } | PathKind::Use | PathKind::Derive, _) => false,
|
(PathKind::Vis { .. } | PathKind::Use, _) => false,
|
||||||
// modules are always fair game
|
// modules are always fair game
|
||||||
(_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
|
(_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
|
||||||
// and so are macros(except for attributes)
|
// 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 { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
|
||||||
(PathKind::Attr { .. }, _) => false,
|
(PathKind::Attr { .. }, _) => false,
|
||||||
|
|
||||||
|
(PathKind::Derive, ItemInNs::Macros(mac)) => {
|
||||||
|
mac.is_derive(ctx.db) && !ctx.existing_derives.contains(&mac)
|
||||||
|
}
|
||||||
|
(PathKind::Derive, _) => false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use ide_db::{
|
||||||
famous_defs::FamousDefs,
|
famous_defs::FamousDefs,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::{find_node_at_offset, non_trivia_sibling},
|
algo::{find_node_at_offset, non_trivia_sibling},
|
||||||
ast::{self, AttrKind, HasName, NameOrNameRef},
|
ast::{self, AttrKind, HasName, NameOrNameRef},
|
||||||
|
@ -127,7 +128,6 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
|
|
||||||
/// The parent function of the cursor position if it exists.
|
/// The parent function of the cursor position if it exists.
|
||||||
pub(super) function_def: Option<ast::Fn>,
|
pub(super) function_def: Option<ast::Fn>,
|
||||||
pub(super) attr: Option<ast::Attr>,
|
|
||||||
/// The parent impl of the cursor position if it exists.
|
/// The parent impl of the cursor position if it exists.
|
||||||
pub(super) impl_def: Option<ast::Impl>,
|
pub(super) impl_def: Option<ast::Impl>,
|
||||||
/// The NameLike under the cursor in the original file if it exists.
|
/// 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) pattern_ctx: Option<PatternContext>,
|
||||||
pub(super) path_context: Option<PathCompletionCtx>,
|
pub(super) path_context: Option<PathCompletionCtx>,
|
||||||
|
|
||||||
|
pub(super) existing_derives: FxHashSet<hir::Macro>,
|
||||||
|
|
||||||
pub(super) locals: Vec<(Name, Local)>,
|
pub(super) locals: Vec<(Name, Local)>,
|
||||||
|
|
||||||
no_completion_required: bool,
|
no_completion_required: bool,
|
||||||
|
@ -440,7 +442,6 @@ impl<'a> CompletionContext<'a> {
|
||||||
expected_name: None,
|
expected_name: None,
|
||||||
expected_type: None,
|
expected_type: None,
|
||||||
function_def: None,
|
function_def: None,
|
||||||
attr: None,
|
|
||||||
impl_def: None,
|
impl_def: None,
|
||||||
name_syntax: None,
|
name_syntax: None,
|
||||||
lifetime_ctx: None,
|
lifetime_ctx: None,
|
||||||
|
@ -453,6 +454,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
locals,
|
locals,
|
||||||
incomplete_let: false,
|
incomplete_let: false,
|
||||||
no_completion_required: false,
|
no_completion_required: false,
|
||||||
|
existing_derives: Default::default(),
|
||||||
};
|
};
|
||||||
ctx.expand_and_fill(
|
ctx.expand_and_fill(
|
||||||
original_file.syntax().clone(),
|
original_file.syntax().clone(),
|
||||||
|
@ -746,11 +748,6 @@ impl<'a> CompletionContext<'a> {
|
||||||
(fn_is_prev && !inside_impl_trait_block) || for_is_prev2
|
(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.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
|
||||||
|
|
||||||
self.incomplete_let =
|
self.incomplete_let =
|
||||||
|
@ -764,9 +761,21 @@ impl<'a> CompletionContext<'a> {
|
||||||
|
|
||||||
// Overwrite the path kind for derives
|
// Overwrite the path kind for derives
|
||||||
if let Some((original_file, file_with_fake_ident, offset)) = derive_ctx {
|
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)) =
|
if let Some(ast::NameLike::NameRef(name_ref)) =
|
||||||
find_node_at_offset(&file_with_fake_ident, offset)
|
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, _)) =
|
if let Some((path_ctx, _)) =
|
||||||
Self::classify_name_ref(&self.sema, &original_file, name_ref)
|
Self::classify_name_ref(&self.sema, &original_file, name_ref)
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,6 +109,7 @@ fn detail(sema: &Semantics<RootDatabase>, macro_: hir::Macro) -> Option<String>
|
||||||
let _ = sema.parse_or_expand(file_id);
|
let _ = sema.parse_or_expand(file_id);
|
||||||
let detail = match value {
|
let detail = match value {
|
||||||
Either::Left(node) => macro_label(&node),
|
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),
|
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||||
};
|
};
|
||||||
Some(detail)
|
Some(detail)
|
||||||
|
|
|
@ -764,7 +764,7 @@ mod derive {
|
||||||
#[derive(der$0)] struct Test;
|
#[derive(der$0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
de DeriveIdentity (use proc_macros::DeriveIdentity)
|
de DeriveIdentity (use proc_macros::DeriveIdentity) pub macro derive_identity
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check_derive(
|
check_derive(
|
||||||
|
@ -805,10 +805,7 @@ use proc_macros::DeriveIdentity;
|
||||||
//- minicore: derive, copy, clone
|
//- minicore: derive, copy, clone
|
||||||
#[derive(proc_macros::$0)] struct Test;
|
#[derive(proc_macros::$0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#""#]],
|
||||||
de Clone, Copy
|
|
||||||
de Clone
|
|
||||||
"#]],
|
|
||||||
);
|
);
|
||||||
check_derive(
|
check_derive(
|
||||||
r#"
|
r#"
|
||||||
|
@ -816,10 +813,7 @@ use proc_macros::DeriveIdentity;
|
||||||
//- minicore: derive, copy, clone
|
//- minicore: derive, copy, clone
|
||||||
#[derive(proc_macros::C$0)] struct Test;
|
#[derive(proc_macros::C$0)] struct Test;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#""#]],
|
||||||
de Clone, Copy
|
|
||||||
de Clone
|
|
||||||
"#]],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue