Skip to content

Commit 7810823

Browse files
bors[bot]Veykril
andauthored
Merge #10657
10657: feat: Make unqualified derive attributes flyimportable r=Veykril a=Veykril ![UuwpKODbpB](https://user-images.githubusercontent.com/3757771/139436613-1e6eb8fd-f591-4fca-9383-ff7408ee9b18.gif) Fixes #10052 Co-authored-by: Lukas Wirth <[email protected]>
2 parents 057558b + ebd63ec commit 7810823

File tree

11 files changed

+124
-31
lines changed

11 files changed

+124
-31
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/base_db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ salsa = "0.17.0-pre.2"
1414
rustc-hash = "1.1.0"
1515

1616
syntax = { path = "../syntax", version = "0.0.0" }
17+
stdx = { path = "../stdx", version = "0.0.0" }
1718
cfg = { path = "../cfg", version = "0.0.0" }
1819
profile = { path = "../profile", version = "0.0.0" }
1920
tt = { path = "../tt", version = "0.0.0" }

crates/base_db/src/fixture.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ fn test_proc_macros(proc_macros: &[String]) -> (Vec<ProcMacro>, String) {
270270
pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
271271
item
272272
}
273-
#[proc_macro_derive(derive_identity)]
273+
#[proc_macro_derive(DeriveIdentity)]
274274
pub fn derive_identity(item: TokenStream) -> TokenStream {
275275
item
276276
}
@@ -290,7 +290,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
290290
expander: Arc::new(IdentityProcMacroExpander),
291291
},
292292
ProcMacro {
293-
name: "derive_identity".into(),
293+
name: "DeriveIdentity".into(),
294294
kind: crate::ProcMacroKind::CustomDerive,
295295
expander: Arc::new(IdentityProcMacroExpander),
296296
},
@@ -306,7 +306,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
306306
},
307307
]
308308
.into_iter()
309-
.filter(|pm| proc_macros.iter().any(|name| name == pm.name))
309+
.filter(|pm| proc_macros.iter().any(|name| name == &stdx::to_lower_snake_case(&pm.name)))
310310
.collect();
311311
(proc_macros, source.into())
312312
}

crates/hir/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,12 @@ impl MacroDef {
16231623
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
16241624
match self.source(db)?.value {
16251625
Either::Left(it) => it.name().map(|it| it.as_name()),
1626-
Either::Right(it) => it.name().map(|it| it.as_name()),
1626+
Either::Right(_) => {
1627+
let krate = self.id.krate;
1628+
let def_map = db.crate_def_map(krate);
1629+
let (_, name) = def_map.exported_proc_macros().find(|&(id, _)| id == self.id)?;
1630+
Some(name)
1631+
}
16271632
}
16281633
}
16291634

crates/hir_def/src/macro_expansion_tests/proc_macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ fn derive_censoring() {
3333
//- proc_macros: derive_identity
3434
#[attr1]
3535
#[derive(Foo)]
36-
#[derive(proc_macros::derive_identity)]
36+
#[derive(proc_macros::DeriveIdentity)]
3737
#[derive(Bar)]
3838
#[attr2]
3939
struct S;
4040
"#,
4141
expect![[r##"
4242
#[attr1]
4343
#[derive(Foo)]
44-
#[derive(proc_macros::derive_identity)]
44+
#[derive(proc_macros::DeriveIdentity)]
4545
#[derive(Bar)]
4646
#[attr2]
4747
struct S;

crates/hir_def/src/nameres.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub struct DefMap {
103103
/// Side table with additional proc. macro info, for use by name resolution in downstream
104104
/// crates.
105105
///
106-
/// (the primary purpose is to resolve derive helpers)
106+
/// (the primary purpose is to resolve derive helpers and fetch a proc-macros name)
107107
exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
108108

109109
edition: Edition,
@@ -279,7 +279,9 @@ impl DefMap {
279279
pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
280280
self.modules.iter()
281281
}
282-
282+
pub fn exported_proc_macros(&self) -> impl Iterator<Item = (MacroDefId, Name)> + '_ {
283+
self.exported_proc_macros.iter().map(|(id, def)| (*id, def.name.clone()))
284+
}
283285
pub fn root(&self) -> LocalModuleId {
284286
self.root
285287
}

crates/hir_expand/src/name.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ impl Name {
6363
/// Ideally, we want a `gensym` semantics for missing names -- each missing
6464
/// name is equal only to itself. It's not clear how to implement this in
6565
/// salsa though, so we punt on that bit for a moment.
66-
pub fn missing() -> Name {
67-
Name::new_text("[missing name]".into())
66+
pub const fn missing() -> Name {
67+
Name::new_inline("[missing name]")
6868
}
6969

7070
/// Returns the tuple index this name represents if it is a tuple field.

crates/ide_completion/src/completions/attribute/derive.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! Completion for derives
22
use hir::{HasAttrs, MacroDef, MacroKind};
3-
use ide_db::helpers::FamousDefs;
3+
use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
44
use itertools::Itertools;
55
use rustc_hash::FxHashSet;
6-
use syntax::ast;
6+
use syntax::{ast, SyntaxKind};
77

88
use crate::{
9+
completions::flyimport::compute_fuzzy_completion_order_key,
910
context::CompletionContext,
1011
item::{CompletionItem, CompletionItemKind},
11-
Completions,
12+
Completions, ImportEdit,
1213
};
1314

1415
pub(super) fn complete_derive(
@@ -66,6 +67,8 @@ pub(super) fn complete_derive(
6667
}
6768
item.add_to(acc);
6869
}
70+
71+
flyimport_attribute(ctx, acc);
6972
}
7073

7174
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)> {
8083
result
8184
}
8285

86+
fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> {
87+
if ctx.token.kind() != SyntaxKind::IDENT {
88+
return None;
89+
};
90+
let potential_import_name = ctx.token.to_string();
91+
let module = ctx.scope.module()?;
92+
let parent = ctx.token.parent()?;
93+
let user_input_lowercased = potential_import_name.to_lowercase();
94+
let import_assets = ImportAssets::for_fuzzy_path(
95+
module,
96+
None,
97+
potential_import_name,
98+
&ctx.sema,
99+
parent.clone(),
100+
)?;
101+
let import_scope = ImportScope::find_insert_use_container_with_macros(&parent, &ctx.sema)?;
102+
acc.add_all(
103+
import_assets
104+
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
105+
.into_iter()
106+
.filter_map(|import| match import.original_item {
107+
hir::ItemInNs::Macros(mac) => Some((import, mac)),
108+
_ => None,
109+
})
110+
.filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
111+
.sorted_by_key(|(import, _)| {
112+
compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
113+
})
114+
.filter_map(|(import, mac)| {
115+
let mut item = CompletionItem::new(
116+
CompletionItemKind::Attribute,
117+
ctx.source_range(),
118+
mac.name(ctx.db)?.to_string(),
119+
);
120+
item.add_import(ImportEdit { import, scope: import_scope.clone() });
121+
if let Some(docs) = mac.docs(ctx.db) {
122+
item.documentation(docs);
123+
}
124+
Some(item.build())
125+
}),
126+
);
127+
Some(())
128+
}
129+
83130
struct DeriveDependencies {
84131
label: &'static str,
85132
dependencies: &'static [&'static str],

crates/ide_completion/src/completions/flyimport.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,12 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
125125
}
126126
};
127127

128-
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
128+
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
129129

130130
let user_input_lowercased = potential_import_name.to_lowercase();
131131
let import_assets = import_assets(ctx, potential_import_name)?;
132132
let import_scope = ImportScope::find_insert_use_container_with_macros(
133-
position_for_import(ctx, Some(import_assets.import_candidate()))?,
133+
&position_for_import(ctx, Some(import_assets.import_candidate()))?,
134134
&ctx.sema,
135135
)?;
136136

@@ -158,21 +158,19 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
158158
Some(())
159159
}
160160

