@@ -25,6 +25,7 @@ use crate::{
25
25
26
26
mod cfg;
27
27
mod derive;
28
+ mod diagnostic;
28
29
mod lint;
29
30
mod macro_use;
30
31
mod repr;
@@ -40,23 +41,22 @@ pub(crate) fn complete_known_attribute_input(
40
41
extern_crate : Option < & ast:: ExternCrate > ,
41
42
) -> Option < ( ) > {
42
43
let attribute = fake_attribute_under_caret;
43
- let name_ref = match attribute. path ( ) {
44
- Some ( p) => Some ( p. as_single_name_ref ( ) ?) ,
45
- None => None ,
46
- } ;
47
- let ( path, tt) = name_ref. zip ( attribute. token_tree ( ) ) ?;
48
- tt. l_paren_token ( ) ?;
44
+ let path = attribute. path ( ) ?;
45
+ let segments = path. segments ( ) . map ( |s| s. name_ref ( ) ) . collect :: < Option < Vec < _ > > > ( ) ?;
46
+ let segments = segments. iter ( ) . map ( |n| n. text ( ) ) . collect :: < Vec < _ > > ( ) ;
47
+ let segments = segments. iter ( ) . map ( |t| t. as_str ( ) ) . collect :: < Vec < _ > > ( ) ;
48
+ let tt = attribute. token_tree ( ) ?;
49
49
50
- match path . text ( ) . as_str ( ) {
51
- "repr" => repr:: complete_repr ( acc, ctx, tt) ,
52
- "feature" => lint:: complete_lint (
50
+ match segments . as_slice ( ) {
51
+ [ "repr" ] => repr:: complete_repr ( acc, ctx, tt) ,
52
+ [ "feature" ] => lint:: complete_lint (
53
53
acc,
54
54
ctx,
55
55
colon_prefix,
56
56
& parse_tt_as_comma_sep_paths ( tt, ctx. edition ) ?,
57
57
FEATURES ,
58
58
) ,
59
- "allow" | "expect" | "deny" | "forbid" | "warn" => {
59
+ [ "allow" ] | [ "expect" ] | [ "deny" ] | [ "forbid" ] | [ "warn" ] => {
60
60
let existing_lints = parse_tt_as_comma_sep_paths ( tt, ctx. edition ) ?;
61
61
62
62
let lints: Vec < Lint > = CLIPPY_LINT_GROUPS
@@ -70,13 +70,14 @@ pub(crate) fn complete_known_attribute_input(
70
70
71
71
lint:: complete_lint ( acc, ctx, colon_prefix, & existing_lints, & lints) ;
72
72
}
73
- "cfg" => cfg:: complete_cfg ( acc, ctx) ,
74
- "macro_use" => macro_use:: complete_macro_use (
73
+ [ "cfg" ] => cfg:: complete_cfg ( acc, ctx) ,
74
+ [ "macro_use" ] => macro_use:: complete_macro_use (
75
75
acc,
76
76
ctx,
77
77
extern_crate,
78
78
& parse_tt_as_comma_sep_paths ( tt, ctx. edition ) ?,
79
79
) ,
80
+ [ "diagnostic" , "on_unimplemented" ] => diagnostic:: complete_on_unimplemented ( acc, ctx, tt) ,
80
81
_ => ( ) ,
81
82
}
82
83
Some ( ( ) )
@@ -139,6 +140,8 @@ pub(crate) fn complete_attribute_path(
139
140
}
140
141
Qualified :: TypeAnchor { .. } | Qualified :: With { .. } => { }
141
142
}
143
+ let qualifier_path =
144
+ if let Qualified :: With { path, .. } = qualified { Some ( path) } else { None } ;
142
145
143
146
let attributes = annotated_item_kind. and_then ( |kind| {
144
147
if ast:: Expr :: can_cast ( kind) {
@@ -149,18 +152,33 @@ pub(crate) fn complete_attribute_path(
149
152
} ) ;
150
153
151
154
let add_completion = |attr_completion : & AttrCompletion | {
152
- let mut item = CompletionItem :: new (
153
- SymbolKind :: Attribute ,
154
- ctx. source_range ( ) ,
155
- attr_completion. label ,
156
- ctx. edition ,
157
- ) ;
155
+ // if we don't already have the qualifiers of the completion, then
156
+ // add the missing parts to the label and snippet
157
+ let mut label = attr_completion. label . to_owned ( ) ;
158
+ let mut snippet = attr_completion. snippet . map ( |s| s. to_owned ( ) ) ;
159
+ let segments = qualifier_path. iter ( ) . flat_map ( |q| q. segments ( ) ) . collect :: < Vec < _ > > ( ) ;
160
+ let qualifiers = attr_completion. qualifiers ;
161
+ let matching_qualifiers = segments
162
+ . iter ( )
163
+ . zip ( qualifiers)
164
+ . take_while ( |( s, q) | s. name_ref ( ) . is_some_and ( |t| t. text ( ) == * * q) )
165
+ . count ( ) ;
166
+ if matching_qualifiers != qualifiers. len ( ) {
167
+ let prefix = qualifiers[ matching_qualifiers..] . join ( "::" ) ;
168
+ label = format ! ( "{prefix}::{label}" ) ;
169
+ if let Some ( s) = snippet. as_mut ( ) {
170
+ * s = format ! ( "{prefix}::{s}" ) ;
171
+ }
172
+ }
173
+
174
+ let mut item =
175
+ CompletionItem :: new ( SymbolKind :: Attribute , ctx. source_range ( ) , label, ctx. edition ) ;
158
176
159
177
if let Some ( lookup) = attr_completion. lookup {
160
178
item. lookup_by ( lookup) ;
161
179
}
162
180
163
- if let Some ( ( snippet, cap) ) = attr_completion . snippet . zip ( ctx. config . snippet_cap ) {
181
+ if let Some ( ( snippet, cap) ) = snippet. zip ( ctx. config . snippet_cap ) {
164
182
item. insert_snippet ( cap, snippet) ;
165
183
}
166
184
@@ -184,6 +202,7 @@ struct AttrCompletion {
184
202
label : & ' static str ,
185
203
lookup : Option < & ' static str > ,
186
204
snippet : Option < & ' static str > ,
205
+ qualifiers : & ' static [ & ' static str ] ,
187
206
prefer_inner : bool ,
188
207
}
189
208
@@ -192,6 +211,10 @@ impl AttrCompletion {
192
211
self . lookup . unwrap_or ( self . label )
193
212
}
194
213
214
+ const fn qualifiers ( self , qualifiers : & ' static [ & ' static str ] ) -> AttrCompletion {
215
+ AttrCompletion { qualifiers, ..self }
216
+ }
217
+
195
218
const fn prefer_inner ( self ) -> AttrCompletion {
196
219
AttrCompletion { prefer_inner : true , ..self }
197
220
}
@@ -202,7 +225,7 @@ const fn attr(
202
225
lookup : Option < & ' static str > ,
203
226
snippet : Option < & ' static str > ,
204
227
) -> AttrCompletion {
205
- AttrCompletion { label, lookup, snippet, prefer_inner : false }
228
+ AttrCompletion { label, lookup, snippet, qualifiers : & [ ] , prefer_inner : false }
206
229
}
207
230
208
231
macro_rules! attrs {
@@ -264,14 +287,14 @@ static KIND_TO_ATTRIBUTES: LazyLock<FxHashMap<SyntaxKind, &[&str]>> = LazyLock::
264
287
FN ,
265
288
attrs ! (
266
289
item, linkable,
267
- "cold" , "ignore" , "inline" , "must_use" , " panic_handler", "proc_macro" ,
290
+ "cold" , "ignore" , "inline" , "panic_handler" , "proc_macro" ,
268
291
"proc_macro_derive" , "proc_macro_attribute" , "should_panic" , "target_feature" ,
269
292
"test" , "track_caller"
270
293
) ,
271
294
) ,
272
295
( STATIC , attrs ! ( item, linkable, "global_allocator" , "used" ) ) ,
273
- ( TRAIT , attrs ! ( item, "must_use " ) ) ,
274
- ( IMPL , attrs ! ( item, "automatically_derived" ) ) ,
296
+ ( TRAIT , attrs ! ( item, "diagnostic::on_unimplemented " ) ) ,
297
+ ( IMPL , attrs ! ( item, "automatically_derived" , "diagnostic::do_not_recommend" ) ) ,
275
298
( ASSOC_ITEM_LIST , attrs ! ( item) ) ,
276
299
( EXTERN_BLOCK , attrs ! ( item, "link" ) ) ,
277
300
( EXTERN_ITEM_LIST , attrs ! ( item, "link" ) ) ,
@@ -311,6 +334,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[
311
334
attr ( "deny(…)" , Some ( "deny" ) , Some ( "deny(${0:lint})" ) ) ,
312
335
attr ( r#"deprecated"# , Some ( "deprecated" ) , Some ( r#"deprecated"# ) ) ,
313
336
attr ( "derive(…)" , Some ( "derive" ) , Some ( r#"derive(${0:Debug})"# ) ) ,
337
+ attr ( "do_not_recommend" , Some ( "diagnostic::do_not_recommend" ) , None )
338
+ . qualifiers ( & [ "diagnostic" ] ) ,
339
+ attr (
340
+ "on_unimplemented" ,
341
+ Some ( "diagnostic::on_unimplemented" ) ,
342
+ Some ( r#"on_unimplemented(${0:keys})"# ) ,
343
+ )
344
+ . qualifiers ( & [ "diagnostic" ] ) ,
314
345
attr ( r#"doc = "…""# , Some ( "doc" ) , Some ( r#"doc = "${0:docs}""# ) ) ,
315
346
attr ( r#"doc(alias = "…")"# , Some ( "docalias" ) , Some ( r#"doc(alias = "${0:docs}")"# ) ) ,
316
347
attr ( r#"doc(hidden)"# , Some ( "dochidden" ) , Some ( r#"doc(hidden)"# ) ) ,
0 commit comments