Skip to content

Commit 0370527

Browse files
authored
Merge pull request rust-lang#18604 from ChayimFriedman2/complete-helpers
feat: Complete derive helper attributes
2 parents 2f3e352 + d2ee916 commit 0370527

File tree

5 files changed

+111
-4
lines changed

5 files changed

+111
-4
lines changed

src/tools/rust-analyzer/crates/hir/src/semantics.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,22 @@ impl<'db> SemanticsImpl<'db> {
510510
self.with_ctx(|ctx| ctx.has_derives(adt))
511511
}
512512

513+
pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> {
514+
let sa = self.analyze_no_infer(adt.syntax())?;
515+
let id = self.db.ast_id_map(sa.file_id).ast_id(adt);
516+
let result = sa
517+
.resolver
518+
.def_map()
519+
.derive_helpers_in_scope(InFile::new(sa.file_id, id))?
520+
.iter()
521+
.map(|(name, macro_, _)| {
522+
let macro_name = Macro::from(*macro_).name(self.db).symbol().clone();
523+
(name.symbol().clone(), macro_name)
524+
})
525+
.collect();
526+
Some(result)
527+
}
528+
513529
pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroFileId)>> {
514530
let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
515531
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),

src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path(
8686
acc: &mut Completions,
8787
ctx: &CompletionContext<'_>,
8888
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
89-
&AttrCtx { kind, annotated_item_kind }: &AttrCtx,
89+
&AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx,
9090
) {
9191
let is_inner = kind == AttrKind::Inner;
9292

93+
for (derive_helper, derive_name) in derive_helpers {
94+
let mut item = CompletionItem::new(
95+
SymbolKind::Attribute,
96+
ctx.source_range(),
97+
derive_helper.as_str(),
98+
ctx.edition,
99+
);
100+
item.detail(format!("derive helper of `{derive_name}`"));
101+
item.add_to(acc, ctx.db);
102+
}
103+
93104
match qualified {
94105
Qualified::With {
95106
resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),

src/tools/rust-analyzer/crates/ide-completion/src/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ mod tests;
77
use std::{iter, ops::ControlFlow};
88

99
use hir::{
10-
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type,
11-
TypeInfo,
10+
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope,
11+
Symbol, Type, TypeInfo,
1212
};
1313
use ide_db::{
1414
base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition,
@@ -133,6 +133,7 @@ pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
133133
pub(crate) struct AttrCtx {
134134
pub(crate) kind: AttrKind,
135135
pub(crate) annotated_item_kind: Option<SyntaxKind>,
136+
pub(crate) derive_helpers: Vec<(Symbol, Symbol)>,
136137
}
137138

138139
#[derive(Debug, PartialEq, Eq)]

src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,22 @@ fn classify_name_ref(
11291129
let is_trailing_outer_attr = kind != AttrKind::Inner
11301130
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
11311131
let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) };
1132-
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
1132+
let derive_helpers = annotated_item_kind
1133+
.filter(|kind| {
1134+
matches!(
1135+
kind,
1136+
SyntaxKind::STRUCT
1137+
| SyntaxKind::ENUM
1138+
| SyntaxKind::UNION
1139+
| SyntaxKind::VARIANT
1140+
| SyntaxKind::TUPLE_FIELD
1141+
| SyntaxKind::RECORD_FIELD
1142+
)
1143+
})
1144+
.and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast))
1145+
.and_then(|adt| sema.derive_helpers_in_scope(&adt))
1146+
.unwrap_or_default();
1147+
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } })
11331148
};
11341149

11351150
// Infer the path kind

src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,70 @@ fn check(ra_fixture: &str, expect: Expect) {
88
expect.assert_eq(&actual);
99
}
1010

11+
#[test]
12+
fn derive_helpers() {
13+
check(
14+
r#"
15+
//- /mac.rs crate:mac
16+
#![crate_type = "proc-macro"]
17+
18+
#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))]
19+
pub fn my_derive() {}
20+
21+
//- /lib.rs crate:lib deps:mac
22+
#[rustc_builtin_macro]
23+
pub macro derive($item:item) {}
24+
25+
#[derive(mac::MyDerive)]
26+
pub struct Foo(#[m$0] i32);
27+
"#,
28+
expect![[r#"
29+
at allow(…)
30+
at automatically_derived
31+
at cfg(…)
32+
at cfg_attr(…)
33+
at cold
34+
at deny(…)
35+
at deprecated
36+
at derive macro derive
37+
at derive(…)
38+
at doc = "…"
39+
at doc(alias = "…")
40+
at doc(hidden)
41+
at expect(…)
42+
at export_name = "…"
43+
at forbid(…)
44+
at global_allocator
45+
at ignore = "…"
46+
at inline
47+
at link
48+
at link_name = "…"
49+
at link_section = "…"
50+
at macro_export
51+
at macro_use
52+
at must_use
53+
at my_cool_helper_attribute derive helper of `MyDerive`
54+
at no_mangle
55+
at non_exhaustive
56+
at panic_handler
57+
at path = "…"
58+
at proc_macro
59+
at proc_macro_attribute
60+
at proc_macro_derive(…)
61+
at repr(…)
62+
at should_panic
63+
at target_feature(enable = "…")
64+
at test
65+
at track_caller
66+
at used
67+
at warn(…)
68+
md mac
69+
kw crate::
70+
kw self::
71+
"#]],
72+
)
73+
}
74+
1175
#[test]
1276
fn proc_macros() {
1377
check(

0 commit comments

Comments
 (0)