diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-31 18:05:12 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-31 18:05:12 +0000 |
commit | 1dc5608d0bb6bf2eee5a1b9190fcb2f8cdfa2ef3 (patch) | |
tree | b3c8a97880c625a81a814f4afa4e461ce5a58b82 | |
parent | e60ef6260f49b2b0438f8649ca71034fbafef631 (diff) | |
parent | c09e14a4ff02f774460a70472e1aeb3c598e01dc (diff) |
Merge #176
176: Move completio to ra_analysis r=matklad a=matklad
While we should handle completion for isolated file, it's better
achieved by using empty Analysis, rather than working only with &File:
we need memoization for type inference even inside a single file.
Co-authored-by: Aleksey Kladov <[email protected]>
20 files changed, 1066 insertions, 1066 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs index 0141d132e..340ae3f66 100644 --- a/crates/ra_analysis/src/completion.rs +++ b/crates/ra_analysis/src/completion.rs | |||
@@ -1,16 +1,32 @@ | |||
1 | use ra_editor::{CompletionItem, find_node_at_offset}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | use ra_editor::{find_node_at_offset}; | ||
2 | use ra_syntax::{ | 3 | use ra_syntax::{ |
3 | AtomEdit, File, TextUnit, AstNode, | 4 | AtomEdit, File, TextUnit, AstNode, SyntaxNodeRef, |
4 | ast::{self, ModuleItemOwner, AstChildren}, | 5 | algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx}, |
6 | ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner}, | ||
7 | SyntaxKind::*, | ||
5 | }; | 8 | }; |
6 | 9 | ||
7 | use crate::{ | 10 | use crate::{ |
8 | FileId, Cancelable, | 11 | FileId, Cancelable, |
9 | input::FilesDatabase, | 12 | input::FilesDatabase, |
10 | db::{self, SyntaxDatabase}, | 13 | db::{self, SyntaxDatabase}, |
11 | descriptors::module::{ModulesDatabase, ModuleTree, ModuleId, scope::ModuleScope}, | 14 | descriptors::DescriptorDatabase, |
15 | descriptors::function::FnScopes, | ||
16 | descriptors::module::{ModuleTree, ModuleId, ModuleScope}, | ||
12 | }; | 17 | }; |
13 | 18 | ||
19 | |||
20 | #[derive(Debug)] | ||
21 | pub struct CompletionItem { | ||
22 | /// What user sees in pop-up | ||
23 | pub label: String, | ||
24 | /// What string is used for filtering, defaults to label | ||
25 | pub lookup: Option<String>, | ||
26 | /// What is inserted, defaults to label | ||
27 | pub snippet: Option<String>, | ||
28 | } | ||
29 | |||
14 | pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { | 30 | pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { |
15 | let source_root_id = db.file_source_root(file_id); | 31 | let source_root_id = db.file_source_root(file_id); |
16 | let file = db.file_syntax(file_id); | 32 | let file = db.file_syntax(file_id); |
@@ -72,3 +88,602 @@ fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> { | |||
72 | res.reverse(); | 88 | res.reverse(); |
73 | Some(res) | 89 | Some(res) |
74 | } | 90 | } |
91 | |||
92 | |||
93 | pub(crate) fn scope_completion( | ||
94 | db: &db::RootDatabase, | ||
95 | file_id: FileId, | ||
96 | offset: TextUnit, | ||
97 | ) -> Option<Vec<CompletionItem>> { | ||
98 | let original_file = db.file_syntax(file_id); | ||
99 | // Insert a fake ident to get a valid parse tree | ||
100 | let file = { | ||
101 | let edit = AtomEdit::insert(offset, "intellijRulezz".to_string()); | ||
102 | original_file.reparse(&edit) | ||
103 | }; | ||
104 | let mut has_completions = false; | ||
105 | let mut res = Vec::new(); | ||
106 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) { | ||
107 | has_completions = true; | ||
108 | complete_name_ref(&file, name_ref, &mut res); | ||
109 | // special case, `trait T { fn foo(i_am_a_name_ref) {} }` | ||
110 | if is_node::<ast::Param>(name_ref.syntax()) { | ||
111 | param_completions(name_ref.syntax(), &mut res); | ||
112 | } | ||
113 | let name_range = name_ref.syntax().range(); | ||
114 | let top_node = name_ref | ||
115 | .syntax() | ||
116 | .ancestors() | ||
117 | .take_while(|it| it.range() == name_range) | ||
118 | .last() | ||
119 | .unwrap(); | ||
120 | match top_node.parent().map(|it| it.kind()) { | ||
121 | Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res), | ||
122 | _ => (), | ||
123 | } | ||
124 | } | ||
125 | if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) { | ||
126 | if is_node::<ast::Param>(name.syntax()) { | ||
127 | has_completions = true; | ||
128 | param_completions(name.syntax(), &mut res); | ||
129 | } | ||
130 | } | ||
131 | if has_completions { | ||
132 | Some(res) | ||
133 | } else { | ||
134 | None | ||
135 | } | ||
136 | } | ||
137 | |||
138 | fn complete_module_items( | ||
139 | file: &File, | ||
140 | items: AstChildren<ast::ModuleItem>, | ||
141 | this_item: Option<ast::NameRef>, | ||
142 | acc: &mut Vec<CompletionItem>, | ||
143 | ) { | ||
144 | let scope = ModuleScope::from_items(items); | ||
145 | acc.extend( | ||
146 | scope | ||
147 | .entries() | ||
148 | .iter() | ||
149 | .filter(|entry| { | ||
150 | let syntax = entry.ptr().resolve(file); | ||
151 | Some(syntax.borrowed()) != this_item.map(|it| it.syntax()) | ||
152 | }) | ||
153 | .map(|entry| CompletionItem { | ||
154 | label: entry.name().to_string(), | ||
155 | lookup: None, | ||
156 | snippet: None, | ||
157 | }), | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | fn complete_name_ref( | ||
162 | file: &File, | ||
163 | name_ref: ast::NameRef, | ||
164 | acc: &mut Vec<CompletionItem>, | ||
165 | ) { | ||
166 | if !is_node::<ast::Path>(name_ref.syntax()) { | ||
167 | return; | ||
168 | } | ||
169 | let mut visited_fn = false; | ||
170 | for node in name_ref.syntax().ancestors() { | ||
171 | if let Some(items) = visitor() | ||
172 | .visit::<ast::Root, _>(|it| Some(it.items())) | ||
173 | .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) | ||
174 | .accept(node) | ||
175 | { | ||
176 | if let Some(items) = items { | ||
177 | complete_module_items(file, items, Some(name_ref), acc); | ||
178 | } | ||
179 | break; | ||
180 | } else if !visited_fn { | ||
181 | if let Some(fn_def) = ast::FnDef::cast(node) { | ||
182 | visited_fn = true; | ||
183 | complete_expr_keywords(&file, fn_def, name_ref, acc); | ||
184 | complete_expr_snippets(acc); | ||
185 | let scopes = FnScopes::new(fn_def); | ||
186 | complete_fn(name_ref, &scopes, acc); | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { | ||
193 | let mut params = FxHashMap::default(); | ||
194 | for node in ctx.ancestors() { | ||
195 | let _ = visitor_ctx(&mut params) | ||
196 | .visit::<ast::Root, _>(process) | ||
197 | .visit::<ast::ItemList, _>(process) | ||
198 | .accept(node); | ||
199 | } | ||
200 | params | ||
201 | .into_iter() | ||
202 | .filter_map(|(label, (count, param))| { | ||
203 | let lookup = param.pat()?.syntax().text().to_string(); | ||
204 | if count < 2 { | ||
205 | None | ||
206 | } else { | ||
207 | Some((label, lookup)) | ||
208 | } | ||
209 | }) | ||
210 | .for_each(|(label, lookup)| { | ||
211 | acc.push(CompletionItem { | ||
212 | label, | ||
213 | lookup: Some(lookup), | ||
214 | snippet: None, | ||
215 | }) | ||
216 | }); | ||
217 | |||
218 | fn process<'a, N: ast::FnDefOwner<'a>>( | ||
219 | node: N, | ||
220 | params: &mut FxHashMap<String, (u32, ast::Param<'a>)>, | ||
221 | ) { | ||
222 | node.functions() | ||
223 | .filter_map(|it| it.param_list()) | ||
224 | .flat_map(|it| it.params()) | ||
225 | .for_each(|param| { | ||
226 | let text = param.syntax().text().to_string(); | ||
227 | params.entry(text).or_insert((0, param)).0 += 1; | ||
228 | }) | ||
229 | } | ||
230 | } | ||
231 | |||
232 | fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { | ||
233 | match node.ancestors().filter_map(N::cast).next() { | ||
234 | None => false, | ||
235 | Some(n) => n.syntax().range() == node.range(), | ||
236 | } | ||
237 | } | ||
238 | |||
239 | fn complete_expr_keywords( | ||
240 | file: &File, | ||
241 | fn_def: ast::FnDef, | ||
242 | name_ref: ast::NameRef, | ||
243 | acc: &mut Vec<CompletionItem>, | ||
244 | ) { | ||
245 | acc.push(keyword("if", "if $0 {}")); | ||
246 | acc.push(keyword("match", "match $0 {}")); | ||
247 | acc.push(keyword("while", "while $0 {}")); | ||
248 | acc.push(keyword("loop", "loop {$0}")); | ||
249 | |||
250 | if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) { | ||
251 | if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) { | ||
252 | if if_expr.syntax().range().end() < name_ref.syntax().range().start() { | ||
253 | acc.push(keyword("else", "else {$0}")); | ||
254 | acc.push(keyword("else if", "else if $0 {}")); | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | if is_in_loop_body(name_ref) { | ||
259 | acc.push(keyword("continue", "continue")); | ||
260 | acc.push(keyword("break", "break")); | ||
261 | } | ||
262 | acc.extend(complete_return(fn_def, name_ref)); | ||
263 | } | ||
264 | |||
265 | fn is_in_loop_body(name_ref: ast::NameRef) -> bool { | ||
266 | for node in name_ref.syntax().ancestors() { | ||
267 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { | ||
268 | break; | ||
269 | } | ||
270 | let loop_body = visitor() | ||
271 | .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body) | ||
272 | .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body) | ||
273 | .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body) | ||
274 | .accept(node); | ||
275 | if let Some(Some(body)) = loop_body { | ||
276 | if name_ref.syntax().range().is_subrange(&body.syntax().range()) { | ||
277 | return true; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | false | ||
282 | } | ||
283 | |||
284 | fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> { | ||
285 | // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast) | ||
286 | // .next() | ||
287 | // .and_then(|it| it.syntax().parent()) | ||
288 | // .and_then(ast::Block::cast) | ||
289 | // .is_some(); | ||
290 | |||
291 | // if is_last_in_block { | ||
292 | // return None; | ||
293 | // } | ||
294 | |||
295 | let is_stmt = match name_ref | ||
296 | .syntax() | ||
297 | .ancestors() | ||
298 | .filter_map(ast::ExprStmt::cast) | ||
299 | .next() | ||
300 | { | ||
301 | None => false, | ||
302 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), | ||
303 | }; | ||
304 | let snip = match (is_stmt, fn_def.ret_type().is_some()) { | ||
305 | (true, true) => "return $0;", | ||
306 | (true, false) => "return;", | ||
307 | (false, true) => "return $0", | ||
308 | (false, false) => "return", | ||
309 | }; | ||
310 | Some(keyword("return", snip)) | ||
311 | } | ||
312 | |||
313 | fn keyword(kw: &str, snip: &str) -> CompletionItem { | ||
314 | CompletionItem { | ||
315 | label: kw.to_string(), | ||
316 | lookup: None, | ||
317 | snippet: Some(snip.to_string()), | ||
318 | } | ||
319 | } | ||
320 | |||
321 | fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { | ||
322 | acc.push(CompletionItem { | ||
323 | label: "pd".to_string(), | ||
324 | lookup: None, | ||
325 | snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()), | ||
326 | }); | ||
327 | acc.push(CompletionItem { | ||
328 | label: "ppd".to_string(), | ||
329 | lookup: None, | ||
330 | snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), | ||
331 | }); | ||
332 | } | ||
333 | |||
334 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | ||
335 | acc.push(CompletionItem { | ||
336 | label: "tfn".to_string(), | ||
337 | lookup: None, | ||
338 | snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), | ||
339 | }); | ||
340 | acc.push(CompletionItem { | ||
341 | label: "pub(crate)".to_string(), | ||
342 | lookup: None, | ||
343 | snippet: Some("pub(crate) $0".to_string()), | ||
344 | }) | ||
345 | } | ||
346 | |||
347 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | ||
348 | let mut shadowed = FxHashSet::default(); | ||
349 | acc.extend( | ||
350 | scopes | ||
351 | .scope_chain(name_ref.syntax()) | ||
352 | .flat_map(|scope| scopes.entries(scope).iter()) | ||
353 | .filter(|entry| shadowed.insert(entry.name())) | ||
354 | .map(|entry| CompletionItem { | ||
355 | label: entry.name().to_string(), | ||
356 | lookup: None, | ||
357 | snippet: None, | ||
358 | }), | ||
359 | ); | ||
360 | if scopes.self_param.is_some() { | ||
361 | acc.push(CompletionItem { | ||
362 | label: "self".to_string(), | ||
363 | lookup: None, | ||
364 | snippet: None, | ||
365 | }) | ||
366 | } | ||
367 | } | ||
368 | |||
369 | #[cfg(test)] | ||
370 | mod tests { | ||
371 | use test_utils::{assert_eq_dbg, extract_offset}; | ||
372 | |||
373 | use crate::FileId; | ||
374 | use crate::mock_analysis::MockAnalysis; | ||
375 | |||
376 | use super::*; | ||
377 | |||
378 | fn check_scope_completion(code: &str, expected_completions: &str) { | ||
379 | let (off, code) = extract_offset(&code); | ||
380 | let analysis = MockAnalysis::with_files(&[("/main.rs", &code)]).analysis(); | ||
381 | let file_id = FileId(1); | ||
382 | let completions = scope_completion(&analysis.imp.db, file_id, off) | ||
383 | .unwrap() | ||
384 | .into_iter() | ||
385 | .filter(|c| c.snippet.is_none()) | ||
386 | .collect::<Vec<_>>(); | ||
387 | assert_eq_dbg(expected_completions, &completions); | ||
388 | } | ||
389 | |||
390 | fn check_snippet_completion(code: &str, expected_completions: &str) { | ||
391 | let (off, code) = extract_offset(&code); | ||
392 | let analysis = MockAnalysis::with_files(&[("/main.rs", &code)]).analysis(); | ||
393 | let file_id = FileId(1); | ||
394 | let completions = scope_completion(&analysis.imp.db, file_id, off) | ||
395 | .unwrap() | ||
396 | .into_iter() | ||
397 | .filter(|c| c.snippet.is_some()) | ||
398 | .collect::<Vec<_>>(); | ||
399 | assert_eq_dbg(expected_completions, &completions); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn test_completion_let_scope() { | ||
404 | check_scope_completion( | ||
405 | r" | ||
406 | fn quux(x: i32) { | ||
407 | let y = 92; | ||
408 | 1 + <|>; | ||
409 | let z = (); | ||
410 | } | ||
411 | ", | ||
412 | r#"[CompletionItem { label: "y", lookup: None, snippet: None }, | ||
413 | CompletionItem { label: "x", lookup: None, snippet: None }, | ||
414 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
415 | ); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn test_completion_if_let_scope() { | ||
420 | check_scope_completion( | ||
421 | r" | ||
422 | fn quux() { | ||
423 | if let Some(x) = foo() { | ||
424 | let y = 92; | ||
425 | }; | ||
426 | if let Some(a) = bar() { | ||
427 | let b = 62; | ||
428 | 1 + <|> | ||
429 | } | ||
430 | } | ||
431 | ", | ||
432 | r#"[CompletionItem { label: "b", lookup: None, snippet: None }, | ||
433 | CompletionItem { label: "a", lookup: None, snippet: None }, | ||
434 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
435 | ); | ||
436 | } | ||
437 | |||
438 | #[test] | ||
439 | fn test_completion_for_scope() { | ||
440 | check_scope_completion( | ||
441 | r" | ||
442 | fn quux() { | ||
443 | for x in &[1, 2, 3] { | ||
444 | <|> | ||
445 | } | ||
446 | } | ||
447 | ", | ||
448 | r#"[CompletionItem { label: "x", lookup: None, snippet: None }, | ||
449 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
450 | ); | ||
451 | } | ||
452 | |||
453 | #[test] | ||
454 | fn test_completion_mod_scope() { | ||
455 | check_scope_completion( | ||
456 | r" | ||
457 | struct Foo; | ||
458 | enum Baz {} | ||
459 | fn quux() { | ||
460 | <|> | ||
461 | } | ||
462 | ", | ||
463 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | ||
464 | CompletionItem { label: "Baz", lookup: None, snippet: None }, | ||
465 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
466 | ); | ||
467 | } | ||
468 | |||
469 | #[test] | ||
470 | fn test_completion_mod_scope_no_self_use() { | ||
471 | check_scope_completion( | ||
472 | r" | ||
473 | use foo<|>; | ||
474 | ", | ||
475 | r#"[]"#, | ||
476 | ); | ||
477 | } | ||
478 | |||
479 | #[test] | ||
480 | fn test_completion_mod_scope_nested() { | ||
481 | check_scope_completion( | ||
482 | r" | ||
483 | struct Foo; | ||
484 | mod m { | ||
485 | struct Bar; | ||
486 | fn quux() { <|> } | ||
487 | } | ||
488 | ", | ||
489 | r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, | ||
490 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
491 | ); | ||
492 | } | ||
493 | |||
494 | #[test] | ||
495 | fn test_complete_type() { | ||
496 | check_scope_completion( | ||
497 | r" | ||
498 | struct Foo; | ||
499 | fn x() -> <|> | ||
500 | ", | ||
501 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | ||
502 | CompletionItem { label: "x", lookup: None, snippet: None }]"#, | ||
503 | ) | ||
504 | } | ||
505 | |||
506 | #[test] | ||
507 | fn test_complete_shadowing() { | ||
508 | check_scope_completion( | ||
509 | r" | ||
510 | fn foo() -> { | ||
511 | let bar = 92; | ||
512 | { | ||
513 | let bar = 62; | ||
514 | <|> | ||
515 | } | ||
516 | } | ||
517 | ", | ||
518 | r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, | ||
519 | CompletionItem { label: "foo", lookup: None, snippet: None }]"#, | ||
520 | ) | ||
521 | } | ||
522 | |||
523 | #[test] | ||
524 | fn test_complete_self() { | ||
525 | check_scope_completion( | ||
526 | r" | ||
527 | impl S { fn foo(&self) { <|> } } | ||
528 | ", | ||
529 | r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#, | ||
530 | ) | ||
531 | } | ||
532 | |||
533 | #[test] | ||
534 | fn test_completion_kewords() { | ||
535 | check_snippet_completion(r" | ||
536 | fn quux() { | ||
537 | <|> | ||
538 | } | ||
539 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
540 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
541 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
542 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
543 | CompletionItem { label: "return", lookup: None, snippet: Some("return") }, | ||
544 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
545 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
546 | } | ||
547 | |||
548 | #[test] | ||
549 | fn test_completion_else() { | ||
550 | check_snippet_completion(r" | ||
551 | fn quux() { | ||
552 | if true { | ||
553 | () | ||
554 | } <|> | ||
555 | } | ||
556 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
557 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
558 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
559 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
560 | CompletionItem { label: "else", lookup: None, snippet: Some("else {$0}") }, | ||
561 | CompletionItem { label: "else if", lookup: None, snippet: Some("else if $0 {}") }, | ||
562 | CompletionItem { label: "return", lookup: None, snippet: Some("return") }, | ||
563 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
564 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
565 | } | ||
566 | |||
567 | #[test] | ||
568 | fn test_completion_return_value() { | ||
569 | check_snippet_completion(r" | ||
570 | fn quux() -> i32 { | ||
571 | <|> | ||
572 | 92 | ||
573 | } | ||
574 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
575 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
576 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
577 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
578 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0;") }, | ||
579 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
580 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
581 | check_snippet_completion(r" | ||
582 | fn quux() { | ||
583 | <|> | ||
584 | 92 | ||
585 | } | ||
586 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
587 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
588 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
589 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
590 | CompletionItem { label: "return", lookup: None, snippet: Some("return;") }, | ||
591 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
592 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn test_completion_return_no_stmt() { | ||
597 | check_snippet_completion(r" | ||
598 | fn quux() -> i32 { | ||
599 | match () { | ||
600 | () => <|> | ||
601 | } | ||
602 | } | ||
603 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
604 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
605 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
606 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
607 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
608 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
609 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn test_continue_break_completion() { | ||
614 | check_snippet_completion(r" | ||
615 | fn quux() -> i32 { | ||
616 | loop { <|> } | ||
617 | } | ||
618 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
619 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
620 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
621 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
622 | CompletionItem { label: "continue", lookup: None, snippet: Some("continue") }, | ||
623 | CompletionItem { label: "break", lookup: None, snippet: Some("break") }, | ||
624 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
625 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
626 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
627 | check_snippet_completion(r" | ||
628 | fn quux() -> i32 { | ||
629 | loop { || { <|> } } | ||
630 | } | ||
631 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
632 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
633 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
634 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
635 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
636 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
637 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
638 | } | ||
639 | |||
640 | #[test] | ||
641 | fn test_param_completion_last_param() { | ||
642 | check_scope_completion(r" | ||
643 | fn foo(file_id: FileId) {} | ||
644 | fn bar(file_id: FileId) {} | ||
645 | fn baz(file<|>) {} | ||
646 | ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
647 | } | ||
648 | |||
649 | #[test] | ||
650 | fn test_param_completion_nth_param() { | ||
651 | check_scope_completion(r" | ||
652 | fn foo(file_id: FileId) {} | ||
653 | fn bar(file_id: FileId) {} | ||
654 | fn baz(file<|>, x: i32) {} | ||
655 | ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
656 | } | ||
657 | |||
658 | #[test] | ||
659 | fn test_param_completion_trait_param() { | ||
660 | check_scope_completion(r" | ||
661 | pub(crate) trait SourceRoot { | ||
662 | pub fn contains(&self, file_id: FileId) -> bool; | ||
663 | pub fn module_map(&self) -> &ModuleMap; | ||
664 | pub fn lines(&self, file_id: FileId) -> &LineIndex; | ||
665 | pub fn syntax(&self, file<|>) | ||
666 | } | ||
667 | ", r#"[CompletionItem { label: "self", lookup: None, snippet: None }, | ||
668 | CompletionItem { label: "SourceRoot", lookup: None, snippet: None }, | ||
669 | CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
670 | } | ||
671 | |||
672 | #[test] | ||
673 | fn test_item_snippets() { | ||
674 | // check_snippet_completion(r" | ||
675 | // <|> | ||
676 | // ", | ||
677 | // r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }]"##, | ||
678 | // ); | ||
679 | check_snippet_completion(r" | ||
680 | #[cfg(test)] | ||
681 | mod tests { | ||
682 | <|> | ||
683 | } | ||
684 | ", | ||
685 | r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }, | ||
686 | CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##, | ||
687 | ); | ||
688 | } | ||
689 | } | ||
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index e7a5d5e2f..fe6587f20 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -9,7 +9,10 @@ use salsa; | |||
9 | use crate::{ | 9 | use crate::{ |
10 | db, | 10 | db, |
11 | Cancelable, Canceled, | 11 | Cancelable, Canceled, |
12 | descriptors::module::{SubmodulesQuery, ModuleTreeQuery, ModulesDatabase, ModuleScopeQuery}, | 12 | descriptors::{ |
13 | DescriptorDatabase, SubmodulesQuery, ModuleTreeQuery, ModuleScopeQuery, | ||
14 | FnSyntaxQuery, FnScopesQuery | ||
15 | }, | ||
13 | symbol_index::SymbolIndex, | 16 | symbol_index::SymbolIndex, |
14 | syntax_ptr::{SyntaxPtrDatabase, ResolveSyntaxPtrQuery}, | 17 | syntax_ptr::{SyntaxPtrDatabase, ResolveSyntaxPtrQuery}, |
15 | FileId, | 18 | FileId, |
@@ -63,10 +66,12 @@ salsa::database_storage! { | |||
63 | fn file_lines() for FileLinesQuery; | 66 | fn file_lines() for FileLinesQuery; |
64 | fn file_symbols() for FileSymbolsQuery; | 67 | fn file_symbols() for FileSymbolsQuery; |
65 | } | 68 | } |
66 | impl ModulesDatabase { | 69 | impl DescriptorDatabase { |
67 | fn module_tree() for ModuleTreeQuery; | 70 | fn module_tree() for ModuleTreeQuery; |
68 | fn module_descriptor() for SubmodulesQuery; | 71 | fn module_descriptor() for SubmodulesQuery; |
69 | fn module_scope() for ModuleScopeQuery; | 72 | fn module_scope() for ModuleScopeQuery; |
73 | fn fn_syntax() for FnSyntaxQuery; | ||
74 | fn fn_scopes() for FnScopesQuery; | ||
70 | } | 75 | } |
71 | impl SyntaxPtrDatabase { | 76 | impl SyntaxPtrDatabase { |
72 | fn resolve_syntax_ptr() for ResolveSyntaxPtrQuery; | 77 | fn resolve_syntax_ptr() for ResolveSyntaxPtrQuery; |
diff --git a/crates/ra_analysis/src/descriptors/function/imp.rs b/crates/ra_analysis/src/descriptors/function/imp.rs new file mode 100644 index 000000000..0a006f733 --- /dev/null +++ b/crates/ra_analysis/src/descriptors/function/imp.rs | |||
@@ -0,0 +1,26 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | ast::{AstNode, FnDef, FnDefNode}, | ||
5 | }; | ||
6 | |||
7 | use crate::{ | ||
8 | descriptors::{ | ||
9 | DescriptorDatabase, | ||
10 | function::{FnId, FnScopes}, | ||
11 | }, | ||
12 | }; | ||
13 | |||
14 | /// Resolve `FnId` to the corresponding `SyntaxNode` | ||
15 | /// TODO: this should return something more type-safe then `SyntaxNode` | ||
16 | pub(crate) fn fn_syntax(db: &impl DescriptorDatabase, fn_id: FnId) -> FnDefNode { | ||
17 | let syntax = db.resolve_syntax_ptr(fn_id.0); | ||
18 | let fn_def = FnDef::cast(syntax.borrowed()).unwrap(); | ||
19 | FnDefNode::new(fn_def) | ||
20 | } | ||
21 | |||
22 | pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> { | ||
23 | let syntax = db.fn_syntax(fn_id); | ||
24 | let res = FnScopes::new(syntax.ast()); | ||
25 | Arc::new(res) | ||
26 | } | ||
diff --git a/crates/ra_analysis/src/descriptors/function/mod.rs b/crates/ra_analysis/src/descriptors/function/mod.rs new file mode 100644 index 000000000..bb68b0ce7 --- /dev/null +++ b/crates/ra_analysis/src/descriptors/function/mod.rs | |||
@@ -0,0 +1,83 @@ | |||
1 | pub(super) mod imp; | ||
2 | mod scope; | ||
3 | |||
4 | use ra_syntax::{ | ||
5 | ast::{self, AstNode, NameOwner} | ||
6 | }; | ||
7 | |||
8 | use crate::{ | ||
9 | FileId, | ||
10 | syntax_ptr::SyntaxPtr | ||
11 | }; | ||
12 | |||
13 | pub(crate) use self::scope::{FnScopes, resolve_local_name}; | ||
14 | |||
15 | |||
16 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
17 | pub(crate) struct FnId(SyntaxPtr); | ||
18 | |||
19 | impl FnId { | ||
20 | pub(crate) fn new(file_id: FileId, fn_def: ast::FnDef) -> FnId { | ||
21 | let ptr = SyntaxPtr::new(file_id, fn_def.syntax()); | ||
22 | FnId(ptr) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | |||
27 | #[derive(Debug, Clone)] | ||
28 | pub struct FnDescriptor { | ||
29 | pub name: String, | ||
30 | pub label: String, | ||
31 | pub ret_type: Option<String>, | ||
32 | pub params: Vec<String>, | ||
33 | } | ||
34 | |||
35 | impl FnDescriptor { | ||
36 | pub fn new(node: ast::FnDef) -> Option<Self> { | ||
37 | let name = node.name()?.text().to_string(); | ||
38 | |||
39 | // Strip the body out for the label. | ||
40 | let label: String = if let Some(body) = node.body() { | ||
41 | let body_range = body.syntax().range(); | ||
42 | let label: String = node | ||
43 | .syntax() | ||
44 | .children() | ||
45 | .filter(|child| !child.range().is_subrange(&body_range)) | ||
46 | .map(|node| node.text().to_string()) | ||
47 | .collect(); | ||
48 | label | ||
49 | } else { | ||
50 | node.syntax().text().to_string() | ||
51 | }; | ||
52 | |||
53 | let params = FnDescriptor::param_list(node); | ||
54 | let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); | ||
55 | |||
56 | Some(FnDescriptor { | ||
57 | name, | ||
58 | ret_type, | ||
59 | params, | ||
60 | label, | ||
61 | }) | ||
62 | } | ||
63 | |||
64 | fn param_list(node: ast::FnDef) -> Vec<String> { | ||
65 | let mut res = vec![]; | ||
66 | if let Some(param_list) = node.param_list() { | ||
67 | if let Some(self_param) = param_list.self_param() { | ||
68 | res.push(self_param.syntax().text().to_string()) | ||
69 | } | ||
70 | |||
71 | // Maybe use param.pat here? See if we can just extract the name? | ||
72 | //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); | ||
73 | res.extend( | ||
74 | param_list | ||
75 | .params() | ||
76 | .filter_map(|p| p.pat()) | ||
77 | .map(|pat| pat.syntax().text().to_string()), | ||
78 | ); | ||
79 | } | ||
80 | res | ||
81 | } | ||
82 | } | ||
83 | |||
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_analysis/src/descriptors/function/scope.rs index f10bdf657..d9929414c 100644 --- a/crates/ra_editor/src/scope/fn_scope.rs +++ b/crates/ra_analysis/src/descriptors/function/scope.rs | |||
@@ -1,29 +1,42 @@ | |||
1 | use std::fmt; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | |||
3 | use rustc_hash::FxHashMap; | ||
4 | 2 | ||
5 | use ra_syntax::{ | 3 | use ra_syntax::{ |
6 | algo::generate, | 4 | algo::generate, |
7 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 5 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
8 | AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, | 6 | AstNode, SmolStr, SyntaxNodeRef, |
9 | }; | 7 | }; |
10 | 8 | ||
11 | type ScopeId = usize; | 9 | use crate::syntax_ptr::LocalSyntaxPtr; |
10 | |||
11 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
12 | pub(crate) struct ScopeId(u32); | ||
12 | 13 | ||
13 | #[derive(Debug)] | 14 | #[derive(Debug, PartialEq, Eq)] |
14 | pub struct FnScopes { | 15 | pub struct FnScopes { |
15 | pub self_param: Option<SyntaxNode>, | 16 | pub(crate) self_param: Option<LocalSyntaxPtr>, |
16 | scopes: Vec<ScopeData>, | 17 | scopes: Vec<ScopeData>, |
17 | scope_for: FxHashMap<SyntaxNode, ScopeId>, | 18 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, |
19 | } | ||
20 | |||
21 | #[derive(Debug, PartialEq, Eq)] | ||
22 | pub struct ScopeEntry { | ||
23 | name: SmolStr, | ||
24 | ptr: LocalSyntaxPtr, | ||
25 | } | ||
26 | |||
27 | #[derive(Debug, PartialEq, Eq)] | ||
28 | struct ScopeData { | ||
29 | parent: Option<ScopeId>, | ||
30 | entries: Vec<ScopeEntry>, | ||
18 | } | 31 | } |
19 | 32 | ||
20 | impl FnScopes { | 33 | impl FnScopes { |
21 | pub fn new(fn_def: ast::FnDef) -> FnScopes { | 34 | pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes { |
22 | let mut scopes = FnScopes { | 35 | let mut scopes = FnScopes { |
23 | self_param: fn_def | 36 | self_param: fn_def |
24 | .param_list() | 37 | .param_list() |
25 | .and_then(|it| it.self_param()) | 38 | .and_then(|it| it.self_param()) |
26 | .map(|it| it.syntax().owned()), | 39 | .map(|it| LocalSyntaxPtr::new(it.syntax())), |
27 | scopes: Vec::new(), | 40 | scopes: Vec::new(), |
28 | scope_for: FxHashMap::default(), | 41 | scope_for: FxHashMap::default(), |
29 | }; | 42 | }; |
@@ -34,16 +47,16 @@ impl FnScopes { | |||
34 | } | 47 | } |
35 | scopes | 48 | scopes |
36 | } | 49 | } |
37 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | 50 | pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
38 | &self.scopes[scope].entries | 51 | &self.get(scope).entries |
39 | } | 52 | } |
40 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { | 53 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { |
41 | generate(self.scope_for(node), move |&scope| { | 54 | generate(self.scope_for(node), move |&scope| { |
42 | self.scopes[scope].parent | 55 | self.get(scope).parent |
43 | }) | 56 | }) |
44 | } | 57 | } |
45 | fn root_scope(&mut self) -> ScopeId { | 58 | fn root_scope(&mut self) -> ScopeId { |
46 | let res = self.scopes.len(); | 59 | let res = ScopeId(self.scopes.len() as u32); |
47 | self.scopes.push(ScopeData { | 60 | self.scopes.push(ScopeData { |
48 | parent: None, | 61 | parent: None, |
49 | entries: vec![], | 62 | entries: vec![], |
@@ -51,7 +64,7 @@ impl FnScopes { | |||
51 | res | 64 | res |
52 | } | 65 | } |
53 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | 66 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { |
54 | let res = self.scopes.len(); | 67 | let res = ScopeId(self.scopes.len() as u32); |
55 | self.scopes.push(ScopeData { | 68 | self.scopes.push(ScopeData { |
56 | parent: Some(parent), | 69 | parent: Some(parent), |
57 | entries: vec![], | 70 | entries: vec![], |
@@ -64,7 +77,7 @@ impl FnScopes { | |||
64 | .descendants() | 77 | .descendants() |
65 | .filter_map(ast::BindPat::cast) | 78 | .filter_map(ast::BindPat::cast) |
66 | .filter_map(ScopeEntry::new); | 79 | .filter_map(ScopeEntry::new); |
67 | self.scopes[scope].entries.extend(entries); | 80 | self.get_mut(scope).entries.extend(entries); |
68 | } | 81 | } |
69 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { | 82 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { |
70 | params | 83 | params |
@@ -74,43 +87,36 @@ impl FnScopes { | |||
74 | .for_each(|it| self.add_bindings(scope, it)); | 87 | .for_each(|it| self.add_bindings(scope, it)); |
75 | } | 88 | } |
76 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { | 89 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { |
77 | self.scope_for.insert(node.owned(), scope); | 90 | self.scope_for.insert(LocalSyntaxPtr::new(node), scope); |
78 | } | 91 | } |
79 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { | 92 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { |
80 | node.ancestors() | 93 | node.ancestors() |
81 | .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope)) | 94 | .map(LocalSyntaxPtr::new) |
95 | .filter_map(|it| self.scope_for.get(&it).map(|&scope| scope)) | ||
82 | .next() | 96 | .next() |
83 | } | 97 | } |
84 | } | 98 | fn get(&self, scope: ScopeId) -> &ScopeData { |
85 | 99 | &self.scopes[scope.0 as usize] | |
86 | pub struct ScopeEntry { | 100 | } |
87 | syntax: SyntaxNode, | 101 | fn get_mut(&mut self, scope: ScopeId) -> &mut ScopeData { |
102 | &mut self.scopes[scope.0 as usize] | ||
103 | } | ||
88 | } | 104 | } |
89 | 105 | ||
90 | impl ScopeEntry { | 106 | impl ScopeEntry { |
91 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { | 107 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { |
92 | if pat.name().is_some() { | 108 | let name = pat.name()?; |
93 | Some(ScopeEntry { | 109 | let res = ScopeEntry { |
94 | syntax: pat.syntax().owned(), | 110 | name: name.text(), |
95 | }) | 111 | ptr: LocalSyntaxPtr::new(pat.syntax()), |
96 | } else { | 112 | }; |
97 | None | 113 | Some(res) |
98 | } | ||
99 | } | ||
100 | pub fn name(&self) -> SmolStr { | ||
101 | self.ast().name().unwrap().text() | ||
102 | } | 114 | } |
103 | pub fn ast(&self) -> ast::BindPat { | 115 | pub(crate) fn name(&self) -> &SmolStr { |
104 | ast::BindPat::cast(self.syntax.borrowed()).unwrap() | 116 | &self.name |
105 | } | 117 | } |
106 | } | 118 | pub(crate) fn ptr(&self) -> LocalSyntaxPtr { |
107 | 119 | self.ptr | |
108 | impl fmt::Debug for ScopeEntry { | ||
109 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
110 | f.debug_struct("ScopeEntry") | ||
111 | .field("name", &self.name()) | ||
112 | .field("syntax", &self.syntax) | ||
113 | .finish() | ||
114 | } | 120 | } |
115 | } | 121 | } |
116 | 122 | ||
@@ -251,33 +257,28 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
251 | } | 257 | } |
252 | } | 258 | } |
253 | 259 | ||
254 | #[derive(Debug)] | ||
255 | struct ScopeData { | ||
256 | parent: Option<ScopeId>, | ||
257 | entries: Vec<ScopeEntry>, | ||
258 | } | ||
259 | |||
260 | pub fn resolve_local_name<'a>( | 260 | pub fn resolve_local_name<'a>( |
261 | name_ref: ast::NameRef, | 261 | name_ref: ast::NameRef, |
262 | scopes: &'a FnScopes, | 262 | scopes: &'a FnScopes, |
263 | ) -> Option<&'a ScopeEntry> { | 263 | ) -> Option<&'a ScopeEntry> { |
264 | use rustc_hash::FxHashSet; | ||
265 | |||
266 | let mut shadowed = FxHashSet::default(); | 264 | let mut shadowed = FxHashSet::default(); |
267 | let ret = scopes | 265 | let ret = scopes |
268 | .scope_chain(name_ref.syntax()) | 266 | .scope_chain(name_ref.syntax()) |
269 | .flat_map(|scope| scopes.entries(scope).iter()) | 267 | .flat_map(|scope| scopes.entries(scope).iter()) |
270 | .filter(|entry| shadowed.insert(entry.name())) | 268 | .filter(|entry| shadowed.insert(entry.name())) |
271 | .filter(|entry| entry.name() == name_ref.text()) | 269 | .filter(|entry| entry.name() == &name_ref.text()) |
272 | .nth(0); | 270 | .nth(0); |
273 | ret | 271 | ret |
274 | } | 272 | } |
275 | 273 | ||
276 | #[cfg(test)] | 274 | #[cfg(test)] |
277 | mod tests { | 275 | mod tests { |
278 | use super::*; | ||
279 | use crate::{find_node_at_offset, test_utils::extract_offset}; | ||
280 | use ra_syntax::File; | 276 | use ra_syntax::File; |
277 | use test_utils::extract_offset; | ||
278 | use ra_editor::{find_node_at_offset}; | ||
279 | |||
280 | use super::*; | ||
281 | |||
281 | 282 | ||
282 | fn do_check(code: &str, expected: &[&str]) { | 283 | fn do_check(code: &str, expected: &[&str]) { |
283 | let (off, code) = extract_offset(code); | 284 | let (off, code) = extract_offset(code); |
@@ -384,14 +385,11 @@ mod tests { | |||
384 | 385 | ||
385 | let scopes = FnScopes::new(fn_def); | 386 | let scopes = FnScopes::new(fn_def); |
386 | 387 | ||
387 | let local_name = resolve_local_name(name_ref, &scopes) | 388 | let local_name_entry = resolve_local_name(name_ref, &scopes).unwrap(); |
388 | .unwrap() | 389 | let local_name = local_name_entry.ptr().resolve(&file); |
389 | .ast() | ||
390 | .name() | ||
391 | .unwrap(); | ||
392 | let expected_name = | 390 | let expected_name = |
393 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | 391 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); |
394 | assert_eq!(local_name.syntax().range(), expected_name.syntax().range()); | 392 | assert_eq!(local_name.range(), expected_name.syntax().range()); |
395 | } | 393 | } |
396 | 394 | ||
397 | #[test] | 395 | #[test] |
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index 0220f7d5d..0c4991757 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs | |||
@@ -1,62 +1,46 @@ | |||
1 | pub(crate) mod module; | 1 | pub(crate) mod module; |
2 | pub(crate) mod function; | ||
3 | |||
4 | use std::sync::Arc; | ||
2 | 5 | ||
3 | use ra_syntax::{ | 6 | use ra_syntax::{ |
4 | ast::{self, AstNode, NameOwner}, | 7 | SmolStr, |
8 | ast::{FnDefNode}, | ||
5 | }; | 9 | }; |
6 | 10 | ||
7 | #[derive(Debug, Clone)] | 11 | use crate::{ |
8 | pub struct FnDescriptor { | 12 | FileId, Cancelable, |
9 | pub name: String, | 13 | db::SyntaxDatabase, |
10 | pub label: String, | 14 | descriptors::module::{ModuleTree, ModuleId, ModuleScope}, |
11 | pub ret_type: Option<String>, | 15 | descriptors::function::{FnId, FnScopes}, |
12 | pub params: Vec<String>, | 16 | input::SourceRootId, |
13 | } | 17 | syntax_ptr::SyntaxPtrDatabase, |
14 | 18 | }; | |
15 | impl FnDescriptor { | ||
16 | pub fn new(node: ast::FnDef) -> Option<Self> { | ||
17 | let name = node.name()?.text().to_string(); | ||
18 | |||
19 | // Strip the body out for the label. | ||
20 | let label: String = if let Some(body) = node.body() { | ||
21 | let body_range = body.syntax().range(); | ||
22 | let label: String = node | ||
23 | .syntax() | ||
24 | .children() | ||
25 | .filter(|child| !child.range().is_subrange(&body_range)) | ||
26 | .map(|node| node.text().to_string()) | ||
27 | .collect(); | ||
28 | label | ||
29 | } else { | ||
30 | node.syntax().text().to_string() | ||
31 | }; | ||
32 | |||
33 | let params = FnDescriptor::param_list(node); | ||
34 | let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); | ||
35 | |||
36 | Some(FnDescriptor { | ||
37 | name, | ||
38 | ret_type, | ||
39 | params, | ||
40 | label, | ||
41 | }) | ||
42 | } | ||
43 | 19 | ||
44 | fn param_list(node: ast::FnDef) -> Vec<String> { | ||
45 | let mut res = vec![]; | ||
46 | if let Some(param_list) = node.param_list() { | ||
47 | if let Some(self_param) = param_list.self_param() { | ||
48 | res.push(self_param.syntax().text().to_string()) | ||
49 | } | ||
50 | 20 | ||
51 | // Maybe use param.pat here? See if we can just extract the name? | 21 | salsa::query_group! { |
52 | //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); | 22 | pub(crate) trait DescriptorDatabase: SyntaxDatabase + SyntaxPtrDatabase { |
53 | res.extend( | 23 | fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { |
54 | param_list | 24 | type ModuleTreeQuery; |
55 | .params() | 25 | use fn module::imp::module_tree; |
56 | .filter_map(|p| p.pat()) | 26 | } |
57 | .map(|pat| pat.syntax().text().to_string()), | 27 | fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { |
58 | ); | 28 | type SubmodulesQuery; |
29 | use fn module::imp::submodules; | ||
30 | } | ||
31 | fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> { | ||
32 | type ModuleScopeQuery; | ||
33 | use fn module::imp::module_scope; | ||
34 | } | ||
35 | fn fn_syntax(fn_id: FnId) -> FnDefNode { | ||
36 | type FnSyntaxQuery; | ||
37 | // Don't retain syntax trees in memory | ||
38 | storage volatile; | ||
39 | use fn function::imp::fn_syntax; | ||
40 | } | ||
41 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { | ||
42 | type FnScopesQuery; | ||
43 | use fn function::imp::fn_scopes; | ||
59 | } | 44 | } |
60 | res | ||
61 | } | 45 | } |
62 | } | 46 | } |
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index 5fdaad137..dae3a356d 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs | |||
@@ -10,14 +10,15 @@ use ra_syntax::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | FileId, Cancelable, FileResolverImp, db, | 11 | FileId, Cancelable, FileResolverImp, db, |
12 | input::{SourceRoot, SourceRootId}, | 12 | input::{SourceRoot, SourceRootId}, |
13 | descriptors::DescriptorDatabase, | ||
13 | }; | 14 | }; |
14 | 15 | ||
15 | use super::{ | 16 | use super::{ |
16 | ModuleData, ModuleTree, ModuleId, LinkId, LinkData, Problem, ModulesDatabase, ModuleScope | 17 | ModuleData, ModuleTree, ModuleId, LinkId, LinkData, Problem, ModuleScope |
17 | }; | 18 | }; |
18 | 19 | ||
19 | 20 | ||
20 | pub(super) fn submodules(db: &impl ModulesDatabase, file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { | 21 | pub(crate) fn submodules(db: &impl DescriptorDatabase, file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { |
21 | db::check_canceled(db)?; | 22 | db::check_canceled(db)?; |
22 | let file = db.file_syntax(file_id); | 23 | let file = db.file_syntax(file_id); |
23 | let root = file.ast(); | 24 | let root = file.ast(); |
@@ -25,7 +26,7 @@ pub(super) fn submodules(db: &impl ModulesDatabase, file_id: FileId) -> Cancelab | |||
25 | Ok(Arc::new(submodules)) | 26 | Ok(Arc::new(submodules)) |
26 | } | 27 | } |
27 | 28 | ||
28 | pub(super) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { | 29 | pub(crate) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { |
29 | root.modules().filter_map(|module| { | 30 | root.modules().filter_map(|module| { |
30 | let name = module.name()?.text(); | 31 | let name = module.name()?.text(); |
31 | if !module.has_semi() { | 32 | if !module.has_semi() { |
@@ -35,8 +36,8 @@ pub(super) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast | |||
35 | }) | 36 | }) |
36 | } | 37 | } |
37 | 38 | ||
38 | pub(super) fn module_scope( | 39 | pub(crate) fn module_scope( |
39 | db: &impl ModulesDatabase, | 40 | db: &impl DescriptorDatabase, |
40 | source_root_id: SourceRootId, | 41 | source_root_id: SourceRootId, |
41 | module_id: ModuleId, | 42 | module_id: ModuleId, |
42 | ) -> Cancelable<Arc<ModuleScope>> { | 43 | ) -> Cancelable<Arc<ModuleScope>> { |
@@ -47,8 +48,8 @@ pub(super) fn module_scope( | |||
47 | Ok(Arc::new(res)) | 48 | Ok(Arc::new(res)) |
48 | } | 49 | } |
49 | 50 | ||
50 | pub(super) fn module_tree( | 51 | pub(crate) fn module_tree( |
51 | db: &impl ModulesDatabase, | 52 | db: &impl DescriptorDatabase, |
52 | source_root: SourceRootId, | 53 | source_root: SourceRootId, |
53 | ) -> Cancelable<Arc<ModuleTree>> { | 54 | ) -> Cancelable<Arc<ModuleTree>> { |
54 | db::check_canceled(db)?; | 55 | db::check_canceled(db)?; |
@@ -64,7 +65,7 @@ pub struct Submodule { | |||
64 | 65 | ||
65 | 66 | ||
66 | fn create_module_tree<'a>( | 67 | fn create_module_tree<'a>( |
67 | db: &impl ModulesDatabase, | 68 | db: &impl DescriptorDatabase, |
68 | source_root: SourceRootId, | 69 | source_root: SourceRootId, |
69 | ) -> Cancelable<ModuleTree> { | 70 | ) -> Cancelable<ModuleTree> { |
70 | let mut tree = ModuleTree { | 71 | let mut tree = ModuleTree { |
@@ -88,7 +89,7 @@ fn create_module_tree<'a>( | |||
88 | } | 89 | } |
89 | 90 | ||
90 | fn build_subtree( | 91 | fn build_subtree( |
91 | db: &impl ModulesDatabase, | 92 | db: &impl DescriptorDatabase, |
92 | source_root: &SourceRoot, | 93 | source_root: &SourceRoot, |
93 | tree: &mut ModuleTree, | 94 | tree: &mut ModuleTree, |
94 | visited: &mut FxHashSet<FileId>, | 95 | visited: &mut FxHashSet<FileId>, |
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 9e5d73f94..667553f74 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -1,37 +1,13 @@ | |||
1 | mod imp; | 1 | pub(super) mod imp; |
2 | pub(crate) mod scope; | 2 | pub(crate) mod scope; |
3 | 3 | ||
4 | use std::sync::Arc; | ||
5 | |||
6 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
7 | use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode}; | 5 | use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode}; |
8 | 6 | ||
9 | use crate::{ | 7 | use crate::FileId; |
10 | FileId, Cancelable, | ||
11 | db::SyntaxDatabase, | ||
12 | input::SourceRootId, | ||
13 | }; | ||
14 | 8 | ||
15 | pub(crate) use self::scope::ModuleScope; | 9 | pub(crate) use self::scope::ModuleScope; |
16 | 10 | ||
17 | salsa::query_group! { | ||
18 | pub(crate) trait ModulesDatabase: SyntaxDatabase { | ||
19 | fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | ||
20 | type ModuleTreeQuery; | ||
21 | use fn imp::module_tree; | ||
22 | } | ||
23 | fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { | ||
24 | type SubmodulesQuery; | ||
25 | use fn imp::submodules; | ||
26 | } | ||
27 | fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> { | ||
28 | type ModuleScopeQuery; | ||
29 | use fn imp::module_scope; | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | |||
35 | #[derive(Debug, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, PartialEq, Eq, Hash)] |
36 | pub(crate) struct ModuleTree { | 12 | pub(crate) struct ModuleTree { |
37 | mods: Vec<ModuleData>, | 13 | mods: Vec<ModuleData>, |
diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs index da58ddce0..846b8b44f 100644 --- a/crates/ra_analysis/src/descriptors/module/scope.rs +++ b/crates/ra_analysis/src/descriptors/module/scope.rs | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | 3 | ||
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, AstChildren, ModuleItemOwner}, | 5 | ast::{self, ModuleItemOwner}, |
6 | File, AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, | 6 | File, AstNode, SmolStr, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::syntax_ptr::LocalSyntaxPtr; | 9 | use crate::syntax_ptr::LocalSyntaxPtr; |
@@ -30,8 +30,12 @@ enum EntryKind { | |||
30 | 30 | ||
31 | impl ModuleScope { | 31 | impl ModuleScope { |
32 | pub fn new(file: &File) -> ModuleScope { | 32 | pub fn new(file: &File) -> ModuleScope { |
33 | ModuleScope::from_items(file.ast().items()) | ||
34 | } | ||
35 | |||
36 | pub fn from_items<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { | ||
33 | let mut entries = Vec::new(); | 37 | let mut entries = Vec::new(); |
34 | for item in file.ast().items() { | 38 | for item in items { |
35 | let entry = match item { | 39 | let entry = match item { |
36 | ast::ModuleItem::StructDef(item) => Entry::new(item), | 40 | ast::ModuleItem::StructDef(item) => Entry::new(item), |
37 | ast::ModuleItem::EnumDef(item) => Entry::new(item), | 41 | ast::ModuleItem::EnumDef(item) => Entry::new(item), |
@@ -99,7 +103,7 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { | |||
99 | #[cfg(test)] | 103 | #[cfg(test)] |
100 | mod tests { | 104 | mod tests { |
101 | use super::*; | 105 | use super::*; |
102 | use ra_syntax::{ast::ModuleItemOwner, File}; | 106 | use ra_syntax::{File}; |
103 | 107 | ||
104 | fn do_check(code: &str, expected: &[&str]) { | 108 | fn do_check(code: &str, expected: &[&str]) { |
105 | let file = File::parse(&code); | 109 | let file = File::parse(&code); |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index efb3182a6..38d4b6a23 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -3,7 +3,7 @@ use std::{ | |||
3 | sync::Arc, | 3 | sync::Arc, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit, CompletionItem}; | 6 | use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | ast::{self, ArgListOwner, Expr, NameOwner}, | 8 | ast::{self, ArgListOwner, Expr, NameOwner}, |
9 | AstNode, File, SmolStr, | 9 | AstNode, File, SmolStr, |
@@ -21,9 +21,14 @@ use crate::{ | |||
21 | self, SyntaxDatabase, FileSyntaxQuery, | 21 | self, SyntaxDatabase, FileSyntaxQuery, |
22 | }, | 22 | }, |
23 | input::{SourceRootId, FilesDatabase, SourceRoot, WORKSPACE}, | 23 | input::{SourceRootId, FilesDatabase, SourceRoot, WORKSPACE}, |
24 | descriptors::module::{ModulesDatabase, ModuleTree, Problem}, | 24 | descriptors::{ |
25 | descriptors::{FnDescriptor}, | 25 | DescriptorDatabase, |
26 | module::{ModuleTree, Problem}, | ||
27 | function::{FnDescriptor, FnId}, | ||
28 | }, | ||
29 | completion::{scope_completion, resolve_based_completion, CompletionItem}, | ||
26 | symbol_index::SymbolIndex, | 30 | symbol_index::SymbolIndex, |
31 | syntax_ptr::SyntaxPtrDatabase, | ||
27 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, | 32 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, |
28 | Query, SourceChange, SourceFileEdit, Cancelable, | 33 | Query, SourceChange, SourceFileEdit, Cancelable, |
29 | }; | 34 | }; |
@@ -175,7 +180,7 @@ impl AnalysisHostImpl { | |||
175 | 180 | ||
176 | #[derive(Debug)] | 181 | #[derive(Debug)] |
177 | pub(crate) struct AnalysisImpl { | 182 | pub(crate) struct AnalysisImpl { |
178 | db: db::RootDatabase, | 183 | pub(crate) db: db::RootDatabase, |
179 | } | 184 | } |
180 | 185 | ||
181 | impl AnalysisImpl { | 186 | impl AnalysisImpl { |
@@ -245,12 +250,11 @@ impl AnalysisImpl { | |||
245 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { | 250 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { |
246 | let mut res = Vec::new(); | 251 | let mut res = Vec::new(); |
247 | let mut has_completions = false; | 252 | let mut has_completions = false; |
248 | let file = self.file_syntax(file_id); | 253 | if let Some(scope_based) = scope_completion(&self.db, file_id, offset) { |
249 | if let Some(scope_based) = ra_editor::scope_completion(&file, offset) { | ||
250 | res.extend(scope_based); | 254 | res.extend(scope_based); |
251 | has_completions = true; | 255 | has_completions = true; |
252 | } | 256 | } |
253 | if let Some(scope_based) = crate::completion::resolve_based_completion(&self.db, file_id, offset)? { | 257 | if let Some(scope_based) = resolve_based_completion(&self.db, file_id, offset)? { |
254 | res.extend(scope_based); | 258 | res.extend(scope_based); |
255 | has_completions = true; | 259 | has_completions = true; |
256 | } | 260 | } |
@@ -271,7 +275,7 @@ impl AnalysisImpl { | |||
271 | let syntax = file.syntax(); | 275 | let syntax = file.syntax(); |
272 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 276 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
273 | // First try to resolve the symbol locally | 277 | // First try to resolve the symbol locally |
274 | return if let Some((name, range)) = resolve_local_name(name_ref) { | 278 | return if let Some((name, range)) = resolve_local_name(&self.db, file_id, name_ref) { |
275 | let mut vec = vec![]; | 279 | let mut vec = vec![]; |
276 | vec.push(( | 280 | vec.push(( |
277 | file_id, | 281 | file_id, |
@@ -325,7 +329,7 @@ impl AnalysisImpl { | |||
325 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 329 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
326 | 330 | ||
327 | // We are only handing local references for now | 331 | // We are only handing local references for now |
328 | if let Some(resolved) = resolve_local_name(name_ref) { | 332 | if let Some(resolved) = resolve_local_name(&self.db, file_id, name_ref) { |
329 | 333 | ||
330 | ret.push((file_id, resolved.1)); | 334 | ret.push((file_id, resolved.1)); |
331 | 335 | ||
@@ -333,7 +337,7 @@ impl AnalysisImpl { | |||
333 | 337 | ||
334 | let refs : Vec<_> = fn_def.syntax().descendants() | 338 | let refs : Vec<_> = fn_def.syntax().descendants() |
335 | .filter_map(ast::NameRef::cast) | 339 | .filter_map(ast::NameRef::cast) |
336 | .filter(|&n: &ast::NameRef| resolve_local_name(n) == Some(resolved.clone())) | 340 | .filter(|&n: &ast::NameRef| resolve_local_name(&self.db, file_id, n) == Some(resolved.clone())) |
337 | .collect(); | 341 | .collect(); |
338 | 342 | ||
339 | for r in refs { | 343 | for r in refs { |
@@ -597,3 +601,16 @@ impl<'a> FnCallNode<'a> { | |||
597 | } | 601 | } |
598 | } | 602 | } |
599 | } | 603 | } |
604 | |||
605 | fn resolve_local_name( | ||
606 | db: &db::RootDatabase, | ||
607 | file_id: FileId, | ||
608 | name_ref: ast::NameRef, | ||
609 | ) -> Option<(SmolStr, TextRange)> { | ||
610 | let fn_def = name_ref.syntax().ancestors().find_map(ast::FnDef::cast)?; | ||
611 | let fn_id = FnId::new(file_id, fn_def); | ||
612 | let scopes = db.fn_scopes(fn_id); | ||
613 | let scope_entry = crate::descriptors::function::resolve_local_name(name_ref, &scopes)?; | ||
614 | let syntax = db.resolve_syntax_ptr(scope_entry.ptr().into_global(file_id)); | ||
615 | Some((scope_entry.name().clone(), syntax.range())) | ||
616 | } | ||
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 363c72c0b..776010281 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -13,6 +13,7 @@ mod imp; | |||
13 | mod symbol_index; | 13 | mod symbol_index; |
14 | mod completion; | 14 | mod completion; |
15 | mod syntax_ptr; | 15 | mod syntax_ptr; |
16 | mod mock_analysis; | ||
16 | 17 | ||
17 | use std::{ | 18 | use std::{ |
18 | fmt, | 19 | fmt, |
@@ -29,11 +30,13 @@ use crate::{ | |||
29 | }; | 30 | }; |
30 | 31 | ||
31 | pub use crate::{ | 32 | pub use crate::{ |
32 | descriptors::FnDescriptor, | 33 | descriptors::function::FnDescriptor, |
33 | input::{FileId, FileResolver, CrateGraph, CrateId} | 34 | completion::CompletionItem, |
35 | input::{FileId, FileResolver, CrateGraph, CrateId}, | ||
36 | mock_analysis::MockAnalysis, | ||
34 | }; | 37 | }; |
35 | pub use ra_editor::{ | 38 | pub use ra_editor::{ |
36 | CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, | 39 | FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, |
37 | RunnableKind, StructureNode, | 40 | RunnableKind, StructureNode, |
38 | }; | 41 | }; |
39 | 42 | ||
@@ -197,7 +200,7 @@ impl Query { | |||
197 | 200 | ||
198 | #[derive(Debug)] | 201 | #[derive(Debug)] |
199 | pub struct Analysis { | 202 | pub struct Analysis { |
200 | imp: AnalysisImpl, | 203 | pub(crate) imp: AnalysisImpl, |
201 | } | 204 | } |
202 | 205 | ||
203 | impl Analysis { | 206 | impl Analysis { |
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs new file mode 100644 index 000000000..1c1dbee7c --- /dev/null +++ b/crates/ra_analysis/src/mock_analysis.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | |||
2 | use std::sync::Arc; | ||
3 | |||
4 | use relative_path::{RelativePath, RelativePathBuf}; | ||
5 | |||
6 | use crate::{ | ||
7 | AnalysisChange, Analysis, AnalysisHost, FileId, FileResolver, | ||
8 | }; | ||
9 | |||
10 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | ||
11 | /// from a set of in-memory files. | ||
12 | #[derive(Debug, Default)] | ||
13 | pub struct MockAnalysis { | ||
14 | files: Vec<(String, String)>, | ||
15 | } | ||
16 | |||
17 | impl MockAnalysis { | ||
18 | pub fn new() -> MockAnalysis { | ||
19 | MockAnalysis::default() | ||
20 | } | ||
21 | pub fn with_files(files: &[(&str, &str)]) -> MockAnalysis { | ||
22 | let files = files.iter() | ||
23 | .map(|it| (it.0.to_string(), it.1.to_string())) | ||
24 | .collect(); | ||
25 | MockAnalysis { files } | ||
26 | } | ||
27 | pub fn analysis_host(self) -> AnalysisHost { | ||
28 | let mut host = AnalysisHost::new(); | ||
29 | let mut file_map = Vec::new(); | ||
30 | let mut change = AnalysisChange::new(); | ||
31 | for (id, (path, contents)) in self.files.into_iter().enumerate() { | ||
32 | let file_id = FileId((id + 1) as u32); | ||
33 | assert!(path.starts_with('/')); | ||
34 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | ||
35 | change.add_file(file_id, contents); | ||
36 | file_map.push((file_id, path)); | ||
37 | } | ||
38 | change.set_file_resolver(Arc::new(FileMap(file_map))); | ||
39 | host.apply_change(change); | ||
40 | host | ||
41 | } | ||
42 | pub fn analysis(self) -> Analysis { | ||
43 | self.analysis_host().analysis() | ||
44 | } | ||
45 | } | ||
46 | |||
47 | #[derive(Debug)] | ||
48 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | ||
49 | |||
50 | impl FileMap { | ||
51 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { | ||
52 | self.0 | ||
53 | .iter() | ||
54 | .map(|(id, path)| (*id, path.as_relative_path())) | ||
55 | } | ||
56 | |||
57 | fn path(&self, id: FileId) -> &RelativePath { | ||
58 | self.iter().find(|&(it, _)| it == id).unwrap().1 | ||
59 | } | ||
60 | } | ||
61 | |||
62 | impl FileResolver for FileMap { | ||
63 | fn file_stem(&self, id: FileId) -> String { | ||
64 | self.path(id).file_stem().unwrap().to_string() | ||
65 | } | ||
66 | fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> { | ||
67 | let path = self.path(id).join(rel).normalize(); | ||
68 | let id = self.iter().find(|&(_, p)| path == p)?.0; | ||
69 | Some(id) | ||
70 | } | ||
71 | } | ||
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs index 6dc89cb43..c3c904633 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_analysis/src/syntax_ptr.rs | |||
@@ -12,6 +12,7 @@ salsa::query_group! { | |||
12 | pub(crate) trait SyntaxPtrDatabase: SyntaxDatabase { | 12 | pub(crate) trait SyntaxPtrDatabase: SyntaxDatabase { |
13 | fn resolve_syntax_ptr(ptr: SyntaxPtr) -> SyntaxNode { | 13 | fn resolve_syntax_ptr(ptr: SyntaxPtr) -> SyntaxNode { |
14 | type ResolveSyntaxPtrQuery; | 14 | type ResolveSyntaxPtrQuery; |
15 | // Don't retain syntax trees in memory | ||
15 | storage volatile; | 16 | storage volatile; |
16 | } | 17 | } |
17 | } | 18 | } |
@@ -83,6 +84,10 @@ impl LocalSyntaxPtr { | |||
83 | .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) | 84 | .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) |
84 | } | 85 | } |
85 | } | 86 | } |
87 | |||
88 | pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr { | ||
89 | SyntaxPtr { file_id, local: self} | ||
90 | } | ||
86 | } | 91 | } |
87 | 92 | ||
88 | 93 | ||
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 806e1fb34..f5683aec5 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -5,62 +5,16 @@ extern crate relative_path; | |||
5 | extern crate rustc_hash; | 5 | extern crate rustc_hash; |
6 | extern crate test_utils; | 6 | extern crate test_utils; |
7 | 7 | ||
8 | use std::{ | ||
9 | sync::Arc, | ||
10 | }; | ||
11 | |||
12 | use ra_syntax::TextRange; | 8 | use ra_syntax::TextRange; |
13 | use relative_path::{RelativePath, RelativePathBuf}; | ||
14 | use test_utils::{assert_eq_dbg, extract_offset}; | 9 | use test_utils::{assert_eq_dbg, extract_offset}; |
15 | 10 | ||
16 | use ra_analysis::{ | 11 | use ra_analysis::{ |
17 | AnalysisChange, Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, | 12 | MockAnalysis, |
13 | AnalysisChange, Analysis, CrateGraph, CrateId, FileId, FnDescriptor, | ||
18 | }; | 14 | }; |
19 | 15 | ||
20 | #[derive(Debug)] | ||
21 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | ||
22 | |||
23 | impl FileMap { | ||
24 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { | ||
25 | self.0 | ||
26 | .iter() | ||
27 | .map(|(id, path)| (*id, path.as_relative_path())) | ||
28 | } | ||
29 | |||
30 | fn path(&self, id: FileId) -> &RelativePath { | ||
31 | self.iter().find(|&(it, _)| it == id).unwrap().1 | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl FileResolver for FileMap { | ||
36 | fn file_stem(&self, id: FileId) -> String { | ||
37 | self.path(id).file_stem().unwrap().to_string() | ||
38 | } | ||
39 | fn resolve(&self, id: FileId, rel: &RelativePath) -> Option<FileId> { | ||
40 | let path = self.path(id).join(rel).normalize(); | ||
41 | let id = self.iter().find(|&(_, p)| path == p)?.0; | ||
42 | Some(id) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | fn analysis_host(files: &[(&str, &str)]) -> AnalysisHost { | ||
47 | let mut host = AnalysisHost::new(); | ||
48 | let mut file_map = Vec::new(); | ||
49 | let mut change = AnalysisChange::new(); | ||
50 | for (id, &(path, contents)) in files.iter().enumerate() { | ||
51 | let file_id = FileId((id + 1) as u32); | ||
52 | assert!(path.starts_with('/')); | ||
53 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | ||
54 | change.add_file(file_id, contents.to_string()); | ||
55 | file_map.push((file_id, path)); | ||
56 | } | ||
57 | change.set_file_resolver(Arc::new(FileMap(file_map))); | ||
58 | host.apply_change(change); | ||
59 | host | ||
60 | } | ||
61 | |||
62 | fn analysis(files: &[(&str, &str)]) -> Analysis { | 16 | fn analysis(files: &[(&str, &str)]) -> Analysis { |
63 | analysis_host(files).analysis() | 17 | MockAnalysis::with_files(files).analysis() |
64 | } | 18 | } |
65 | 19 | ||
66 | fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { | 20 | fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { |
@@ -125,7 +79,9 @@ fn test_resolve_parent_module() { | |||
125 | 79 | ||
126 | #[test] | 80 | #[test] |
127 | fn test_resolve_crate_root() { | 81 | fn test_resolve_crate_root() { |
128 | let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); | 82 | let mut host = MockAnalysis::with_files( |
83 | &[("/lib.rs", "mod foo;"), ("/foo.rs", "")] | ||
84 | ).analysis_host(); | ||
129 | let snap = host.analysis(); | 85 | let snap = host.analysis(); |
130 | assert!(snap.crate_for(FileId(2)).unwrap().is_empty()); | 86 | assert!(snap.crate_for(FileId(2)).unwrap().is_empty()); |
131 | 87 | ||
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs deleted file mode 100644 index 20c8546a4..000000000 --- a/crates/ra_editor/src/completion.rs +++ /dev/null | |||
@@ -1,602 +0,0 @@ | |||
1 | /// FIXME: move completion from ra_editor to ra_analysis | ||
2 | |||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
4 | |||
5 | use ra_syntax::{ | ||
6 | algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx}, | ||
7 | ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner}, | ||
8 | AstNode, File, | ||
9 | SyntaxKind::*, | ||
10 | SyntaxNodeRef, TextUnit, | ||
11 | }; | ||
12 | |||
13 | use crate::{ | ||
14 | find_node_at_offset, | ||
15 | scope::{FnScopes, ModuleScope}, | ||
16 | AtomEdit, | ||
17 | }; | ||
18 | |||
19 | #[derive(Debug)] | ||
20 | pub struct CompletionItem { | ||
21 | /// What user sees in pop-up | ||
22 | pub label: String, | ||
23 | /// What string is used for filtering, defaults to label | ||
24 | pub lookup: Option<String>, | ||
25 | /// What is inserted, defaults to label | ||
26 | pub snippet: Option<String>, | ||
27 | } | ||
28 | |||
29 | pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { | ||
30 | // Insert a fake ident to get a valid parse tree | ||
31 | let file = { | ||
32 | let edit = AtomEdit::insert(offset, "intellijRulezz".to_string()); | ||
33 | file.reparse(&edit) | ||
34 | }; | ||
35 | let mut has_completions = false; | ||
36 | let mut res = Vec::new(); | ||
37 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) { | ||
38 | has_completions = true; | ||
39 | complete_name_ref(&file, name_ref, &mut res); | ||
40 | // special case, `trait T { fn foo(i_am_a_name_ref) {} }` | ||
41 | if is_node::<ast::Param>(name_ref.syntax()) { | ||
42 | param_completions(name_ref.syntax(), &mut res); | ||
43 | } | ||
44 | let name_range = name_ref.syntax().range(); | ||
45 | let top_node = name_ref | ||
46 | .syntax() | ||
47 | .ancestors() | ||
48 | .take_while(|it| it.range() == name_range) | ||
49 | .last() | ||
50 | .unwrap(); | ||
51 | match top_node.parent().map(|it| it.kind()) { | ||
52 | Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res), | ||
53 | _ => (), | ||
54 | } | ||
55 | } | ||
56 | if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) { | ||
57 | if is_node::<ast::Param>(name.syntax()) { | ||
58 | has_completions = true; | ||
59 | param_completions(name.syntax(), &mut res); | ||
60 | } | ||
61 | } | ||
62 | if has_completions { | ||
63 | Some(res) | ||
64 | } else { | ||
65 | None | ||
66 | } | ||
67 | } | ||
68 | |||
69 | pub fn complete_module_items(items: AstChildren<ast::ModuleItem>, this_item: Option<ast::NameRef>, acc: &mut Vec<CompletionItem>) { | ||
70 | let scope = ModuleScope::new(items); | ||
71 | acc.extend( | ||
72 | scope | ||
73 | .entries() | ||
74 | .iter() | ||
75 | .filter(|entry| Some(entry.syntax()) != this_item.map(|it| it.syntax())) | ||
76 | .map(|entry| CompletionItem { | ||
77 | label: entry.name().to_string(), | ||
78 | lookup: None, | ||
79 | snippet: None, | ||
80 | }), | ||
81 | ); | ||
82 | } | ||
83 | |||
84 | fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) { | ||
85 | if !is_node::<ast::Path>(name_ref.syntax()) { | ||
86 | return; | ||
87 | } | ||
88 | let mut visited_fn = false; | ||
89 | for node in name_ref.syntax().ancestors() { | ||
90 | if let Some(items) = visitor() | ||
91 | .visit::<ast::Root, _>(|it| Some(it.items())) | ||
92 | .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) | ||
93 | .accept(node) | ||
94 | { | ||
95 | if let Some(items) = items { | ||
96 | complete_module_items(items, Some(name_ref), acc); | ||
97 | } | ||
98 | break; | ||
99 | } else if !visited_fn { | ||
100 | if let Some(fn_def) = ast::FnDef::cast(node) { | ||
101 | visited_fn = true; | ||
102 | complete_expr_keywords(&file, fn_def, name_ref, acc); | ||
103 | complete_expr_snippets(acc); | ||
104 | let scopes = FnScopes::new(fn_def); | ||
105 | complete_fn(name_ref, &scopes, acc); | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { | ||
112 | let mut params = FxHashMap::default(); | ||
113 | for node in ctx.ancestors() { | ||
114 | let _ = visitor_ctx(&mut params) | ||
115 | .visit::<ast::Root, _>(process) | ||
116 | .visit::<ast::ItemList, _>(process) | ||
117 | .accept(node); | ||
118 | } | ||
119 | params | ||
120 | .into_iter() | ||
121 | .filter_map(|(label, (count, param))| { | ||
122 | let lookup = param.pat()?.syntax().text().to_string(); | ||
123 | if count < 2 { | ||
124 | None | ||
125 | } else { | ||
126 | Some((label, lookup)) | ||
127 | } | ||
128 | }) | ||
129 | .for_each(|(label, lookup)| { | ||
130 | acc.push(CompletionItem { | ||
131 | label, | ||
132 | lookup: Some(lookup), | ||
133 | snippet: None, | ||
134 | }) | ||
135 | }); | ||
136 | |||
137 | fn process<'a, N: ast::FnDefOwner<'a>>( | ||
138 | node: N, | ||
139 | params: &mut FxHashMap<String, (u32, ast::Param<'a>)>, | ||
140 | ) { | ||
141 | node.functions() | ||
142 | .filter_map(|it| it.param_list()) | ||
143 | .flat_map(|it| it.params()) | ||
144 | .for_each(|param| { | ||
145 | let text = param.syntax().text().to_string(); | ||
146 | params.entry(text).or_insert((0, param)).0 += 1; | ||
147 | }) | ||
148 | } | ||
149 | } | ||
150 | |||
151 | fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { | ||
152 | match node.ancestors().filter_map(N::cast).next() { | ||
153 | None => false, | ||
154 | Some(n) => n.syntax().range() == node.range(), | ||
155 | } | ||
156 | } | ||
157 | |||
158 | fn complete_expr_keywords( | ||
159 | file: &File, | ||
160 | fn_def: ast::FnDef, | ||
161 | name_ref: ast::NameRef, | ||
162 | acc: &mut Vec<CompletionItem>, | ||
163 | ) { | ||
164 | acc.push(keyword("if", "if $0 {}")); | ||
165 | acc.push(keyword("match", "match $0 {}")); | ||
166 | acc.push(keyword("while", "while $0 {}")); | ||
167 | acc.push(keyword("loop", "loop {$0}")); | ||
168 | |||
169 | if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) { | ||
170 | if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) { | ||
171 | if if_expr.syntax().range().end() < name_ref.syntax().range().start() { | ||
172 | acc.push(keyword("else", "else {$0}")); | ||
173 | acc.push(keyword("else if", "else if $0 {}")); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | if is_in_loop_body(name_ref) { | ||
178 | acc.push(keyword("continue", "continue")); | ||
179 | acc.push(keyword("break", "break")); | ||
180 | } | ||
181 | acc.extend(complete_return(fn_def, name_ref)); | ||
182 | } | ||
183 | |||
184 | fn is_in_loop_body(name_ref: ast::NameRef) -> bool { | ||
185 | for node in name_ref.syntax().ancestors() { | ||
186 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { | ||
187 | break; | ||
188 | } | ||
189 | let loop_body = visitor() | ||
190 | .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body) | ||
191 | .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body) | ||
192 | .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body) | ||
193 | .accept(node); | ||
194 | if let Some(Some(body)) = loop_body { | ||
195 | if name_ref.syntax().range().is_subrange(&body.syntax().range()) { | ||
196 | return true; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | false | ||
201 | } | ||
202 | |||
203 | fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> { | ||
204 | // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast) | ||
205 | // .next() | ||
206 | // .and_then(|it| it.syntax().parent()) | ||
207 | // .and_then(ast::Block::cast) | ||
208 | // .is_some(); | ||
209 | |||
210 | // if is_last_in_block { | ||
211 | // return None; | ||
212 | // } | ||
213 | |||
214 | let is_stmt = match name_ref | ||
215 | .syntax() | ||
216 | .ancestors() | ||
217 | .filter_map(ast::ExprStmt::cast) | ||
218 | .next() | ||
219 | { | ||
220 | None => false, | ||
221 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), | ||
222 | }; | ||
223 | let snip = match (is_stmt, fn_def.ret_type().is_some()) { | ||
224 | (true, true) => "return $0;", | ||
225 | (true, false) => "return;", | ||
226 | (false, true) => "return $0", | ||
227 | (false, false) => "return", | ||
228 | }; | ||
229 | Some(keyword("return", snip)) | ||
230 | } | ||
231 | |||
232 | fn keyword(kw: &str, snip: &str) -> CompletionItem { | ||
233 | CompletionItem { | ||
234 | label: kw.to_string(), | ||
235 | lookup: None, | ||
236 | snippet: Some(snip.to_string()), | ||
237 | } | ||
238 | } | ||
239 | |||
240 | fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { | ||
241 | acc.push(CompletionItem { | ||
242 | label: "pd".to_string(), | ||
243 | lookup: None, | ||
244 | snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()), | ||
245 | }); | ||
246 | acc.push(CompletionItem { | ||
247 | label: "ppd".to_string(), | ||
248 | lookup: None, | ||
249 | snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), | ||
250 | }); | ||
251 | } | ||
252 | |||
253 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | ||
254 | acc.push(CompletionItem { | ||
255 | label: "tfn".to_string(), | ||
256 | lookup: None, | ||
257 | snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), | ||
258 | }); | ||
259 | acc.push(CompletionItem { | ||
260 | label: "pub(crate)".to_string(), | ||
261 | lookup: None, | ||
262 | snippet: Some("pub(crate) $0".to_string()), | ||
263 | }) | ||
264 | } | ||
265 | |||
266 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | ||
267 | let mut shadowed = FxHashSet::default(); | ||
268 | acc.extend( | ||
269 | scopes | ||
270 | .scope_chain(name_ref.syntax()) | ||
271 | .flat_map(|scope| scopes.entries(scope).iter()) | ||
272 | .filter(|entry| shadowed.insert(entry.name())) | ||
273 | .map(|entry| CompletionItem { | ||
274 | label: entry.name().to_string(), | ||
275 | lookup: None, | ||
276 | snippet: None, | ||
277 | }), | ||
278 | ); | ||
279 | if scopes.self_param.is_some() { | ||
280 | acc.push(CompletionItem { | ||
281 | label: "self".to_string(), | ||
282 | lookup: None, | ||
283 | snippet: None, | ||
284 | }) | ||
285 | } | ||
286 | } | ||
287 | |||
288 | #[cfg(test)] | ||
289 | mod tests { | ||
290 | use super::*; | ||
291 | use test_utils::{assert_eq_dbg, extract_offset}; | ||
292 | |||
293 | fn check_scope_completion(code: &str, expected_completions: &str) { | ||
294 | let (off, code) = extract_offset(&code); | ||
295 | let file = File::parse(&code); | ||
296 | let completions = scope_completion(&file, off) | ||
297 | .unwrap() | ||
298 | .into_iter() | ||
299 | .filter(|c| c.snippet.is_none()) | ||
300 | .collect::<Vec<_>>(); | ||
301 | assert_eq_dbg(expected_completions, &completions); | ||
302 | } | ||
303 | |||
304 | fn check_snippet_completion(code: &str, expected_completions: &str) { | ||
305 | let (off, code) = extract_offset(&code); | ||
306 | let file = File::parse(&code); | ||
307 | let completions = scope_completion(&file, off) | ||
308 | .unwrap() | ||
309 | .into_iter() | ||
310 | .filter(|c| c.snippet.is_some()) | ||
311 | .collect::<Vec<_>>(); | ||
312 | assert_eq_dbg(expected_completions, &completions); | ||
313 | } | ||
314 | |||
315 | #[test] | ||
316 | fn test_completion_let_scope() { | ||
317 | check_scope_completion( | ||
318 | r" | ||
319 | fn quux(x: i32) { | ||
320 | let y = 92; | ||
321 | 1 + <|>; | ||
322 | let z = (); | ||
323 | } | ||
324 | ", | ||
325 | r#"[CompletionItem { label: "y", lookup: None, snippet: None }, | ||
326 | CompletionItem { label: "x", lookup: None, snippet: None }, | ||
327 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
328 | ); | ||
329 | } | ||
330 | |||
331 | #[test] | ||
332 | fn test_completion_if_let_scope() { | ||
333 | check_scope_completion( | ||
334 | r" | ||
335 | fn quux() { | ||
336 | if let Some(x) = foo() { | ||
337 | let y = 92; | ||
338 | }; | ||
339 | if let Some(a) = bar() { | ||
340 | let b = 62; | ||
341 | 1 + <|> | ||
342 | } | ||
343 | } | ||
344 | ", | ||
345 | r#"[CompletionItem { label: "b", lookup: None, snippet: None }, | ||
346 | CompletionItem { label: "a", lookup: None, snippet: None }, | ||
347 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
348 | ); | ||
349 | } | ||
350 | |||
351 | #[test] | ||
352 | fn test_completion_for_scope() { | ||
353 | check_scope_completion( | ||
354 | r" | ||
355 | fn quux() { | ||
356 | for x in &[1, 2, 3] { | ||
357 | <|> | ||
358 | } | ||
359 | } | ||
360 | ", | ||
361 | r#"[CompletionItem { label: "x", lookup: None, snippet: None }, | ||
362 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
363 | ); | ||
364 | } | ||
365 | |||
366 | #[test] | ||
367 | fn test_completion_mod_scope() { | ||
368 | check_scope_completion( | ||
369 | r" | ||
370 | struct Foo; | ||
371 | enum Baz {} | ||
372 | fn quux() { | ||
373 | <|> | ||
374 | } | ||
375 | ", | ||
376 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | ||
377 | CompletionItem { label: "Baz", lookup: None, snippet: None }, | ||
378 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
379 | ); | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn test_completion_mod_scope_no_self_use() { | ||
384 | check_scope_completion( | ||
385 | r" | ||
386 | use foo<|>; | ||
387 | ", | ||
388 | r#"[]"#, | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn test_completion_mod_scope_nested() { | ||
394 | check_scope_completion( | ||
395 | r" | ||
396 | struct Foo; | ||
397 | mod m { | ||
398 | struct Bar; | ||
399 | fn quux() { <|> } | ||
400 | } | ||
401 | ", | ||
402 | r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, | ||
403 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#, | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
408 | fn test_complete_type() { | ||
409 | check_scope_completion( | ||
410 | r" | ||
411 | struct Foo; | ||
412 | fn x() -> <|> | ||
413 | ", | ||
414 | r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, | ||
415 | CompletionItem { label: "x", lookup: None, snippet: None }]"#, | ||
416 | ) | ||
417 | } | ||
418 | |||
419 | #[test] | ||
420 | fn test_complete_shadowing() { | ||
421 | check_scope_completion( | ||
422 | r" | ||
423 | fn foo() -> { | ||
424 | let bar = 92; | ||
425 | { | ||
426 | let bar = 62; | ||
427 | <|> | ||
428 | } | ||
429 | } | ||
430 | ", | ||
431 | r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, | ||
432 | CompletionItem { label: "foo", lookup: None, snippet: None }]"#, | ||
433 | ) | ||
434 | } | ||
435 | |||
436 | #[test] | ||
437 | fn test_complete_self() { | ||
438 | check_scope_completion( | ||
439 | r" | ||
440 | impl S { fn foo(&self) { <|> } } | ||
441 | ", | ||
442 | r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#, | ||
443 | ) | ||
444 | } | ||
445 | |||
446 | #[test] | ||
447 | fn test_completion_kewords() { | ||
448 | check_snippet_completion(r" | ||
449 | fn quux() { | ||
450 | <|> | ||
451 | } | ||
452 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
453 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
454 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
455 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
456 | CompletionItem { label: "return", lookup: None, snippet: Some("return") }, | ||
457 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
458 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
459 | } | ||
460 | |||
461 | #[test] | ||
462 | fn test_completion_else() { | ||
463 | check_snippet_completion(r" | ||
464 | fn quux() { | ||
465 | if true { | ||
466 | () | ||
467 | } <|> | ||
468 | } | ||
469 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
470 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
471 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
472 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
473 | CompletionItem { label: "else", lookup: None, snippet: Some("else {$0}") }, | ||
474 | CompletionItem { label: "else if", lookup: None, snippet: Some("else if $0 {}") }, | ||
475 | CompletionItem { label: "return", lookup: None, snippet: Some("return") }, | ||
476 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
477 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
478 | } | ||
479 | |||
480 | #[test] | ||
481 | fn test_completion_return_value() { | ||
482 | check_snippet_completion(r" | ||
483 | fn quux() -> i32 { | ||
484 | <|> | ||
485 | 92 | ||
486 | } | ||
487 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
488 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
489 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
490 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
491 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0;") }, | ||
492 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
493 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
494 | check_snippet_completion(r" | ||
495 | fn quux() { | ||
496 | <|> | ||
497 | 92 | ||
498 | } | ||
499 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
500 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
501 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
502 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
503 | CompletionItem { label: "return", lookup: None, snippet: Some("return;") }, | ||
504 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
505 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
506 | } | ||
507 | |||
508 | #[test] | ||
509 | fn test_completion_return_no_stmt() { | ||
510 | check_snippet_completion(r" | ||
511 | fn quux() -> i32 { | ||
512 | match () { | ||
513 | () => <|> | ||
514 | } | ||
515 | } | ||
516 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
517 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
518 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
519 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
520 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
521 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
522 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
523 | } | ||
524 | |||
525 | #[test] | ||
526 | fn test_continue_break_completion() { | ||
527 | check_snippet_completion(r" | ||
528 | fn quux() -> i32 { | ||
529 | loop { <|> } | ||
530 | } | ||
531 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
532 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
533 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
534 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
535 | CompletionItem { label: "continue", lookup: None, snippet: Some("continue") }, | ||
536 | CompletionItem { label: "break", lookup: None, snippet: Some("break") }, | ||
537 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
538 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
539 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
540 | check_snippet_completion(r" | ||
541 | fn quux() -> i32 { | ||
542 | loop { || { <|> } } | ||
543 | } | ||
544 | ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, | ||
545 | CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, | ||
546 | CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, | ||
547 | CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, | ||
548 | CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }, | ||
549 | CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") }, | ||
550 | CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#); | ||
551 | } | ||
552 | |||
553 | #[test] | ||
554 | fn test_param_completion_last_param() { | ||
555 | check_scope_completion(r" | ||
556 | fn foo(file_id: FileId) {} | ||
557 | fn bar(file_id: FileId) {} | ||
558 | fn baz(file<|>) {} | ||
559 | ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
560 | } | ||
561 | |||
562 | #[test] | ||
563 | fn test_param_completion_nth_param() { | ||
564 | check_scope_completion(r" | ||
565 | fn foo(file_id: FileId) {} | ||
566 | fn bar(file_id: FileId) {} | ||
567 | fn baz(file<|>, x: i32) {} | ||
568 | ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
569 | } | ||
570 | |||
571 | #[test] | ||
572 | fn test_param_completion_trait_param() { | ||
573 | check_scope_completion(r" | ||
574 | pub(crate) trait SourceRoot { | ||
575 | pub fn contains(&self, file_id: FileId) -> bool; | ||
576 | pub fn module_map(&self) -> &ModuleMap; | ||
577 | pub fn lines(&self, file_id: FileId) -> &LineIndex; | ||
578 | pub fn syntax(&self, file<|>) | ||
579 | } | ||
580 | ", r#"[CompletionItem { label: "self", lookup: None, snippet: None }, | ||
581 | CompletionItem { label: "SourceRoot", lookup: None, snippet: None }, | ||
582 | CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); | ||
583 | } | ||
584 | |||
585 | #[test] | ||
586 | fn test_item_snippets() { | ||
587 | // check_snippet_completion(r" | ||
588 | // <|> | ||
589 | // ", | ||
590 | // r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }]"##, | ||
591 | // ); | ||
592 | check_snippet_completion(r" | ||
593 | #[cfg(test)] | ||
594 | mod tests { | ||
595 | <|> | ||
596 | } | ||
597 | ", | ||
598 | r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }, | ||
599 | CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##, | ||
600 | ); | ||
601 | } | ||
602 | } | ||
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index b73eb4ac7..02a1b2d45 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -8,12 +8,10 @@ extern crate superslice; | |||
8 | extern crate test_utils as _test_utils; | 8 | extern crate test_utils as _test_utils; |
9 | 9 | ||
10 | mod code_actions; | 10 | mod code_actions; |
11 | mod completion; | ||
12 | mod edit; | 11 | mod edit; |
13 | mod extend_selection; | 12 | mod extend_selection; |
14 | mod folding_ranges; | 13 | mod folding_ranges; |
15 | mod line_index; | 14 | mod line_index; |
16 | mod scope; | ||
17 | mod symbols; | 15 | mod symbols; |
18 | #[cfg(test)] | 16 | #[cfg(test)] |
19 | mod test_utils; | 17 | mod test_utils; |
@@ -21,7 +19,6 @@ mod typing; | |||
21 | 19 | ||
22 | pub use self::{ | 20 | pub use self::{ |
23 | code_actions::{add_derive, add_impl, flip_comma, introduce_variable, LocalEdit}, | 21 | code_actions::{add_derive, add_impl, flip_comma, introduce_variable, LocalEdit}, |
24 | completion::{scope_completion, complete_module_items, CompletionItem}, | ||
25 | edit::{Edit, EditBuilder}, | 22 | edit::{Edit, EditBuilder}, |
26 | extend_selection::extend_selection, | 23 | extend_selection::extend_selection, |
27 | folding_ranges::{folding_ranges, Fold, FoldKind}, | 24 | folding_ranges::{folding_ranges, Fold, FoldKind}, |
@@ -33,7 +30,7 @@ pub use ra_syntax::AtomEdit; | |||
33 | use ra_syntax::{ | 30 | use ra_syntax::{ |
34 | algo::find_leaf_at_offset, | 31 | algo::find_leaf_at_offset, |
35 | ast::{self, AstNode, NameOwner}, | 32 | ast::{self, AstNode, NameOwner}, |
36 | File, SmolStr, | 33 | File, |
37 | SyntaxKind::{self, *}, | 34 | SyntaxKind::{self, *}, |
38 | SyntaxNodeRef, TextRange, TextUnit, | 35 | SyntaxNodeRef, TextRange, TextUnit, |
39 | }; | 36 | }; |
@@ -151,15 +148,7 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>( | |||
151 | leaf.ancestors().filter_map(N::cast).next() | 148 | leaf.ancestors().filter_map(N::cast).next() |
152 | } | 149 | } |
153 | 150 | ||
154 | pub fn resolve_local_name( | 151 | |
155 | name_ref: ast::NameRef, | ||
156 | ) -> Option<(SmolStr, TextRange)> { | ||
157 | let fn_def = name_ref.syntax().ancestors().find_map(ast::FnDef::cast)?; | ||
158 | let scopes = scope::FnScopes::new(fn_def); | ||
159 | let scope_entry = scope::resolve_local_name(name_ref, &scopes)?; | ||
160 | let name = scope_entry.ast().name()?; | ||
161 | Some((scope_entry.name(), name.syntax().range())) | ||
162 | } | ||
163 | 152 | ||
164 | #[cfg(test)] | 153 | #[cfg(test)] |
165 | mod tests { | 154 | mod tests { |
diff --git a/crates/ra_editor/src/scope/mod.rs b/crates/ra_editor/src/scope/mod.rs deleted file mode 100644 index cc2d49392..000000000 --- a/crates/ra_editor/src/scope/mod.rs +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | mod fn_scope; | ||
2 | mod mod_scope; | ||
3 | |||
4 | pub use self::{ | ||
5 | fn_scope::{resolve_local_name, FnScopes}, | ||
6 | mod_scope::ModuleScope, | ||
7 | }; | ||
diff --git a/crates/ra_editor/src/scope/mod_scope.rs b/crates/ra_editor/src/scope/mod_scope.rs deleted file mode 100644 index 818749a12..000000000 --- a/crates/ra_editor/src/scope/mod_scope.rs +++ /dev/null | |||
@@ -1,124 +0,0 @@ | |||
1 | /// FIXME: this is now moved to ra_analysis::descriptors::module::scope. | ||
2 | /// | ||
3 | /// Current copy will be deleted as soon as we move the rest of the completion | ||
4 | /// to the analyezer. | ||
5 | |||
6 | |||
7 | use ra_syntax::{ | ||
8 | ast::{self, AstChildren}, | ||
9 | AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, | ||
10 | }; | ||
11 | |||
12 | pub struct ModuleScope { | ||
13 | entries: Vec<Entry>, | ||
14 | } | ||
15 | |||
16 | pub struct Entry { | ||
17 | node: SyntaxNode, | ||
18 | kind: EntryKind, | ||
19 | } | ||
20 | |||
21 | enum EntryKind { | ||
22 | Item, | ||
23 | Import, | ||
24 | } | ||
25 | |||
26 | impl ModuleScope { | ||
27 | pub fn new(items: AstChildren<ast::ModuleItem>) -> ModuleScope { | ||
28 | let mut entries = Vec::new(); | ||
29 | for item in items { | ||
30 | let entry = match item { | ||
31 | ast::ModuleItem::StructDef(item) => Entry::new_item(item), | ||
32 | ast::ModuleItem::EnumDef(item) => Entry::new_item(item), | ||
33 | ast::ModuleItem::FnDef(item) => Entry::new_item(item), | ||
34 | ast::ModuleItem::ConstDef(item) => Entry::new_item(item), | ||
35 | ast::ModuleItem::StaticDef(item) => Entry::new_item(item), | ||
36 | ast::ModuleItem::TraitDef(item) => Entry::new_item(item), | ||
37 | ast::ModuleItem::TypeDef(item) => Entry::new_item(item), | ||
38 | ast::ModuleItem::Module(item) => Entry::new_item(item), | ||
39 | ast::ModuleItem::UseItem(item) => { | ||
40 | if let Some(tree) = item.use_tree() { | ||
41 | collect_imports(tree, &mut entries); | ||
42 | } | ||
43 | continue; | ||
44 | } | ||
45 | ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ImplItem(_) => continue, | ||
46 | }; | ||
47 | entries.extend(entry) | ||
48 | } | ||
49 | |||
50 | ModuleScope { entries } | ||
51 | } | ||
52 | |||
53 | pub fn entries(&self) -> &[Entry] { | ||
54 | self.entries.as_slice() | ||
55 | } | ||
56 | } | ||
57 | |||
58 | impl Entry { | ||
59 | fn new_item<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> { | ||
60 | let name = item.name()?; | ||
61 | Some(Entry { | ||
62 | node: name.syntax().owned(), | ||
63 | kind: EntryKind::Item, | ||
64 | }) | ||
65 | } | ||
66 | fn new_import(path: ast::Path) -> Option<Entry> { | ||
67 | let name_ref = path.segment()?.name_ref()?; | ||
68 | Some(Entry { | ||
69 | node: name_ref.syntax().owned(), | ||
70 | kind: EntryKind::Import, | ||
71 | }) | ||
72 | } | ||
73 | pub fn name(&self) -> SmolStr { | ||
74 | match self.kind { | ||
75 | EntryKind::Item => ast::Name::cast(self.node.borrowed()).unwrap().text(), | ||
76 | EntryKind::Import => ast::NameRef::cast(self.node.borrowed()).unwrap().text(), | ||
77 | } | ||
78 | } | ||
79 | pub fn syntax(&self) -> SyntaxNodeRef { | ||
80 | self.node.borrowed() | ||
81 | } | ||
82 | } | ||
83 | |||
84 | fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { | ||
85 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
86 | return use_tree_list | ||
87 | .use_trees() | ||
88 | .for_each(|it| collect_imports(it, acc)); | ||
89 | } | ||
90 | if let Some(path) = tree.path() { | ||
91 | acc.extend(Entry::new_import(path)); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | #[cfg(test)] | ||
96 | mod tests { | ||
97 | use super::*; | ||
98 | use ra_syntax::{ast::ModuleItemOwner, File}; | ||
99 | |||
100 | fn do_check(code: &str, expected: &[&str]) { | ||
101 | let file = File::parse(&code); | ||
102 | let scope = ModuleScope::new(file.ast().items()); | ||
103 | let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); | ||
104 | assert_eq!(expected, actual.as_slice()); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn test_module_scope() { | ||
109 | do_check( | ||
110 | " | ||
111 | struct Foo; | ||
112 | enum Bar {} | ||
113 | mod baz {} | ||
114 | fn quux() {} | ||
115 | use x::{ | ||
116 | y::z, | ||
117 | t, | ||
118 | }; | ||
119 | type T = (); | ||
120 | ", | ||
121 | &["Foo", "Bar", "baz", "quux", "z", "t", "T"], | ||
122 | ) | ||
123 | } | ||
124 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 9ba775e1c..d0cd060d3 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | pub struct ArgListNode(SyntaxNode); | 15 | pub struct ArgListNode(SyntaxNode); |
16 | 16 | ||
17 | impl ArgListNode { | 17 | impl ArgListNode { |
18 | pub fn new(&self, ast: ArgList) -> ArgListNode { | 18 | pub fn new(ast: ArgList) -> ArgListNode { |
19 | let syntax = ast.syntax().owned(); | 19 | let syntax = ast.syntax().owned(); |
20 | ArgListNode(syntax) | 20 | ArgListNode(syntax) |
21 | } | 21 | } |
@@ -50,7 +50,7 @@ impl<'a> ArgList<'a> { | |||
50 | pub struct ArrayExprNode(SyntaxNode); | 50 | pub struct ArrayExprNode(SyntaxNode); |
51 | 51 | ||
52 | impl ArrayExprNode { | 52 | impl ArrayExprNode { |
53 | pub fn new(&self, ast: ArrayExpr) -> ArrayExprNode { | 53 | pub fn new(ast: ArrayExpr) -> ArrayExprNode { |
54 | let syntax = ast.syntax().owned(); | 54 | let syntax = ast.syntax().owned(); |
55 | ArrayExprNode(syntax) | 55 | ArrayExprNode(syntax) |
56 | } | 56 | } |
@@ -81,7 +81,7 @@ impl<'a> ArrayExpr<'a> {} | |||
81 | pub struct ArrayTypeNode(SyntaxNode); | 81 | pub struct ArrayTypeNode(SyntaxNode); |
82 | 82 | ||
83 | impl ArrayTypeNode { | 83 | impl ArrayTypeNode { |
84 | pub fn new(&self, ast: ArrayType) -> ArrayTypeNode { | 84 | pub fn new(ast: ArrayType) -> ArrayTypeNode { |
85 | let syntax = ast.syntax().owned(); | 85 | let syntax = ast.syntax().owned(); |
86 | ArrayTypeNode(syntax) | 86 | ArrayTypeNode(syntax) |
87 | } | 87 | } |
@@ -112,7 +112,7 @@ impl<'a> ArrayType<'a> {} | |||
112 | pub struct AttrNode(SyntaxNode); | 112 | pub struct AttrNode(SyntaxNode); |
113 | 113 | ||
114 | impl AttrNode { | 114 | impl AttrNode { |
115 | pub fn new(&self, ast: Attr) -> AttrNode { | 115 | pub fn new(ast: Attr) -> AttrNode { |
116 | let syntax = ast.syntax().owned(); | 116 | let syntax = ast.syntax().owned(); |
117 | AttrNode(syntax) | 117 | AttrNode(syntax) |
118 | } | 118 | } |
@@ -147,7 +147,7 @@ impl<'a> Attr<'a> { | |||
147 | pub struct BinExprNode(SyntaxNode); | 147 | pub struct BinExprNode(SyntaxNode); |
148 | 148 | ||
149 | impl BinExprNode { | 149 | impl BinExprNode { |
150 | pub fn new(&self, ast: BinExpr) -> BinExprNode { | 150 | pub fn new(ast: BinExpr) -> BinExprNode { |
151 | let syntax = ast.syntax().owned(); | 151 | let syntax = ast.syntax().owned(); |
152 | BinExprNode(syntax) | 152 | BinExprNode(syntax) |
153 | } | 153 | } |
@@ -178,7 +178,7 @@ impl<'a> BinExpr<'a> {} | |||
178 | pub struct BindPatNode(SyntaxNode); | 178 | pub struct BindPatNode(SyntaxNode); |
179 | 179 | ||
180 | impl BindPatNode { | 180 | impl BindPatNode { |
181 | pub fn new(&self, ast: BindPat) -> BindPatNode { | 181 | pub fn new(ast: BindPat) -> BindPatNode { |
182 | let syntax = ast.syntax().owned(); | 182 | let syntax = ast.syntax().owned(); |
183 | BindPatNode(syntax) | 183 | BindPatNode(syntax) |
184 | } | 184 | } |
@@ -210,7 +210,7 @@ impl<'a> BindPat<'a> {} | |||
210 | pub struct BlockNode(SyntaxNode); | 210 | pub struct BlockNode(SyntaxNode); |
211 | 211 | ||
212 | impl BlockNode { | 212 | impl BlockNode { |
213 | pub fn new(&self, ast: Block) -> BlockNode { | 213 | pub fn new(ast: Block) -> BlockNode { |
214 | let syntax = ast.syntax().owned(); | 214 | let syntax = ast.syntax().owned(); |
215 | BlockNode(syntax) | 215 | BlockNode(syntax) |
216 | } | 216 | } |
@@ -249,7 +249,7 @@ impl<'a> Block<'a> { | |||
249 | pub struct BlockExprNode(SyntaxNode); | 249 | pub struct BlockExprNode(SyntaxNode); |
250 | 250 | ||
251 | impl BlockExprNode { | 251 | impl BlockExprNode { |
252 | pub fn new(&self, ast: BlockExpr) -> BlockExprNode { | 252 | pub fn new(ast: BlockExpr) -> BlockExprNode { |
253 | let syntax = ast.syntax().owned(); | 253 | let syntax = ast.syntax().owned(); |
254 | BlockExprNode(syntax) | 254 | BlockExprNode(syntax) |
255 | } | 255 | } |
@@ -284,7 +284,7 @@ impl<'a> BlockExpr<'a> { | |||
284 | pub struct BreakExprNode(SyntaxNode); | 284 | pub struct BreakExprNode(SyntaxNode); |
285 | 285 | ||
286 | impl BreakExprNode { | 286 | impl BreakExprNode { |
287 | pub fn new(&self, ast: BreakExpr) -> BreakExprNode { | 287 | pub fn new(ast: BreakExpr) -> BreakExprNode { |
288 | let syntax = ast.syntax().owned(); | 288 | let syntax = ast.syntax().owned(); |
289 | BreakExprNode(syntax) | 289 | BreakExprNode(syntax) |
290 | } | 290 | } |
@@ -315,7 +315,7 @@ impl<'a> BreakExpr<'a> {} | |||
315 | pub struct CallExprNode(SyntaxNode); | 315 | pub struct CallExprNode(SyntaxNode); |
316 | 316 | ||
317 | impl CallExprNode { | 317 | impl CallExprNode { |
318 | pub fn new(&self, ast: CallExpr) -> CallExprNode { | 318 | pub fn new(ast: CallExpr) -> CallExprNode { |
319 | let syntax = ast.syntax().owned(); | 319 | let syntax = ast.syntax().owned(); |
320 | CallExprNode(syntax) | 320 | CallExprNode(syntax) |
321 | } | 321 | } |
@@ -351,7 +351,7 @@ impl<'a> CallExpr<'a> { | |||
351 | pub struct CastExprNode(SyntaxNode); | 351 | pub struct CastExprNode(SyntaxNode); |
352 | 352 | ||
353 | impl CastExprNode { | 353 | impl CastExprNode { |
354 | pub fn new(&self, ast: CastExpr) -> CastExprNode { | 354 | pub fn new(ast: CastExpr) -> CastExprNode { |
355 | let syntax = ast.syntax().owned(); | 355 | let syntax = ast.syntax().owned(); |
356 | CastExprNode(syntax) | 356 | CastExprNode(syntax) |
357 | } | 357 | } |
@@ -382,7 +382,7 @@ impl<'a> CastExpr<'a> {} | |||
382 | pub struct CommentNode(SyntaxNode); | 382 | pub struct CommentNode(SyntaxNode); |
383 | 383 | ||
384 | impl CommentNode { | 384 | impl CommentNode { |
385 | pub fn new(&self, ast: Comment) -> CommentNode { | 385 | pub fn new(ast: Comment) -> CommentNode { |
386 | let syntax = ast.syntax().owned(); | 386 | let syntax = ast.syntax().owned(); |
387 | CommentNode(syntax) | 387 | CommentNode(syntax) |
388 | } | 388 | } |
@@ -413,7 +413,7 @@ impl<'a> Comment<'a> {} | |||
413 | pub struct ConditionNode(SyntaxNode); | 413 | pub struct ConditionNode(SyntaxNode); |
414 | 414 | ||
415 | impl ConditionNode { | 415 | impl ConditionNode { |
416 | pub fn new(&self, ast: Condition) -> ConditionNode { | 416 | pub fn new(ast: Condition) -> ConditionNode { |
417 | let syntax = ast.syntax().owned(); | 417 | let syntax = ast.syntax().owned(); |
418 | ConditionNode(syntax) | 418 | ConditionNode(syntax) |
419 | } | 419 | } |
@@ -452,7 +452,7 @@ impl<'a> Condition<'a> { | |||
452 | pub struct ConstDefNode(SyntaxNode); | 452 | pub struct ConstDefNode(SyntaxNode); |
453 | 453 | ||
454 | impl ConstDefNode { | 454 | impl ConstDefNode { |
455 | pub fn new(&self, ast: ConstDef) -> ConstDefNode { | 455 | pub fn new(ast: ConstDef) -> ConstDefNode { |
456 | let syntax = ast.syntax().owned(); | 456 | let syntax = ast.syntax().owned(); |
457 | ConstDefNode(syntax) | 457 | ConstDefNode(syntax) |
458 | } | 458 | } |
@@ -486,7 +486,7 @@ impl<'a> ConstDef<'a> {} | |||
486 | pub struct ContinueExprNode(SyntaxNode); | 486 | pub struct ContinueExprNode(SyntaxNode); |
487 | 487 | ||
488 | impl ContinueExprNode { | 488 | impl ContinueExprNode { |
489 | pub fn new(&self, ast: ContinueExpr) -> ContinueExprNode { | 489 | pub fn new(ast: ContinueExpr) -> ContinueExprNode { |
490 | let syntax = ast.syntax().owned(); | 490 | let syntax = ast.syntax().owned(); |
491 | ContinueExprNode(syntax) | 491 | ContinueExprNode(syntax) |
492 | } | 492 | } |
@@ -517,7 +517,7 @@ impl<'a> ContinueExpr<'a> {} | |||
517 | pub struct DynTraitTypeNode(SyntaxNode); | 517 | pub struct DynTraitTypeNode(SyntaxNode); |
518 | 518 | ||
519 | impl DynTraitTypeNode { | 519 | impl DynTraitTypeNode { |
520 | pub fn new(&self, ast: DynTraitType) -> DynTraitTypeNode { | 520 | pub fn new(ast: DynTraitType) -> DynTraitTypeNode { |
521 | let syntax = ast.syntax().owned(); | 521 | let syntax = ast.syntax().owned(); |
522 | DynTraitTypeNode(syntax) | 522 | DynTraitTypeNode(syntax) |
523 | } | 523 | } |
@@ -548,7 +548,7 @@ impl<'a> DynTraitType<'a> {} | |||
548 | pub struct EnumDefNode(SyntaxNode); | 548 | pub struct EnumDefNode(SyntaxNode); |
549 | 549 | ||
550 | impl EnumDefNode { | 550 | impl EnumDefNode { |
551 | pub fn new(&self, ast: EnumDef) -> EnumDefNode { | 551 | pub fn new(ast: EnumDef) -> EnumDefNode { |
552 | let syntax = ast.syntax().owned(); | 552 | let syntax = ast.syntax().owned(); |
553 | EnumDefNode(syntax) | 553 | EnumDefNode(syntax) |
554 | } | 554 | } |
@@ -582,7 +582,7 @@ impl<'a> EnumDef<'a> {} | |||
582 | pub struct ExprNode(SyntaxNode); | 582 | pub struct ExprNode(SyntaxNode); |
583 | 583 | ||
584 | impl ExprNode { | 584 | impl ExprNode { |
585 | pub fn new(&self, ast: Expr) -> ExprNode { | 585 | pub fn new(ast: Expr) -> ExprNode { |
586 | let syntax = ast.syntax().owned(); | 586 | let syntax = ast.syntax().owned(); |
587 | ExprNode(syntax) | 587 | ExprNode(syntax) |
588 | } | 588 | } |
@@ -710,7 +710,7 @@ impl<'a> Expr<'a> {} | |||
710 | pub struct ExprStmtNode(SyntaxNode); | 710 | pub struct ExprStmtNode(SyntaxNode); |
711 | 711 | ||
712 | impl ExprStmtNode { | 712 | impl ExprStmtNode { |
713 | pub fn new(&self, ast: ExprStmt) -> ExprStmtNode { | 713 | pub fn new(ast: ExprStmt) -> ExprStmtNode { |
714 | let syntax = ast.syntax().owned(); | 714 | let syntax = ast.syntax().owned(); |
715 | ExprStmtNode(syntax) | 715 | ExprStmtNode(syntax) |
716 | } | 716 | } |
@@ -745,7 +745,7 @@ impl<'a> ExprStmt<'a> { | |||
745 | pub struct ExternCrateItemNode(SyntaxNode); | 745 | pub struct ExternCrateItemNode(SyntaxNode); |
746 | 746 | ||
747 | impl ExternCrateItemNode { | 747 | impl ExternCrateItemNode { |
748 | pub fn new(&self, ast: ExternCrateItem) -> ExternCrateItemNode { | 748 | pub fn new(ast: ExternCrateItem) -> ExternCrateItemNode { |
749 | let syntax = ast.syntax().owned(); | 749 | let syntax = ast.syntax().owned(); |
750 | ExternCrateItemNode(syntax) | 750 | ExternCrateItemNode(syntax) |
751 | } | 751 | } |
@@ -776,7 +776,7 @@ impl<'a> ExternCrateItem<'a> {} | |||
776 | pub struct FieldExprNode(SyntaxNode); | 776 | pub struct FieldExprNode(SyntaxNode); |
777 | 777 | ||
778 | impl FieldExprNode { | 778 | impl FieldExprNode { |
779 | pub fn new(&self, ast: FieldExpr) -> FieldExprNode { | 779 | pub fn new(ast: FieldExpr) -> FieldExprNode { |
780 | let syntax = ast.syntax().owned(); | 780 | let syntax = ast.syntax().owned(); |
781 | FieldExprNode(syntax) | 781 | FieldExprNode(syntax) |
782 | } | 782 | } |
@@ -807,7 +807,7 @@ impl<'a> FieldExpr<'a> {} | |||
807 | pub struct FieldPatListNode(SyntaxNode); | 807 | pub struct FieldPatListNode(SyntaxNode); |
808 | 808 | ||
809 | impl FieldPatListNode { | 809 | impl FieldPatListNode { |
810 | pub fn new(&self, ast: FieldPatList) -> FieldPatListNode { | 810 | pub fn new(ast: FieldPatList) -> FieldPatListNode { |
811 | let syntax = ast.syntax().owned(); | 811 | let syntax = ast.syntax().owned(); |
812 | FieldPatListNode(syntax) | 812 | FieldPatListNode(syntax) |
813 | } | 813 | } |
@@ -838,7 +838,7 @@ impl<'a> FieldPatList<'a> {} | |||
838 | pub struct FnDefNode(SyntaxNode); | 838 | pub struct FnDefNode(SyntaxNode); |
839 | 839 | ||
840 | impl FnDefNode { | 840 | impl FnDefNode { |
841 | pub fn new(&self, ast: FnDef) -> FnDefNode { | 841 | pub fn new(ast: FnDef) -> FnDefNode { |
842 | let syntax = ast.syntax().owned(); | 842 | let syntax = ast.syntax().owned(); |
843 | FnDefNode(syntax) | 843 | FnDefNode(syntax) |
844 | } | 844 | } |
@@ -884,7 +884,7 @@ impl<'a> FnDef<'a> { | |||
884 | pub struct FnPointerTypeNode(SyntaxNode); | 884 | pub struct FnPointerTypeNode(SyntaxNode); |
885 | 885 | ||
886 | impl FnPointerTypeNode { | 886 | impl FnPointerTypeNode { |
887 | pub fn new(&self, ast: FnPointerType) -> FnPointerTypeNode { | 887 | pub fn new(ast: FnPointerType) -> FnPointerTypeNode { |
888 | let syntax = ast.syntax().owned(); | 888 | let syntax = ast.syntax().owned(); |
889 | FnPointerTypeNode(syntax) | 889 | FnPointerTypeNode(syntax) |
890 | } | 890 | } |
@@ -915,7 +915,7 @@ impl<'a> FnPointerType<'a> {} | |||
915 | pub struct ForExprNode(SyntaxNode); | 915 | pub struct ForExprNode(SyntaxNode); |
916 | 916 | ||
917 | impl ForExprNode { | 917 | impl ForExprNode { |
918 | pub fn new(&self, ast: ForExpr) -> ForExprNode { | 918 | pub fn new(ast: ForExpr) -> ForExprNode { |
919 | let syntax = ast.syntax().owned(); | 919 | let syntax = ast.syntax().owned(); |
920 | ForExprNode(syntax) | 920 | ForExprNode(syntax) |
921 | } | 921 | } |
@@ -955,7 +955,7 @@ impl<'a> ForExpr<'a> { | |||
955 | pub struct ForTypeNode(SyntaxNode); | 955 | pub struct ForTypeNode(SyntaxNode); |
956 | 956 | ||
957 | impl ForTypeNode { | 957 | impl ForTypeNode { |
958 | pub fn new(&self, ast: ForType) -> ForTypeNode { | 958 | pub fn new(ast: ForType) -> ForTypeNode { |
959 | let syntax = ast.syntax().owned(); | 959 | let syntax = ast.syntax().owned(); |
960 | ForTypeNode(syntax) | 960 | ForTypeNode(syntax) |
961 | } | 961 | } |
@@ -986,7 +986,7 @@ impl<'a> ForType<'a> {} | |||
986 | pub struct IfExprNode(SyntaxNode); | 986 | pub struct IfExprNode(SyntaxNode); |
987 | 987 | ||
988 | impl IfExprNode { | 988 | impl IfExprNode { |
989 | pub fn new(&self, ast: IfExpr) -> IfExprNode { | 989 | pub fn new(ast: IfExpr) -> IfExprNode { |
990 | let syntax = ast.syntax().owned(); | 990 | let syntax = ast.syntax().owned(); |
991 | IfExprNode(syntax) | 991 | IfExprNode(syntax) |
992 | } | 992 | } |
@@ -1021,7 +1021,7 @@ impl<'a> IfExpr<'a> { | |||
1021 | pub struct ImplItemNode(SyntaxNode); | 1021 | pub struct ImplItemNode(SyntaxNode); |
1022 | 1022 | ||
1023 | impl ImplItemNode { | 1023 | impl ImplItemNode { |
1024 | pub fn new(&self, ast: ImplItem) -> ImplItemNode { | 1024 | pub fn new(ast: ImplItem) -> ImplItemNode { |
1025 | let syntax = ast.syntax().owned(); | 1025 | let syntax = ast.syntax().owned(); |
1026 | ImplItemNode(syntax) | 1026 | ImplItemNode(syntax) |
1027 | } | 1027 | } |
@@ -1052,7 +1052,7 @@ impl<'a> ImplItem<'a> {} | |||
1052 | pub struct ImplTraitTypeNode(SyntaxNode); | 1052 | pub struct ImplTraitTypeNode(SyntaxNode); |
1053 | 1053 | ||
1054 | impl ImplTraitTypeNode { | 1054 | impl ImplTraitTypeNode { |
1055 | pub fn new(&self, ast: ImplTraitType) -> ImplTraitTypeNode { | 1055 | pub fn new(ast: ImplTraitType) -> ImplTraitTypeNode { |
1056 | let syntax = ast.syntax().owned(); | 1056 | let syntax = ast.syntax().owned(); |
1057 | ImplTraitTypeNode(syntax) | 1057 | ImplTraitTypeNode(syntax) |
1058 | } | 1058 | } |
@@ -1083,7 +1083,7 @@ impl<'a> ImplTraitType<'a> {} | |||
1083 | pub struct IndexExprNode(SyntaxNode); | 1083 | pub struct IndexExprNode(SyntaxNode); |
1084 | 1084 | ||
1085 | impl IndexExprNode { | 1085 | impl IndexExprNode { |
1086 | pub fn new(&self, ast: IndexExpr) -> IndexExprNode { | 1086 | pub fn new(ast: IndexExpr) -> IndexExprNode { |
1087 | let syntax = ast.syntax().owned(); | 1087 | let syntax = ast.syntax().owned(); |
1088 | IndexExprNode(syntax) | 1088 | IndexExprNode(syntax) |
1089 | } | 1089 | } |
@@ -1114,7 +1114,7 @@ impl<'a> IndexExpr<'a> {} | |||
1114 | pub struct ItemListNode(SyntaxNode); | 1114 | pub struct ItemListNode(SyntaxNode); |
1115 | 1115 | ||
1116 | impl ItemListNode { | 1116 | impl ItemListNode { |
1117 | pub fn new(&self, ast: ItemList) -> ItemListNode { | 1117 | pub fn new(ast: ItemList) -> ItemListNode { |
1118 | let syntax = ast.syntax().owned(); | 1118 | let syntax = ast.syntax().owned(); |
1119 | ItemListNode(syntax) | 1119 | ItemListNode(syntax) |
1120 | } | 1120 | } |
@@ -1147,7 +1147,7 @@ impl<'a> ItemList<'a> {} | |||
1147 | pub struct LabelNode(SyntaxNode); | 1147 | pub struct LabelNode(SyntaxNode); |
1148 | 1148 | ||
1149 | impl LabelNode { | 1149 | impl LabelNode { |
1150 | pub fn new(&self, ast: Label) -> LabelNode { | 1150 | pub fn new(ast: Label) -> LabelNode { |
1151 | let syntax = ast.syntax().owned(); | 1151 | let syntax = ast.syntax().owned(); |
1152 | LabelNode(syntax) | 1152 | LabelNode(syntax) |
1153 | } | 1153 | } |
@@ -1178,7 +1178,7 @@ impl<'a> Label<'a> {} | |||
1178 | pub struct LambdaExprNode(SyntaxNode); | 1178 | pub struct LambdaExprNode(SyntaxNode); |
1179 | 1179 | ||
1180 | impl LambdaExprNode { | 1180 | impl LambdaExprNode { |
1181 | pub fn new(&self, ast: LambdaExpr) -> LambdaExprNode { | 1181 | pub fn new(ast: LambdaExpr) -> LambdaExprNode { |
1182 | let syntax = ast.syntax().owned(); | 1182 | let syntax = ast.syntax().owned(); |
1183 | LambdaExprNode(syntax) | 1183 | LambdaExprNode(syntax) |
1184 | } | 1184 | } |
@@ -1217,7 +1217,7 @@ impl<'a> LambdaExpr<'a> { | |||
1217 | pub struct LetStmtNode(SyntaxNode); | 1217 | pub struct LetStmtNode(SyntaxNode); |
1218 | 1218 | ||
1219 | impl LetStmtNode { | 1219 | impl LetStmtNode { |
1220 | pub fn new(&self, ast: LetStmt) -> LetStmtNode { | 1220 | pub fn new(ast: LetStmt) -> LetStmtNode { |
1221 | let syntax = ast.syntax().owned(); | 1221 | let syntax = ast.syntax().owned(); |
1222 | LetStmtNode(syntax) | 1222 | LetStmtNode(syntax) |
1223 | } | 1223 | } |
@@ -1256,7 +1256,7 @@ impl<'a> LetStmt<'a> { | |||
1256 | pub struct LifetimeNode(SyntaxNode); | 1256 | pub struct LifetimeNode(SyntaxNode); |
1257 | 1257 | ||
1258 | impl LifetimeNode { | 1258 | impl LifetimeNode { |
1259 | pub fn new(&self, ast: Lifetime) -> LifetimeNode { | 1259 | pub fn new(ast: Lifetime) -> LifetimeNode { |
1260 | let syntax = ast.syntax().owned(); | 1260 | let syntax = ast.syntax().owned(); |
1261 | LifetimeNode(syntax) | 1261 | LifetimeNode(syntax) |
1262 | } | 1262 | } |
@@ -1287,7 +1287,7 @@ impl<'a> Lifetime<'a> {} | |||
1287 | pub struct LifetimeParamNode(SyntaxNode); | 1287 | pub struct LifetimeParamNode(SyntaxNode); |
1288 | 1288 | ||
1289 | impl LifetimeParamNode { | 1289 | impl LifetimeParamNode { |
1290 | pub fn new(&self, ast: LifetimeParam) -> LifetimeParamNode { | 1290 | pub fn new(ast: LifetimeParam) -> LifetimeParamNode { |
1291 | let syntax = ast.syntax().owned(); | 1291 | let syntax = ast.syntax().owned(); |
1292 | LifetimeParamNode(syntax) | 1292 | LifetimeParamNode(syntax) |
1293 | } | 1293 | } |
@@ -1322,7 +1322,7 @@ impl<'a> LifetimeParam<'a> { | |||
1322 | pub struct LiteralNode(SyntaxNode); | 1322 | pub struct LiteralNode(SyntaxNode); |
1323 | 1323 | ||
1324 | impl LiteralNode { | 1324 | impl LiteralNode { |
1325 | pub fn new(&self, ast: Literal) -> LiteralNode { | 1325 | pub fn new(ast: Literal) -> LiteralNode { |
1326 | let syntax = ast.syntax().owned(); | 1326 | let syntax = ast.syntax().owned(); |
1327 | LiteralNode(syntax) | 1327 | LiteralNode(syntax) |
1328 | } | 1328 | } |
@@ -1353,7 +1353,7 @@ impl<'a> Literal<'a> {} | |||
1353 | pub struct LoopExprNode(SyntaxNode); | 1353 | pub struct LoopExprNode(SyntaxNode); |
1354 | 1354 | ||
1355 | impl LoopExprNode { | 1355 | impl LoopExprNode { |
1356 | pub fn new(&self, ast: LoopExpr) -> LoopExprNode { | 1356 | pub fn new(ast: LoopExpr) -> LoopExprNode { |
1357 | let syntax = ast.syntax().owned(); | 1357 | let syntax = ast.syntax().owned(); |
1358 | LoopExprNode(syntax) | 1358 | LoopExprNode(syntax) |
1359 | } | 1359 | } |
@@ -1385,7 +1385,7 @@ impl<'a> LoopExpr<'a> {} | |||
1385 | pub struct MatchArmNode(SyntaxNode); | 1385 | pub struct MatchArmNode(SyntaxNode); |
1386 | 1386 | ||
1387 | impl MatchArmNode { | 1387 | impl MatchArmNode { |
1388 | pub fn new(&self, ast: MatchArm) -> MatchArmNode { | 1388 | pub fn new(ast: MatchArm) -> MatchArmNode { |
1389 | let syntax = ast.syntax().owned(); | 1389 | let syntax = ast.syntax().owned(); |
1390 | MatchArmNode(syntax) | 1390 | MatchArmNode(syntax) |
1391 | } | 1391 | } |
@@ -1428,7 +1428,7 @@ impl<'a> MatchArm<'a> { | |||
1428 | pub struct MatchArmListNode(SyntaxNode); | 1428 | pub struct MatchArmListNode(SyntaxNode); |
1429 | 1429 | ||
1430 | impl MatchArmListNode { | 1430 | impl MatchArmListNode { |
1431 | pub fn new(&self, ast: MatchArmList) -> MatchArmListNode { | 1431 | pub fn new(ast: MatchArmList) -> MatchArmListNode { |
1432 | let syntax = ast.syntax().owned(); | 1432 | let syntax = ast.syntax().owned(); |
1433 | MatchArmListNode(syntax) | 1433 | MatchArmListNode(syntax) |
1434 | } | 1434 | } |
@@ -1463,7 +1463,7 @@ impl<'a> MatchArmList<'a> { | |||
1463 | pub struct MatchExprNode(SyntaxNode); | 1463 | pub struct MatchExprNode(SyntaxNode); |
1464 | 1464 | ||
1465 | impl MatchExprNode { | 1465 | impl MatchExprNode { |
1466 | pub fn new(&self, ast: MatchExpr) -> MatchExprNode { | 1466 | pub fn new(ast: MatchExpr) -> MatchExprNode { |
1467 | let syntax = ast.syntax().owned(); | 1467 | let syntax = ast.syntax().owned(); |
1468 | MatchExprNode(syntax) | 1468 | MatchExprNode(syntax) |
1469 | } | 1469 | } |
@@ -1502,7 +1502,7 @@ impl<'a> MatchExpr<'a> { | |||
1502 | pub struct MatchGuardNode(SyntaxNode); | 1502 | pub struct MatchGuardNode(SyntaxNode); |
1503 | 1503 | ||
1504 | impl MatchGuardNode { | 1504 | impl MatchGuardNode { |
1505 | pub fn new(&self, ast: MatchGuard) -> MatchGuardNode { | 1505 | pub fn new(ast: MatchGuard) -> MatchGuardNode { |
1506 | let syntax = ast.syntax().owned(); | 1506 | let syntax = ast.syntax().owned(); |
1507 | MatchGuardNode(syntax) | 1507 | MatchGuardNode(syntax) |
1508 | } | 1508 | } |
@@ -1533,7 +1533,7 @@ impl<'a> MatchGuard<'a> {} | |||
1533 | pub struct MethodCallExprNode(SyntaxNode); | 1533 | pub struct MethodCallExprNode(SyntaxNode); |
1534 | 1534 | ||
1535 | impl MethodCallExprNode { | 1535 | impl MethodCallExprNode { |
1536 | pub fn new(&self, ast: MethodCallExpr) -> MethodCallExprNode { | 1536 | pub fn new(ast: MethodCallExpr) -> MethodCallExprNode { |
1537 | let syntax = ast.syntax().owned(); | 1537 | let syntax = ast.syntax().owned(); |
1538 | MethodCallExprNode(syntax) | 1538 | MethodCallExprNode(syntax) |
1539 | } | 1539 | } |
@@ -1569,7 +1569,7 @@ impl<'a> MethodCallExpr<'a> { | |||
1569 | pub struct ModuleNode(SyntaxNode); | 1569 | pub struct ModuleNode(SyntaxNode); |
1570 | 1570 | ||
1571 | impl ModuleNode { | 1571 | impl ModuleNode { |
1572 | pub fn new(&self, ast: Module) -> ModuleNode { | 1572 | pub fn new(ast: Module) -> ModuleNode { |
1573 | let syntax = ast.syntax().owned(); | 1573 | let syntax = ast.syntax().owned(); |
1574 | ModuleNode(syntax) | 1574 | ModuleNode(syntax) |
1575 | } | 1575 | } |
@@ -1606,7 +1606,7 @@ impl<'a> Module<'a> { | |||
1606 | pub struct ModuleItemNode(SyntaxNode); | 1606 | pub struct ModuleItemNode(SyntaxNode); |
1607 | 1607 | ||
1608 | impl ModuleItemNode { | 1608 | impl ModuleItemNode { |
1609 | pub fn new(&self, ast: ModuleItem) -> ModuleItemNode { | 1609 | pub fn new(ast: ModuleItem) -> ModuleItemNode { |
1610 | let syntax = ast.syntax().owned(); | 1610 | let syntax = ast.syntax().owned(); |
1611 | ModuleItemNode(syntax) | 1611 | ModuleItemNode(syntax) |
1612 | } | 1612 | } |
@@ -1671,7 +1671,7 @@ impl<'a> ModuleItem<'a> {} | |||
1671 | pub struct NameNode(SyntaxNode); | 1671 | pub struct NameNode(SyntaxNode); |
1672 | 1672 | ||
1673 | impl NameNode { | 1673 | impl NameNode { |
1674 | pub fn new(&self, ast: Name) -> NameNode { | 1674 | pub fn new(ast: Name) -> NameNode { |
1675 | let syntax = ast.syntax().owned(); | 1675 | let syntax = ast.syntax().owned(); |
1676 | NameNode(syntax) | 1676 | NameNode(syntax) |
1677 | } | 1677 | } |
@@ -1702,7 +1702,7 @@ impl<'a> Name<'a> {} | |||
1702 | pub struct NameRefNode(SyntaxNode); | 1702 | pub struct NameRefNode(SyntaxNode); |
1703 | 1703 | ||
1704 | impl NameRefNode { | 1704 | impl NameRefNode { |
1705 | pub fn new(&self, ast: NameRef) -> NameRefNode { | 1705 | pub fn new(ast: NameRef) -> NameRefNode { |
1706 | let syntax = ast.syntax().owned(); | 1706 | let syntax = ast.syntax().owned(); |
1707 | NameRefNode(syntax) | 1707 | NameRefNode(syntax) |
1708 | } | 1708 | } |
@@ -1733,7 +1733,7 @@ impl<'a> NameRef<'a> {} | |||
1733 | pub struct NamedFieldNode(SyntaxNode); | 1733 | pub struct NamedFieldNode(SyntaxNode); |
1734 | 1734 | ||
1735 | impl NamedFieldNode { | 1735 | impl NamedFieldNode { |
1736 | pub fn new(&self, ast: NamedField) -> NamedFieldNode { | 1736 | pub fn new(ast: NamedField) -> NamedFieldNode { |
1737 | let syntax = ast.syntax().owned(); | 1737 | let syntax = ast.syntax().owned(); |
1738 | NamedFieldNode(syntax) | 1738 | NamedFieldNode(syntax) |
1739 | } | 1739 | } |
@@ -1764,7 +1764,7 @@ impl<'a> NamedField<'a> {} | |||
1764 | pub struct NamedFieldDefNode(SyntaxNode); | 1764 | pub struct NamedFieldDefNode(SyntaxNode); |
1765 | 1765 | ||
1766 | impl NamedFieldDefNode { | 1766 | impl NamedFieldDefNode { |
1767 | pub fn new(&self, ast: NamedFieldDef) -> NamedFieldDefNode { | 1767 | pub fn new(ast: NamedFieldDef) -> NamedFieldDefNode { |
1768 | let syntax = ast.syntax().owned(); | 1768 | let syntax = ast.syntax().owned(); |
1769 | NamedFieldDefNode(syntax) | 1769 | NamedFieldDefNode(syntax) |
1770 | } | 1770 | } |
@@ -1797,7 +1797,7 @@ impl<'a> NamedFieldDef<'a> {} | |||
1797 | pub struct NamedFieldListNode(SyntaxNode); | 1797 | pub struct NamedFieldListNode(SyntaxNode); |
1798 | 1798 | ||
1799 | impl NamedFieldListNode { | 1799 | impl NamedFieldListNode { |
1800 | pub fn new(&self, ast: NamedFieldList) -> NamedFieldListNode { | 1800 | pub fn new(ast: NamedFieldList) -> NamedFieldListNode { |
1801 | let syntax = ast.syntax().owned(); | 1801 | let syntax = ast.syntax().owned(); |
1802 | NamedFieldListNode(syntax) | 1802 | NamedFieldListNode(syntax) |
1803 | } | 1803 | } |
@@ -1828,7 +1828,7 @@ impl<'a> NamedFieldList<'a> {} | |||
1828 | pub struct NeverTypeNode(SyntaxNode); | 1828 | pub struct NeverTypeNode(SyntaxNode); |
1829 | 1829 | ||
1830 | impl NeverTypeNode { | 1830 | impl NeverTypeNode { |
1831 | pub fn new(&self, ast: NeverType) -> NeverTypeNode { | 1831 | pub fn new(ast: NeverType) -> NeverTypeNode { |
1832 | let syntax = ast.syntax().owned(); | 1832 | let syntax = ast.syntax().owned(); |
1833 | NeverTypeNode(syntax) | 1833 | NeverTypeNode(syntax) |
1834 | } | 1834 | } |
@@ -1859,7 +1859,7 @@ impl<'a> NeverType<'a> {} | |||
1859 | pub struct NominalDefNode(SyntaxNode); | 1859 | pub struct NominalDefNode(SyntaxNode); |
1860 | 1860 | ||
1861 | impl NominalDefNode { | 1861 | impl NominalDefNode { |
1862 | pub fn new(&self, ast: NominalDef) -> NominalDefNode { | 1862 | pub fn new(ast: NominalDef) -> NominalDefNode { |
1863 | let syntax = ast.syntax().owned(); | 1863 | let syntax = ast.syntax().owned(); |
1864 | NominalDefNode(syntax) | 1864 | NominalDefNode(syntax) |
1865 | } | 1865 | } |
@@ -1900,7 +1900,7 @@ impl<'a> NominalDef<'a> {} | |||
1900 | pub struct ParamNode(SyntaxNode); | 1900 | pub struct ParamNode(SyntaxNode); |
1901 | 1901 | ||
1902 | impl ParamNode { | 1902 | impl ParamNode { |
1903 | pub fn new(&self, ast: Param) -> ParamNode { | 1903 | pub fn new(ast: Param) -> ParamNode { |
1904 | let syntax = ast.syntax().owned(); | 1904 | let syntax = ast.syntax().owned(); |
1905 | ParamNode(syntax) | 1905 | ParamNode(syntax) |
1906 | } | 1906 | } |
@@ -1935,7 +1935,7 @@ impl<'a> Param<'a> { | |||
1935 | pub struct ParamListNode(SyntaxNode); | 1935 | pub struct ParamListNode(SyntaxNode); |
1936 | 1936 | ||
1937 | impl ParamListNode { | 1937 | impl ParamListNode { |
1938 | pub fn new(&self, ast: ParamList) -> ParamListNode { | 1938 | pub fn new(ast: ParamList) -> ParamListNode { |
1939 | let syntax = ast.syntax().owned(); | 1939 | let syntax = ast.syntax().owned(); |
1940 | ParamListNode(syntax) | 1940 | ParamListNode(syntax) |
1941 | } | 1941 | } |
@@ -1974,7 +1974,7 @@ impl<'a> ParamList<'a> { | |||
1974 | pub struct ParenExprNode(SyntaxNode); | 1974 | pub struct ParenExprNode(SyntaxNode); |
1975 | 1975 | ||
1976 | impl ParenExprNode { | 1976 | impl ParenExprNode { |
1977 | pub fn new(&self, ast: ParenExpr) -> ParenExprNode { | 1977 | pub fn new(ast: ParenExpr) -> ParenExprNode { |
1978 | let syntax = ast.syntax().owned(); | 1978 | let syntax = ast.syntax().owned(); |
1979 | ParenExprNode(syntax) | 1979 | ParenExprNode(syntax) |
1980 | } | 1980 | } |
@@ -2005,7 +2005,7 @@ impl<'a> ParenExpr<'a> {} | |||
2005 | pub struct ParenTypeNode(SyntaxNode); | 2005 | pub struct ParenTypeNode(SyntaxNode); |
2006 | 2006 | ||
2007 | impl ParenTypeNode { | 2007 | impl ParenTypeNode { |
2008 | pub fn new(&self, ast: ParenType) -> ParenTypeNode { | 2008 | pub fn new(ast: ParenType) -> ParenTypeNode { |
2009 | let syntax = ast.syntax().owned(); | 2009 | let syntax = ast.syntax().owned(); |
2010 | ParenTypeNode(syntax) | 2010 | ParenTypeNode(syntax) |
2011 | } | 2011 | } |
@@ -2036,7 +2036,7 @@ impl<'a> ParenType<'a> {} | |||
2036 | pub struct PatNode(SyntaxNode); | 2036 | pub struct PatNode(SyntaxNode); |
2037 | 2037 | ||
2038 | impl PatNode { | 2038 | impl PatNode { |
2039 | pub fn new(&self, ast: Pat) -> PatNode { | 2039 | pub fn new(ast: Pat) -> PatNode { |
2040 | let syntax = ast.syntax().owned(); | 2040 | let syntax = ast.syntax().owned(); |
2041 | PatNode(syntax) | 2041 | PatNode(syntax) |
2042 | } | 2042 | } |
@@ -2098,7 +2098,7 @@ impl<'a> Pat<'a> {} | |||
2098 | pub struct PathNode(SyntaxNode); | 2098 | pub struct PathNode(SyntaxNode); |
2099 | 2099 | ||
2100 | impl PathNode { | 2100 | impl PathNode { |
2101 | pub fn new(&self, ast: Path) -> PathNode { | 2101 | pub fn new(ast: Path) -> PathNode { |
2102 | let syntax = ast.syntax().owned(); | 2102 | let syntax = ast.syntax().owned(); |
2103 | PathNode(syntax) | 2103 | PathNode(syntax) |
2104 | } | 2104 | } |
@@ -2137,7 +2137,7 @@ impl<'a> Path<'a> { | |||
2137 | pub struct PathExprNode(SyntaxNode); | 2137 | pub struct PathExprNode(SyntaxNode); |
2138 | 2138 | ||
2139 | impl PathExprNode { | 2139 | impl PathExprNode { |
2140 | pub fn new(&self, ast: PathExpr) -> PathExprNode { | 2140 | pub fn new(ast: PathExpr) -> PathExprNode { |
2141 | let syntax = ast.syntax().owned(); | 2141 | let syntax = ast.syntax().owned(); |
2142 | PathExprNode(syntax) | 2142 | PathExprNode(syntax) |
2143 | } | 2143 | } |
@@ -2172,7 +2172,7 @@ impl<'a> PathExpr<'a> { | |||
2172 | pub struct PathPatNode(SyntaxNode); | 2172 | pub struct PathPatNode(SyntaxNode); |
2173 | 2173 | ||
2174 | impl PathPatNode { | 2174 | impl PathPatNode { |
2175 | pub fn new(&self, ast: PathPat) -> PathPatNode { | 2175 | pub fn new(ast: PathPat) -> PathPatNode { |
2176 | let syntax = ast.syntax().owned(); | 2176 | let syntax = ast.syntax().owned(); |
2177 | PathPatNode(syntax) | 2177 | PathPatNode(syntax) |
2178 | } | 2178 | } |
@@ -2203,7 +2203,7 @@ impl<'a> PathPat<'a> {} | |||
2203 | pub struct PathSegmentNode(SyntaxNode); | 2203 | pub struct PathSegmentNode(SyntaxNode); |
2204 | 2204 | ||
2205 | impl PathSegmentNode { | 2205 | impl PathSegmentNode { |
2206 | pub fn new(&self, ast: PathSegment) -> PathSegmentNode { | 2206 | pub fn new(ast: PathSegment) -> PathSegmentNode { |
2207 | let syntax = ast.syntax().owned(); | 2207 | let syntax = ast.syntax().owned(); |
2208 | PathSegmentNode(syntax) | 2208 | PathSegmentNode(syntax) |
2209 | } | 2209 | } |
@@ -2238,7 +2238,7 @@ impl<'a> PathSegment<'a> { | |||
2238 | pub struct PathTypeNode(SyntaxNode); | 2238 | pub struct PathTypeNode(SyntaxNode); |
2239 | 2239 | ||
2240 | impl PathTypeNode { | 2240 | impl PathTypeNode { |
2241 | pub fn new(&self, ast: PathType) -> PathTypeNode { | 2241 | pub fn new(ast: PathType) -> PathTypeNode { |
2242 | let syntax = ast.syntax().owned(); | 2242 | let syntax = ast.syntax().owned(); |
2243 | PathTypeNode(syntax) | 2243 | PathTypeNode(syntax) |
2244 | } | 2244 | } |
@@ -2269,7 +2269,7 @@ impl<'a> PathType<'a> {} | |||
2269 | pub struct PlaceholderPatNode(SyntaxNode); | 2269 | pub struct PlaceholderPatNode(SyntaxNode); |
2270 | 2270 | ||
2271 | impl PlaceholderPatNode { | 2271 | impl PlaceholderPatNode { |
2272 | pub fn new(&self, ast: PlaceholderPat) -> PlaceholderPatNode { | 2272 | pub fn new(ast: PlaceholderPat) -> PlaceholderPatNode { |
2273 | let syntax = ast.syntax().owned(); | 2273 | let syntax = ast.syntax().owned(); |
2274 | PlaceholderPatNode(syntax) | 2274 | PlaceholderPatNode(syntax) |
2275 | } | 2275 | } |
@@ -2300,7 +2300,7 @@ impl<'a> PlaceholderPat<'a> {} | |||
2300 | pub struct PlaceholderTypeNode(SyntaxNode); | 2300 | pub struct PlaceholderTypeNode(SyntaxNode); |
2301 | 2301 | ||
2302 | impl PlaceholderTypeNode { | 2302 | impl PlaceholderTypeNode { |
2303 | pub fn new(&self, ast: PlaceholderType) -> PlaceholderTypeNode { | 2303 | pub fn new(ast: PlaceholderType) -> PlaceholderTypeNode { |
2304 | let syntax = ast.syntax().owned(); | 2304 | let syntax = ast.syntax().owned(); |
2305 | PlaceholderTypeNode(syntax) | 2305 | PlaceholderTypeNode(syntax) |
2306 | } | 2306 | } |
@@ -2331,7 +2331,7 @@ impl<'a> PlaceholderType<'a> {} | |||
2331 | pub struct PointerTypeNode(SyntaxNode); | 2331 | pub struct PointerTypeNode(SyntaxNode); |
2332 | 2332 | ||
2333 | impl PointerTypeNode { | 2333 | impl PointerTypeNode { |
2334 | pub fn new(&self, ast: PointerType) -> PointerTypeNode { | 2334 | pub fn new(ast: PointerType) -> PointerTypeNode { |
2335 | let syntax = ast.syntax().owned(); | 2335 | let syntax = ast.syntax().owned(); |
2336 | PointerTypeNode(syntax) | 2336 | PointerTypeNode(syntax) |
2337 | } | 2337 | } |
@@ -2362,7 +2362,7 @@ impl<'a> PointerType<'a> {} | |||
2362 | pub struct PrefixExprNode(SyntaxNode); | 2362 | pub struct PrefixExprNode(SyntaxNode); |
2363 | 2363 | ||
2364 | impl PrefixExprNode { | 2364 | impl PrefixExprNode { |
2365 | pub fn new(&self, ast: PrefixExpr) -> PrefixExprNode { | 2365 | pub fn new(ast: PrefixExpr) -> PrefixExprNode { |
2366 | let syntax = ast.syntax().owned(); | 2366 | let syntax = ast.syntax().owned(); |
2367 | PrefixExprNode(syntax) | 2367 | PrefixExprNode(syntax) |
2368 | } | 2368 | } |
@@ -2393,7 +2393,7 @@ impl<'a> PrefixExpr<'a> {} | |||
2393 | pub struct RangeExprNode(SyntaxNode); | 2393 | pub struct RangeExprNode(SyntaxNode); |
2394 | 2394 | ||
2395 | impl RangeExprNode { | 2395 | impl RangeExprNode { |
2396 | pub fn new(&self, ast: RangeExpr) -> RangeExprNode { | 2396 | pub fn new(ast: RangeExpr) -> RangeExprNode { |
2397 | let syntax = ast.syntax().owned(); | 2397 | let syntax = ast.syntax().owned(); |
2398 | RangeExprNode(syntax) | 2398 | RangeExprNode(syntax) |
2399 | } | 2399 | } |
@@ -2424,7 +2424,7 @@ impl<'a> RangeExpr<'a> {} | |||
2424 | pub struct RangePatNode(SyntaxNode); | 2424 | pub struct RangePatNode(SyntaxNode); |
2425 | 2425 | ||
2426 | impl RangePatNode { | 2426 | impl RangePatNode { |
2427 | pub fn new(&self, ast: RangePat) -> RangePatNode { | 2427 | pub fn new(ast: RangePat) -> RangePatNode { |
2428 | let syntax = ast.syntax().owned(); | 2428 | let syntax = ast.syntax().owned(); |
2429 | RangePatNode(syntax) | 2429 | RangePatNode(syntax) |
2430 | } | 2430 | } |
@@ -2455,7 +2455,7 @@ impl<'a> RangePat<'a> {} | |||
2455 | pub struct RefExprNode(SyntaxNode); | 2455 | pub struct RefExprNode(SyntaxNode); |
2456 | 2456 | ||
2457 | impl RefExprNode { | 2457 | impl RefExprNode { |
2458 | pub fn new(&self, ast: RefExpr) -> RefExprNode { | 2458 | pub fn new(ast: RefExpr) -> RefExprNode { |
2459 | let syntax = ast.syntax().owned(); | 2459 | let syntax = ast.syntax().owned(); |
2460 | RefExprNode(syntax) | 2460 | RefExprNode(syntax) |
2461 | } | 2461 | } |
@@ -2486,7 +2486,7 @@ impl<'a> RefExpr<'a> {} | |||
2486 | pub struct RefPatNode(SyntaxNode); | 2486 | pub struct RefPatNode(SyntaxNode); |
2487 | 2487 | ||
2488 | impl RefPatNode { | 2488 | impl RefPatNode { |
2489 | pub fn new(&self, ast: RefPat) -> RefPatNode { | 2489 | pub fn new(ast: RefPat) -> RefPatNode { |
2490 | let syntax = ast.syntax().owned(); | 2490 | let syntax = ast.syntax().owned(); |
2491 | RefPatNode(syntax) | 2491 | RefPatNode(syntax) |
2492 | } | 2492 | } |
@@ -2517,7 +2517,7 @@ impl<'a> RefPat<'a> {} | |||
2517 | pub struct ReferenceTypeNode(SyntaxNode); | 2517 | pub struct ReferenceTypeNode(SyntaxNode); |
2518 | 2518 | ||
2519 | impl ReferenceTypeNode { | 2519 | impl ReferenceTypeNode { |
2520 | pub fn new(&self, ast: ReferenceType) -> ReferenceTypeNode { | 2520 | pub fn new(ast: ReferenceType) -> ReferenceTypeNode { |
2521 | let syntax = ast.syntax().owned(); | 2521 | let syntax = ast.syntax().owned(); |
2522 | ReferenceTypeNode(syntax) | 2522 | ReferenceTypeNode(syntax) |
2523 | } | 2523 | } |
@@ -2548,7 +2548,7 @@ impl<'a> ReferenceType<'a> {} | |||
2548 | pub struct RetTypeNode(SyntaxNode); | 2548 | pub struct RetTypeNode(SyntaxNode); |
2549 | 2549 | ||
2550 | impl RetTypeNode { | 2550 | impl RetTypeNode { |
2551 | pub fn new(&self, ast: RetType) -> RetTypeNode { | 2551 | pub fn new(ast: RetType) -> RetTypeNode { |
2552 | let syntax = ast.syntax().owned(); | 2552 | let syntax = ast.syntax().owned(); |
2553 | RetTypeNode(syntax) | 2553 | RetTypeNode(syntax) |
2554 | } | 2554 | } |
@@ -2579,7 +2579,7 @@ impl<'a> RetType<'a> {} | |||
2579 | pub struct ReturnExprNode(SyntaxNode); | 2579 | pub struct ReturnExprNode(SyntaxNode); |
2580 | 2580 | ||
2581 | impl ReturnExprNode { | 2581 | impl ReturnExprNode { |
2582 | pub fn new(&self, ast: ReturnExpr) -> ReturnExprNode { | 2582 | pub fn new(ast: ReturnExpr) -> ReturnExprNode { |
2583 | let syntax = ast.syntax().owned(); | 2583 | let syntax = ast.syntax().owned(); |
2584 | ReturnExprNode(syntax) | 2584 | ReturnExprNode(syntax) |
2585 | } | 2585 | } |
@@ -2610,7 +2610,7 @@ impl<'a> ReturnExpr<'a> {} | |||
2610 | pub struct RootNode(SyntaxNode); | 2610 | pub struct RootNode(SyntaxNode); |
2611 | 2611 | ||
2612 | impl RootNode { | 2612 | impl RootNode { |
2613 | pub fn new(&self, ast: Root) -> RootNode { | 2613 | pub fn new(ast: Root) -> RootNode { |
2614 | let syntax = ast.syntax().owned(); | 2614 | let syntax = ast.syntax().owned(); |
2615 | RootNode(syntax) | 2615 | RootNode(syntax) |
2616 | } | 2616 | } |
@@ -2647,7 +2647,7 @@ impl<'a> Root<'a> { | |||
2647 | pub struct SelfParamNode(SyntaxNode); | 2647 | pub struct SelfParamNode(SyntaxNode); |
2648 | 2648 | ||
2649 | impl SelfParamNode { | 2649 | impl SelfParamNode { |
2650 | pub fn new(&self, ast: SelfParam) -> SelfParamNode { | 2650 | pub fn new(ast: SelfParam) -> SelfParamNode { |
2651 | let syntax = ast.syntax().owned(); | 2651 | let syntax = ast.syntax().owned(); |
2652 | SelfParamNode(syntax) | 2652 | SelfParamNode(syntax) |
2653 | } | 2653 | } |
@@ -2678,7 +2678,7 @@ impl<'a> SelfParam<'a> {} | |||
2678 | pub struct SlicePatNode(SyntaxNode); | 2678 | pub struct SlicePatNode(SyntaxNode); |
2679 | 2679 | ||
2680 | impl SlicePatNode { | 2680 | impl SlicePatNode { |
2681 | pub fn new(&self, ast: SlicePat) -> SlicePatNode { | 2681 | pub fn new(ast: SlicePat) -> SlicePatNode { |
2682 | let syntax = ast.syntax().owned(); | 2682 | let syntax = ast.syntax().owned(); |
2683 | SlicePatNode(syntax) | 2683 | SlicePatNode(syntax) |
2684 | } | 2684 | } |
@@ -2709,7 +2709,7 @@ impl<'a> SlicePat<'a> {} | |||
2709 | pub struct SliceTypeNode(SyntaxNode); | 2709 | pub struct SliceTypeNode(SyntaxNode); |
2710 | 2710 | ||
2711 | impl SliceTypeNode { | 2711 | impl SliceTypeNode { |
2712 | pub fn new(&self, ast: SliceType) -> SliceTypeNode { | 2712 | pub fn new(ast: SliceType) -> SliceTypeNode { |
2713 | let syntax = ast.syntax().owned(); | 2713 | let syntax = ast.syntax().owned(); |
2714 | SliceTypeNode(syntax) | 2714 | SliceTypeNode(syntax) |
2715 | } | 2715 | } |
@@ -2740,7 +2740,7 @@ impl<'a> SliceType<'a> {} | |||
2740 | pub struct StaticDefNode(SyntaxNode); | 2740 | pub struct StaticDefNode(SyntaxNode); |
2741 | 2741 | ||
2742 | impl StaticDefNode { | 2742 | impl StaticDefNode { |
2743 | pub fn new(&self, ast: StaticDef) -> StaticDefNode { | 2743 | pub fn new(ast: StaticDef) -> StaticDefNode { |
2744 | let syntax = ast.syntax().owned(); | 2744 | let syntax = ast.syntax().owned(); |
2745 | StaticDefNode(syntax) | 2745 | StaticDefNode(syntax) |
2746 | } | 2746 | } |
@@ -2774,7 +2774,7 @@ impl<'a> StaticDef<'a> {} | |||
2774 | pub struct StmtNode(SyntaxNode); | 2774 | pub struct StmtNode(SyntaxNode); |
2775 | 2775 | ||
2776 | impl StmtNode { | 2776 | impl StmtNode { |
2777 | pub fn new(&self, ast: Stmt) -> StmtNode { | 2777 | pub fn new(ast: Stmt) -> StmtNode { |
2778 | let syntax = ast.syntax().owned(); | 2778 | let syntax = ast.syntax().owned(); |
2779 | StmtNode(syntax) | 2779 | StmtNode(syntax) |
2780 | } | 2780 | } |
@@ -2812,7 +2812,7 @@ impl<'a> Stmt<'a> {} | |||
2812 | pub struct StructDefNode(SyntaxNode); | 2812 | pub struct StructDefNode(SyntaxNode); |
2813 | 2813 | ||
2814 | impl StructDefNode { | 2814 | impl StructDefNode { |
2815 | pub fn new(&self, ast: StructDef) -> StructDefNode { | 2815 | pub fn new(ast: StructDef) -> StructDefNode { |
2816 | let syntax = ast.syntax().owned(); | 2816 | let syntax = ast.syntax().owned(); |
2817 | StructDefNode(syntax) | 2817 | StructDefNode(syntax) |
2818 | } | 2818 | } |
@@ -2850,7 +2850,7 @@ impl<'a> StructDef<'a> { | |||
2850 | pub struct StructLitNode(SyntaxNode); | 2850 | pub struct StructLitNode(SyntaxNode); |
2851 | 2851 | ||
2852 | impl StructLitNode { | 2852 | impl StructLitNode { |
2853 | pub fn new(&self, ast: StructLit) -> StructLitNode { | 2853 | pub fn new(ast: StructLit) -> StructLitNode { |
2854 | let syntax = ast.syntax().owned(); | 2854 | let syntax = ast.syntax().owned(); |
2855 | StructLitNode(syntax) | 2855 | StructLitNode(syntax) |
2856 | } | 2856 | } |
@@ -2881,7 +2881,7 @@ impl<'a> StructLit<'a> {} | |||
2881 | pub struct StructPatNode(SyntaxNode); | 2881 | pub struct StructPatNode(SyntaxNode); |
2882 | 2882 | ||
2883 | impl StructPatNode { | 2883 | impl StructPatNode { |
2884 | pub fn new(&self, ast: StructPat) -> StructPatNode { | 2884 | pub fn new(ast: StructPat) -> StructPatNode { |
2885 | let syntax = ast.syntax().owned(); | 2885 | let syntax = ast.syntax().owned(); |
2886 | StructPatNode(syntax) | 2886 | StructPatNode(syntax) |
2887 | } | 2887 | } |
@@ -2912,7 +2912,7 @@ impl<'a> StructPat<'a> {} | |||
2912 | pub struct TokenTreeNode(SyntaxNode); | 2912 | pub struct TokenTreeNode(SyntaxNode); |
2913 | 2913 | ||
2914 | impl TokenTreeNode { | 2914 | impl TokenTreeNode { |
2915 | pub fn new(&self, ast: TokenTree) -> TokenTreeNode { | 2915 | pub fn new(ast: TokenTree) -> TokenTreeNode { |
2916 | let syntax = ast.syntax().owned(); | 2916 | let syntax = ast.syntax().owned(); |
2917 | TokenTreeNode(syntax) | 2917 | TokenTreeNode(syntax) |
2918 | } | 2918 | } |
@@ -2943,7 +2943,7 @@ impl<'a> TokenTree<'a> {} | |||
2943 | pub struct TraitDefNode(SyntaxNode); | 2943 | pub struct TraitDefNode(SyntaxNode); |
2944 | 2944 | ||
2945 | impl TraitDefNode { | 2945 | impl TraitDefNode { |
2946 | pub fn new(&self, ast: TraitDef) -> TraitDefNode { | 2946 | pub fn new(ast: TraitDef) -> TraitDefNode { |
2947 | let syntax = ast.syntax().owned(); | 2947 | let syntax = ast.syntax().owned(); |
2948 | TraitDefNode(syntax) | 2948 | TraitDefNode(syntax) |
2949 | } | 2949 | } |
@@ -2976,7 +2976,7 @@ impl<'a> TraitDef<'a> {} | |||
2976 | pub struct TryExprNode(SyntaxNode); | 2976 | pub struct TryExprNode(SyntaxNode); |
2977 | 2977 | ||
2978 | impl TryExprNode { | 2978 | impl TryExprNode { |
2979 | pub fn new(&self, ast: TryExpr) -> TryExprNode { | 2979 | pub fn new(ast: TryExpr) -> TryExprNode { |
2980 | let syntax = ast.syntax().owned(); | 2980 | let syntax = ast.syntax().owned(); |
2981 | TryExprNode(syntax) | 2981 | TryExprNode(syntax) |
2982 | } | 2982 | } |
@@ -3007,7 +3007,7 @@ impl<'a> TryExpr<'a> {} | |||
3007 | pub struct TupleExprNode(SyntaxNode); | 3007 | pub struct TupleExprNode(SyntaxNode); |
3008 | 3008 | ||
3009 | impl TupleExprNode { | 3009 | impl TupleExprNode { |
3010 | pub fn new(&self, ast: TupleExpr) -> TupleExprNode { | 3010 | pub fn new(ast: TupleExpr) -> TupleExprNode { |
3011 | let syntax = ast.syntax().owned(); | 3011 | let syntax = ast.syntax().owned(); |
3012 | TupleExprNode(syntax) | 3012 | TupleExprNode(syntax) |
3013 | } | 3013 | } |
@@ -3038,7 +3038,7 @@ impl<'a> TupleExpr<'a> {} | |||
3038 | pub struct TuplePatNode(SyntaxNode); | 3038 | pub struct TuplePatNode(SyntaxNode); |
3039 | 3039 | ||
3040 | impl TuplePatNode { | 3040 | impl TuplePatNode { |
3041 | pub fn new(&self, ast: TuplePat) -> TuplePatNode { | 3041 | pub fn new(ast: TuplePat) -> TuplePatNode { |
3042 | let syntax = ast.syntax().owned(); | 3042 | let syntax = ast.syntax().owned(); |
3043 | TuplePatNode(syntax) | 3043 | TuplePatNode(syntax) |
3044 | } | 3044 | } |
@@ -3069,7 +3069,7 @@ impl<'a> TuplePat<'a> {} | |||
3069 | pub struct TupleStructPatNode(SyntaxNode); | 3069 | pub struct TupleStructPatNode(SyntaxNode); |
3070 | 3070 | ||
3071 | impl TupleStructPatNode { | 3071 | impl TupleStructPatNode { |
3072 | pub fn new(&self, ast: TupleStructPat) -> TupleStructPatNode { | 3072 | pub fn new(ast: TupleStructPat) -> TupleStructPatNode { |
3073 | let syntax = ast.syntax().owned(); | 3073 | let syntax = ast.syntax().owned(); |
3074 | TupleStructPatNode(syntax) | 3074 | TupleStructPatNode(syntax) |
3075 | } | 3075 | } |
@@ -3100,7 +3100,7 @@ impl<'a> TupleStructPat<'a> {} | |||
3100 | pub struct TupleTypeNode(SyntaxNode); | 3100 | pub struct TupleTypeNode(SyntaxNode); |
3101 | 3101 | ||
3102 | impl TupleTypeNode { | 3102 | impl TupleTypeNode { |
3103 | pub fn new(&self, ast: TupleType) -> TupleTypeNode { | 3103 | pub fn new(ast: TupleType) -> TupleTypeNode { |
3104 | let syntax = ast.syntax().owned(); | 3104 | let syntax = ast.syntax().owned(); |
3105 | TupleTypeNode(syntax) | 3105 | TupleTypeNode(syntax) |
3106 | } | 3106 | } |
@@ -3131,7 +3131,7 @@ impl<'a> TupleType<'a> {} | |||
3131 | pub struct TypeDefNode(SyntaxNode); | 3131 | pub struct TypeDefNode(SyntaxNode); |
3132 | 3132 | ||
3133 | impl TypeDefNode { | 3133 | impl TypeDefNode { |
3134 | pub fn new(&self, ast: TypeDef) -> TypeDefNode { | 3134 | pub fn new(ast: TypeDef) -> TypeDefNode { |
3135 | let syntax = ast.syntax().owned(); | 3135 | let syntax = ast.syntax().owned(); |
3136 | TypeDefNode(syntax) | 3136 | TypeDefNode(syntax) |
3137 | } | 3137 | } |
@@ -3165,7 +3165,7 @@ impl<'a> TypeDef<'a> {} | |||
3165 | pub struct TypeParamNode(SyntaxNode); | 3165 | pub struct TypeParamNode(SyntaxNode); |
3166 | 3166 | ||
3167 | impl TypeParamNode { | 3167 | impl TypeParamNode { |
3168 | pub fn new(&self, ast: TypeParam) -> TypeParamNode { | 3168 | pub fn new(ast: TypeParam) -> TypeParamNode { |
3169 | let syntax = ast.syntax().owned(); | 3169 | let syntax = ast.syntax().owned(); |
3170 | TypeParamNode(syntax) | 3170 | TypeParamNode(syntax) |
3171 | } | 3171 | } |
@@ -3197,7 +3197,7 @@ impl<'a> TypeParam<'a> {} | |||
3197 | pub struct TypeParamListNode(SyntaxNode); | 3197 | pub struct TypeParamListNode(SyntaxNode); |
3198 | 3198 | ||
3199 | impl TypeParamListNode { | 3199 | impl TypeParamListNode { |
3200 | pub fn new(&self, ast: TypeParamList) -> TypeParamListNode { | 3200 | pub fn new(ast: TypeParamList) -> TypeParamListNode { |
3201 | let syntax = ast.syntax().owned(); | 3201 | let syntax = ast.syntax().owned(); |
3202 | TypeParamListNode(syntax) | 3202 | TypeParamListNode(syntax) |
3203 | } | 3203 | } |
@@ -3236,7 +3236,7 @@ impl<'a> TypeParamList<'a> { | |||
3236 | pub struct TypeRefNode(SyntaxNode); | 3236 | pub struct TypeRefNode(SyntaxNode); |
3237 | 3237 | ||
3238 | impl TypeRefNode { | 3238 | impl TypeRefNode { |
3239 | pub fn new(&self, ast: TypeRef) -> TypeRefNode { | 3239 | pub fn new(ast: TypeRef) -> TypeRefNode { |
3240 | let syntax = ast.syntax().owned(); | 3240 | let syntax = ast.syntax().owned(); |
3241 | TypeRefNode(syntax) | 3241 | TypeRefNode(syntax) |
3242 | } | 3242 | } |
@@ -3307,7 +3307,7 @@ impl<'a> TypeRef<'a> {} | |||
3307 | pub struct UseItemNode(SyntaxNode); | 3307 | pub struct UseItemNode(SyntaxNode); |
3308 | 3308 | ||
3309 | impl UseItemNode { | 3309 | impl UseItemNode { |
3310 | pub fn new(&self, ast: UseItem) -> UseItemNode { | 3310 | pub fn new(ast: UseItem) -> UseItemNode { |
3311 | let syntax = ast.syntax().owned(); | 3311 | let syntax = ast.syntax().owned(); |
3312 | UseItemNode(syntax) | 3312 | UseItemNode(syntax) |
3313 | } | 3313 | } |
@@ -3342,7 +3342,7 @@ impl<'a> UseItem<'a> { | |||
3342 | pub struct UseTreeNode(SyntaxNode); | 3342 | pub struct UseTreeNode(SyntaxNode); |
3343 | 3343 | ||
3344 | impl UseTreeNode { | 3344 | impl UseTreeNode { |
3345 | pub fn new(&self, ast: UseTree) -> UseTreeNode { | 3345 | pub fn new(ast: UseTree) -> UseTreeNode { |
3346 | let syntax = ast.syntax().owned(); | 3346 | let syntax = ast.syntax().owned(); |
3347 | UseTreeNode(syntax) | 3347 | UseTreeNode(syntax) |
3348 | } | 3348 | } |
@@ -3381,7 +3381,7 @@ impl<'a> UseTree<'a> { | |||
3381 | pub struct UseTreeListNode(SyntaxNode); | 3381 | pub struct UseTreeListNode(SyntaxNode); |
3382 | 3382 | ||
3383 | impl UseTreeListNode { | 3383 | impl UseTreeListNode { |
3384 | pub fn new(&self, ast: UseTreeList) -> UseTreeListNode { | 3384 | pub fn new(ast: UseTreeList) -> UseTreeListNode { |
3385 | let syntax = ast.syntax().owned(); | 3385 | let syntax = ast.syntax().owned(); |
3386 | UseTreeListNode(syntax) | 3386 | UseTreeListNode(syntax) |
3387 | } | 3387 | } |
@@ -3416,7 +3416,7 @@ impl<'a> UseTreeList<'a> { | |||
3416 | pub struct WhereClauseNode(SyntaxNode); | 3416 | pub struct WhereClauseNode(SyntaxNode); |
3417 | 3417 | ||
3418 | impl WhereClauseNode { | 3418 | impl WhereClauseNode { |
3419 | pub fn new(&self, ast: WhereClause) -> WhereClauseNode { | 3419 | pub fn new(ast: WhereClause) -> WhereClauseNode { |
3420 | let syntax = ast.syntax().owned(); | 3420 | let syntax = ast.syntax().owned(); |
3421 | WhereClauseNode(syntax) | 3421 | WhereClauseNode(syntax) |
3422 | } | 3422 | } |
@@ -3447,7 +3447,7 @@ impl<'a> WhereClause<'a> {} | |||
3447 | pub struct WhileExprNode(SyntaxNode); | 3447 | pub struct WhileExprNode(SyntaxNode); |
3448 | 3448 | ||
3449 | impl WhileExprNode { | 3449 | impl WhileExprNode { |
3450 | pub fn new(&self, ast: WhileExpr) -> WhileExprNode { | 3450 | pub fn new(ast: WhileExpr) -> WhileExprNode { |
3451 | let syntax = ast.syntax().owned(); | 3451 | let syntax = ast.syntax().owned(); |
3452 | WhileExprNode(syntax) | 3452 | WhileExprNode(syntax) |
3453 | } | 3453 | } |
@@ -3483,7 +3483,7 @@ impl<'a> WhileExpr<'a> { | |||
3483 | pub struct WhitespaceNode(SyntaxNode); | 3483 | pub struct WhitespaceNode(SyntaxNode); |
3484 | 3484 | ||
3485 | impl WhitespaceNode { | 3485 | impl WhitespaceNode { |
3486 | pub fn new(&self, ast: Whitespace) -> WhitespaceNode { | 3486 | pub fn new(ast: Whitespace) -> WhitespaceNode { |
3487 | let syntax = ast.syntax().owned(); | 3487 | let syntax = ast.syntax().owned(); |
3488 | WhitespaceNode(syntax) | 3488 | WhitespaceNode(syntax) |
3489 | } | 3489 | } |
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera index c61c3e80b..d30038cba 100644 --- a/crates/ra_syntax/src/ast/generated.rs.tera +++ b/crates/ra_syntax/src/ast/generated.rs.tera | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | pub struct {{ node }}Node(SyntaxNode); | 17 | pub struct {{ node }}Node(SyntaxNode); |
18 | 18 | ||
19 | impl {{ node }}Node { | 19 | impl {{ node }}Node { |
20 | pub fn new(&self, ast: {{ node }}) -> {{ node }}Node { | 20 | pub fn new(ast: {{ node }}) -> {{ node }}Node { |
21 | let syntax = ast.syntax().owned(); | 21 | let syntax = ast.syntax().owned(); |
22 | {{ node }}Node(syntax) | 22 | {{ node }}Node(syntax) |
23 | } | 23 | } |