1
1
//! Completion for derives
2
- use hir:: HasAttrs ;
2
+ use hir:: { HasAttrs , MacroDef , MacroKind } ;
3
+ use ide_db:: helpers:: FamousDefs ;
3
4
use itertools:: Itertools ;
4
- use rustc_hash:: FxHashMap ;
5
- use syntax:: { ast, SmolStr } ;
5
+ use rustc_hash:: FxHashSet ;
6
+ use syntax:: ast;
6
7
7
8
use crate :: {
8
9
context:: CompletionContext ,
@@ -15,36 +16,51 @@ pub(super) fn complete_derive(
15
16
ctx : & CompletionContext ,
16
17
derive_input : ast:: TokenTree ,
17
18
) {
18
- if let Some ( existing_derives) = super :: parse_comma_sep_paths ( derive_input) {
19
- for ( derive, docs) in get_derive_names_in_scope ( ctx) {
19
+ if let Some ( existing_derives) = super :: parse_comma_sep_paths ( derive_input. clone ( ) ) {
20
+ let core = FamousDefs ( & ctx. sema , ctx. krate ) . core ( ) ;
21
+ let existing_derives: FxHashSet < _ > = existing_derives
22
+ . into_iter ( )
23
+ . filter_map ( |path| ctx. scope . speculative_resolve_as_mac ( & path) )
24
+ . filter ( |mac| mac. kind ( ) == MacroKind :: Derive )
25
+ . collect ( ) ;
26
+
27
+ for ( name, mac) in get_derives_in_scope ( ctx) {
28
+ if existing_derives. contains ( & mac) {
29
+ continue ;
30
+ }
31
+
32
+ let name = name. to_smol_str ( ) ;
20
33
let label;
21
- let ( label, lookup) = if let Some ( derive_completion) = DEFAULT_DERIVE_COMPLETIONS
22
- . iter ( )
23
- . find ( |derive_completion| derive_completion. label == derive)
24
- {
25
- let mut components = vec ! [ derive_completion. label] ;
26
- components. extend ( derive_completion. dependencies . iter ( ) . filter ( |& & dependency| {
27
- !existing_derives
34
+ let ( label, lookup) = match core. zip ( mac. module ( ctx. db ) . map ( |it| it. krate ( ) ) ) {
35
+ // show derive dependencies for `core`/`std` derives
36
+ Some ( ( core, mac_krate) ) if core == mac_krate => {
37
+ if let Some ( derive_completion) = DEFAULT_DERIVE_DEPENDENCIES
28
38
. iter ( )
29
- . filter_map ( |it| it. as_single_name_ref ( ) )
30
- . any ( |it| it. text ( ) == dependency)
31
- } ) ) ;
32
- let lookup = components. join ( ", " ) ;
33
- label = components. iter ( ) . rev ( ) . join ( ", " ) ;
34
- ( & * label, Some ( lookup) )
35
- } else if existing_derives
36
- . iter ( )
37
- . filter_map ( |it| it. as_single_name_ref ( ) )
38
- . any ( |it| it. text ( ) . as_str ( ) == derive)
39
- {
40
- continue ;
41
- } else {
42
- ( & * derive, None )
39
+ . find ( |derive_completion| derive_completion. label == name)
40
+ {
41
+ let mut components = vec ! [ derive_completion. label] ;
42
+ components. extend ( derive_completion. dependencies . iter ( ) . filter (
43
+ |& & dependency| {
44
+ !existing_derives
45
+ . iter ( )
46
+ . filter_map ( |it| it. name ( ctx. db ) )
47
+ . any ( |it| it. to_smol_str ( ) == dependency)
48
+ } ,
49
+ ) ) ;
50
+ let lookup = components. join ( ", " ) ;
51
+ label = components. iter ( ) . rev ( ) . join ( ", " ) ;
52
+ ( label. as_str ( ) , Some ( lookup) )
53
+ } else {
54
+ ( & * name, None )
55
+ }
56
+ }
57
+ _ => ( & * name, None ) ,
43
58
} ;
59
+
44
60
let mut item =
45
61
CompletionItem :: new ( CompletionKind :: Attribute , ctx. source_range ( ) , label) ;
46
62
item. kind ( CompletionItemKind :: Attribute ) ;
47
- if let Some ( docs) = docs {
63
+ if let Some ( docs) = mac . docs ( ctx . db ) {
48
64
item. documentation ( docs) ;
49
65
}
50
66
if let Some ( lookup) = lookup {
@@ -55,14 +71,12 @@ pub(super) fn complete_derive(
55
71
}
56
72
}
57
73
58
- fn get_derive_names_in_scope (
59
- ctx : & CompletionContext ,
60
- ) -> FxHashMap < SmolStr , Option < hir:: Documentation > > {
61
- let mut result = FxHashMap :: default ( ) ;
74
+ fn get_derives_in_scope ( ctx : & CompletionContext ) -> Vec < ( hir:: Name , MacroDef ) > {
75
+ let mut result = Vec :: default ( ) ;
62
76
ctx. process_all_names ( & mut |name, scope_def| {
63
77
if let hir:: ScopeDef :: MacroDef ( mac) = scope_def {
64
78
if mac. kind ( ) == hir:: MacroKind :: Derive {
65
- result. insert ( name . to_smol_str ( ) , mac. docs ( ctx . db ) ) ;
79
+ result. push ( ( name , mac) ) ;
66
80
}
67
81
}
68
82
} ) ;
@@ -76,7 +90,7 @@ struct DeriveDependencies {
76
90
77
91
/// Standard Rust derives that have dependencies
78
92
/// (the dependencies are needed so that the main derive don't break the compilation when added)
79
- const DEFAULT_DERIVE_COMPLETIONS : & [ DeriveDependencies ] = & [
93
+ const DEFAULT_DERIVE_DEPENDENCIES : & [ DeriveDependencies ] = & [
80
94
DeriveDependencies { label : "Copy" , dependencies : & [ "Clone" ] } ,
81
95
DeriveDependencies { label : "Eq" , dependencies : & [ "PartialEq" ] } ,
82
96
DeriveDependencies { label : "Ord" , dependencies : & [ "PartialOrd" , "Eq" , "PartialEq" ] } ,
0 commit comments