aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs13
-rw-r--r--crates/ra_ide/src/call_info.rs789
-rw-r--r--crates/ra_ide/src/completion.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs8
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs69
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs36
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs15
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs9
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs1624
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs39
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs4
-rw-r--r--crates/ra_ide/src/completion/presentation.rs87
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs22
-rw-r--r--crates/ra_ide/src/diagnostics.rs733
-rw-r--r--crates/ra_ide/src/display.rs90
-rw-r--r--crates/ra_ide/src/display/function_signature.rs334
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs152
-rw-r--r--crates/ra_ide/src/display/short_label.rs2
-rw-r--r--crates/ra_ide/src/file_structure.rs (renamed from crates/ra_ide/src/display/structure.rs)1
-rw-r--r--crates/ra_ide/src/folding_ranges.rs17
-rw-r--r--crates/ra_ide/src/goto_definition.rs120
-rw-r--r--crates/ra_ide/src/goto_implementation.rs2
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs132
-rw-r--r--crates/ra_ide/src/hover.rs3400
-rw-r--r--crates/ra_ide/src/inlay_hints.rs174
-rw-r--r--crates/ra_ide/src/lib.rs122
-rw-r--r--crates/ra_ide/src/markup.rs38
-rw-r--r--crates/ra_ide/src/mock_analysis.rs20
-rw-r--r--crates/ra_ide/src/references.rs6
-rw-r--r--crates/ra_ide/src/runnables.rs60
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs90
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs5
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs10
-rw-r--r--crates/ra_ide/src/typing.rs1
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs67
41 files changed, 3710 insertions, 4614 deletions
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index 884353808..c28af8ab3 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -95,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
95 if let Some(func_target) = match &call_node { 95 if let Some(func_target) = match &call_node {
96 FnCallNode::CallExpr(expr) => { 96 FnCallNode::CallExpr(expr) => {
97 //FIXME: Type::as_callable is broken 97 //FIXME: Type::as_callable is broken
98 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
99 match callable_def { 99 match callable.kind() {
100 hir::CallableDef::FunctionId(it) => { 100 hir::CallableKind::Function(it) => {
101 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.to_nav(db); 102 let nav = fn_def.to_nav(db);
103 Some(nav) 103 Some(nav)
@@ -109,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
109 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
110 Some(function.to_nav(db)) 110 Some(function.to_nav(db))
111 } 111 }
112 FnCallNode::MacroCallExpr(macro_call) => {
113 let macro_def = sema.resolve_macro_call(&macro_call)?;
114 Some(macro_def.to_nav(db))
115 }
116 } { 112 } {
117 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
118 } else { 114 } else {
@@ -158,7 +154,8 @@ mod tests {
158 let nav = navs.pop().unwrap(); 154 let nav = navs.pop().unwrap();
159 nav.assert_match(expected); 155 nav.assert_match(expected);
160 156
161 let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() }; 157 let item_pos =
158 FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
162 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); 159 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
163 assert_eq!(incoming_calls.len(), expected_incoming.len()); 160 assert_eq!(incoming_calls.len(), expected_incoming.len());
164 161
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index a6bdf1c9d..ff602202f 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,13 +1,43 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use hir::Semantics; 2use either::Either;
3use hir::{Docs, HirDisplay, Semantics, Type};
3use ra_ide_db::RootDatabase; 4use ra_ide_db::RootDatabase;
4use ra_syntax::{ 5use ra_syntax::{
5 ast::{self, ArgListOwner}, 6 ast::{self, ArgListOwner},
6 match_ast, AstNode, SyntaxNode, SyntaxToken, 7 match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize,
7}; 8};
9use stdx::format_to;
8use test_utils::mark; 10use test_utils::mark;
9 11
10use crate::{CallInfo, FilePosition, FunctionSignature}; 12use crate::FilePosition;
13
14/// Contains information about a call site. Specifically the
15/// `FunctionSignature`and current parameter.
16#[derive(Debug)]
17pub struct CallInfo {
18 pub doc: Option<String>,
19 pub signature: String,
20 pub active_parameter: Option<usize>,
21 parameters: Vec<TextRange>,
22}
23
24impl CallInfo {
25 pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
26 self.parameters.iter().map(move |&it| &self.signature[it])
27 }
28 pub fn parameter_ranges(&self) -> &[TextRange] {
29 &self.parameters
30 }
31 fn push_param(&mut self, param: &str) {
32 if !self.signature.ends_with('(') {
33 self.signature.push_str(", ");
34 }
35 let start = TextSize::of(&self.signature);
36 self.signature.push_str(param);
37 let end = TextSize::of(&self.signature);
38 self.parameters.push(TextRange::new(start, end))
39 }
40}
11 41
12/// Computes parameter information for the given call expression. 42/// Computes parameter information for the given call expression.
13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 43pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
@@ -16,106 +46,135 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
16 let file = file.syntax(); 46 let file = file.syntax();
17 let token = file.token_at_offset(position.offset).next()?; 47 let token = file.token_at_offset(position.offset).next()?;
18 let token = sema.descend_into_macros(token); 48 let token = sema.descend_into_macros(token);
19 call_info_for_token(&sema, token)
20}
21 49
22#[derive(Debug)] 50 let (callable, active_parameter) = call_info_impl(&sema, token)?;
23pub(crate) struct ActiveParameter {
24 /// FIXME: should be `Type` and `Name
25 pub(crate) ty: String,
26 pub(crate) name: String,
27}
28 51
29impl ActiveParameter { 52 let mut res =
30 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 53 CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
31 call_info(db, position)?.into_active_parameter() 54
55 match callable.kind() {
56 hir::CallableKind::Function(func) => {
57 res.doc = func.docs(db).map(|it| it.as_str().to_string());
58 format_to!(res.signature, "fn {}", func.name(db));
59 }
60 hir::CallableKind::TupleStruct(strukt) => {
61 res.doc = strukt.docs(db).map(|it| it.as_str().to_string());
62 format_to!(res.signature, "struct {}", strukt.name(db));
63 }
64 hir::CallableKind::TupleEnumVariant(variant) => {
65 res.doc = variant.docs(db).map(|it| it.as_str().to_string());
66 format_to!(
67 res.signature,
68 "enum {}::{}",
69 variant.parent_enum(db).name(db),
70 variant.name(db)
71 );
72 }
73 hir::CallableKind::Closure => (),
32 } 74 }
33 75
34 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 76 res.signature.push('(');
35 call_info_for_token(sema, token)?.into_active_parameter() 77 {
78 if let Some(self_param) = callable.receiver_param(db) {
79 format_to!(res.signature, "{}", self_param)
80 }
81 let mut buf = String::new();
82 for (pat, ty) in callable.params(db) {
83 buf.clear();
84 if let Some(pat) = pat {
85 match pat {
86 Either::Left(_self) => format_to!(buf, "self: "),
87 Either::Right(pat) => format_to!(buf, "{}: ", pat),
88 }
89 }
90 format_to!(buf, "{}", ty.display(db));
91 res.push_param(&buf);
92 }
36 } 93 }
94 res.signature.push(')');
95
96 match callable.kind() {
97 hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
98 let ret_type = callable.return_type();
99 if !ret_type.is_unit() {
100 format_to!(res.signature, " -> {}", ret_type.display(db));
101 }
102 }
103 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
104 }
105 Some(res)
37} 106}
38 107
39fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 108fn call_info_impl(
109 sema: &Semantics<RootDatabase>,
110 token: SyntaxToken,
111) -> Option<(hir::Callable, Option<usize>)> {
40 // Find the calling expression and it's NameRef 112 // Find the calling expression and it's NameRef
41 let calling_node = FnCallNode::with_node(&token.parent())?; 113 let calling_node = FnCallNode::with_node(&token.parent())?;
42 114
43 let (mut call_info, has_self) = match &calling_node { 115 let callable = match &calling_node {
44 FnCallNode::CallExpr(call) => { 116 FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?,
45 //FIXME: Type::as_callable is broken 117 FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?,
46 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; 118 };
47 match callable_def { 119 let active_param = if let Some(arg_list) = calling_node.arg_list() {
48 hir::CallableDef::FunctionId(it) => { 120 // Number of arguments specified at the call site
49 let fn_def = it.into(); 121 let num_args_at_callsite = arg_list.args().count();
50 (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db)) 122
51 } 123 let arg_list_range = arg_list.syntax().text_range();
52 hir::CallableDef::StructId(it) => { 124 if !arg_list_range.contains_inclusive(token.text_range().start()) {
53 (CallInfo::with_struct(sema.db, it.into())?, false) 125 mark::hit!(call_info_bad_offset);
54 } 126 return None;
55 hir::CallableDef::EnumVariantId(it) => {
56 (CallInfo::with_enum_variant(sema.db, it.into())?, false)
57 }
58 }
59 }
60 FnCallNode::MethodCallExpr(method_call) => {
61 let function = sema.resolve_method_call(&method_call)?;
62 (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db))
63 }
64 FnCallNode::MacroCallExpr(macro_call) => {
65 let macro_def = sema.resolve_macro_call(&macro_call)?;
66 (CallInfo::with_macro(sema.db, macro_def)?, false)
67 } 127 }
128 let param = std::cmp::min(
129 num_args_at_callsite,
130 arg_list
131 .args()
132 .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
133 .count(),
134 );
135
136 Some(param)
137 } else {
138 None
68 }; 139 };
140 Some((callable, active_param))
141}
69 142
70 // If we have a calling expression let's find which argument we are on 143#[derive(Debug)]
71 let num_params = call_info.parameters().len(); 144pub(crate) struct ActiveParameter {
145 pub(crate) ty: Type,
146 pub(crate) name: String,
147}
72 148
73 match num_params { 149impl ActiveParameter {
74 0 => (), 150 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
75 1 => { 151 let sema = Semantics::new(db);
76 if !has_self { 152 let file = sema.parse(position.file_id);
77 call_info.active_parameter = Some(0); 153 let file = file.syntax();
78 } 154 let token = file.token_at_offset(position.offset).next()?;
79 } 155 let token = sema.descend_into_macros(token);
80 _ => { 156 Self::at_token(&sema, token)
81 if let Some(arg_list) = calling_node.arg_list() { 157 }
82 // Number of arguments specified at the call site
83 let num_args_at_callsite = arg_list.args().count();
84
85 let arg_list_range = arg_list.syntax().text_range();
86 if !arg_list_range.contains_inclusive(token.text_range().start()) {
87 mark::hit!(call_info_bad_offset);
88 return None;
89 }
90 158
91 let mut param = std::cmp::min( 159 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
92 num_args_at_callsite, 160 let (signature, active_parameter) = call_info_impl(&sema, token)?;
93 arg_list
94 .args()
95 .take_while(|arg| {
96 arg.syntax().text_range().end() < token.text_range().start()
97 })
98 .count(),
99 );
100
101 // If we are in a method account for `self`
102 if has_self {
103 param += 1;
104 }
105 161
106 call_info.active_parameter = Some(param); 162 let idx = active_parameter?;
107 } 163 let mut params = signature.params(sema.db);
164 if !(idx < params.len()) {
165 mark::hit!(too_many_arguments);
166 return None;
108 } 167 }
168 let (pat, ty) = params.swap_remove(idx);
169 let name = pat?.to_string();
170 Some(ActiveParameter { ty, name })
109 } 171 }
110
111 Some(call_info)
112} 172}
113 173
114#[derive(Debug)] 174#[derive(Debug)]
115pub(crate) enum FnCallNode { 175pub(crate) enum FnCallNode {
116 CallExpr(ast::CallExpr), 176 CallExpr(ast::CallExpr),
117 MethodCallExpr(ast::MethodCallExpr), 177 MethodCallExpr(ast::MethodCallExpr),
118 MacroCallExpr(ast::MacroCall),
119} 178}
120 179
121impl FnCallNode { 180impl FnCallNode {
@@ -131,7 +190,6 @@ impl FnCallNode {
131 } 190 }
132 Some(FnCallNode::MethodCallExpr(it)) 191 Some(FnCallNode::MethodCallExpr(it))
133 }, 192 },
134 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
135 _ => None, 193 _ => None,
136 } 194 }
137 } 195 }
@@ -143,7 +201,6 @@ impl FnCallNode {
143 match node { 201 match node {
144 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 202 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
145 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), 203 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)),
146 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
147 _ => None, 204 _ => None,
148 } 205 }
149 } 206 }
@@ -159,8 +216,6 @@ impl FnCallNode {
159 FnCallNode::MethodCallExpr(call_expr) => { 216 FnCallNode::MethodCallExpr(call_expr) => {
160 call_expr.syntax().children().filter_map(ast::NameRef::cast).next() 217 call_expr.syntax().children().filter_map(ast::NameRef::cast).next()
161 } 218 }
162
163 FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(),
164 } 219 }
165 } 220 }
166 221
@@ -168,214 +223,209 @@ impl FnCallNode {
168 match self { 223 match self {
169 FnCallNode::CallExpr(expr) => expr.arg_list(), 224 FnCallNode::CallExpr(expr) => expr.arg_list(),
170 FnCallNode::MethodCallExpr(expr) => expr.arg_list(), 225 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
171 FnCallNode::MacroCallExpr(_) => None,
172 } 226 }
173 } 227 }
174} 228}
175 229
176impl CallInfo {
177 fn into_active_parameter(self) -> Option<ActiveParameter> {
178 let idx = self.active_parameter?;
179 let ty = self.signature.parameter_types.get(idx)?.clone();
180 let name = self.signature.parameter_names.get(idx)?.clone();
181 let res = ActiveParameter { ty, name };
182 Some(res)
183 }
184
185 fn with_fn(db: &RootDatabase, function: hir::Function) -> Self {
186 let signature = FunctionSignature::from_hir(db, function);
187
188 CallInfo { signature, active_parameter: None }
189 }
190
191 fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
192 let signature = FunctionSignature::from_struct(db, st)?;
193
194 Some(CallInfo { signature, active_parameter: None })
195 }
196
197 fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
198 let signature = FunctionSignature::from_enum_variant(db, variant)?;
199
200 Some(CallInfo { signature, active_parameter: None })
201 }
202
203 fn with_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
204 let signature = FunctionSignature::from_macro(db, macro_def)?;
205
206 Some(CallInfo { signature, active_parameter: None })
207 }
208
209 fn parameters(&self) -> &[String] {
210 &self.signature.parameters
211 }
212}
213
214#[cfg(test)] 230#[cfg(test)]
215mod tests { 231mod tests {
232 use expect::{expect, Expect};
216 use test_utils::mark; 233 use test_utils::mark;
217 234
218 use crate::mock_analysis::analysis_and_position; 235 use crate::mock_analysis::analysis_and_position;
219 236
220 use super::*; 237 fn check(ra_fixture: &str, expect: Expect) {
221 238 let (analysis, position) = analysis_and_position(ra_fixture);
222 // These are only used when testing 239 let call_info = analysis.call_info(position).unwrap();
223 impl CallInfo { 240 let actual = match call_info {
224 fn doc(&self) -> Option<hir::Documentation> { 241 Some(call_info) => {
225 self.signature.doc.clone() 242 let docs = match &call_info.doc {
226 } 243 None => "".to_string(),
227 244 Some(docs) => format!("{}\n------\n", docs.as_str()),
228 fn label(&self) -> String { 245 };
229 self.signature.to_string() 246 let params = call_info
230 } 247 .parameter_labels()
231 } 248 .enumerate()
232 249 .map(|(i, param)| {
233 fn call_info_helper(text: &str) -> Option<CallInfo> { 250 if Some(i) == call_info.active_parameter {
234 let (analysis, position) = analysis_and_position(text); 251 format!("<{}>", param)
235 analysis.call_info(position).unwrap() 252 } else {
236 } 253 param.to_string()
237 254 }
238 fn call_info(text: &str) -> CallInfo { 255 })
239 let info = call_info_helper(text); 256 .collect::<Vec<_>>()
240 assert!(info.is_some()); 257 .join(", ");
241 info.unwrap() 258 format!("{}{}\n({})\n", docs, call_info.signature, params)
242 } 259 }
243 260 None => String::new(),
244 fn no_call_info(text: &str) { 261 };
245 let info = call_info_helper(text); 262 expect.assert_eq(&actual);
246 assert!(info.is_none());
247 } 263 }
248 264
249 #[test] 265 #[test]
250 fn test_fn_signature_two_args_firstx() { 266 fn test_fn_signature_two_args() {
251 let info = call_info( 267 check(
252 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 268 r#"
253fn bar() { foo(<|>3, ); }"#, 269fn foo(x: u32, y: u32) -> u32 {x + y}
270fn bar() { foo(<|>3, ); }
271"#,
272 expect![[r#"
273 fn foo(x: u32, y: u32) -> u32
274 (<x: u32>, y: u32)
275 "#]],
254 ); 276 );
255 277 check(
256 assert_eq!(info.parameters(), ["x: u32", "y: u32"]); 278 r#"
257 assert_eq!(info.active_parameter, Some(0)); 279fn foo(x: u32, y: u32) -> u32 {x + y}
258 } 280fn bar() { foo(3<|>, ); }
259 281"#,
260 #[test] 282 expect![[r#"
261 fn test_fn_signature_two_args_second() { 283 fn foo(x: u32, y: u32) -> u32
262 let info = call_info( 284 (<x: u32>, y: u32)
263 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 285 "#]],
264fn bar() { foo(3, <|>); }"#, 286 );
287 check(
288 r#"
289fn foo(x: u32, y: u32) -> u32 {x + y}
290fn bar() { foo(3,<|> ); }
291"#,
292 expect![[r#"
293 fn foo(x: u32, y: u32) -> u32
294 (x: u32, <y: u32>)
295 "#]],
296 );
297 check(
298 r#"
299fn foo(x: u32, y: u32) -> u32 {x + y}
300fn bar() { foo(3, <|>); }
301"#,
302 expect![[r#"
303 fn foo(x: u32, y: u32) -> u32
304 (x: u32, <y: u32>)
305 "#]],
265 ); 306 );
266
267 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
268 assert_eq!(info.active_parameter, Some(1));
269 } 307 }
270 308
271 #[test] 309 #[test]
272 fn test_fn_signature_two_args_empty() { 310 fn test_fn_signature_two_args_empty() {
273 let info = call_info( 311 check(
274 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 312 r#"
275fn bar() { foo(<|>); }"#, 313fn foo(x: u32, y: u32) -> u32 {x + y}
314fn bar() { foo(<|>); }
315"#,
316 expect![[r#"
317 fn foo(x: u32, y: u32) -> u32
318 (<x: u32>, y: u32)
319 "#]],
276 ); 320 );
277
278 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
279 assert_eq!(info.active_parameter, Some(0));
280 } 321 }
281 322
282 #[test] 323 #[test]
283 fn test_fn_signature_two_args_first_generics() { 324 fn test_fn_signature_two_args_first_generics() {
284 let info = call_info( 325 check(
285 r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
286fn bar() { foo(<|>3, ); }"#,
287 );
288
289 assert_eq!(info.parameters(), ["x: T", "y: U"]);
290 assert_eq!(
291 info.label(),
292 r#" 326 r#"
293fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 327fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
294where T: Copy + Display, 328 where T: Copy + Display, U: Debug
295 U: Debug 329{ x + y }
296 "# 330
297 .trim() 331fn bar() { foo(<|>3, ); }
332"#,
333 expect![[r#"
334 fn foo(x: i32, y: {unknown}) -> u32
335 (<x: i32>, y: {unknown})
336 "#]],
298 ); 337 );
299 assert_eq!(info.active_parameter, Some(0));
300 } 338 }
301 339
302 #[test] 340 #[test]
303 fn test_fn_signature_no_params() { 341 fn test_fn_signature_no_params() {
304 let info = call_info( 342 check(
305 r#"fn foo<T>() -> T where T: Copy + Display {}
306fn bar() { foo(<|>); }"#,
307 );
308
309 assert!(info.parameters().is_empty());
310 assert_eq!(
311 info.label(),
312 r#" 343 r#"
313fn foo<T>() -> T 344fn foo<T>() -> T where T: Copy + Display {}
314where T: Copy + Display 345fn bar() { foo(<|>); }
315 "# 346"#,
316 .trim() 347 expect![[r#"
348 fn foo() -> {unknown}
349 ()
350 "#]],
317 ); 351 );
318 assert!(info.active_parameter.is_none());
319 } 352 }
320 353
321 #[test] 354 #[test]
322 fn test_fn_signature_for_impl() { 355 fn test_fn_signature_for_impl() {
323 let info = call_info( 356 check(
324 r#"struct F; impl F { pub fn new() { F{}} } 357 r#"
325fn bar() {let _ : F = F::new(<|>);}"#, 358struct F;
359impl F { pub fn new() { } }
360fn bar() {
361 let _ : F = F::new(<|>);
362}
363"#,
364 expect![[r#"
365 fn new()
366 ()
367 "#]],
326 ); 368 );
327
328 assert!(info.parameters().is_empty());
329 assert_eq!(info.active_parameter, None);
330 } 369 }
331 370
332 #[test] 371 #[test]
333 fn test_fn_signature_for_method_self() { 372 fn test_fn_signature_for_method_self() {
334 let info = call_info( 373 check(
335 r#"struct F; 374 r#"
336impl F { 375struct S;
337 pub fn new() -> F{ 376impl S { pub fn do_it(&self) {} }
338 F{}
339 }
340
341 pub fn do_it(&self) {}
342}
343 377
344fn bar() { 378fn bar() {
345 let f : F = F::new(); 379 let s: S = S;
346 f.do_it(<|>); 380 s.do_it(<|>);
347}"#, 381}
382"#,
383 expect![[r#"
384 fn do_it(&self)
385 ()
386 "#]],
348 ); 387 );
349
350 assert_eq!(info.parameters(), ["&self"]);
351 assert_eq!(info.active_parameter, None);
352 } 388 }
353 389
354 #[test] 390 #[test]
355 fn test_fn_signature_for_method_with_arg() { 391 fn test_fn_signature_for_method_with_arg() {
356 let info = call_info( 392 check(
357 r#"struct F; 393 r#"
358impl F { 394struct S;
359 pub fn new() -> F{ 395impl S {
360 F{} 396 fn foo(&self, x: i32) {}
397}
398
399fn main() { S.foo(<|>); }
400"#,
401 expect![[r#"
402 fn foo(&self, x: i32)
403 (<x: i32>)
404 "#]],
405 );
361 } 406 }
362 407
363 pub fn do_it(&self, x: i32) {} 408 #[test]
409 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
410 check(
411 r#"
412struct S;
413impl S {
414 fn foo(&self, x: i32) {}
364} 415}
365 416
366fn bar() { 417fn main() { S::foo(<|>); }
367 let f : F = F::new(); 418"#,
368 f.do_it(<|>); 419 expect![[r#"
369}"#, 420 fn foo(self: &S, x: i32)
421 (<self: &S>, x: i32)
422 "#]],
370 ); 423 );
371
372 assert_eq!(info.parameters(), ["&self", "x: i32"]);
373 assert_eq!(info.active_parameter, Some(1));
374 } 424 }
375 425
376 #[test] 426 #[test]
377 fn test_fn_signature_with_docs_simple() { 427 fn test_fn_signature_with_docs_simple() {
378 let info = call_info( 428 check(
379 r#" 429 r#"
380/// test 430/// test
381// non-doc-comment 431// non-doc-comment
@@ -387,17 +437,18 @@ fn bar() {
387 let _ = foo(<|>); 437 let _ = foo(<|>);
388} 438}
389"#, 439"#,
440 expect![[r#"
441 test
442 ------
443 fn foo(j: u32) -> u32
444 (<j: u32>)
445 "#]],
390 ); 446 );
391
392 assert_eq!(info.parameters(), ["j: u32"]);
393 assert_eq!(info.active_parameter, Some(0));
394 assert_eq!(info.label(), "fn foo(j: u32) -> u32");
395 assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
396 } 447 }
397 448
398 #[test] 449 #[test]
399 fn test_fn_signature_with_docs() { 450 fn test_fn_signature_with_docs() {
400 let info = call_info( 451 check(
401 r#" 452 r#"
402/// Adds one to the number given. 453/// Adds one to the number given.
403/// 454///
@@ -415,31 +466,26 @@ pub fn add_one(x: i32) -> i32 {
415pub fn do() { 466pub fn do() {
416 add_one(<|> 467 add_one(<|>
417}"#, 468}"#,
418 ); 469 expect![[r##"
419 470 Adds one to the number given.
420 assert_eq!(info.parameters(), ["x: i32"]);
421 assert_eq!(info.active_parameter, Some(0));
422 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
423 assert_eq!(
424 info.doc().map(|it| it.into()),
425 Some(
426 r#"Adds one to the number given.
427 471
428# Examples 472 # Examples
429 473
430``` 474 ```
431let five = 5; 475 let five = 5;
432 476
433assert_eq!(6, my_crate::add_one(5)); 477 assert_eq!(6, my_crate::add_one(5));
434```"# 478 ```
435 .to_string() 479 ------
436 ) 480 fn add_one(x: i32) -> i32
481 (<x: i32>)
482 "##]],
437 ); 483 );
438 } 484 }
439 485
440 #[test] 486 #[test]
441 fn test_fn_signature_with_docs_impl() { 487 fn test_fn_signature_with_docs_impl() {
442 let info = call_info( 488 check(
443 r#" 489 r#"
444struct addr; 490struct addr;
445impl addr { 491impl addr {
@@ -460,32 +506,28 @@ impl addr {
460pub fn do_it() { 506pub fn do_it() {
461 addr {}; 507 addr {};
462 addr::add_one(<|>); 508 addr::add_one(<|>);
463}"#, 509}
464 ); 510"#,
465 511 expect![[r##"
466 assert_eq!(info.parameters(), ["x: i32"]); 512 Adds one to the number given.
467 assert_eq!(info.active_parameter, Some(0));
468 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
469 assert_eq!(
470 info.doc().map(|it| it.into()),
471 Some(
472 r#"Adds one to the number given.
473 513
474# Examples 514 # Examples
475 515
476``` 516 ```
477let five = 5; 517 let five = 5;
478 518
479assert_eq!(6, my_crate::add_one(5)); 519 assert_eq!(6, my_crate::add_one(5));
480```"# 520 ```
481 .to_string() 521 ------
482 ) 522 fn add_one(x: i32) -> i32
523 (<x: i32>)
524 "##]],
483 ); 525 );
484 } 526 }
485 527
486 #[test] 528 #[test]
487 fn test_fn_signature_with_docs_from_actix() { 529 fn test_fn_signature_with_docs_from_actix() {
488 let info = call_info( 530 check(
489 r#" 531 r#"
490struct WriteHandler<E>; 532struct WriteHandler<E>;
491 533
@@ -509,101 +551,89 @@ impl<E> WriteHandler<E> {
509pub fn foo(mut r: WriteHandler<()>) { 551pub fn foo(mut r: WriteHandler<()>) {
510 r.finished(<|>); 552 r.finished(<|>);
511} 553}
512
513"#, 554"#,
514 ); 555 expect![[r#"
515 556 Method is called when writer finishes.
516 assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); 557
517 assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); 558 By default this method stops actor's `Context`.
518 assert_eq!(info.active_parameter, Some(1)); 559 ------
519 assert_eq!( 560 fn finished(&mut self, ctx: &mut {unknown})
520 info.doc().map(|it| it.into()), 561 (<ctx: &mut {unknown}>)
521 Some( 562 "#]],
522 r#"Method is called when writer finishes.
523
524By default this method stops actor's `Context`."#
525 .to_string()
526 )
527 ); 563 );
528 } 564 }
529 565
530 #[test] 566 #[test]
531 fn call_info_bad_offset() { 567 fn call_info_bad_offset() {
532 mark::check!(call_info_bad_offset); 568 mark::check!(call_info_bad_offset);
533 let (analysis, position) = analysis_and_position( 569 check(
534 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 570 r#"
535 fn bar() { foo <|> (3, ); }"#, 571fn foo(x: u32, y: u32) -> u32 {x + y}
572fn bar() { foo <|> (3, ); }
573"#,
574 expect![[""]],
536 ); 575 );
537 let call_info = analysis.call_info(position).unwrap();
538 assert!(call_info.is_none());
539 } 576 }
540 577
541 #[test] 578 #[test]
542 fn test_nested_method_in_lamba() { 579 fn test_nested_method_in_lambda() {
543 let info = call_info( 580 check(
544 r#"struct Foo; 581 r#"
545 582struct Foo;
546impl Foo { 583impl Foo { fn bar(&self, _: u32) { } }
547 fn bar(&self, _: u32) { }
548}
549 584
550fn bar(_: u32) { } 585fn bar(_: u32) { }
551 586
552fn main() { 587fn main() {
553 let foo = Foo; 588 let foo = Foo;
554 std::thread::spawn(move || foo.bar(<|>)); 589 std::thread::spawn(move || foo.bar(<|>));
555}"#, 590}
591"#,
592 expect![[r#"
593 fn bar(&self, _: u32)
594 (<_: u32>)
595 "#]],
556 ); 596 );
557
558 assert_eq!(info.parameters(), ["&self", "_: u32"]);
559 assert_eq!(info.active_parameter, Some(1));
560 assert_eq!(info.label(), "fn bar(&self, _: u32)");
561 } 597 }
562 598
563 #[test] 599 #[test]
564 fn works_for_tuple_structs() { 600 fn works_for_tuple_structs() {
565 let info = call_info( 601 check(
566 r#" 602 r#"
567/// A cool tuple struct 603/// A cool tuple struct
568struct TS(u32, i32); 604struct S(u32, i32);
569fn main() { 605fn main() {
570 let s = TS(0, <|>); 606 let s = S(0, <|>);
571}"#, 607}
608"#,
609 expect![[r#"
610 A cool tuple struct
611 ------
612 struct S(u32, i32)
613 (u32, <i32>)
614 "#]],
572 ); 615 );
573
574 assert_eq!(info.label(), "struct TS(u32, i32) -> TS");
575 assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string()));
576 assert_eq!(info.active_parameter, Some(1));
577 } 616 }
578 617
579 #[test] 618 #[test]
580 fn generic_struct() { 619 fn generic_struct() {
581 let info = call_info( 620 check(
582 r#" 621 r#"
583struct TS<T>(T); 622struct S<T>(T);
584fn main() { 623fn main() {
585 let s = TS(<|>); 624 let s = S(<|>);
586}"#, 625}
587 ); 626"#,
588 627 expect![[r#"
589 assert_eq!(info.label(), "struct TS<T>(T) -> TS"); 628 struct S({unknown})
590 assert_eq!(info.active_parameter, Some(0)); 629 (<{unknown}>)
591 } 630 "#]],
592
593 #[test]
594 fn cant_call_named_structs() {
595 no_call_info(
596 r#"
597struct TS { x: u32, y: i32 }
598fn main() {
599 let s = TS(<|>);
600}"#,
601 ); 631 );
602 } 632 }
603 633
604 #[test] 634 #[test]
605 fn works_for_enum_variants() { 635 fn works_for_enum_variants() {
606 let info = call_info( 636 check(
607 r#" 637 r#"
608enum E { 638enum E {
609 /// A Variant 639 /// A Variant
@@ -617,17 +647,32 @@ enum E {
617fn main() { 647fn main() {
618 let a = E::A(<|>); 648 let a = E::A(<|>);
619} 649}
620 "#, 650"#,
651 expect![[r#"
652 A Variant
653 ------
654 enum E::A(i32)
655 (<i32>)
656 "#]],
621 ); 657 );
658 }
622 659
623 assert_eq!(info.label(), "E::A(0: i32)"); 660 #[test]
624 assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); 661 fn cant_call_struct_record() {
625 assert_eq!(info.active_parameter, Some(0)); 662 check(
663 r#"
664struct S { x: u32, y: i32 }
665fn main() {
666 let s = S(<|>);
667}
668"#,
669 expect![[""]],
670 );
626 } 671 }
627 672
628 #[test] 673 #[test]
629 fn cant_call_enum_records() { 674 fn cant_call_enum_record() {
630 no_call_info( 675 check(
631 r#" 676 r#"
632enum E { 677enum E {
633 /// A Variant 678 /// A Variant
@@ -641,47 +686,57 @@ enum E {
641fn main() { 686fn main() {
642 let a = E::C(<|>); 687 let a = E::C(<|>);
643} 688}
644 "#, 689"#,
690 expect![[""]],
645 ); 691 );
646 } 692 }
647 693
648 #[test] 694 #[test]
649 fn fn_signature_for_macro() { 695 fn fn_signature_for_call_in_macro() {
650 let info = call_info( 696 check(
651 r#" 697 r#"
652/// empty macro 698macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
653macro_rules! foo { 699fn foo() { }
654 () => {} 700id! {
701 fn bar() { foo(<|>); }
655} 702}
703"#,
704 expect![[r#"
705 fn foo()
706 ()
707 "#]],
708 );
709 }
656 710
657fn f() { 711 #[test]
658 foo!(<|>); 712 fn call_info_for_lambdas() {
713 check(
714 r#"
715struct S;
716fn foo(s: S) -> i32 { 92 }
717fn main() {
718 (|s| foo(s))(<|>)
659} 719}
660 "#, 720 "#,
661 ); 721 expect![[r#"
662 722 (S) -> i32
663 assert_eq!(info.label(), "foo!()"); 723 (<S>)
664 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 724 "#]],
725 )
665 } 726 }
666 727
667 #[test] 728 #[test]
668 fn fn_signature_for_call_in_macro() { 729 fn call_info_for_fn_ptr() {
669 let info = call_info( 730 check(
670 r#" 731 r#"
671 macro_rules! id { 732fn main(f: fn(i32, f64) -> char) {
672 ($($tt:tt)*) => { $($tt)* } 733 f(0, <|>)
673 } 734}
674 fn foo() { 735 "#,
675 736 expect![[r#"
676 } 737 (i32, f64) -> char
677 id! { 738 (i32, <f64>)
678 fn bar() { 739 "#]],
679 foo(<|>); 740 )
680 }
681 }
682 "#,
683 );
684
685 assert_eq!(info.label(), "fn foo()");
686 } 741 }
687} 742}
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index f3a5e9573..68ac05e4c 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -63,7 +63,7 @@ pub use crate::completion::{
63// There also snippet completions: 63// There also snippet completions:
64// 64//
65// .Expressions 65// .Expressions
66// - `pd` -> `eprintln!(" = {:?}", );")` 66// - `pd` -> `eprintln!(" = {:?}", );`
67// - `ppd` -> `eprintln!(" = {:#?}", );` 67// - `ppd` -> `eprintln!(" = {:#?}", );`
68// 68//
69// .Items 69// .Items
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index 9db317509..d268c92be 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -85,7 +85,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[
85 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), 85 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
86 // FIXME: resolve through macro resolution? 86 // FIXME: resolve through macro resolution?
87 attr("global_allocator", None, None).prefer_inner(), 87 attr("global_allocator", None, None).prefer_inner(),
88 attr("ignore()", Some("ignore"), Some("ignore(${0:lint})")), 88 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
89 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), 89 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
90 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), 90 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
91 attr("link", None, None), 91 attr("link", None, None),
@@ -195,7 +195,7 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>,
195 195
196fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 196fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
197 let mut result = FxHashSet::default(); 197 let mut result = FxHashSet::default();
198 ctx.scope().process_all_names(&mut |name, scope_def| { 198 ctx.scope.process_all_names(&mut |name, scope_def| {
199 if let hir::ScopeDef::MacroDef(mac) = scope_def { 199 if let hir::ScopeDef::MacroDef(mac) = scope_def {
200 if mac.is_derive_macro() { 200 if mac.is_derive_macro() {
201 result.insert(name.to_string()); 201 result.insert(name.to_string());
@@ -300,7 +300,7 @@ struct Test {}
300 at derive(…) 300 at derive(…)
301 at doc = "…" 301 at doc = "…"
302 at forbid(…) 302 at forbid(…)
303 at ignore() 303 at ignore = ""
304 at inline(…) 304 at inline(…)
305 at link 305 at link
306 at link_name = "…" 306 at link_name = "…"
@@ -343,7 +343,7 @@ struct Test {}
343 at feature(…) 343 at feature(…)
344 at forbid(…) 344 at forbid(…)
345 at global_allocator 345 at global_allocator
346 at ignore() 346 at ignore = ""
347 at inline(…) 347 at inline(…)
348 at link 348 at link
349 at link_name = "…" 349 at link_name = "…"
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 3c6c8c81a..532665285 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -29,7 +29,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
29fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 29fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
30 for receiver in receiver.autoderef(ctx.db) { 30 for receiver in receiver.autoderef(ctx.db) {
31 for (field, ty) in receiver.fields(ctx.db) { 31 for (field, ty) in receiver.fields(ctx.db) {
32 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { 32 if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
33 // Skip private field. FIXME: If the definition location of the 33 // Skip private field. FIXME: If the definition location of the
34 // field is editable, we should show the completion 34 // field is editable, we should show the completion
35 continue; 35 continue;
@@ -46,10 +46,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
46fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 46fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
47 if let Some(krate) = ctx.krate { 47 if let Some(krate) = ctx.krate {
48 let mut seen_methods = FxHashSet::default(); 48 let mut seen_methods = FxHashSet::default();
49 let traits_in_scope = ctx.scope().traits_in_scope(); 49 let traits_in_scope = ctx.scope.traits_in_scope();
50 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { 50 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
51 if func.has_self_param(ctx.db) 51 if func.has_self_param(ctx.db)
52 && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) 52 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
53 && seen_methods.insert(func.name(ctx.db)) 53 && seen_methods.insert(func.name(ctx.db))
54 { 54 {
55 acc.add_function(ctx, func, None); 55 acc.add_function(ctx, func, None);
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs
index 9fb5c050e..db2abb4f1 100644
--- a/crates/ra_ide/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide/src/completion/complete_fn_param.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `complete_fn_param`.
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, ModuleItemOwner}, 4 ast::{self, ModuleItemOwner},
@@ -18,6 +18,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
18 } 18 }
19 19
20 let mut params = FxHashMap::default(); 20 let mut params = FxHashMap::default();
21 let me = ctx.token.ancestors().find_map(ast::FnDef::cast);
21 for node in ctx.token.parent().ancestors() { 22 for node in ctx.token.parent().ancestors() {
22 let items = match_ast! { 23 let items = match_ast! {
23 match node { 24 match node {
@@ -28,25 +29,26 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
28 }; 29 };
29 for item in items { 30 for item in items {
30 if let ast::ModuleItem::FnDef(func) = item { 31 if let ast::ModuleItem::FnDef(func) = item {
32 if Some(&func) == me.as_ref() {
33 continue;
34 }
31 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { 35 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32 let text = param.syntax().text().to_string(); 36 let text = param.syntax().text().to_string();
33 params.entry(text).or_insert((0, param)).0 += 1; 37 params.entry(text).or_insert(param);
34 }) 38 })
35 } 39 }
36 } 40 }
37 } 41 }
42
38 params 43 params
39 .into_iter() 44 .into_iter()
40 .filter_map(|(label, (count, param))| { 45 .filter_map(|(label, param)| {
41 let lookup = param.pat()?.syntax().text().to_string(); 46 let lookup = param.pat()?.syntax().text().to_string();
42 if count < 2 { 47 Some((label, lookup))
43 None
44 } else {
45 Some((label, lookup))
46 }
47 }) 48 })
48 .for_each(|(label, lookup)| { 49 .for_each(|(label, lookup)| {
49 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 50 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
51 .kind(crate::CompletionItemKind::Binding)
50 .lookup_by(lookup) 52 .lookup_by(lookup)
51 .add_to(acc) 53 .add_to(acc)
52 }); 54 });
@@ -56,11 +58,11 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
56mod tests { 58mod tests {
57 use expect::{expect, Expect}; 59 use expect::{expect, Expect};
58 60
59 use crate::completion::{test_utils::do_completion, CompletionKind}; 61 use crate::completion::{test_utils::completion_list, CompletionKind};
60 62
61 fn check(ra_fixture: &str, expect: Expect) { 63 fn check(ra_fixture: &str, expect: Expect) {
62 let actual = do_completion(ra_fixture, CompletionKind::Magic); 64 let actual = completion_list(ra_fixture, CompletionKind::Magic);
63 expect.assert_debug_eq(&actual); 65 expect.assert_eq(&actual);
64 } 66 }
65 67
66 #[test] 68 #[test]
@@ -72,15 +74,7 @@ fn bar(file_id: FileId) {}
72fn baz(file<|>) {} 74fn baz(file<|>) {}
73"#, 75"#,
74 expect![[r#" 76 expect![[r#"
75 [ 77 bn file_id: FileId
76 CompletionItem {
77 label: "file_id: FileId",
78 source_range: 61..65,
79 delete: 61..65,
80 insert: "file_id: FileId",
81 lookup: "file_id",
82 },
83 ]
84 "#]], 78 "#]],
85 ); 79 );
86 } 80 }
@@ -90,19 +84,10 @@ fn baz(file<|>) {}
90 check( 84 check(
91 r#" 85 r#"
92fn foo(file_id: FileId) {} 86fn foo(file_id: FileId) {}
93fn bar(file_id: FileId) {}
94fn baz(file<|>, x: i32) {} 87fn baz(file<|>, x: i32) {}
95"#, 88"#,
96 expect![[r#" 89 expect![[r#"
97 [ 90 bn file_id: FileId
98 CompletionItem {
99 label: "file_id: FileId",
100 source_range: 61..65,
101 delete: 61..65,
102 insert: "file_id: FileId",
103 lookup: "file_id",
104 },
105 ]
106 "#]], 91 "#]],
107 ); 92 );
108 } 93 }
@@ -119,16 +104,22 @@ pub(crate) trait SourceRoot {
119} 104}
120"#, 105"#,
121 expect![[r#" 106 expect![[r#"
122 [ 107 bn file_id: FileId
123 CompletionItem {
124 label: "file_id: FileId",
125 source_range: 208..212,
126 delete: 208..212,
127 insert: "file_id: FileId",
128 lookup: "file_id",
129 },
130 ]
131 "#]], 108 "#]],
132 ); 109 );
133 } 110 }
111
112 #[test]
113 fn completes_param_in_inner_function() {
114 check(
115 r#"
116fn outer(text: String) {
117 fn inner(<|>)
118}
119"#,
120 expect![[r#"
121 bn text: String
122 "#]],
123 )
124 }
134} 125}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 2dc401f57..fcdaeef49 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -88,24 +88,22 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
88 88
89 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent { 89 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
90 add_keyword(ctx, acc, "enum", "enum $0 {}"); 90 add_keyword(ctx, acc, "enum", "enum $0 {}");
91 add_keyword(ctx, acc, "struct", "struct $0 {}"); 91 add_keyword(ctx, acc, "struct", "struct $0");
92 add_keyword(ctx, acc, "union", "union $0 {}"); 92 add_keyword(ctx, acc, "union", "union $0 {}");
93 } 93 }
94 94
95 if ctx.block_expr_parent || ctx.is_match_arm { 95 if ctx.is_expr {
96 add_keyword(ctx, acc, "match", "match $0 {}"); 96 add_keyword(ctx, acc, "match", "match $0 {}");
97 add_keyword(ctx, acc, "loop", "loop {$0}");
98 }
99 if ctx.block_expr_parent {
100 add_keyword(ctx, acc, "while", "while $0 {}"); 97 add_keyword(ctx, acc, "while", "while $0 {}");
98 add_keyword(ctx, acc, "loop", "loop {$0}");
99 add_keyword(ctx, acc, "if", "if ");
100 add_keyword(ctx, acc, "if let", "if let ");
101 } 101 }
102
102 if ctx.if_is_prev || ctx.block_expr_parent { 103 if ctx.if_is_prev || ctx.block_expr_parent {
103 add_keyword(ctx, acc, "let", "let "); 104 add_keyword(ctx, acc, "let", "let ");
104 } 105 }
105 if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm { 106
106 add_keyword(ctx, acc, "if", "if ");
107 add_keyword(ctx, acc, "if let", "if let ");
108 }
109 if ctx.after_if { 107 if ctx.after_if {
110 add_keyword(ctx, acc, "else", "else {$0}"); 108 add_keyword(ctx, acc, "else", "else {$0}");
111 add_keyword(ctx, acc, "else if", "else if $0 {}"); 109 add_keyword(ctx, acc, "else if", "else if $0 {}");
@@ -343,9 +341,7 @@ mod tests {
343 check( 341 check(
344 r#" 342 r#"
345fn quux() -> i32 { 343fn quux() -> i32 {
346 match () { 344 match () { () => <|> }
347 () => <|>
348 }
349} 345}
350"#, 346"#,
351 expect![[r#" 347 expect![[r#"
@@ -355,6 +351,7 @@ fn quux() -> i32 {
355 kw match 351 kw match
356 kw return 352 kw return
357 kw unsafe 353 kw unsafe
354 kw while
358 "#]], 355 "#]],
359 ); 356 );
360 } 357 }
@@ -525,4 +522,19 @@ pub mod future {
525 "#]], 522 "#]],
526 ) 523 )
527 } 524 }
525
526 #[test]
527 fn after_let() {
528 check(
529 r#"fn main() { let _ = <|> }"#,
530 expect![[r#"
531 kw if
532 kw if let
533 kw loop
534 kw match
535 kw return
536 kw while
537 "#]],
538 )
539 }
528} 540}
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
index d6613ed7b..0447f0511 100644
--- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
7 if ctx.is_new_item { 7 if ctx.is_new_item {
8 ctx.scope().process_all_names(&mut |name, res| { 8 ctx.scope.process_all_names(&mut |name, res| {
9 if let hir::ScopeDef::MacroDef(mac) = res { 9 if let hir::ScopeDef::MacroDef(mac) = res {
10 acc.add_macro(ctx, Some(name.to_string()), mac); 10 acc.add_macro(ctx, Some(name.to_string()), mac);
11 } 11 }
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index 13fa7548d..aceb77cb5 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -13,7 +13,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
13 13
14 // FIXME: ideally, we should look at the type we are matching against and 14 // FIXME: ideally, we should look at the type we are matching against and
15 // suggest variants + auto-imports 15 // suggest variants + auto-imports
16 ctx.scope().process_all_names(&mut |name, res| { 16 ctx.scope.process_all_names(&mut |name, res| {
17 match &res { 17 match &res {
18 hir::ScopeDef::ModuleDef(def) => match def { 18 hir::ScopeDef::ModuleDef(def) => match def {
19 hir::ModuleDef::Adt(hir::Adt::Enum(..)) 19 hir::ModuleDef::Adt(hir::Adt::Enum(..))
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index e5553e28f..b08f5b9b4 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -17,21 +17,20 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
17 return; 17 return;
18 } 18 }
19 19
20 let scope = ctx.scope(); 20 let context_module = ctx.scope.module();
21 let context_module = scope.module();
22 21
23 let res = match scope.resolve_hir_path_qualifier(&path) { 22 let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 23 Some(res) => res,
25 None => return, 24 None => return,
26 }; 25 };
27 26
28 // Add associated types on type parameters and `Self`. 27 // Add associated types on type parameters and `Self`.
29 res.assoc_type_shorthand_candidates(ctx.db, |alias| { 28 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
30 acc.add_type_alias(ctx, alias); 29 acc.add_type_alias(ctx, alias);
31 None::<()> 30 None::<()>
32 }); 31 });
33 32
34 match res { 33 match resolution {
35 PathResolution::Def(hir::ModuleDef::Module(module)) => { 34 PathResolution::Def(hir::ModuleDef::Module(module)) => {
36 let module_scope = module.scope(ctx.db, context_module); 35 let module_scope = module.scope(ctx.db, context_module);
37 for (name, def) in module_scope { 36 for (name, def) in module_scope {
@@ -68,7 +67,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
68 67
69 let krate = ctx.krate; 68 let krate = ctx.krate;
70 if let Some(krate) = krate { 69 if let Some(krate) = krate {
71 let traits_in_scope = ctx.scope().traits_in_scope(); 70 let traits_in_scope = ctx.scope.traits_in_scope();
72 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 71 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
73 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 72 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
74 return None; 73 return None;
@@ -113,13 +112,13 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
113 } 112 }
114 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { 113 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
115 if let Some(krate) = ctx.krate { 114 if let Some(krate) = ctx.krate {
116 let ty = match res { 115 let ty = match resolution {
117 PathResolution::TypeParam(param) => param.ty(ctx.db), 116 PathResolution::TypeParam(param) => param.ty(ctx.db),
118 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), 117 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
119 _ => return, 118 _ => return,
120 }; 119 };
121 120
122 let traits_in_scope = ctx.scope().traits_in_scope(); 121 let traits_in_scope = ctx.scope.traits_in_scope();
123 let mut seen = FxHashSet::default(); 122 let mut seen = FxHashSet::default();
124 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 123 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
125 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 124 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index a610fd6d1..cf716540f 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -43,7 +43,7 @@ use crate::{
43 completion::{ 43 completion::{
44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
45 }, 45 },
46 display::FunctionSignature, 46 display::function_declaration,
47}; 47};
48 48
49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
@@ -125,8 +125,6 @@ fn add_function_impl(
125 ctx: &CompletionContext, 125 ctx: &CompletionContext,
126 func: hir::Function, 126 func: hir::Function,
127) { 127) {
128 let signature = FunctionSignature::from_hir(ctx.db, func);
129
130 let fn_name = func.name(ctx.db).to_string(); 128 let fn_name = func.name(ctx.db).to_string();
131 129
132 let label = if !func.params(ctx.db).is_empty() { 130 let label = if !func.params(ctx.db).is_empty() {
@@ -146,13 +144,14 @@ fn add_function_impl(
146 }; 144 };
147 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 145 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
148 146
147 let function_decl = function_declaration(&func.source(ctx.db).value);
149 match ctx.config.snippet_cap { 148 match ctx.config.snippet_cap {
150 Some(cap) => { 149 Some(cap) => {
151 let snippet = format!("{} {{\n $0\n}}", signature); 150 let snippet = format!("{} {{\n $0\n}}", function_decl);
152 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 151 builder.snippet_edit(cap, TextEdit::replace(range, snippet))
153 } 152 }
154 None => { 153 None => {
155 let header = format!("{} {{", signature); 154 let header = format!("{} {{", function_decl);
156 builder.text_edit(TextEdit::replace(range, header)) 155 builder.text_edit(TextEdit::replace(range, header))
157 } 156 }
158 } 157 }
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index 0d1e9f8ea..bd9551f35 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -1,11 +1,10 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::{Adt, ModuleDef, ScopeDef, Type};
4use ra_syntax::AstNode;
4use test_utils::mark; 5use test_utils::mark;
5 6
6use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
7use hir::{Adt, ModuleDef, Type};
8use ra_syntax::AstNode;
9 8
10pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -26,7 +25,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
26 return; 25 return;
27 } 26 }
28 27
29 ctx.scope().process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
30 if ctx.use_item_syntax.is_some() { 29 if ctx.use_item_syntax.is_some() {
31 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 30 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
32 if name_ref.syntax().text() == name.to_string().as_str() { 31 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -43,7 +42,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
43 if let Some(Adt::Enum(enum_data)) = ty.as_adt() { 42 if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
44 let variants = enum_data.variants(ctx.db); 43 let variants = enum_data.variants(ctx.db);
45 44
46 let module = if let Some(module) = ctx.scope().module() { 45 let module = if let Some(module) = ctx.scope.module() {
47 // Compute path from the completion site if available. 46 // Compute path from the completion site if available.
48 module 47 module
49 } else { 48 } else {
@@ -65,1370 +64,595 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
65 64
66#[cfg(test)] 65#[cfg(test)]
67mod tests { 66mod tests {
68 use insta::assert_debug_snapshot; 67 use expect::{expect, Expect};
69 use test_utils::mark; 68 use test_utils::mark;
70 69
71 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 use crate::completion::{
71 test_utils::{check_edit, completion_list},
72 CompletionKind,
73 };
72 74
73 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 75 fn check(ra_fixture: &str, expect: Expect) {
74 do_completion(ra_fixture, CompletionKind::Reference) 76 let actual = completion_list(ra_fixture, CompletionKind::Reference);
77 expect.assert_eq(&actual)
75 } 78 }
76 79
77 #[test] 80 #[test]
78 fn self_fulfilling_completion() { 81 fn self_fulfilling_completion() {
79 mark::check!(self_fulfilling_completion); 82 mark::check!(self_fulfilling_completion);
80 assert_debug_snapshot!( 83 check(
81 do_reference_completion( 84 r#"
82 r#" 85use foo<|>
83 use foo<|> 86use std::collections;
84 use std::collections; 87"#,
85 "#, 88 expect![[r#"
86 ), 89 ?? collections
87 @r###" 90 "#]],
88 [
89 CompletionItem {
90 label: "collections",
91 source_range: 4..7,
92 delete: 4..7,
93 insert: "collections",
94 },
95 ]
96 "###
97 ); 91 );
98 } 92 }
99 93
100 #[test] 94 #[test]
101 fn bind_pat_and_path_ignore_at() { 95 fn bind_pat_and_path_ignore_at() {
102 assert_debug_snapshot!( 96 check(
103 do_reference_completion( 97 r#"
104 r" 98enum Enum { A, B }
105 enum Enum { 99fn quux(x: Option<Enum>) {
106 A, 100 match x {
107 B, 101 None => (),
108 } 102 Some(en<|> @ Enum::A) => (),
109 fn quux(x: Option<Enum>) { 103 }
110 match x { 104}
111 None => (), 105"#,
112 Some(en<|> @ Enum::A) => (), 106 expect![[""]],
113 }
114 }
115 "
116 ),
117 @"[]"
118 ); 107 );
119 } 108 }
120 109
121 #[test] 110 #[test]
122 fn bind_pat_and_path_ignore_ref() { 111 fn bind_pat_and_path_ignore_ref() {
123 assert_debug_snapshot!( 112 check(
124 do_reference_completion( 113 r#"
125 r" 114enum Enum { A, B }
126 enum Enum { 115fn quux(x: Option<Enum>) {
127 A, 116 match x {
128 B, 117 None => (),
129 } 118 Some(ref en<|>) => (),
130 fn quux(x: Option<Enum>) { 119 }
131 match x { 120}
132 None => (), 121"#,
133 Some(ref en<|>) => (), 122 expect![[""]],
134 }
135 }
136 "
137 ),
138 @r###"[]"###
139 ); 123 );
140 } 124 }
141 125
142 #[test] 126 #[test]
143 fn bind_pat_and_path() { 127 fn bind_pat_and_path() {
144 assert_debug_snapshot!( 128 check(
145 do_reference_completion( 129 r#"
146 r" 130enum Enum { A, B }
147 enum Enum { 131fn quux(x: Option<Enum>) {
148 A, 132 match x {
149 B, 133 None => (),
150 } 134 Some(En<|>) => (),
151 fn quux(x: Option<Enum>) { 135 }
152 match x { 136}
153 None => (), 137"#,
154 Some(En<|>) => (), 138 expect![[r#"
155 } 139 en Enum
156 } 140 "#]],
157 "
158 ),
159 @r###"
160 [
161 CompletionItem {
162 label: "Enum",
163 source_range: 102..104,
164 delete: 102..104,
165 insert: "Enum",
166 kind: Enum,
167 },
168 ]
169 "###
170 ); 141 );
171 } 142 }
172 143
173 #[test] 144 #[test]
174 fn completes_bindings_from_let() { 145 fn completes_bindings_from_let() {
175 assert_debug_snapshot!( 146 check(
176 do_reference_completion( 147 r#"
177 r" 148fn quux(x: i32) {
178 fn quux(x: i32) { 149 let y = 92;
179 let y = 92; 150 1 + <|>;
180 1 + <|>; 151 let z = ();
181 let z = (); 152}
182 } 153"#,
183 " 154 expect![[r#"
184 ), 155 fn quux(…) fn quux(x: i32)
185 @r###" 156 bn x i32
186 [ 157 bn y i32
187 CompletionItem { 158 "#]],
188 label: "quux(…)",
189 source_range: 42..42,
190 delete: 42..42,
191 insert: "quux(${1:x})$0",
192 kind: Function,
193 lookup: "quux",
194 detail: "fn quux(x: i32)",
195 trigger_call_info: true,
196 },
197 CompletionItem {
198 label: "x",
199 source_range: 42..42,
200 delete: 42..42,
201 insert: "x",
202 kind: Binding,
203 detail: "i32",
204 },
205 CompletionItem {
206 label: "y",
207 source_range: 42..42,
208 delete: 42..42,
209 insert: "y",
210 kind: Binding,
211 detail: "i32",
212 },
213 ]
214 "###
215 ); 159 );
216 } 160 }
217 161
218 #[test] 162 #[test]
219 fn completes_bindings_from_if_let() { 163 fn completes_bindings_from_if_let() {
220 assert_debug_snapshot!( 164 check(
221 do_reference_completion( 165 r#"
222 r" 166fn quux() {
223 fn quux() { 167 if let Some(x) = foo() {
224 if let Some(x) = foo() { 168 let y = 92;
225 let y = 92; 169 };
226 }; 170 if let Some(a) = bar() {
227 if let Some(a) = bar() { 171 let b = 62;
228 let b = 62; 172 1 + <|>
229 1 + <|> 173 }
230 } 174}
231 } 175"#,
232 " 176 expect![[r#"
233 ), 177 bn a
234 @r###" 178 bn b i32
235 [ 179 fn quux() fn quux()
236 CompletionItem { 180 "#]],
237 label: "a",
238 source_range: 129..129,
239 delete: 129..129,
240 insert: "a",
241 kind: Binding,
242 },
243 CompletionItem {
244 label: "b",
245 source_range: 129..129,
246 delete: 129..129,
247 insert: "b",
248 kind: Binding,
249 detail: "i32",
250 },
251 CompletionItem {
252 label: "quux()",
253 source_range: 129..129,
254 delete: 129..129,
255 insert: "quux()$0",
256 kind: Function,
257 lookup: "quux",
258 detail: "fn quux()",
259 },
260 ]
261 "###
262 ); 181 );
263 } 182 }
264 183
265 #[test] 184 #[test]
266 fn completes_bindings_from_for() { 185 fn completes_bindings_from_for() {
267 assert_debug_snapshot!( 186 check(
268 do_reference_completion( 187 r#"
269 r" 188fn quux() {
270 fn quux() { 189 for x in &[1, 2, 3] { <|> }
271 for x in &[1, 2, 3] { 190}
272 <|> 191"#,
273 } 192 expect![[r#"
274 } 193 fn quux() fn quux()
275 " 194 bn x
276 ), 195 "#]],
277 @r###"
278 [
279 CompletionItem {
280 label: "quux()",
281 source_range: 46..46,
282 delete: 46..46,
283 insert: "quux()$0",
284 kind: Function,
285 lookup: "quux",
286 detail: "fn quux()",
287 },
288 CompletionItem {
289 label: "x",
290 source_range: 46..46,
291 delete: 46..46,
292 insert: "x",
293 kind: Binding,
294 },
295 ]
296 "###
297 ); 196 );
298 } 197 }
299 198
300 #[test] 199 #[test]
301 fn completes_bindings_from_for_with_in_prefix() { 200 fn completes_if_prefix_is_keyword() {
302 mark::check!(completes_bindings_from_for_with_in_prefix); 201 mark::check!(completes_if_prefix_is_keyword);
303 assert_debug_snapshot!( 202 check_edit(
304 do_reference_completion( 203 "wherewolf",
305 r" 204 r#"
306 fn test() { 205fn main() {
307 for index in &[1, 2, 3] { 206 let wherewolf = 92;
308 let t = in<|> 207 drop(where<|>)
309 } 208}
310 } 209"#,
311 " 210 r#"
312 ), 211fn main() {
313 @r###" 212 let wherewolf = 92;
314 [ 213 drop(wherewolf)
315 CompletionItem { 214}
316 label: "index", 215"#,
317 source_range: 58..58, 216 )
318 delete: 58..58,
319 insert: "index",
320 kind: Binding,
321 },
322 CompletionItem {
323 label: "test()",
324 source_range: 58..58,
325 delete: 58..58,
326 insert: "test()$0",
327 kind: Function,
328 lookup: "test",
329 detail: "fn test()",
330 },
331 ]
332 "###
333 );
334 } 217 }
335 218
336 #[test] 219 #[test]
337 fn completes_generic_params() { 220 fn completes_generic_params() {
338 assert_debug_snapshot!( 221 check(
339 do_reference_completion( 222 r#"fn quux<T>() { <|> }"#,
340 r" 223 expect![[r#"
341 fn quux<T>() { 224 tp T
342 <|> 225 fn quux() fn quux<T>()
343 } 226 "#]],
344 "
345 ),
346 @r###"
347 [
348 CompletionItem {
349 label: "T",
350 source_range: 19..19,
351 delete: 19..19,
352 insert: "T",
353 kind: TypeParam,
354 },
355 CompletionItem {
356 label: "quux()",
357 source_range: 19..19,
358 delete: 19..19,
359 insert: "quux()$0",
360 kind: Function,
361 lookup: "quux",
362 detail: "fn quux<T>()",
363 },
364 ]
365 "###
366 ); 227 );
367 } 228 }
368 229
369 #[test] 230 #[test]
370 fn completes_generic_params_in_struct() { 231 fn completes_generic_params_in_struct() {
371 assert_debug_snapshot!( 232 check(
372 do_reference_completion( 233 r#"struct S<T> { x: <|>}"#,
373 r" 234 expect![[r#"
374 struct X<T> { 235 st S<…>
375 x: <|> 236 tp Self
376 } 237 tp T
377 " 238 "#]],
378 ),
379 @r###"
380 [
381 CompletionItem {
382 label: "Self",
383 source_range: 21..21,
384 delete: 21..21,
385 insert: "Self",
386 kind: TypeParam,
387 },
388 CompletionItem {
389 label: "T",
390 source_range: 21..21,
391 delete: 21..21,
392 insert: "T",
393 kind: TypeParam,
394 },
395 CompletionItem {
396 label: "X<…>",
397 source_range: 21..21,
398 delete: 21..21,
399 insert: "X<$0>",
400 kind: Struct,
401 lookup: "X",
402 },
403 ]
404 "###
405 ); 239 );
406 } 240 }
407 241
408 #[test] 242 #[test]
409 fn completes_self_in_enum() { 243 fn completes_self_in_enum() {
410 assert_debug_snapshot!( 244 check(
411 do_reference_completion( 245 r#"enum X { Y(<|>) }"#,
412 r" 246 expect![[r#"
413 enum X { 247 tp Self
414 Y(<|>) 248 en X
415 } 249 "#]],
416 "
417 ),
418 @r###"
419 [
420 CompletionItem {
421 label: "Self",
422 source_range: 15..15,
423 delete: 15..15,
424 insert: "Self",
425 kind: TypeParam,
426 },
427 CompletionItem {
428 label: "X",
429 source_range: 15..15,
430 delete: 15..15,
431 insert: "X",
432 kind: Enum,
433 },
434 ]
435 "###
436 ); 250 );
437 } 251 }
438 252
439 #[test] 253 #[test]
440 fn completes_module_items() { 254 fn completes_module_items() {
441 assert_debug_snapshot!( 255 check(
442 do_reference_completion( 256 r#"
443 r" 257struct S;
444 struct Foo; 258enum E {}
445 enum Baz {} 259fn quux() { <|> }
446 fn quux() { 260"#,
447 <|> 261 expect![[r#"
448 } 262 en E
449 " 263 st S
450 ), 264 fn quux() fn quux()
451 @r###" 265 "#]],
452 [ 266 );
453 CompletionItem {
454 label: "Baz",
455 source_range: 40..40,
456 delete: 40..40,
457 insert: "Baz",
458 kind: Enum,
459 },
460 CompletionItem {
461 label: "Foo",
462 source_range: 40..40,
463 delete: 40..40,
464 insert: "Foo",
465 kind: Struct,
466 },
467 CompletionItem {
468 label: "quux()",
469 source_range: 40..40,
470 delete: 40..40,
471 insert: "quux()$0",
472 kind: Function,
473 lookup: "quux",
474 detail: "fn quux()",
475 },
476 ]
477 "###
478 );
479 } 267 }
480 268
481 #[test] 269 #[test]
482 fn completes_extern_prelude() { 270 fn completes_extern_prelude() {
483 assert_debug_snapshot!( 271 check(
484 do_reference_completion( 272 r#"
485 r" 273//- /lib.rs
486 //- /lib.rs 274use <|>;
487 use <|>; 275
488 276//- /other_crate/lib.rs
489 //- /other_crate/lib.rs 277// nothing here
490 // nothing here 278"#,
491 " 279 expect![[r#"
492 ), 280 md other_crate
493 @r###" 281 "#]],
494 [
495 CompletionItem {
496 label: "other_crate",
497 source_range: 4..4,
498 delete: 4..4,
499 insert: "other_crate",
500 kind: Module,
501 },
502 ]
503 "###
504 ); 282 );
505 } 283 }
506 284
507 #[test] 285 #[test]
508 fn completes_module_items_in_nested_modules() { 286 fn completes_module_items_in_nested_modules() {
509 assert_debug_snapshot!( 287 check(
510 do_reference_completion( 288 r#"
511 r" 289struct Foo;
512 struct Foo; 290mod m {
513 mod m { 291 struct Bar;
514 struct Bar; 292 fn quux() { <|> }
515 fn quux() { <|> } 293}
516 } 294"#,
517 " 295 expect![[r#"
518 ), 296 st Bar
519 @r###" 297 fn quux() fn quux()
520 [ 298 "#]],
521 CompletionItem {
522 label: "Bar",
523 source_range: 52..52,
524 delete: 52..52,
525 insert: "Bar",
526 kind: Struct,
527 },
528 CompletionItem {
529 label: "quux()",
530 source_range: 52..52,
531 delete: 52..52,
532 insert: "quux()$0",
533 kind: Function,
534 lookup: "quux",
535 detail: "fn quux()",
536 },
537 ]
538 "###
539 ); 299 );
540 } 300 }
541 301
542 #[test] 302 #[test]
543 fn completes_return_type() { 303 fn completes_return_type() {
544 assert_debug_snapshot!( 304 check(
545 do_reference_completion( 305 r#"
546 r" 306struct Foo;
547 struct Foo; 307fn x() -> <|>
548 fn x() -> <|> 308"#,
549 " 309 expect![[r#"
550 ), 310 st Foo
551 @r###" 311 fn x() fn x()
552 [ 312 "#]],
553 CompletionItem {
554 label: "Foo",
555 source_range: 22..22,
556 delete: 22..22,
557 insert: "Foo",
558 kind: Struct,
559 },
560 CompletionItem {
561 label: "x()",
562 source_range: 22..22,
563 delete: 22..22,
564 insert: "x()$0",
565 kind: Function,
566 lookup: "x",
567 detail: "fn x()",
568 },
569 ]
570 "###
571 ); 313 );
572 } 314 }
573 315
574 #[test] 316 #[test]
575 fn dont_show_both_completions_for_shadowing() { 317 fn dont_show_both_completions_for_shadowing() {
576 assert_debug_snapshot!( 318 check(
577 do_reference_completion( 319 r#"
578 r" 320fn foo() {
579 fn foo() { 321 let bar = 92;
580 let bar = 92; 322 {
581 { 323 let bar = 62;
582 let bar = 62; 324 drop(<|>)
583 <|> 325 }
584 } 326}
585 } 327"#,
586 " 328 // FIXME: should be only one bar here
587 ), 329 expect![[r#"
588 @r###" 330 bn bar i32
589 [ 331 bn bar i32
590 CompletionItem { 332 fn foo() fn foo()
591 label: "bar", 333 "#]],
592 source_range: 65..65,
593 delete: 65..65,
594 insert: "bar",
595 kind: Binding,
596 detail: "i32",
597 },
598 CompletionItem {
599 label: "foo()",
600 source_range: 65..65,
601 delete: 65..65,
602 insert: "foo()$0",
603 kind: Function,
604 lookup: "foo",
605 detail: "fn foo()",
606 },
607 ]
608 "###
609 ); 334 );
610 } 335 }
611 336
612 #[test] 337 #[test]
613 fn completes_self_in_methods() { 338 fn completes_self_in_methods() {
614 assert_debug_snapshot!( 339 check(
615 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), 340 r#"impl S { fn foo(&self) { <|> } }"#,
616 @r###" 341 expect![[r#"
617 [ 342 tp Self
618 CompletionItem { 343 bn self &{unknown}
619 label: "Self", 344 "#]],
620 source_range: 25..25,
621 delete: 25..25,
622 insert: "Self",
623 kind: TypeParam,
624 },
625 CompletionItem {
626 label: "self",
627 source_range: 25..25,
628 delete: 25..25,
629 insert: "self",
630 kind: Binding,
631 detail: "&{unknown}",
632 },
633 ]
634 "###
635 ); 345 );
636 } 346 }
637 347
638 #[test] 348 #[test]
639 fn completes_prelude() { 349 fn completes_prelude() {
640 assert_debug_snapshot!( 350 check(
641 do_reference_completion( 351 r#"
642 " 352//- /main.rs
643 //- /main.rs 353fn foo() { let x: <|> }
644 fn foo() { let x: <|> } 354
645 355//- /std/lib.rs
646 //- /std/lib.rs 356#[prelude_import]
647 #[prelude_import] 357use prelude::*;
648 use prelude::*; 358
649 359mod prelude { struct Option; }
650 mod prelude { 360"#,
651 struct Option; 361 expect![[r#"
652 } 362 st Option
653 " 363 fn foo() fn foo()
654 ), 364 md std
655 @r###" 365 "#]],
656 [
657 CompletionItem {
658 label: "Option",
659 source_range: 18..18,
660 delete: 18..18,
661 insert: "Option",
662 kind: Struct,
663 },
664 CompletionItem {
665 label: "foo()",
666 source_range: 18..18,
667 delete: 18..18,
668 insert: "foo()$0",
669 kind: Function,
670 lookup: "foo",
671 detail: "fn foo()",
672 },
673 CompletionItem {
674 label: "std",
675 source_range: 18..18,
676 delete: 18..18,
677 insert: "std",
678 kind: Module,
679 },
680 ]
681 "###
682 ); 366 );
683 } 367 }
684 368
685 #[test] 369 #[test]
686 fn completes_std_prelude_if_core_is_defined() { 370 fn completes_std_prelude_if_core_is_defined() {
687 assert_debug_snapshot!( 371 check(
688 do_reference_completion( 372 r#"
689 " 373//- /main.rs
690 //- /main.rs 374fn foo() { let x: <|> }
691 fn foo() { let x: <|> } 375
692 376//- /core/lib.rs
693 //- /core/lib.rs 377#[prelude_import]
694 #[prelude_import] 378use prelude::*;
695 use prelude::*; 379
696 380mod prelude { struct Option; }
697 mod prelude { 381
698 struct Option; 382//- /std/lib.rs
699 } 383#[prelude_import]
700 384use prelude::*;
701 //- /std/lib.rs 385
702 #[prelude_import] 386mod prelude { struct String; }
703 use prelude::*; 387"#,
704 388 expect![[r#"
705 mod prelude { 389 st String
706 struct String; 390 md core
707 } 391 fn foo() fn foo()
708 " 392 md std
709 ), 393 "#]],
710 @r###"
711 [
712 CompletionItem {
713 label: "String",
714 source_range: 18..18,
715 delete: 18..18,
716 insert: "String",
717 kind: Struct,
718 },
719 CompletionItem {
720 label: "core",
721 source_range: 18..18,
722 delete: 18..18,
723 insert: "core",
724 kind: Module,
725 },
726 CompletionItem {
727 label: "foo()",
728 source_range: 18..18,
729 delete: 18..18,
730 insert: "foo()$0",
731 kind: Function,
732 lookup: "foo",
733 detail: "fn foo()",
734 },
735 CompletionItem {
736 label: "std",
737 source_range: 18..18,
738 delete: 18..18,
739 insert: "std",
740 kind: Module,
741 },
742 ]
743 "###
744 ); 394 );
745 } 395 }
746 396
747 #[test] 397 #[test]
748 fn completes_macros_as_value() { 398 fn completes_macros_as_value() {
749 assert_debug_snapshot!( 399 check(
750 do_reference_completion( 400 r#"
751 " 401macro_rules! foo { () => {} }
752 //- /main.rs
753 macro_rules! foo {
754 () => {}
755 }
756 402
757 #[macro_use] 403#[macro_use]
758 mod m1 { 404mod m1 {
759 macro_rules! bar { 405 macro_rules! bar { () => {} }
760 () => {} 406}
761 }
762 }
763 407
764 mod m2 { 408mod m2 {
765 macro_rules! nope { 409 macro_rules! nope { () => {} }
766 () => {}
767 }
768 410
769 #[macro_export] 411 #[macro_export]
770 macro_rules! baz { 412 macro_rules! baz { () => {} }
771 () => {} 413}
772 }
773 }
774 414
775 fn main() { 415fn main() { let v = <|> }
776 let v = <|> 416"#,
777 } 417 expect![[r##"
778 " 418 ma bar!(…) macro_rules! bar
779 ), 419 ma baz!(…) #[macro_export]
780 @r###" 420 macro_rules! baz
781 [ 421 ma foo!(…) macro_rules! foo
782 CompletionItem { 422 md m1
783 label: "bar!(…)", 423 md m2
784 source_range: 256..256, 424 fn main() fn main()
785 delete: 256..256, 425 "##]],
786 insert: "bar!($0)",
787 kind: Macro,
788 lookup: "bar!",
789 detail: "macro_rules! bar",
790 },
791 CompletionItem {
792 label: "baz!(…)",
793 source_range: 256..256,
794 delete: 256..256,
795 insert: "baz!($0)",
796 kind: Macro,
797 lookup: "baz!",
798 detail: "#[macro_export]\nmacro_rules! baz",
799 },
800 CompletionItem {
801 label: "foo!(…)",
802 source_range: 256..256,
803 delete: 256..256,
804 insert: "foo!($0)",
805 kind: Macro,
806 lookup: "foo!",
807 detail: "macro_rules! foo",
808 },
809 CompletionItem {
810 label: "m1",
811 source_range: 256..256,
812 delete: 256..256,
813 insert: "m1",
814 kind: Module,
815 },
816 CompletionItem {
817 label: "m2",
818 source_range: 256..256,
819 delete: 256..256,
820 insert: "m2",
821 kind: Module,
822 },
823 CompletionItem {
824 label: "main()",
825 source_range: 256..256,
826 delete: 256..256,
827 insert: "main()$0",
828 kind: Function,
829 lookup: "main",
830 detail: "fn main()",
831 },
832 ]
833 "###
834 ); 426 );
835 } 427 }
836 428
837 #[test] 429 #[test]
838 fn completes_both_macro_and_value() { 430 fn completes_both_macro_and_value() {
839 assert_debug_snapshot!( 431 check(
840 do_reference_completion( 432 r#"
841 " 433macro_rules! foo { () => {} }
842 //- /main.rs 434fn foo() { <|> }
843 macro_rules! foo { 435"#,
844 () => {} 436 expect![[r#"
845 } 437 ma foo!(…) macro_rules! foo
846 438 fn foo() fn foo()
847 fn foo() { 439 "#]],
848 <|>
849 }
850 "
851 ),
852 @r###"
853 [
854 CompletionItem {
855 label: "foo!(…)",
856 source_range: 50..50,
857 delete: 50..50,
858 insert: "foo!($0)",
859 kind: Macro,
860 lookup: "foo!",
861 detail: "macro_rules! foo",
862 },
863 CompletionItem {
864 label: "foo()",
865 source_range: 50..50,
866 delete: 50..50,
867 insert: "foo()$0",
868 kind: Function,
869 lookup: "foo",
870 detail: "fn foo()",
871 },
872 ]
873 "###
874 ); 440 );
875 } 441 }
876 442
877 #[test] 443 #[test]
878 fn completes_macros_as_type() { 444 fn completes_macros_as_type() {
879 assert_debug_snapshot!( 445 check(
880 do_reference_completion( 446 r#"
881 " 447macro_rules! foo { () => {} }
882 //- /main.rs 448fn main() { let x: <|> }
883 macro_rules! foo { 449"#,
884 () => {} 450 expect![[r#"
885 } 451 ma foo!(…) macro_rules! foo
886 452 fn main() fn main()
887 fn main() { 453 "#]],
888 let x: <|>
889 }
890 "
891 ),
892 @r###"
893 [
894 CompletionItem {
895 label: "foo!(…)",
896 source_range: 58..58,
897 delete: 58..58,
898 insert: "foo!($0)",
899 kind: Macro,
900 lookup: "foo!",
901 detail: "macro_rules! foo",
902 },
903 CompletionItem {
904 label: "main()",
905 source_range: 58..58,
906 delete: 58..58,
907 insert: "main()$0",
908 kind: Function,
909 lookup: "main",
910 detail: "fn main()",
911 },
912 ]
913 "###
914 ); 454 );
915 } 455 }
916 456
917 #[test] 457 #[test]
918 fn completes_macros_as_stmt() { 458 fn completes_macros_as_stmt() {
919 assert_debug_snapshot!( 459 check(
920 do_reference_completion( 460 r#"
921 " 461macro_rules! foo { () => {} }
922 //- /main.rs 462fn main() { <|> }
923 macro_rules! foo { 463"#,
924 () => {} 464 expect![[r#"
925 } 465 ma foo!(…) macro_rules! foo
926 466 fn main() fn main()
927 fn main() { 467 "#]],
928 <|>
929 }
930 "
931 ),
932 @r###"
933 [
934 CompletionItem {
935 label: "foo!(…)",
936 source_range: 51..51,
937 delete: 51..51,
938 insert: "foo!($0)",
939 kind: Macro,
940 lookup: "foo!",
941 detail: "macro_rules! foo",
942 },
943 CompletionItem {
944 label: "main()",
945 source_range: 51..51,
946 delete: 51..51,
947 insert: "main()$0",
948 kind: Function,
949 lookup: "main",
950 detail: "fn main()",
951 },
952 ]
953 "###
954 ); 468 );
955 } 469 }
956 470
957 #[test] 471 #[test]
958 fn completes_local_item() { 472 fn completes_local_item() {
959 assert_debug_snapshot!( 473 check(
960 do_reference_completion( 474 r#"
961 " 475fn main() {
962 //- /main.rs 476 return f<|>;
963 fn main() { 477 fn frobnicate() {}
964 return f<|>; 478}
965 fn frobnicate() {} 479"#,
966 } 480 expect![[r#"
967 " 481 fn frobnicate() fn frobnicate()
968 ), 482 fn main() fn main()
969 @r###" 483 "#]],
970 [ 484 );
971 CompletionItem {
972 label: "frobnicate()",
973 source_range: 23..24,
974 delete: 23..24,
975 insert: "frobnicate()$0",
976 kind: Function,
977 lookup: "frobnicate",
978 detail: "fn frobnicate()",
979 },
980 CompletionItem {
981 label: "main()",
982 source_range: 23..24,
983 delete: 23..24,
984 insert: "main()$0",
985 kind: Function,
986 lookup: "main",
987 detail: "fn main()",
988 },
989 ]
990 "###
991 )
992 } 485 }
993 486
994 #[test] 487 #[test]
995 fn completes_in_simple_macro_1() { 488 fn completes_in_simple_macro_1() {
996 assert_debug_snapshot!( 489 check(
997 do_reference_completion( 490 r#"
998 r" 491macro_rules! m { ($e:expr) => { $e } }
999 macro_rules! m { ($e:expr) => { $e } } 492fn quux(x: i32) {
1000 fn quux(x: i32) { 493 let y = 92;
1001 let y = 92; 494 m!(<|>);
1002 m!(<|>); 495}
1003 } 496"#,
1004 " 497 expect![[r#"
1005 ), 498 ma m!(…) macro_rules! m
1006 @r###" 499 fn quux(…) fn quux(x: i32)
1007 [ 500 bn x i32
1008 CompletionItem { 501 bn y i32
1009 label: "m!(…)", 502 "#]],
1010 source_range: 80..80,
1011 delete: 80..80,
1012 insert: "m!($0)",
1013 kind: Macro,
1014 lookup: "m!",
1015 detail: "macro_rules! m",
1016 },
1017 CompletionItem {
1018 label: "quux(…)",
1019 source_range: 80..80,
1020 delete: 80..80,
1021 insert: "quux(${1:x})$0",
1022 kind: Function,
1023 lookup: "quux",
1024 detail: "fn quux(x: i32)",
1025 trigger_call_info: true,
1026 },
1027 CompletionItem {
1028 label: "x",
1029 source_range: 80..80,
1030 delete: 80..80,
1031 insert: "x",
1032 kind: Binding,
1033 detail: "i32",
1034 },
1035 CompletionItem {
1036 label: "y",
1037 source_range: 80..80,
1038 delete: 80..80,
1039 insert: "y",
1040 kind: Binding,
1041 detail: "i32",
1042 },
1043 ]
1044 "###
1045 ); 503 );
1046 } 504 }
1047 505
1048 #[test] 506 #[test]
1049 fn completes_in_simple_macro_2() { 507 fn completes_in_simple_macro_2() {
1050 assert_debug_snapshot!( 508 check(
1051 do_reference_completion( 509 r"
1052 r" 510macro_rules! m { ($e:expr) => { $e } }
1053 macro_rules! m { ($e:expr) => { $e } } 511fn quux(x: i32) {
1054 fn quux(x: i32) { 512 let y = 92;
1055 let y = 92; 513 m!(x<|>);
1056 m!(x<|>); 514}
1057 } 515",
1058 " 516 expect![[r#"
1059 ), 517 ma m!(…) macro_rules! m
1060 @r###" 518 fn quux(…) fn quux(x: i32)
1061 [ 519 bn x i32
1062 CompletionItem { 520 bn y i32
1063 label: "m!(…)", 521 "#]],
1064 source_range: 80..81,
1065 delete: 80..81,
1066 insert: "m!($0)",
1067 kind: Macro,
1068 lookup: "m!",
1069 detail: "macro_rules! m",
1070 },
1071 CompletionItem {
1072 label: "quux(…)",
1073 source_range: 80..81,
1074 delete: 80..81,
1075 insert: "quux(${1:x})$0",
1076 kind: Function,
1077 lookup: "quux",
1078 detail: "fn quux(x: i32)",
1079 trigger_call_info: true,
1080 },
1081 CompletionItem {
1082 label: "x",
1083 source_range: 80..81,
1084 delete: 80..81,
1085 insert: "x",
1086 kind: Binding,
1087 detail: "i32",
1088 },
1089 CompletionItem {
1090 label: "y",
1091 source_range: 80..81,
1092 delete: 80..81,
1093 insert: "y",
1094 kind: Binding,
1095 detail: "i32",
1096 },
1097 ]
1098 "###
1099 ); 522 );
1100 } 523 }
1101 524
1102 #[test] 525 #[test]
1103 fn completes_in_simple_macro_without_closing_parens() { 526 fn completes_in_simple_macro_without_closing_parens() {
1104 assert_debug_snapshot!( 527 check(
1105 do_reference_completion( 528 r#"
1106 r" 529macro_rules! m { ($e:expr) => { $e } }
1107 macro_rules! m { ($e:expr) => { $e } } 530fn quux(x: i32) {
1108 fn quux(x: i32) { 531 let y = 92;
1109 let y = 92; 532 m!(x<|>
1110 m!(x<|> 533}
1111 } 534"#,
1112 " 535 expect![[r#"
1113 ), 536 ma m!(…) macro_rules! m
1114 @r###" 537 fn quux(…) fn quux(x: i32)
1115 [ 538 bn x i32
1116 CompletionItem { 539 bn y i32
1117 label: "m!(…)", 540 "#]],
1118 source_range: 80..81,
1119 delete: 80..81,
1120 insert: "m!($0)",
1121 kind: Macro,
1122 lookup: "m!",
1123 detail: "macro_rules! m",
1124 },
1125 CompletionItem {
1126 label: "quux(…)",
1127 source_range: 80..81,
1128 delete: 80..81,
1129 insert: "quux(${1:x})$0",
1130 kind: Function,
1131 lookup: "quux",
1132 detail: "fn quux(x: i32)",
1133 trigger_call_info: true,
1134 },
1135 CompletionItem {
1136 label: "x",
1137 source_range: 80..81,
1138 delete: 80..81,
1139 insert: "x",
1140 kind: Binding,
1141 detail: "i32",
1142 },
1143 CompletionItem {
1144 label: "y",
1145 source_range: 80..81,
1146 delete: 80..81,
1147 insert: "y",
1148 kind: Binding,
1149 detail: "i32",
1150 },
1151 ]
1152 "###
1153 ); 541 );
1154 } 542 }
1155 543
1156 #[test] 544 #[test]
1157 fn completes_unresolved_uses() { 545 fn completes_unresolved_uses() {
1158 assert_debug_snapshot!( 546 check(
1159 do_reference_completion( 547 r#"
1160 r" 548use spam::Quux;
1161 use spam::Quux; 549
1162 550fn main() { <|> }
1163 fn main() { 551"#,
1164 <|> 552 expect![[r#"
1165 } 553 ?? Quux
1166 " 554 fn main() fn main()
1167 ), 555 "#]],
1168 @r###"
1169 [
1170 CompletionItem {
1171 label: "Quux",
1172 source_range: 33..33,
1173 delete: 33..33,
1174 insert: "Quux",
1175 },
1176 CompletionItem {
1177 label: "main()",
1178 source_range: 33..33,
1179 delete: 33..33,
1180 insert: "main()$0",
1181 kind: Function,
1182 lookup: "main",
1183 detail: "fn main()",
1184 },
1185 ]
1186 "###
1187 ); 556 );
1188 } 557 }
1189 #[test] 558 #[test]
1190 fn completes_enum_variant_matcharm() { 559 fn completes_enum_variant_matcharm() {
1191 assert_debug_snapshot!( 560 check(
1192 do_reference_completion( 561 r#"
1193 r" 562enum Foo { Bar, Baz, Quux }
1194 enum Foo {
1195 Bar,
1196 Baz,
1197 Quux
1198 }
1199
1200 fn main() {
1201 let foo = Foo::Quux;
1202 563
1203 match foo { 564fn main() {
1204 Qu<|> 565 let foo = Foo::Quux;
1205 } 566 match foo { Qu<|> }
1206 } 567}
1207 " 568"#,
1208 ), 569 expect![[r#"
1209 @r###" 570 en Foo
1210 [ 571 ev Foo::Bar ()
1211 CompletionItem { 572 ev Foo::Baz ()
1212 label: "Foo", 573 ev Foo::Quux ()
1213 source_range: 103..105, 574 "#]],
1214 delete: 103..105,
1215 insert: "Foo",
1216 kind: Enum,
1217 },
1218 CompletionItem {
1219 label: "Foo::Bar",
1220 source_range: 103..105,
1221 delete: 103..105,
1222 insert: "Foo::Bar",
1223 kind: EnumVariant,
1224 lookup: "Bar",
1225 detail: "()",
1226 },
1227 CompletionItem {
1228 label: "Foo::Baz",
1229 source_range: 103..105,
1230 delete: 103..105,
1231 insert: "Foo::Baz",
1232 kind: EnumVariant,
1233 lookup: "Baz",
1234 detail: "()",
1235 },
1236 CompletionItem {
1237 label: "Foo::Quux",
1238 source_range: 103..105,
1239 delete: 103..105,
1240 insert: "Foo::Quux",
1241 kind: EnumVariant,
1242 lookup: "Quux",
1243 detail: "()",
1244 },
1245 ]
1246 "###
1247 ) 575 )
1248 } 576 }
1249 577
1250 #[test] 578 #[test]
1251 fn completes_enum_variant_iflet() { 579 fn completes_enum_variant_iflet() {
1252 assert_debug_snapshot!( 580 check(
1253 do_reference_completion( 581 r#"
1254 r" 582enum Foo { Bar, Baz, Quux }
1255 enum Foo {
1256 Bar,
1257 Baz,
1258 Quux
1259 }
1260 583
1261 fn main() { 584fn main() {
1262 let foo = Foo::Quux; 585 let foo = Foo::Quux;
1263 586 if let Qu<|> = foo { }
1264 if let Qu<|> = foo { 587}
1265 588"#,
1266 } 589 expect![[r#"
1267 } 590 en Foo
1268 " 591 ev Foo::Bar ()
1269 ), 592 ev Foo::Baz ()
1270 @r###" 593 ev Foo::Quux ()
1271 [ 594 "#]],
1272 CompletionItem {
1273 label: "Foo",
1274 source_range: 90..92,
1275 delete: 90..92,
1276 insert: "Foo",
1277 kind: Enum,
1278 },
1279 CompletionItem {
1280 label: "Foo::Bar",
1281 source_range: 90..92,
1282 delete: 90..92,
1283 insert: "Foo::Bar",
1284 kind: EnumVariant,
1285 lookup: "Bar",
1286 detail: "()",
1287 },
1288 CompletionItem {
1289 label: "Foo::Baz",
1290 source_range: 90..92,
1291 delete: 90..92,
1292 insert: "Foo::Baz",
1293 kind: EnumVariant,
1294 lookup: "Baz",
1295 detail: "()",
1296 },
1297 CompletionItem {
1298 label: "Foo::Quux",
1299 source_range: 90..92,
1300 delete: 90..92,
1301 insert: "Foo::Quux",
1302 kind: EnumVariant,
1303 lookup: "Quux",
1304 detail: "()",
1305 },
1306 ]
1307 "###
1308 ) 595 )
1309 } 596 }
1310 597
1311 #[test] 598 #[test]
1312 fn completes_enum_variant_basic_expr() { 599 fn completes_enum_variant_basic_expr() {
1313 assert_debug_snapshot!( 600 check(
1314 do_reference_completion( 601 r#"
1315 r" 602enum Foo { Bar, Baz, Quux }
1316 enum Foo { 603fn main() { let foo: Foo = Q<|> }
1317 Bar, 604"#,
1318 Baz, 605 expect![[r#"
1319 Quux 606 en Foo
1320 } 607 ev Foo::Bar ()
1321 608 ev Foo::Baz ()
1322 fn main() { 609 ev Foo::Quux ()
1323 let foo: Foo = Q<|> 610 fn main() fn main()
1324 } 611 "#]],
1325 "
1326 ),
1327 @r###"
1328 [
1329 CompletionItem {
1330 label: "Foo",
1331 source_range: 72..73,
1332 delete: 72..73,
1333 insert: "Foo",
1334 kind: Enum,
1335 },
1336 CompletionItem {
1337 label: "Foo::Bar",
1338 source_range: 72..73,
1339 delete: 72..73,
1340 insert: "Foo::Bar",
1341 kind: EnumVariant,
1342 lookup: "Bar",
1343 detail: "()",
1344 },
1345 CompletionItem {
1346 label: "Foo::Baz",
1347 source_range: 72..73,
1348 delete: 72..73,
1349 insert: "Foo::Baz",
1350 kind: EnumVariant,
1351 lookup: "Baz",
1352 detail: "()",
1353 },
1354 CompletionItem {
1355 label: "Foo::Quux",
1356 source_range: 72..73,
1357 delete: 72..73,
1358 insert: "Foo::Quux",
1359 kind: EnumVariant,
1360 lookup: "Quux",
1361 detail: "()",
1362 },
1363 CompletionItem {
1364 label: "main()",
1365 source_range: 72..73,
1366 delete: 72..73,
1367 insert: "main()$0",
1368 kind: Function,
1369 lookup: "main",
1370 detail: "fn main()",
1371 },
1372 ]
1373 "###
1374 ) 612 )
1375 } 613 }
1376 614
1377 #[test] 615 #[test]
1378 fn completes_enum_variant_from_module() { 616 fn completes_enum_variant_from_module() {
1379 assert_debug_snapshot!( 617 check(
1380 do_reference_completion( 618 r#"
1381 r" 619mod m { pub enum E { V } }
1382 mod m { pub enum E { V } } 620fn f() -> m::E { V<|> }
1383 621"#,
1384 fn f() -> m::E { 622 expect![[r#"
1385 V<|> 623 fn f() fn f() -> m::E
1386 } 624 md m
1387 " 625 ev m::E::V ()
1388 ), 626 "#]],
1389 @r###"
1390 [
1391 CompletionItem {
1392 label: "f()",
1393 source_range: 49..50,
1394 delete: 49..50,
1395 insert: "f()$0",
1396 kind: Function,
1397 lookup: "f",
1398 detail: "fn f() -> m::E",
1399 },
1400 CompletionItem {
1401 label: "m",
1402 source_range: 49..50,
1403 delete: 49..50,
1404 insert: "m",
1405 kind: Module,
1406 },
1407 CompletionItem {
1408 label: "m::E::V",
1409 source_range: 49..50,
1410 delete: 49..50,
1411 insert: "m::E::V",
1412 kind: EnumVariant,
1413 lookup: "V",
1414 detail: "()",
1415 },
1416 ]
1417 "###
1418 ) 627 )
1419 } 628 }
1420 629
1421 #[test] 630 #[test]
1422 fn dont_complete_attr() { 631 fn dont_complete_attr() {
1423 assert_debug_snapshot!( 632 check(
1424 do_reference_completion( 633 r#"
1425 r" 634struct Foo;
1426 struct Foo; 635#[<|>]
1427 #[<|>] 636fn f() {}
1428 fn f() {} 637"#,
1429 " 638 expect![[""]],
1430 ), 639 )
1431 @r###"[]"### 640 }
641
642 #[test]
643 fn completes_type_or_trait_in_impl_block() {
644 check(
645 r#"
646trait MyTrait {}
647struct MyStruct {}
648
649impl My<|>
650"#,
651 expect![[r#"
652 st MyStruct
653 tt MyTrait
654 tp Self
655 "#]],
1432 ) 656 )
1433 } 657 }
1434} 658}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index ef22ea54d..c84d43d77 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -24,6 +24,7 @@ use test_utils::mark;
24#[derive(Debug)] 24#[derive(Debug)]
25pub(crate) struct CompletionContext<'a> { 25pub(crate) struct CompletionContext<'a> {
26 pub(super) sema: Semantics<'a, RootDatabase>, 26 pub(super) sema: Semantics<'a, RootDatabase>,
27 pub(super) scope: SemanticsScope<'a>,
27 pub(super) db: &'a RootDatabase, 28 pub(super) db: &'a RootDatabase,
28 pub(super) config: &'a CompletionConfig, 29 pub(super) config: &'a CompletionConfig,
29 pub(super) offset: TextSize, 30 pub(super) offset: TextSize,
@@ -53,6 +54,8 @@ pub(crate) struct CompletionContext<'a> {
53 pub(super) after_if: bool, 54 pub(super) after_if: bool,
54 /// `true` if we are a statement or a last expr in the block. 55 /// `true` if we are a statement or a last expr in the block.
55 pub(super) can_be_stmt: bool, 56 pub(super) can_be_stmt: bool,
57 /// `true` if we expect an expression at the cursor position.
58 pub(super) is_expr: bool,
56 /// Something is typed at the "top" level, in module or impl/trait. 59 /// Something is typed at the "top" level, in module or impl/trait.
57 pub(super) is_new_item: bool, 60 pub(super) is_new_item: bool,
58 /// The receiver if this is a field or method access, i.e. writing something.<|> 61 /// The receiver if this is a field or method access, i.e. writing something.<|>
@@ -60,6 +63,8 @@ pub(crate) struct CompletionContext<'a> {
60 pub(super) dot_receiver_is_ambiguous_float_literal: bool, 63 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
61 /// If this is a call (method or function) in particular, i.e. the () are already there. 64 /// If this is a call (method or function) in particular, i.e. the () are already there.
62 pub(super) is_call: bool, 65 pub(super) is_call: bool,
66 /// Like `is_call`, but for tuple patterns.
67 pub(super) is_pattern_call: bool,
63 /// If this is a macro call, i.e. the () are already there. 68 /// If this is a macro call, i.e. the () are already there.
64 pub(super) is_macro_call: bool, 69 pub(super) is_macro_call: bool,
65 pub(super) is_path_type: bool, 70 pub(super) is_path_type: bool,
@@ -104,8 +109,10 @@ impl<'a> CompletionContext<'a> {
104 let original_token = 109 let original_token =
105 original_file.syntax().token_at_offset(position.offset).left_biased()?; 110 original_file.syntax().token_at_offset(position.offset).left_biased()?;
106 let token = sema.descend_into_macros(original_token.clone()); 111 let token = sema.descend_into_macros(original_token.clone());
112 let scope = sema.scope_at_offset(&token.parent(), position.offset);
107 let mut ctx = CompletionContext { 113 let mut ctx = CompletionContext {
108 sema, 114 sema,
115 scope,
109 db, 116 db,
110 config, 117 config,
111 original_token, 118 original_token,
@@ -127,9 +134,11 @@ impl<'a> CompletionContext<'a> {
127 path_prefix: None, 134 path_prefix: None,
128 after_if: false, 135 after_if: false,
129 can_be_stmt: false, 136 can_be_stmt: false,
137 is_expr: false,
130 is_new_item: false, 138 is_new_item: false,
131 dot_receiver: None, 139 dot_receiver: None,
132 is_call: false, 140 is_call: false,
141 is_pattern_call: false,
133 is_macro_call: false, 142 is_macro_call: false,
134 is_path_type: false, 143 is_path_type: false,
135 has_type_args: false, 144 has_type_args: false,
@@ -196,30 +205,17 @@ impl<'a> CompletionContext<'a> {
196 // The range of the identifier that is being completed. 205 // The range of the identifier that is being completed.
197 pub(crate) fn source_range(&self) -> TextRange { 206 pub(crate) fn source_range(&self) -> TextRange {
198 // check kind of macro-expanded token, but use range of original token 207 // check kind of macro-expanded token, but use range of original token
199 match self.token.kind() { 208 if self.token.kind() == IDENT || self.token.kind().is_keyword() {
200 // workaroud when completion is triggered by trigger characters. 209 mark::hit!(completes_if_prefix_is_keyword);
201 IDENT => self.original_token.text_range(), 210 self.original_token.text_range()
202 _ => { 211 } else {
203 // If we haven't characters between keyword and our cursor we take the keyword start range to edit 212 TextRange::empty(self.offset)
204 if self.token.kind().is_keyword()
205 && self.offset == self.original_token.text_range().end()
206 {
207 mark::hit!(completes_bindings_from_for_with_in_prefix);
208 TextRange::empty(self.original_token.text_range().start())
209 } else {
210 TextRange::empty(self.offset)
211 }
212 }
213 } 213 }
214 } 214 }
215 215
216 pub(crate) fn scope(&self) -> SemanticsScope<'_> {
217 self.sema.scope_at_offset(&self.token.parent(), self.offset)
218 }
219
220 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 216 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
221 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); 217 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
222 let syntax_element = NodeOrToken::Token(fake_ident_token.clone()); 218 let syntax_element = NodeOrToken::Token(fake_ident_token);
223 self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); 219 self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
224 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); 220 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone());
225 self.if_is_prev = if_is_prev(syntax_element.clone()); 221 self.if_is_prev = if_is_prev(syntax_element.clone());
@@ -232,7 +228,7 @@ impl<'a> CompletionContext<'a> {
232 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 228 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
233 self.is_match_arm = is_match_arm(syntax_element.clone()); 229 self.is_match_arm = is_match_arm(syntax_element.clone());
234 self.has_item_list_or_source_file_parent = 230 self.has_item_list_or_source_file_parent =
235 has_item_list_or_source_file_parent(syntax_element.clone()); 231 has_item_list_or_source_file_parent(syntax_element);
236 } 232 }
237 233
238 fn fill( 234 fn fill(
@@ -377,6 +373,8 @@ impl<'a> CompletionContext<'a> {
377 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 373 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
378 .is_some(); 374 .is_some();
379 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); 375 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();
376 self.is_pattern_call =
377 path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some();
380 378
381 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 379 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
382 self.has_type_args = segment.type_arg_list().is_some(); 380 self.has_type_args = segment.type_arg_list().is_some();
@@ -412,6 +410,7 @@ impl<'a> CompletionContext<'a> {
412 None 410 None
413 }) 411 })
414 .unwrap_or(false); 412 .unwrap_or(false);
413 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
415 414
416 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { 415 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
417 if let Some(if_expr) = 416 if let Some(if_expr) =
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index 477d6f6f6..7bdda316c 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -58,7 +58,7 @@ pub struct CompletionItem {
58 score: Option<CompletionScore>, 58 score: Option<CompletionScore>,
59} 59}
60 60
61// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 61// We use custom debug for CompletionItem to make snapshot tests more readable.
62impl fmt::Debug for CompletionItem { 62impl fmt::Debug for CompletionItem {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 let mut s = f.debug_struct("CompletionItem"); 64 let mut s = f.debug_struct("CompletionItem");
@@ -123,6 +123,7 @@ pub enum CompletionItemKind {
123 TypeParam, 123 TypeParam,
124 Macro, 124 Macro,
125 Attribute, 125 Attribute,
126 UnresolvedReference,
126} 127}
127 128
128impl CompletionItemKind { 129impl CompletionItemKind {
@@ -147,6 +148,7 @@ impl CompletionItemKind {
147 CompletionItemKind::Trait => "tt", 148 CompletionItemKind::Trait => "tt",
148 CompletionItemKind::TypeAlias => "ta", 149 CompletionItemKind::TypeAlias => "ta",
149 CompletionItemKind::TypeParam => "tp", 150 CompletionItemKind::TypeParam => "tp",
151 CompletionItemKind::UnresolvedReference => "??",
150 } 152 }
151 } 153 }
152} 154}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index bfa7e08be..9a94ff476 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -11,7 +11,7 @@ use crate::{
11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, 11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
12 CompletionKind, Completions, 12 CompletionKind, Completions,
13 }, 13 },
14 display::{const_label, macro_label, type_label, FunctionSignature}, 14 display::{const_label, function_declaration, macro_label, type_label},
15 CompletionScore, RootDatabase, 15 CompletionScore, RootDatabase,
16}; 16};
17 17
@@ -79,11 +79,10 @@ impl Completions {
79 return self.add_macro(ctx, Some(local_name), *mac); 79 return self.add_macro(ctx, Some(local_name), *mac);
80 } 80 }
81 ScopeDef::Unknown => { 81 ScopeDef::Unknown => {
82 return self.add(CompletionItem::new( 82 return self.add(
83 CompletionKind::Reference, 83 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
84 ctx.source_range(), 84 .kind(CompletionItemKind::UnresolvedReference),
85 local_name, 85 );
86 ));
87 } 86 }
88 }; 87 };
89 88
@@ -196,7 +195,6 @@ impl Completions {
196 195
197 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); 196 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
198 let ast_node = func.source(ctx.db).value; 197 let ast_node = func.source(ctx.db).value;
199 let function_signature = FunctionSignature::from(&ast_node);
200 198
201 let mut builder = 199 let mut builder =
202 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) 200 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
@@ -207,13 +205,14 @@ impl Completions {
207 }) 205 })
208 .set_documentation(func.docs(ctx.db)) 206 .set_documentation(func.docs(ctx.db))
209 .set_deprecated(is_deprecated(func, ctx.db)) 207 .set_deprecated(is_deprecated(func, ctx.db))
210 .detail(function_signature.to_string()); 208 .detail(function_declaration(&ast_node));
211 209
212 let params = function_signature 210 let params = ast_node
213 .parameter_names 211 .param_list()
214 .iter() 212 .into_iter()
215 .skip(if function_signature.has_self_param { 1 } else { 0 }) 213 .flat_map(|it| it.params())
216 .map(|name| name.trim_start_matches('_').into()) 214 .flat_map(|it| it.pat())
215 .map(|pat| pat.to_string().trim_start_matches('_').into())
217 .collect(); 216 .collect();
218 217
219 builder = builder.add_call_parens(ctx, name, Params::Named(params)); 218 builder = builder.add_call_parens(ctx, name, Params::Named(params));
@@ -316,6 +315,7 @@ impl Completions {
316 } 315 }
317 316
318 if variant_kind == StructKind::Tuple { 317 if variant_kind == StructKind::Tuple {
318 mark::hit!(inserts_parens_for_tuple_enums);
319 let params = Params::Anonymous(variant.fields(ctx.db).len()); 319 let params = Params::Anonymous(variant.fields(ctx.db).len());
320 res = res.add_call_parens(ctx, qualified_name, params) 320 res = res.add_call_parens(ctx, qualified_name, params)
321 } 321 }
@@ -329,15 +329,10 @@ pub(crate) fn compute_score(
329 ty: &Type, 329 ty: &Type,
330 name: &str, 330 name: &str,
331) -> Option<CompletionScore> { 331) -> Option<CompletionScore> {
332 // FIXME: this should not fall back to string equality.
333 let ty = &ty.display(ctx.db).to_string();
334 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
335 mark::hit!(record_field_type_match); 333 mark::hit!(record_field_type_match);
336 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
337 ( 335 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
338 struct_field.name(ctx.db).to_string(),
339 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
340 )
341 } else if let Some(active_parameter) = &ctx.active_parameter { 336 } else if let Some(active_parameter) = &ctx.active_parameter {
342 mark::hit!(active_param_type_match); 337 mark::hit!(active_param_type_match);
343 (active_parameter.name.clone(), active_parameter.ty.clone()) 338 (active_parameter.name.clone(), active_parameter.ty.clone())
@@ -384,10 +379,17 @@ impl Builder {
384 if !ctx.config.add_call_parenthesis { 379 if !ctx.config.add_call_parenthesis {
385 return self; 380 return self;
386 } 381 }
387 if ctx.use_item_syntax.is_some() || ctx.is_call { 382 if ctx.use_item_syntax.is_some() {
388 mark::hit!(no_parens_in_use_item); 383 mark::hit!(no_parens_in_use_item);
389 return self; 384 return self;
390 } 385 }
386 if ctx.is_pattern_call {
387 mark::hit!(dont_duplicate_pattern_parens);
388 return self;
389 }
390 if ctx.is_call {
391 return self;
392 }
391 393
392 // Don't add parentheses if the expected type is some function reference. 394 // Don't add parentheses if the expected type is some function reference.
393 if let Some(ty) = &ctx.expected_type { 395 if let Some(ty) = &ctx.expected_type {
@@ -492,7 +494,7 @@ mod tests {
492 } 494 }
493 } 495 }
494 496
495 let mut completions = get_all_completion_items(ra_fixture, &CompletionConfig::default()); 497 let mut completions = get_all_completion_items(CompletionConfig::default(), ra_fixture);
496 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); 498 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
497 let actual = completions 499 let actual = completions
498 .into_iter() 500 .into_iter()
@@ -836,6 +838,7 @@ fn bar(s: &S) {
836 fn suppress_arg_snippets() { 838 fn suppress_arg_snippets() {
837 mark::check!(suppress_arg_snippets); 839 mark::check!(suppress_arg_snippets);
838 check_edit_with_config( 840 check_edit_with_config(
841 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
839 "with_args", 842 "with_args",
840 r#" 843 r#"
841fn with_args(x: i32, y: String) {} 844fn with_args(x: i32, y: String) {}
@@ -845,7 +848,6 @@ fn main() { with_<|> }
845fn with_args(x: i32, y: String) {} 848fn with_args(x: i32, y: String) {}
846fn main() { with_args($0) } 849fn main() { with_args($0) }
847"#, 850"#,
848 &CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
849 ); 851 );
850 } 852 }
851 853
@@ -866,6 +868,7 @@ fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
866 868
867 #[test] 869 #[test]
868 fn inserts_parens_for_tuple_enums() { 870 fn inserts_parens_for_tuple_enums() {
871 mark::check!(inserts_parens_for_tuple_enums);
869 check_edit( 872 check_edit(
870 "Some", 873 "Some",
871 r#" 874 r#"
@@ -907,6 +910,30 @@ fn main(value: Option<i32>) {
907 } 910 }
908 911
909 #[test] 912 #[test]
913 fn dont_duplicate_pattern_parens() {
914 mark::check!(dont_duplicate_pattern_parens);
915 check_edit(
916 "Var",
917 r#"
918enum E { Var(i32) }
919fn main() {
920 match E::Var(92) {
921 E::<|>(92) => (),
922 }
923}
924"#,
925 r#"
926enum E { Var(i32) }
927fn main() {
928 match E::Var(92) {
929 E::Var(92) => (),
930 }
931}
932"#,
933 );
934 }
935
936 #[test]
910 fn no_call_parens_if_fn_ptr_needed() { 937 fn no_call_parens_if_fn_ptr_needed() {
911 mark::check!(no_call_parens_if_fn_ptr_needed); 938 mark::check!(no_call_parens_if_fn_ptr_needed);
912 check_edit( 939 check_edit(
@@ -1133,6 +1160,22 @@ fn go(world: &WorldSnapshot) { go(w<|>) }
1133 } 1160 }
1134 1161
1135 #[test] 1162 #[test]
1163 fn too_many_arguments() {
1164 mark::check!(too_many_arguments);
1165 check_scores(
1166 r#"
1167struct Foo;
1168fn f(foo: &Foo) { f(foo, w<|>) }
1169"#,
1170 expect![[r#"
1171 st Foo []
1172 fn f(…) []
1173 bn foo []
1174 "#]],
1175 );
1176 }
1177
1178 #[test]
1136 fn guesses_macro_braces() { 1179 fn guesses_macro_braces() {
1137 check_edit( 1180 check_edit(
1138 "vec!", 1181 "vec!",
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index c2be23697..919177745 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -13,15 +13,15 @@ use crate::{
13}; 13};
14 14
15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
16 do_completion_with_config(code, kind, &CompletionConfig::default()) 16 do_completion_with_config(CompletionConfig::default(), code, kind)
17} 17}
18 18
19pub(crate) fn do_completion_with_config( 19pub(crate) fn do_completion_with_config(
20 config: CompletionConfig,
20 code: &str, 21 code: &str,
21 kind: CompletionKind, 22 kind: CompletionKind,
22 config: &CompletionConfig,
23) -> Vec<CompletionItem> { 23) -> Vec<CompletionItem> {
24 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, config) 24 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
25 .into_iter() 25 .into_iter()
26 .filter(|c| c.completion_kind == kind) 26 .filter(|c| c.completion_kind == kind)
27 .collect(); 27 .collect();
@@ -30,15 +30,15 @@ pub(crate) fn do_completion_with_config(
30} 30}
31 31
32pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { 32pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String {
33 completion_list_with_config(code, kind, &CompletionConfig::default()) 33 completion_list_with_config(CompletionConfig::default(), code, kind)
34} 34}
35 35
36pub(crate) fn completion_list_with_config( 36pub(crate) fn completion_list_with_config(
37 config: CompletionConfig,
37 code: &str, 38 code: &str,
38 kind: CompletionKind, 39 kind: CompletionKind,
39 config: &CompletionConfig,
40) -> String { 40) -> String {
41 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, config) 41 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
42 .into_iter() 42 .into_iter()
43 .filter(|c| c.completion_kind == kind) 43 .filter(|c| c.completion_kind == kind)
44 .collect(); 44 .collect();
@@ -70,19 +70,19 @@ fn monospace_width(s: &str) -> usize {
70} 70}
71 71
72pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 72pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
73 check_edit_with_config(what, ra_fixture_before, ra_fixture_after, &CompletionConfig::default()) 73 check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after)
74} 74}
75 75
76pub(crate) fn check_edit_with_config( 76pub(crate) fn check_edit_with_config(
77 config: CompletionConfig,
77 what: &str, 78 what: &str,
78 ra_fixture_before: &str, 79 ra_fixture_before: &str,
79 ra_fixture_after: &str, 80 ra_fixture_after: &str,
80 config: &CompletionConfig,
81) { 81) {
82 let ra_fixture_after = trim_indent(ra_fixture_after); 82 let ra_fixture_after = trim_indent(ra_fixture_after);
83 let (analysis, position) = analysis_and_position(ra_fixture_before); 83 let (analysis, position) = analysis_and_position(ra_fixture_before);
84 let completions: Vec<CompletionItem> = 84 let completions: Vec<CompletionItem> =
85 analysis.completions(config, position).unwrap().unwrap().into(); 85 analysis.completions(&config, position).unwrap().unwrap().into();
86 let (completion,) = completions 86 let (completion,) = completions
87 .iter() 87 .iter()
88 .filter(|it| it.lookup() == what) 88 .filter(|it| it.lookup() == what)
@@ -106,9 +106,9 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -
106} 106}
107 107
108pub(crate) fn get_all_completion_items( 108pub(crate) fn get_all_completion_items(
109 config: CompletionConfig,
109 code: &str, 110 code: &str,
110 options: &CompletionConfig,
111) -> Vec<CompletionItem> { 111) -> Vec<CompletionItem> {
112 let (analysis, position) = analysis_and_position(code); 112 let (analysis, position) = analysis_and_position(code);
113 analysis.completions(options, position).unwrap().unwrap().into() 113 analysis.completions(&config, position).unwrap().unwrap().into()
114} 114}
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 46f8c31c7..e029af0dc 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -35,7 +35,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
35 let parse = db.parse(file_id); 35 let parse = db.parse(file_id);
36 let mut res = Vec::new(); 36 let mut res = Vec::new();
37 37
38 res.extend(parse.errors().iter().map(|err| Diagnostic { 38 // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
39 res.extend(parse.errors().iter().take(128).map(|err| Diagnostic {
39 range: err.range(), 40 range: err.range(),
40 message: format!("Syntax Error: {}", err), 41 message: format!("Syntax Error: {}", err),
41 severity: Severity::Error, 42 severity: Severity::Error,
@@ -99,14 +100,6 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
99 fix, 100 fix,
100 }) 101 })
101 }) 102 })
102 .on::<hir::diagnostics::MissingMatchArms, _>(|d| {
103 res.borrow_mut().push(Diagnostic {
104 range: sema.diagnostics_range(d).range,
105 message: d.message(),
106 severity: Severity::Error,
107 fix: None,
108 })
109 })
110 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 103 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
111 let node = d.ast(db); 104 let node = d.ast(db);
112 let replacement = format!("Ok({})", node.syntax()); 105 let replacement = format!("Ok({})", node.syntax());
@@ -138,7 +131,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
138 131
139fn missing_struct_field_fix( 132fn missing_struct_field_fix(
140 sema: &Semantics<RootDatabase>, 133 sema: &Semantics<RootDatabase>,
141 file_id: FileId, 134 usage_file_id: FileId,
142 d: &hir::diagnostics::NoSuchField, 135 d: &hir::diagnostics::NoSuchField,
143) -> Option<Fix> { 136) -> Option<Fix> {
144 let record_expr = sema.ast(d); 137 let record_expr = sema.ast(d);
@@ -146,25 +139,30 @@ fn missing_struct_field_fix(
146 let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?; 139 let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?;
147 let def_id = sema.resolve_variant(record_lit)?; 140 let def_id = sema.resolve_variant(record_lit)?;
148 let module; 141 let module;
142 let def_file_id;
149 let record_fields = match VariantDef::from(def_id) { 143 let record_fields = match VariantDef::from(def_id) {
150 VariantDef::Struct(s) => { 144 VariantDef::Struct(s) => {