aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/completion/complete_keyword.rs43
-rw-r--r--crates/ra_analysis/src/completion/complete_path.rs14
-rw-r--r--crates/ra_analysis/src/completion/complete_scope.rs38
-rw-r--r--crates/ra_analysis/src/completion/completion_context.rs22
-rw-r--r--crates/ra_analysis/src/completion/completion_item.rs29
-rw-r--r--crates/ra_analysis/src/imp.rs3
-rw-r--r--crates/ra_analysis/src/lib.rs3
7 files changed, 120 insertions, 32 deletions
diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs
index d1e0a20a8..2869e67e0 100644
--- a/crates/ra_analysis/src/completion/complete_keyword.rs
+++ b/crates/ra_analysis/src/completion/complete_keyword.rs
@@ -35,7 +35,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
35 acc.add(keyword("continue", "continue")); 35 acc.add(keyword("continue", "continue"));
36 acc.add(keyword("break", "break")); 36 acc.add(keyword("break", "break"));
37 } 37 }
38 acc.add_all(complete_return(fn_def, ctx.is_stmt)); 38 acc.add_all(complete_return(fn_def, ctx.can_be_stmt));
39} 39}
40 40
41fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { 41fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool {
@@ -57,8 +57,8 @@ fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool {
57 false 57 false
58} 58}
59 59
60fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem> { 60fn complete_return(fn_def: ast::FnDef, can_be_stmt: bool) -> Option<CompletionItem> {
61 let snip = match (is_stmt, fn_def.ret_type().is_some()) { 61 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
62 (true, true) => "return $0;", 62 (true, true) => "return $0;",
63 (true, false) => "return;", 63 (true, false) => "return;",
64 (false, true) => "return $0", 64 (false, true) => "return $0",
@@ -75,7 +75,7 @@ mod tests {
75 } 75 }
76 76
77 #[test] 77 #[test]
78 fn test_completion_kewords() { 78 fn completes_various_keywords_in_function() {
79 check_keyword_completion( 79 check_keyword_completion(
80 r" 80 r"
81 fn quux() { 81 fn quux() {
@@ -87,13 +87,13 @@ mod tests {
87 match "match $0 {}" 87 match "match $0 {}"
88 while "while $0 {}" 88 while "while $0 {}"
89 loop "loop {$0}" 89 loop "loop {$0}"
90 return "return" 90 return "return;"
91 "#, 91 "#,
92 ); 92 );
93 } 93 }
94 94
95 #[test] 95 #[test]
96 fn test_completion_else() { 96 fn completes_else_after_if() {
97 check_keyword_completion( 97 check_keyword_completion(
98 r" 98 r"
99 fn quux() { 99 fn quux() {
@@ -109,7 +109,7 @@ mod tests {
109 loop "loop {$0}" 109 loop "loop {$0}"
110 else "else {$0}" 110 else "else {$0}"
111 else if "else if $0 {}" 111 else if "else if $0 {}"
112 return "return" 112 return "return;"
113 "#, 113 "#,
114 ); 114 );
115 } 115 }
@@ -149,7 +149,7 @@ mod tests {
149 } 149 }
150 150
151 #[test] 151 #[test]
152 fn test_completion_return_no_stmt() { 152 fn dont_add_semi_after_return_if_not_a_statement() {
153 check_keyword_completion( 153 check_keyword_completion(
154 r" 154 r"
155 fn quux() -> i32 { 155 fn quux() -> i32 {
@@ -169,7 +169,27 @@ mod tests {
169 } 169 }
170 170
171 #[test] 171 #[test]
172 fn test_continue_break_completion() { 172 fn last_return_in_block_has_semi() {
173 check_keyword_completion(
174 r"
175 fn quux() -> i32 {
176 if condition {
177 <|>
178 }
179 }
180 ",
181 r#"
182 if "if $0 {}"
183 match "match $0 {}"
184 while "while $0 {}"
185 loop "loop {$0}"
186 return "return $0;"
187 "#,
188 );
189 }
190
191 #[test]
192 fn completes_break_and_continue_in_loops() {
173 check_keyword_completion( 193 check_keyword_completion(
174 r" 194 r"
175 fn quux() -> i32 { 195 fn quux() -> i32 {
@@ -183,9 +203,10 @@ mod tests {
183 loop "loop {$0}" 203 loop "loop {$0}"
184 continue "continue" 204 continue "continue"
185 break "break" 205 break "break"
186 return "return $0" 206 return "return $0;"
187 "#, 207 "#,
188 ); 208 );
209 // No completion: lambda isolates control flow
189 check_keyword_completion( 210 check_keyword_completion(
190 r" 211 r"
191 fn quux() -> i32 { 212 fn quux() -> i32 {
@@ -197,7 +218,7 @@ mod tests {
197 match "match $0 {}" 218 match "match $0 {}"
198 while "while $0 {}" 219 while "while $0 {}"
199 loop "loop {$0}" 220 loop "loop {$0}"
200 return "return $0" 221 return "return $0;"
201 "#, 222 "#,
202 ); 223 );
203 } 224 }
diff --git a/crates/ra_analysis/src/completion/complete_path.rs b/crates/ra_analysis/src/completion/complete_path.rs
index c73a083a4..4723a65a6 100644
--- a/crates/ra_analysis/src/completion/complete_path.rs
+++ b/crates/ra_analysis/src/completion/complete_path.rs
@@ -17,7 +17,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
17 let module_scope = module.scope(ctx.db)?; 17 let module_scope = module.scope(ctx.db)?;
18 module_scope.entries().for_each(|(name, res)| { 18 module_scope.entries().for_each(|(name, res)| {
19 CompletionItem::new(CompletionKind::Reference, name.to_string()) 19 CompletionItem::new(CompletionKind::Reference, name.to_string())
20 .from_resolution(ctx.db, res) 20 .from_resolution(ctx, res)
21 .add_to(acc) 21 .add_to(acc)
22 }); 22 });
23 } 23 }
@@ -113,4 +113,16 @@ mod tests {
113 "Foo;Bar", 113 "Foo;Bar",
114 ); 114 );
115 } 115 }
116
117 #[test]
118 fn dont_render_function_parens_in_use_item() {
119 check_reference_completion(
120 "
121 //- /lib.rs
122 mod m { pub fn foo() {} }
123 use crate::m::f<|>;
124 ",
125 "foo",
126 )
127 }
116} 128}
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs
index 514fd2f88..daf666505 100644
--- a/crates/ra_analysis/src/completion/complete_scope.rs
+++ b/crates/ra_analysis/src/completion/complete_scope.rs
@@ -34,7 +34,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
34 }) 34 })
35 .for_each(|(name, res)| { 35 .for_each(|(name, res)| {
36 CompletionItem::new(CompletionKind::Reference, name.to_string()) 36 CompletionItem::new(CompletionKind::Reference, name.to_string())
37 .from_resolution(ctx.db, res) 37 .from_resolution(ctx, res)
38 .add_to(acc) 38 .add_to(acc)
39 }); 39 });
40 Ok(()) 40 Ok(())
@@ -74,7 +74,7 @@ mod tests {
74 let z = (); 74 let z = ();
75 } 75 }
76 ", 76 ",
77 "y;x;quux", 77 r#"y;x;quux "quux($0)""#,
78 ); 78 );
79 } 79 }
80 80
@@ -92,7 +92,7 @@ mod tests {
92 } 92 }
93 } 93 }
94 ", 94 ",
95 "b;a;quux", 95 r#"b;a;quux "quux()$0""#,
96 ); 96 );
97 } 97 }
98 98
@@ -106,7 +106,7 @@ mod tests {
106 } 106 }
107 } 107 }
108 ", 108 ",
109 "x;quux", 109 r#"x;quux "quux()$0""#,
110 ); 110 );
111 } 111 }
112 112
@@ -120,7 +120,7 @@ mod tests {
120 <|> 120 <|>
121 } 121 }
122 ", 122 ",
123 "quux;Foo;Baz", 123 r#"quux "quux()$0";Foo;Baz"#,
124 ); 124 );
125 } 125 }
126 126
@@ -134,7 +134,7 @@ mod tests {
134 fn quux() { <|> } 134 fn quux() { <|> }
135 } 135 }
136 ", 136 ",
137 "quux;Bar", 137 r#"quux "quux()$0";Bar"#,
138 ); 138 );
139 } 139 }
140 140
@@ -145,12 +145,12 @@ mod tests {
145 struct Foo; 145 struct Foo;
146 fn x() -> <|> 146 fn x() -> <|>
147 ", 147 ",
148 "Foo;x", 148 r#"Foo;x "x()$0""#,
149 ) 149 )
150 } 150 }
151 151
152 #[test] 152 #[test]
153 fn dont_show_to_completions_for_shadowing() { 153 fn dont_show_both_completions_for_shadowing() {
154 check_reference_completion( 154 check_reference_completion(
155 r" 155 r"
156 fn foo() -> { 156 fn foo() -> {
@@ -161,7 +161,7 @@ mod tests {
161 } 161 }
162 } 162 }
163 ", 163 ",
164 "bar;foo", 164 r#"bar;foo "foo()$0""#,
165 ) 165 )
166 } 166 }
167 167
@@ -169,4 +169,24 @@ mod tests {
169 fn completes_self_in_methods() { 169 fn completes_self_in_methods() {
170 check_reference_completion(r"impl S { fn foo(&self) { <|> } }", "self") 170 check_reference_completion(r"impl S { fn foo(&self) { <|> } }", "self")
171 } 171 }
172
173 #[test]
174 fn inserts_parens_for_function_calls() {
175 check_reference_completion(
176 r"
177 fn no_args() {}
178 fn main() { no_<|> }
179 ",
180 r#"no_args "no_args()$0"
181 main "main()$0""#,
182 );
183 check_reference_completion(
184 r"
185 fn with_args(x: i32, y: String) {}
186 fn main() { with_<|> }
187 ",
188 r#"main "main()$0"
189 with_args "with_args($0)""#,
190 );
191 }
172} 192}
diff --git a/crates/ra_analysis/src/completion/completion_context.rs b/crates/ra_analysis/src/completion/completion_context.rs
index 71bf7fd32..4685c9328 100644
--- a/crates/ra_analysis/src/completion/completion_context.rs
+++ b/crates/ra_analysis/src/completion/completion_context.rs
@@ -24,13 +24,15 @@ pub(super) struct CompletionContext<'a> {
24 pub(super) module: Option<hir::Module>, 24 pub(super) module: Option<hir::Module>,
25 pub(super) function: Option<hir::Function>, 25 pub(super) function: Option<hir::Function>,
26 pub(super) function_syntax: Option<ast::FnDef<'a>>, 26 pub(super) function_syntax: Option<ast::FnDef<'a>>,
27 pub(super) use_item_syntax: Option<ast::UseItem<'a>>,
27 pub(super) is_param: bool, 28 pub(super) is_param: bool,
28 /// A single-indent path, like `foo`. 29 /// A single-indent path, like `foo`.
29 pub(super) is_trivial_path: bool, 30 pub(super) is_trivial_path: bool,
30 /// If not a trivial, path, the prefix (qualifier). 31 /// If not a trivial, path, the prefix (qualifier).
31 pub(super) path_prefix: Option<hir::Path>, 32 pub(super) path_prefix: Option<hir::Path>,
32 pub(super) after_if: bool, 33 pub(super) after_if: bool,
33 pub(super) is_stmt: bool, 34 /// `true` if we are a statement or a last expr in the block.
35 pub(super) can_be_stmt: bool,
34 /// Something is typed at the "top" level, in module or impl/trait. 36 /// Something is typed at the "top" level, in module or impl/trait.
35 pub(super) is_new_item: bool, 37 pub(super) is_new_item: bool,
36 /// The receiver if this is a field or method access, i.e. writing something.<|> 38 /// The receiver if this is a field or method access, i.e. writing something.<|>
@@ -55,11 +57,12 @@ impl<'a> CompletionContext<'a> {
55 module, 57 module,
56 function: None, 58 function: None,
57 function_syntax: None, 59 function_syntax: None,
60 use_item_syntax: None,
58 is_param: false, 61 is_param: false,
59 is_trivial_path: false, 62 is_trivial_path: false,
60 path_prefix: None, 63 path_prefix: None,
61 after_if: false, 64 after_if: false,
62 is_stmt: false, 65 can_be_stmt: false,
63 is_new_item: false, 66 is_new_item: false,
64 dot_receiver: None, 67 dot_receiver: None,
65 is_method_call: false, 68 is_method_call: false,
@@ -114,6 +117,8 @@ impl<'a> CompletionContext<'a> {
114 _ => (), 117 _ => (),
115 } 118 }
116 119
120 self.use_item_syntax = self.leaf.ancestors().find_map(ast::UseItem::cast);
121
117 self.function_syntax = self 122 self.function_syntax = self
118 .leaf 123 .leaf
119 .ancestors() 124 .ancestors()
@@ -143,13 +148,22 @@ impl<'a> CompletionContext<'a> {
143 if path.qualifier().is_none() { 148 if path.qualifier().is_none() {
144 self.is_trivial_path = true; 149 self.is_trivial_path = true;
145 150
146 self.is_stmt = match name_ref 151 self.can_be_stmt = match name_ref
147 .syntax() 152 .syntax()
148 .ancestors() 153 .ancestors()
149 .filter_map(ast::ExprStmt::cast) 154 .filter_map(ast::ExprStmt::cast)
150 .next() 155 .next()
151 { 156 {
152 None => false, 157 None => {
158 name_ref
159 .syntax()
160 .ancestors()
161 .filter_map(ast::Block::cast)
162 .next()
163 .and_then(|block| block.expr())
164 .map(|e| e.syntax().range())
165 == Some(name_ref.syntax().range())
166 }
153 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), 167 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
154 }; 168 };
155 169
diff --git a/crates/ra_analysis/src/completion/completion_item.rs b/crates/ra_analysis/src/completion/completion_item.rs
index 1d294c553..cd4d529f9 100644
--- a/crates/ra_analysis/src/completion/completion_item.rs
+++ b/crates/ra_analysis/src/completion/completion_item.rs
@@ -1,7 +1,7 @@
1use crate::db;
2
3use hir::PerNs; 1use hir::PerNs;
4 2
3use crate::completion::CompletionContext;
4
5/// `CompletionItem` describes a single completion variant in the editor pop-up. 5/// `CompletionItem` describes a single completion variant in the editor pop-up.
6/// It is basically a POD with various properties. To construct a 6/// It is basically a POD with various properties. To construct a
7/// `CompletionItem`, use `new` method and the `Builder` struct. 7/// `CompletionItem`, use `new` method and the `Builder` struct.
@@ -118,12 +118,12 @@ impl Builder {
118 self.kind = Some(kind); 118 self.kind = Some(kind);
119 self 119 self
120 } 120 }
121 pub(crate) fn from_resolution( 121 pub(super) fn from_resolution(
122 mut self, 122 mut self,
123 db: &db::RootDatabase, 123 ctx: &CompletionContext,
124 resolution: &hir::Resolution, 124 resolution: &hir::Resolution,
125 ) -> Builder { 125 ) -> Builder {
126 let resolved = resolution.def_id.and_then(|d| d.resolve(db).ok()); 126 let resolved = resolution.def_id.and_then(|d| d.resolve(ctx.db).ok());
127 let kind = match resolved { 127 let kind = match resolved {
128 PerNs { 128 PerNs {
129 types: Some(hir::Def::Module(..)), 129 types: Some(hir::Def::Module(..)),
@@ -138,14 +138,29 @@ impl Builder {
138 .. 138 ..
139 } => CompletionItemKind::Enum, 139 } => CompletionItemKind::Enum,
140 PerNs { 140 PerNs {
141 values: Some(hir::Def::Function(..)), 141 values: Some(hir::Def::Function(function)),
142 .. 142 ..
143 } => CompletionItemKind::Function, 143 } => return self.from_function(ctx, function),
144 _ => return self, 144 _ => return self,
145 }; 145 };
146 self.kind = Some(kind); 146 self.kind = Some(kind);
147 self 147 self
148 } 148 }
149
150 fn from_function(mut self, ctx: &CompletionContext, function: hir::Function) -> Builder {
151 // If not an import, add parenthesis automatically.
152 if ctx.use_item_syntax.is_none() {
153 if let Some(sig_info) = function.signature_info(ctx.db) {
154 if sig_info.params.is_empty() {
155 self.snippet = Some(format!("{}()$0", self.label));
156 } else {
157 self.snippet = Some(format!("{}($0)", self.label));
158 }
159 }
160 }
161 self.kind = Some(CompletionItemKind::Function);
162 self
163 }
149} 164}
150 165
151impl Into<CompletionItem> for Builder { 166impl Into<CompletionItem> for Builder {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index fcb4cd957..bff2e00c9 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -140,6 +140,9 @@ impl fmt::Debug for AnalysisImpl {
140} 140}
141 141
142impl AnalysisImpl { 142impl AnalysisImpl {
143 pub fn file_text(&self, file_id: FileId) -> Arc<String> {
144 self.db.file_text(file_id)
145 }
143 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { 146 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
144 self.db.source_file(file_id) 147 self.db.source_file(file_id)
145 } 148 }
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 67b1c1482..9f5e9f358 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -274,6 +274,9 @@ pub struct Analysis {
274} 274}
275 275
276impl Analysis { 276impl Analysis {
277 pub fn file_text(&self, file_id: FileId) -> Arc<String> {
278 self.imp.file_text(file_id)
279 }
277 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { 280 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
278 self.imp.file_syntax(file_id).clone() 281 self.imp.file_syntax(file_id).clone()
279 } 282 }