161-
pub(crate) fn position_for_import<'a>(
162-
ctx: &'a CompletionContext,
161+
pub(crate) fn position_for_import(
162+
ctx: &CompletionContext,
163163
import_candidate: Option<&ImportCandidate>,
164-
) -> Option<&'a SyntaxNode> {
165-
Some(match import_candidate {
166-
Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
167-
Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
168-
Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
169-
None => ctx
170-
.name_syntax
171-
.as_ref()
172-
.map(|name_ref| name_ref.syntax())
173-
.or_else(|| ctx.path_qual().map(|path| path.syntax()))
174-
.or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?,
175-
})
164+
) -> Option<SyntaxNode> {
165+
Some(
166+
match import_candidate {
167+
Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
168+
Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
169+
Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
170+
None => return ctx.original_token.parent(),
171+
}
172+
.clone(),
173+
)
176174
}
177175

178176
fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
@@ -205,7 +203,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
205203
}
206204
}
207205

208-
fn compute_fuzzy_completion_order_key(
206+
pub(crate) fn compute_fuzzy_completion_order_key(
209207
proposed_mod_path: &hir::ModPath,
210208
user_input_lowercased: &str,
211209
) -> usize {

crates/ide_completion/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ pub fn resolve_completion_edits(
182182
) -> Option<Vec<TextEdit>> {
183183
let _p = profile::span("resolve_completion_edits");
184184
let ctx = CompletionContext::new(db, position, config)?;
185-
let position_for_import = position_for_import(&ctx, None)?;
185+
let position_for_import = &position_for_import(&ctx, None)?;
186186
let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
187187

188188
let current_module = ctx.sema.scope(position_for_import).module()?;

crates/ide_completion/src/tests/attribute.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,45 @@ mod derive {
640640
"#]],
641641
)
642642
}
643+
644+
#[test]
645+
fn derive_flyimport() {
646+
check_derive(
647+
r#"
648+
//- proc_macros: derive_identity
649+
#[derive(der$0)] struct Test;
650+
"#,
651+
expect![[r#"
652+
at DeriveIdentity (use proc_macros::DeriveIdentity)
653+
"#]],
654+
);
655+
check_derive(
656+
r#"
657+
//- proc_macros: derive_identity
658+
use proc_macros::DeriveIdentity;
659+
#[derive(der$0)] struct Test;
660+
"#,
661+
expect![[r#"
662+
at DeriveIdentity
663+
"#]],
664+
);
665+
}
666+
667+
#[test]
668+
fn derive_flyimport_edit() {
669+
check_edit(
670+
"DeriveIdentity",
671+
r#"
672+
//- proc_macros: derive_identity
673+
#[derive(der$0)] struct Test;
674+
"#,
675+
r#"
676+
use proc_macros::DeriveIdentity;
677+
678+
#[derive(DeriveIdentity)] struct Test;
679+
"#,
680+
);
681+
}
643682
}
644683

645684
mod lint {

0 commit comments

Comments
 (0)