mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
feat: Make unqualified derive attributes flyimportable
This commit is contained in:
parent
7fdbdc4ab2
commit
ebd63ec1cf
11 changed files with 124 additions and 31 deletions
|
@ -1,14 +1,15 @@
|
|||
//! Completion for derives
|
||||
use hir::{HasAttrs, MacroDef, MacroKind};
|
||||
use ide_db::helpers::FamousDefs;
|
||||
use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::ast;
|
||||
use syntax::{ast, SyntaxKind};
|
||||
|
||||
use crate::{
|
||||
completions::flyimport::compute_fuzzy_completion_order_key,
|
||||
context::CompletionContext,
|
||||
item::{CompletionItem, CompletionItemKind},
|
||||
Completions,
|
||||
Completions, ImportEdit,
|
||||
};
|
||||
|
||||
pub(super) fn complete_derive(
|
||||
|
@ -66,6 +67,8 @@ pub(super) fn complete_derive(
|
|||
}
|
||||
item.add_to(acc);
|
||||
}
|
||||
|
||||
flyimport_attribute(ctx, acc);
|
||||
}
|
||||
|
||||
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
|
||||
|
@ -80,6 +83,50 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
|
|||
result
|
||||
}
|
||||
|
||||
fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> {
|
||||
if ctx.token.kind() != SyntaxKind::IDENT {
|
||||
return None;
|
||||
};
|
||||
let potential_import_name = ctx.token.to_string();
|
||||
let module = ctx.scope.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_with_macros(&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)| !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(
|
||||
CompletionItemKind::Attribute,
|
||||
ctx.source_range(),
|
||||
mac.name(ctx.db)?.to_string(),
|
||||
);
|
||||
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],
|
||||
|
|
|
@ -125,12 +125,12 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
|||
}
|
||||
};
|
||||
|
||||
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
|
||||
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
|
||||
|
||||
let user_input_lowercased = potential_import_name.to_lowercase();
|
||||
let import_assets = import_assets(ctx, potential_import_name)?;
|
||||
let import_scope = ImportScope::find_insert_use_container_with_macros(
|
||||
position_for_import(ctx, Some(import_assets.import_candidate()))?,
|
||||
&position_for_import(ctx, Some(import_assets.import_candidate()))?,
|
||||
&ctx.sema,
|
||||
)?;
|
||||
|
||||
|
@ -158,21 +158,19 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
|||
Some(())
|
||||
}
|
||||
|
||||
pub(crate) fn position_for_import<'a>(
|
||||
ctx: &'a CompletionContext,
|
||||
pub(crate) fn position_for_import(
|
||||
ctx: &CompletionContext,
|
||||
import_candidate: Option<&ImportCandidate>,
|
||||
) -> Option<&'a SyntaxNode> {
|
||||
Some(match import_candidate {
|
||||
Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
|
||||
Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
|
||||
Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
|
||||
None => ctx
|
||||
.name_syntax
|
||||
.as_ref()
|
||||
.map(|name_ref| name_ref.syntax())
|
||||
.or_else(|| ctx.path_qual().map(|path| path.syntax()))
|
||||
.or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?,
|
||||
})
|
||||
) -> Option<SyntaxNode> {
|
||||
Some(
|
||||
match import_candidate {
|
||||
Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
|
||||
Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
|
||||
Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
|
||||
None => return ctx.original_token.parent(),
|
||||
}
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
|
||||
|
@ -205,7 +203,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_fuzzy_completion_order_key(
|
||||
pub(crate) fn compute_fuzzy_completion_order_key(
|
||||
proposed_mod_path: &hir::ModPath,
|
||||
user_input_lowercased: &str,
|
||||
) -> usize {
|
||||
|
|
|
@ -182,7 +182,7 @@ pub fn resolve_completion_edits(
|
|||
) -> Option<Vec<TextEdit>> {
|
||||
let _p = profile::span("resolve_completion_edits");
|
||||
let ctx = CompletionContext::new(db, position, config)?;
|
||||
let position_for_import = position_for_import(&ctx, None)?;
|
||||
let position_for_import = &position_for_import(&ctx, None)?;
|
||||
let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
|
||||
|
||||
let current_module = ctx.sema.scope(position_for_import).module()?;
|
||||
|
|
|
@ -640,6 +640,45 @@ mod derive {
|
|||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_flyimport() {
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
at DeriveIdentity (use proc_macros::DeriveIdentity)
|
||||
"#]],
|
||||
);
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
use proc_macros::DeriveIdentity;
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
at DeriveIdentity
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_flyimport_edit() {
|
||||
check_edit(
|
||||
"DeriveIdentity",
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
r#"
|
||||
use proc_macros::DeriveIdentity;
|
||||
|
||||
#[derive(DeriveIdentity)] struct Test;
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod lint {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue