From 4798a89a12f40af17174a160f6d6a2f1c53db8d6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 3 Sep 2018 15:10:06 +0300 Subject: Complete params --- crates/libeditor/src/completion.rs | 222 ++++++++++++------- crates/libsyntax2/src/ast/generated.rs | 33 ++- crates/libsyntax2/src/ast/mod.rs | 6 + crates/libsyntax2/src/grammar.ron | 11 +- crates/libsyntax2/src/grammar/patterns.rs | 2 +- crates/libsyntax2/src/grammar/types.rs | 5 +- .../tests/data/parser/err/0018_incomplete_fn.txt | 245 +++++++++------------ .../tests/data/parser/err/0021_incomplete_param.rs | 2 + .../data/parser/err/0021_incomplete_param.txt | 34 +++ crates/server/src/main_loop/handlers.rs | 3 +- 10 files changed, 326 insertions(+), 237 deletions(-) create mode 100644 crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.rs create mode 100644 crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.txt diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs index b296f6fd5..6c3775127 100644 --- a/crates/libeditor/src/completion.rs +++ b/crates/libeditor/src/completion.rs @@ -1,11 +1,11 @@ -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use libsyntax2::{ - File, TextUnit, AstNode, SyntaxKind::*, + File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, ast::{self, LoopBodyOwner}, algo::{ ancestors, - visit::{visitor, Visitor}, + visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, }, text_utils::is_subrange, }; @@ -17,7 +17,11 @@ use { #[derive(Debug)] pub struct CompletionItem { - pub name: String, + /// What user sees in pop-up + pub label: String, + /// What string is used for filtering, defaults to label + pub lookup: Option, + /// What is inserted, defaults to label pub snippet: Option } @@ -27,40 +31,89 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option(file.syntax(), offset)?; - if !is_single_segment(name_ref) { - return None; + let mut has_completions = false; + let mut res = Vec::new(); + if let Some(name_ref) = find_node_at_offset::(file.syntax(), offset) { + has_completions = true; + complete_name_ref(&file, name_ref, &mut res) + } + if let Some(name) = find_node_at_offset::(file.syntax(), offset) { + has_completions = true; + complete_name(&file, name, &mut res) + } + if has_completions { + Some(res) + } else { + None } +} - let mut res = Vec::new(); +fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec) { + if !is_node::(name_ref.syntax()) { + return; + } if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() { - complete_expr_keywords(&file, fn_def, name_ref, &mut res); + complete_expr_keywords(&file, fn_def, name_ref, acc); let scopes = FnScopes::new(fn_def); - complete_fn(name_ref, &scopes, &mut res); + complete_fn(name_ref, &scopes, acc); } if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() { let scope = ModuleScope::new(root); - res.extend( + acc.extend( scope.entries().iter() .filter(|entry| entry.syntax() != name_ref.syntax()) .map(|entry| CompletionItem { - name: entry.name().to_string(), + label: entry.name().to_string(), + lookup: None, snippet: None, }) ); } - Some(res) } -fn is_single_segment(name_ref: ast::NameRef) -> bool { - match ancestors(name_ref.syntax()).filter_map(ast::Path::cast).next() { +fn complete_name(_file: &File, name: ast::Name, acc: &mut Vec) { + if !is_node::(name.syntax()) { + return; + } + + let mut params = HashMap::new(); + for node in ancestors(name.syntax()) { + let _ = visitor_ctx(&mut params) + .visit::(process) + .accept(node); + } + params.into_iter() + .filter_map(|(label, (count, param))| { + let lookup = param.pat()?.syntax().text().to_string(); + if count < 2 { None } else { Some((label, lookup)) } + }) + .for_each(|(label, lookup)| { + acc.push(CompletionItem { + label, lookup: Some(lookup), snippet: None + }) + }); + + fn process<'a, N: ast::FnDefOwner<'a>>(node: N, params: &mut HashMap)>) { + node.functions() + .filter_map(|it| it.param_list()) + .flat_map(|it| it.params()) + .for_each(|param| { + let text = param.syntax().text().to_string(); + params.entry(text) + .or_insert((0, param)) + .0 += 1; + }) + } +} + +fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { + match ancestors(node).filter_map(N::cast).next() { None => false, - Some(path) => { - path.syntax().range() == name_ref.syntax().range() - } + Some(n) => n.syntax().range() == node.range(), } } + fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRef, acc: &mut Vec) { acc.push(keyword("if", "if $0 {}")); acc.push(keyword("match", "match $0 {}")); @@ -127,7 +180,8 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option CompletionItem { CompletionItem { - name: kw.to_string(), + label: kw.to_string(), + lookup: None, snippet: Some(snip.to_string()), } } @@ -139,13 +193,15 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec; let z = (); } - ", r#"[CompletionItem { name: "y", snippet: None }, - CompletionItem { name: "x", snippet: None }, - CompletionItem { name: "quux", snippet: None }]"#); + ", r#"[CompletionItem { label: "y", lookup: None, snippet: None }, + CompletionItem { label: "x", lookup: None, snippet: None }, + CompletionItem { label: "quux", lookup: None, snippet: None }]"#); } #[test] @@ -203,9 +259,9 @@ mod tests { 1 + <|> } } - ", r#"[CompletionItem { name: "b", snippet: None }, - CompletionItem { name: "a", snippet: None }, - CompletionItem { name: "quux", snippet: None }]"#); + ", r#"[CompletionItem { label: "b", lookup: None, snippet: None }, + CompletionItem { label: "a", lookup: None, snippet: None }, + CompletionItem { label: "quux", lookup: None, snippet: None }]"#); } #[test] @@ -216,8 +272,8 @@ mod tests { <|> } } - ", r#"[CompletionItem { name: "x", snippet: None }, - CompletionItem { name: "quux", snippet: None }]"#); + ", r#"[CompletionItem { label: "x", lookup: None, snippet: None }, + CompletionItem { label: "quux", lookup: None, snippet: None }]"#); } #[test] @@ -228,9 +284,9 @@ mod tests { fn quux() { <|> } - ", r#"[CompletionItem { name: "Foo", snippet: None }, - CompletionItem { name: "Baz", snippet: None }, - CompletionItem { name: "quux", snippet: None }]"#); + ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, + CompletionItem { label: "Baz", lookup: None, snippet: None }, + CompletionItem { label: "quux", lookup: None, snippet: None }]"#); } #[test] @@ -245,8 +301,8 @@ mod tests { check_scope_completion(r" struct Foo; fn x() -> <|> - ", r#"[CompletionItem { name: "Foo", snippet: None }, - CompletionItem { name: "x", snippet: None }]"#) + ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, + CompletionItem { label: "x", lookup: None, snippet: None }]"#) } #[test] @@ -259,15 +315,15 @@ mod tests { <|> } } - ", r#"[CompletionItem { name: "bar", snippet: None }, - CompletionItem { name: "foo", snippet: None }]"#) + ", r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, + CompletionItem { label: "foo", lookup: None, snippet: None }]"#) } #[test] fn test_complete_self() { check_scope_completion(r" impl S { fn foo(&self) { <|> } } - ", r#"[CompletionItem { name: "self", snippet: None }]"#) + ", r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#) } #[test] @@ -276,11 +332,11 @@ mod tests { fn quux() { <|> } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "return", snippet: Some("return") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return") }]"#); } #[test] @@ -291,13 +347,13 @@ mod tests { () } <|> } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "else", snippet: Some("else {$0}") }, - CompletionItem { name: "else if", snippet: Some("else if $0 {}") }, - CompletionItem { name: "return", snippet: Some("return") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "else", lookup: None, snippet: Some("else {$0}") }, + CompletionItem { label: "else if", lookup: None, snippet: Some("else if $0 {}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return") }]"#); } #[test] @@ -307,21 +363,21 @@ mod tests { <|> 92 } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "return", snippet: Some("return $0;") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return $0;") }]"#); check_snippet_completion(r" fn quux() { <|> 92 } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "return", snippet: Some("return;") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return;") }]"#); } #[test] @@ -332,11 +388,11 @@ mod tests { () => <|> } } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "return", snippet: Some("return $0") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }]"#); } #[test] @@ -345,21 +401,35 @@ mod tests { fn quux() -> i32 { loop { <|> } } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "continue", snippet: Some("continue") }, - CompletionItem { name: "break", snippet: Some("break") }, - CompletionItem { name: "return", snippet: Some("return $0") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "continue", lookup: None, snippet: Some("continue") }, + CompletionItem { label: "break", lookup: None, snippet: Some("break") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }]"#); check_snippet_completion(r" fn quux() -> i32 { loop { || { <|> } } } - ", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") }, - CompletionItem { name: "match", snippet: Some("match $0 {}") }, - CompletionItem { name: "while", snippet: Some("while $0 {}") }, - CompletionItem { name: "loop", snippet: Some("loop {$0}") }, - CompletionItem { name: "return", snippet: Some("return $0") }]"#); + ", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") }, + CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") }, + CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") }, + CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") }, + CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }]"#); + } + + #[test] + fn test_param_completion() { + check_scope_completion(r" + fn foo(file_id: FileId) {} + fn bar(file_id: FileId) {} + fn baz(file<|>) {} + ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); + check_scope_completion(r" + fn foo(file_id: FileId) {} + fn bar(file_id: FileId) {} + fn baz(file<|>, x: i32) {} + ", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#); } } diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index 11306a835..4a57837df 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs @@ -682,6 +682,28 @@ impl<'a> AstNode<'a> for IndexExpr<'a> { impl<'a> IndexExpr<'a> {} +// ItemList +#[derive(Debug, Clone, Copy)] +pub struct ItemList<'a> { + syntax: SyntaxNodeRef<'a>, +} + +impl<'a> AstNode<'a> for ItemList<'a> { + fn cast(syntax: SyntaxNodeRef<'a>) -> Option { + match syntax.kind() { + ITEM_LIST => Some(ItemList { syntax }), + _ => None, + } + } + fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } +} + +impl<'a> ItemList<'a> { + pub fn items(self) -> impl Iterator> + 'a { + super::children(self) + } +} + // Label #[derive(Debug, Clone, Copy)] pub struct Label<'a> { @@ -956,9 +978,9 @@ impl<'a> AstNode<'a> for Module<'a> { impl<'a> ast::NameOwner<'a> for Module<'a> {} impl<'a> ast::AttrsOwner<'a> for Module<'a> {} -impl<'a> Module<'a> { - pub fn items(self) -> impl Iterator> + 'a { - super::children(self) +impl<'a> ast::FnDefOwner<'a> for Module<'a> {} +impl<'a> Module<'a> {pub fn item_list(self) -> Option> { + super::child_opt(self) } } @@ -1593,15 +1615,12 @@ impl<'a> AstNode<'a> for Root<'a> { fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } } +impl<'a> ast::FnDefOwner<'a> for Root<'a> {} impl<'a> Root<'a> { pub fn items(self) -> impl Iterator> + 'a { super::children(self) } - pub fn functions(self) -> impl Iterator> + 'a { - super::children(self) - } - pub fn modules(self) -> impl Iterator> + 'a { super::children(self) } diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 274996171..881f380f3 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs @@ -32,6 +32,12 @@ pub trait ArgListOwner<'a>: AstNode<'a> { } } +pub trait FnDefOwner<'a>: AstNode<'a> { + fn functions(self) -> Box> + 'a> { + Box::new(children(self)) + } +} + pub trait TypeParamsOwner<'a>: AstNode<'a> { fn type_param_list(self) -> Option> { child_opt(self) diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index 683623a5d..8a2b780f0 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron @@ -238,9 +238,9 @@ Grammar( ], ast: { "Root": ( + traits: [ "FnDefOwner" ], collections: [ ["items", "ModuleItem"], - ["functions", "FnDef"], ["modules", "Module"], ] ), @@ -271,10 +271,11 @@ Grammar( ] ), "TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ), "Module": ( - traits: ["NameOwner", "AttrsOwner"], - collections: [ - ["items", "ModuleItem"] - ] + traits: ["NameOwner", "AttrsOwner", "FnDefOwner" ], + options: [ "ItemList" ] + ), + "ItemList": ( + collections: [ ["items", "ModuleItem"] ] ), "ConstDef": ( traits: [ "NameOwner", diff --git a/crates/libsyntax2/src/grammar/patterns.rs b/crates/libsyntax2/src/grammar/patterns.rs index 065570b99..aa20ae8e4 100644 --- a/crates/libsyntax2/src/grammar/patterns.rs +++ b/crates/libsyntax2/src/grammar/patterns.rs @@ -23,7 +23,7 @@ pub(super) fn pattern(p: &mut Parser) { } const PAT_RECOVERY_SET: TokenSet = - token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW]; + token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; fn atom_pat(p: &mut Parser) -> Option { diff --git a/crates/libsyntax2/src/grammar/types.rs b/crates/libsyntax2/src/grammar/types.rs index 89030e66c..a52355b50 100644 --- a/crates/libsyntax2/src/grammar/types.rs +++ b/crates/libsyntax2/src/grammar/types.rs @@ -8,6 +8,9 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST, ]; +const TYPE_RECOVERY_SET: TokenSet = + token_set![R_PAREN, COMMA]; + pub(super) fn type_(p: &mut Parser) { match p.current() { L_PAREN => paren_or_tuple_type(p), @@ -23,7 +26,7 @@ pub(super) fn type_(p: &mut Parser) { L_ANGLE => path_type(p), _ if paths::is_path_start(p) => path_type(p), _ => { - p.err_and_bump("expected type"); + p.err_recover("expected type", TYPE_RECOVERY_SET); } } } diff --git a/crates/libsyntax2/tests/data/parser/err/0018_incomplete_fn.txt b/crates/libsyntax2/tests/data/parser/err/0018_incomplete_fn.txt index 58e39a341..c4d9f5e7e 100644 --- a/crates/libsyntax2/tests/data/parser/err/0018_incomplete_fn.txt +++ b/crates/libsyntax2/tests/data/parser/err/0018_incomplete_fn.txt @@ -11,168 +11,121 @@ ROOT@[0; 183) ITEM_LIST@[14; 182) L_CURLY@[14; 15) WHITESPACE@[15; 20) - FN_DEF@[20; 180) + FN_DEF@[20; 161) FN_KW@[20; 22) WHITESPACE@[22; 23) NAME@[23; 32) IDENT@[23; 32) "new_scope" - PARAM_LIST@[32; 180) + PARAM_LIST@[32; 35) L_PAREN@[32; 33) - PARAM@[33; 38) - REF_PAT@[33; 35) + PARAM@[33; 34) + REF_PAT@[33; 34) AMP@[33; 34) err: `expected pattern` - ERROR@[34; 35) - R_PAREN@[34; 35) - err: `expected COLON` - WHITESPACE@[35; 36) - err: `expected type` - ERROR@[36; 38) - THIN_ARROW@[36; 38) - err: `expected COMMA` + err: `expected COLON` + err: `expected type` + R_PAREN@[34; 35) + WHITESPACE@[35; 36) + RET_TYPE@[36; 46) + THIN_ARROW@[36; 38) WHITESPACE@[38; 39) - PARAM@[39; 169) - STRUCT_PAT@[39; 161) - PATH@[39; 46) - PATH_SEGMENT@[39; 46) - NAME_REF@[39; 46) - IDENT@[39; 46) "ScopeId" - WHITESPACE@[46; 47) - FIELD_PAT_LIST@[47; 161) - L_CURLY@[47; 48) - WHITESPACE@[48; 57) - err: `expected a name` - BIND_PAT@[57; 60) - ERROR@[57; 60) - LET_KW@[57; 60) - err: `expected COMMA` - WHITESPACE@[60; 61) - BIND_PAT@[61; 64) - NAME@[61; 64) - IDENT@[61; 64) "res" - err: `expected COMMA` - WHITESPACE@[64; 65) - err: `expected a name` - BIND_PAT@[65; 66) - ERROR@[65; 66) - EQ@[65; 66) - err: `expected COMMA` - WHITESPACE@[66; 67) - err: `expected a name` - BIND_PAT@[67; 71) - ERROR@[67; 71) - SELF_KW@[67; 71) - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[71; 72) - ERROR@[71; 72) - DOT@[71; 72) - err: `expected COMMA` - BIND_PAT@[72; 78) - NAME@[72; 78) - IDENT@[72; 78) "scopes" - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[78; 79) - ERROR@[78; 79) - DOT@[78; 79) - err: `expected COMMA` - BIND_PAT@[79; 82) - NAME@[79; 82) - IDENT@[79; 82) "len" - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[82; 83) - ERROR@[82; 83) - L_PAREN@[82; 83) - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[83; 84) - ERROR@[83; 84) - R_PAREN@[83; 84) - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[84; 85) - ERROR@[84; 85) - SEMI@[84; 85) - err: `expected COMMA` - WHITESPACE@[85; 94) - err: `expected a name` - BIND_PAT@[94; 98) - ERROR@[94; 98) + PATH_TYPE@[39; 46) + PATH@[39; 46) + PATH_SEGMENT@[39; 46) + NAME_REF@[39; 46) + IDENT@[39; 46) "ScopeId" + WHITESPACE@[46; 47) + BLOCK@[47; 161) + L_CURLY@[47; 48) + WHITESPACE@[48; 57) + LET_STMT@[57; 85) + LET_KW@[57; 60) + WHITESPACE@[60; 61) + BIND_PAT@[61; 64) + NAME@[61; 64) + IDENT@[61; 64) "res" + WHITESPACE@[64; 65) + EQ@[65; 66) + WHITESPACE@[66; 67) + METHOD_CALL_EXPR@[67; 84) + FIELD_EXPR@[67; 78) + PATH_EXPR@[67; 71) + PATH@[67; 71) + PATH_SEGMENT@[67; 71) + SELF_KW@[67; 71) + DOT@[71; 72) + NAME_REF@[72; 78) + IDENT@[72; 78) "scopes" + DOT@[78; 79) + NAME_REF@[79; 82) + IDENT@[79; 82) "len" + ARG_LIST@[82; 84) + L_PAREN@[82; 83) + R_PAREN@[83; 84) + SEMI@[84; 85) + WHITESPACE@[85; 94) + METHOD_CALL_EXPR@[94; 155) + FIELD_EXPR@[94; 105) + PATH_EXPR@[94; 98) + PATH@[94; 98) + PATH_SEGMENT@[94; 98) SELF_KW@[94; 98) - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[98; 99) - ERROR@[98; 99) - DOT@[98; 99) - err: `expected COMMA` - BIND_PAT@[99; 105) - NAME@[99; 105) - IDENT@[99; 105) "scopes" - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[105; 106) - ERROR@[105; 106) - DOT@[105; 106) - err: `expected COMMA` - BIND_PAT@[106; 110) - NAME@[106; 110) - IDENT@[106; 110) "push" - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[110; 111) - ERROR@[110; 111) - L_PAREN@[110; 111) - err: `expected COMMA` - BIND_PAT@[111; 120) - NAME@[111; 120) - IDENT@[111; 120) "ScopeData" - err: `expected COMMA` + DOT@[98; 99) + NAME_REF@[99; 105) + IDENT@[99; 105) "scopes" + DOT@[105; 106) + NAME_REF@[106; 110) + IDENT@[106; 110) "push" + ARG_LIST@[110; 155) + L_PAREN@[110; 111) + STRUCT_LIT@[111; 154) + PATH@[111; 120) + PATH_SEGMENT@[111; 120) + NAME_REF@[111; 120) + IDENT@[111; 120) "ScopeData" WHITESPACE@[120; 121) - err: `expected ident` - ERROR@[121; 154) + NAMED_FIELD_LIST@[121; 154) L_CURLY@[121; 122) WHITESPACE@[122; 123) - IDENT@[123; 129) "parent" - COLON@[129; 130) - WHITESPACE@[130; 131) - IDENT@[131; 135) "None" + NAMED_FIELD@[123; 135) + NAME_REF@[123; 129) + IDENT@[123; 129) "parent" + COLON@[129; 130) + WHITESPACE@[130; 131) + PATH_EXPR@[131; 135) + PATH@[131; 135) + PATH_SEGMENT@[131; 135) + NAME_REF@[131; 135) + IDENT@[131; 135) "None" COMMA@[135; 136) WHITESPACE@[136; 137) - IDENT@[137; 144) "entries" - COLON@[144; 145) - WHITESPACE@[145; 146) - IDENT@[146; 149) "vec" - EXCL@[149; 150) - L_BRACK@[150; 151) - R_BRACK@[151; 152) + NAMED_FIELD@[137; 152) + NAME_REF@[137; 144) + IDENT@[137; 144) "entries" + COLON@[144; 145) + WHITESPACE@[145; 146) + MACRO_CALL@[146; 152) + PATH@[146; 149) + PATH_SEGMENT@[146; 149) + NAME_REF@[146; 149) + IDENT@[146; 149) "vec" + EXCL@[149; 150) + TOKEN_TREE@[150; 152) + L_BRACK@[150; 151) + R_BRACK@[151; 152) WHITESPACE@[152; 153) R_CURLY@[153; 154) - err: `expected COMMA` - err: `expected a name` - BIND_PAT@[154; 155) - ERROR@[154; 155) - R_PAREN@[154; 155) - WHITESPACE@[155; 160) - R_CURLY@[160; 161) - err: `expected COLON` - WHITESPACE@[161; 167) - FN_POINTER_TYPE@[167; 169) - FN_KW@[167; 169) - err: `expected parameters` - err: `expected COMMA` - WHITESPACE@[169; 170) - PARAM@[170; 180) - BIND_PAT@[170; 180) - NAME@[170; 180) - IDENT@[170; 180) "set_parent" - err: `expected COLON` - err: `expected type` - err: `expected COMMA` - err: `expected value parameter` - err: `expected R_PAREN` - err: `expected a block` + R_PAREN@[154; 155) + WHITESPACE@[155; 160) + R_CURLY@[160; 161) + WHITESPACE@[161; 167) + FN_DEF@[167; 180) + FN_KW@[167; 169) + WHITESPACE@[169; 170) + NAME@[170; 180) + IDENT@[170; 180) "set_parent" + err: `expected function arguments` + err: `expected a block` WHITESPACE@[180; 181) R_CURLY@[181; 182) WHITESPACE@[182; 183) diff --git a/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.rs b/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.rs new file mode 100644 index 000000000..7a6c264f6 --- /dev/null +++ b/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.rs @@ -0,0 +1,2 @@ +fn foo(x: i32, y) { +} diff --git a/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.txt b/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.txt new file mode 100644 index 000000000..8dcb58ae2 --- /dev/null +++ b/crates/libsyntax2/tests/data/parser/err/0021_incomplete_param.txt @@ -0,0 +1,34 @@ +ROOT@[0; 22) + FN_DEF@[0; 21) + FN_KW@[0; 2) + WHITESPACE@[2; 3) + NAME@[3; 6) + IDENT@[3; 6) "foo" + PARAM_LIST@[6; 17) + L_PAREN@[6; 7) + PARAM@[7; 13) + BIND_PAT@[7; 8) + NAME@[7; 8) + IDENT@[7; 8) "x" + COLON@[8; 9) + WHITESPACE@[9; 10) + PATH_TYPE@[10; 13) + PATH@[10; 13) + PATH_SEGMENT@[10; 13) + NAME_REF@[10; 13) + IDENT@[10; 13) "i32" + COMMA@[13; 14) + WHITESPACE@[14; 15) + PARAM@[15; 16) + BIND_PAT@[15; 16) + NAME@[15; 16) + IDENT@[15; 16) "y" + err: `expected COLON` + err: `expected type` + R_PAREN@[16; 17) + WHITESPACE@[17; 18) + BLOCK@[18; 21) + L_CURLY@[18; 19) + WHITESPACE@[19; 20) + R_CURLY@[20; 21) + WHITESPACE@[21; 22) diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 93d8bd9fe..898195f6d 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -345,7 +345,8 @@ pub fn handle_completion( let items = items.into_iter() .map(|item| { let mut res = CompletionItem { - label: item.name, + label: item.label, + filter_text: item.lookup, .. Default::default() }; if let Some(snip) = item.snippet { -- cgit v1.2.3