1
1
//! FIXME: write short doc here
2
2
3
+ use hir:: Semantics ;
4
+ use ra_db:: SourceDatabase ;
3
5
use ra_ide_db:: RootDatabase ;
4
6
use ra_syntax:: {
5
7
algo:: { find_covering_element, find_node_at_offset} ,
6
- ast, AstNode , Parse , SourceFile ,
8
+ ast, AstNode , SourceFile ,
7
9
SyntaxKind :: * ,
8
10
SyntaxNode , SyntaxToken , TextRange , TextUnit ,
9
11
} ;
@@ -15,6 +17,7 @@ use crate::FilePosition;
15
17
/// exactly is the cursor, syntax-wise.
16
18
#[ derive( Debug ) ]
17
19
pub ( crate ) struct CompletionContext < ' a > {
20
+ pub ( super ) sema : Semantics < ' a , RootDatabase > ,
18
21
pub ( super ) db : & ' a RootDatabase ,
19
22
pub ( super ) analyzer : hir:: SourceAnalyzer ,
20
23
pub ( super ) offset : TextUnit ,
@@ -51,18 +54,30 @@ pub(crate) struct CompletionContext<'a> {
51
54
impl < ' a > CompletionContext < ' a > {
52
55
pub ( super ) fn new (
53
56
db : & ' a RootDatabase ,
54
- original_parse : & ' a Parse < ast:: SourceFile > ,
55
57
position : FilePosition ,
56
58
) -> Option < CompletionContext < ' a > > {
59
+ let sema = Semantics :: new ( db) ;
60
+
61
+ let original_file = sema. file_syntax ( position. file_id ) ;
62
+
63
+ // Insert a fake ident to get a valid parse tree. We will use this file
64
+ // to determine context, though the original_file will be used for
65
+ // actual completion.
66
+ let file_with_fake_ident = {
67
+ let parse = db. parse ( position. file_id ) ;
68
+ let edit = AtomTextEdit :: insert ( position. offset , "intellijRulezz" . to_string ( ) ) ;
69
+ parse. reparse ( & edit) . tree ( )
70
+ } ;
71
+
57
72
let mut sb = hir:: SourceBinder :: new ( db) ;
58
- let module = sb. to_module_def ( position. file_id ) ;
59
- let token =
60
- original_parse. tree ( ) . syntax ( ) . token_at_offset ( position. offset ) . left_biased ( ) ?;
73
+ let module = sema. to_module_def ( position. file_id ) ;
74
+ let token = original_file. syntax ( ) . token_at_offset ( position. offset ) . left_biased ( ) ?;
61
75
let analyzer = sb. analyze (
62
76
hir:: InFile :: new ( position. file_id . into ( ) , & token. parent ( ) ) ,
63
77
Some ( position. offset ) ,
64
78
) ;
65
79
let mut ctx = CompletionContext {
80
+ sema,
66
81
db,
67
82
analyzer,
68
83
token,
@@ -87,7 +102,7 @@ impl<'a> CompletionContext<'a> {
87
102
has_type_args : false ,
88
103
dot_receiver_is_ambiguous_float_literal : false ,
89
104
} ;
90
- ctx. fill ( & original_parse , position. offset ) ;
105
+ ctx. fill ( & original_file , file_with_fake_ident , position. offset ) ;
91
106
Some ( ctx)
92
107
}
93
108
@@ -100,29 +115,29 @@ impl<'a> CompletionContext<'a> {
100
115
}
101
116
}
102
117
103
- fn fill ( & mut self , original_parse : & ' a Parse < ast:: SourceFile > , offset : TextUnit ) {
104
- // Insert a fake ident to get a valid parse tree. We will use this file
105
- // to determine context, though the original_file will be used for
106
- // actual completion.
107
- let file = {
108
- let edit = AtomTextEdit :: insert ( offset, "intellijRulezz" . to_string ( ) ) ;
109
- original_parse. reparse ( & edit) . tree ( )
110
- } ;
111
-
118
+ fn fill (
119
+ & mut self ,
120
+ original_file : & ast:: SourceFile ,
121
+ file_with_fake_ident : ast:: SourceFile ,
122
+ offset : TextUnit ,
123
+ ) {
112
124
// First, let's try to complete a reference to some declaration.
113
- if let Some ( name_ref) = find_node_at_offset :: < ast:: NameRef > ( file. syntax ( ) , offset) {
125
+ if let Some ( name_ref) =
126
+ find_node_at_offset :: < ast:: NameRef > ( file_with_fake_ident. syntax ( ) , offset)
127
+ {
114
128
// Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
115
129
// See RFC#1685.
116
130
if is_node :: < ast:: Param > ( name_ref. syntax ( ) ) {
117
131
self . is_param = true ;
118
132
return ;
119
133
}
120
- self . classify_name_ref ( original_parse . tree ( ) , name_ref) ;
134
+ self . classify_name_ref ( original_file , name_ref) ;
121
135
}
122
136
123
137
// Otherwise, see if this is a declaration. We can use heuristics to
124
138
// suggest declaration names, see `CompletionKind::Magic`.
125
- if let Some ( name) = find_node_at_offset :: < ast:: Name > ( file. syntax ( ) , offset) {
139
+ if let Some ( name) = find_node_at_offset :: < ast:: Name > ( file_with_fake_ident. syntax ( ) , offset)
140
+ {
126
141
if let Some ( bind_pat) = name. syntax ( ) . ancestors ( ) . find_map ( ast:: BindPat :: cast) {
127
142
let parent = bind_pat. syntax ( ) . parent ( ) ;
128
143
if parent. clone ( ) . and_then ( ast:: MatchArm :: cast) . is_some ( )
@@ -136,13 +151,12 @@ impl<'a> CompletionContext<'a> {
136
151
return ;
137
152
}
138
153
if name. syntax ( ) . ancestors ( ) . find_map ( ast:: RecordFieldPatList :: cast) . is_some ( ) {
139
- self . record_lit_pat =
140
- find_node_at_offset ( original_parse. tree ( ) . syntax ( ) , self . offset ) ;
154
+ self . record_lit_pat = find_node_at_offset ( original_file. syntax ( ) , self . offset ) ;
141
155
}
142
156
}
143
157
}
144
158
145
- fn classify_name_ref ( & mut self , original_file : SourceFile , name_ref : ast:: NameRef ) {
159
+ fn classify_name_ref ( & mut self , original_file : & SourceFile , name_ref : ast:: NameRef ) {
146
160
self . name_ref_syntax =
147
161
find_node_at_offset ( original_file. syntax ( ) , name_ref. syntax ( ) . text_range ( ) . start ( ) ) ;
148
162
let name_range = name_ref. syntax ( ) . text_range ( ) ;
0 commit comments