mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Complete params
This commit is contained in:
parent
58480b9190
commit
4798a89a12
10 changed files with 328 additions and 239 deletions
|
@ -1,11 +1,11 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashSet, HashMap};
|
||||||
|
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
File, TextUnit, AstNode, SyntaxKind::*,
|
File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*,
|
||||||
ast::{self, LoopBodyOwner},
|
ast::{self, LoopBodyOwner},
|
||||||
algo::{
|
algo::{
|
||||||
ancestors,
|
ancestors,
|
||||||
visit::{visitor, Visitor},
|
visit::{visitor, Visitor, visitor_ctx, VisitorCtx},
|
||||||
},
|
},
|
||||||
text_utils::is_subrange,
|
text_utils::is_subrange,
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,11 @@ use {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CompletionItem {
|
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<String>,
|
||||||
|
/// What is inserted, defaults to label
|
||||||
pub snippet: Option<String>
|
pub snippet: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,40 +31,89 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI
|
||||||
let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
|
let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
|
||||||
file.reparse(&edit)
|
file.reparse(&edit)
|
||||||
};
|
};
|
||||||
let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
|
let mut has_completions = false;
|
||||||
if !is_single_segment(name_ref) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) {
|
||||||
|
has_completions = true;
|
||||||
|
complete_name_ref(&file, name_ref, &mut res)
|
||||||
|
}
|
||||||
|
if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) {
|
||||||
|
has_completions = true;
|
||||||
|
complete_name(&file, name, &mut res)
|
||||||
|
}
|
||||||
|
if has_completions {
|
||||||
|
Some(res)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
|
||||||
|
if !is_node::<ast::Path>(name_ref.syntax()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
|
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);
|
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() {
|
if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
|
||||||
let scope = ModuleScope::new(root);
|
let scope = ModuleScope::new(root);
|
||||||
res.extend(
|
acc.extend(
|
||||||
scope.entries().iter()
|
scope.entries().iter()
|
||||||
.filter(|entry| entry.syntax() != name_ref.syntax())
|
.filter(|entry| entry.syntax() != name_ref.syntax())
|
||||||
.map(|entry| CompletionItem {
|
.map(|entry| CompletionItem {
|
||||||
name: entry.name().to_string(),
|
label: entry.name().to_string(),
|
||||||
|
lookup: None,
|
||||||
snippet: None,
|
snippet: None,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_single_segment(name_ref: ast::NameRef) -> bool {
|
fn complete_name(_file: &File, name: ast::Name, acc: &mut Vec<CompletionItem>) {
|
||||||
match ancestors(name_ref.syntax()).filter_map(ast::Path::cast).next() {
|
if !is_node::<ast::Param>(name.syntax()) {
|
||||||
None => false,
|
return;
|
||||||
Some(path) => {
|
}
|
||||||
path.syntax().range() == name_ref.syntax().range()
|
|
||||||
}
|
let mut params = HashMap::new();
|
||||||
|
for node in ancestors(name.syntax()) {
|
||||||
|
let _ = visitor_ctx(&mut params)
|
||||||
|
.visit::<ast::Root, _>(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<String, (u32, ast::Param<'a>)>) {
|
||||||
|
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(n) => n.syntax().range() == node.range(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
|
fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
|
||||||
acc.push(keyword("if", "if $0 {}"));
|
acc.push(keyword("if", "if $0 {}"));
|
||||||
acc.push(keyword("match", "match $0 {}"));
|
acc.push(keyword("match", "match $0 {}"));
|
||||||
|
@ -127,7 +180,8 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<Complet
|
||||||
|
|
||||||
fn keyword(kw: &str, snip: &str) -> CompletionItem {
|
fn keyword(kw: &str, snip: &str) -> CompletionItem {
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
name: kw.to_string(),
|
label: kw.to_string(),
|
||||||
|
lookup: None,
|
||||||
snippet: Some(snip.to_string()),
|
snippet: Some(snip.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,13 +193,15 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi
|
||||||
.flat_map(|scope| scopes.entries(scope).iter())
|
.flat_map(|scope| scopes.entries(scope).iter())
|
||||||
.filter(|entry| shadowed.insert(entry.name()))
|
.filter(|entry| shadowed.insert(entry.name()))
|
||||||
.map(|entry| CompletionItem {
|
.map(|entry| CompletionItem {
|
||||||
name: entry.name().to_string(),
|
label: entry.name().to_string(),
|
||||||
|
lookup: None,
|
||||||
snippet: None,
|
snippet: None,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if scopes.self_param.is_some() {
|
if scopes.self_param.is_some() {
|
||||||
acc.push(CompletionItem {
|
acc.push(CompletionItem {
|
||||||
name: "self".to_string(),
|
label: "self".to_string(),
|
||||||
|
lookup: None,
|
||||||
snippet: None,
|
snippet: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -186,9 +242,9 @@ mod tests {
|
||||||
1 + <|>;
|
1 + <|>;
|
||||||
let z = ();
|
let z = ();
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "y", snippet: None },
|
", r#"[CompletionItem { label: "y", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "x", snippet: None },
|
CompletionItem { label: "x", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "quux", snippet: None }]"#);
|
CompletionItem { label: "quux", lookup: None, snippet: None }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -203,9 +259,9 @@ mod tests {
|
||||||
1 + <|>
|
1 + <|>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "b", snippet: None },
|
", r#"[CompletionItem { label: "b", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "a", snippet: None },
|
CompletionItem { label: "a", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "quux", snippet: None }]"#);
|
CompletionItem { label: "quux", lookup: None, snippet: None }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -216,8 +272,8 @@ mod tests {
|
||||||
<|>
|
<|>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "x", snippet: None },
|
", r#"[CompletionItem { label: "x", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "quux", snippet: None }]"#);
|
CompletionItem { label: "quux", lookup: None, snippet: None }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -228,9 +284,9 @@ mod tests {
|
||||||
fn quux() {
|
fn quux() {
|
||||||
<|>
|
<|>
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "Foo", snippet: None },
|
", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "Baz", snippet: None },
|
CompletionItem { label: "Baz", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "quux", snippet: None }]"#);
|
CompletionItem { label: "quux", lookup: None, snippet: None }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -245,8 +301,8 @@ mod tests {
|
||||||
check_scope_completion(r"
|
check_scope_completion(r"
|
||||||
struct Foo;
|
struct Foo;
|
||||||
fn x() -> <|>
|
fn x() -> <|>
|
||||||
", r#"[CompletionItem { name: "Foo", snippet: None },
|
", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "x", snippet: None }]"#)
|
CompletionItem { label: "x", lookup: None, snippet: None }]"#)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -259,15 +315,15 @@ mod tests {
|
||||||
<|>
|
<|>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "bar", snippet: None },
|
", r#"[CompletionItem { label: "bar", lookup: None, snippet: None },
|
||||||
CompletionItem { name: "foo", snippet: None }]"#)
|
CompletionItem { label: "foo", lookup: None, snippet: None }]"#)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complete_self() {
|
fn test_complete_self() {
|
||||||
check_scope_completion(r"
|
check_scope_completion(r"
|
||||||
impl S { fn foo(&self) { <|> } }
|
impl S { fn foo(&self) { <|> } }
|
||||||
", r#"[CompletionItem { name: "self", snippet: None }]"#)
|
", r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -276,11 +332,11 @@ mod tests {
|
||||||
fn quux() {
|
fn quux() {
|
||||||
<|>
|
<|>
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return") }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -291,13 +347,13 @@ mod tests {
|
||||||
()
|
()
|
||||||
} <|>
|
} <|>
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "else", snippet: Some("else {$0}") },
|
CompletionItem { label: "else", lookup: None, snippet: Some("else {$0}") },
|
||||||
CompletionItem { name: "else if", snippet: Some("else if $0 {}") },
|
CompletionItem { label: "else if", lookup: None, snippet: Some("else if $0 {}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return") }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -307,21 +363,21 @@ mod tests {
|
||||||
<|>
|
<|>
|
||||||
92
|
92
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return $0;") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return $0;") }]"#);
|
||||||
check_snippet_completion(r"
|
check_snippet_completion(r"
|
||||||
fn quux() {
|
fn quux() {
|
||||||
<|>
|
<|>
|
||||||
92
|
92
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return;") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return;") }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -332,11 +388,11 @@ mod tests {
|
||||||
() => <|>
|
() => <|>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return $0") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -345,21 +401,35 @@ mod tests {
|
||||||
fn quux() -> i32 {
|
fn quux() -> i32 {
|
||||||
loop { <|> }
|
loop { <|> }
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "continue", snippet: Some("continue") },
|
CompletionItem { label: "continue", lookup: None, snippet: Some("continue") },
|
||||||
CompletionItem { name: "break", snippet: Some("break") },
|
CompletionItem { label: "break", lookup: None, snippet: Some("break") },
|
||||||
CompletionItem { name: "return", snippet: Some("return $0") }]"#);
|
CompletionItem { label: "return", lookup: None, snippet: Some("return $0") }]"#);
|
||||||
check_snippet_completion(r"
|
check_snippet_completion(r"
|
||||||
fn quux() -> i32 {
|
fn quux() -> i32 {
|
||||||
loop { || { <|> } }
|
loop { || { <|> } }
|
||||||
}
|
}
|
||||||
", r#"[CompletionItem { name: "if", snippet: Some("if $0 {}") },
|
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
|
||||||
CompletionItem { name: "match", snippet: Some("match $0 {}") },
|
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
|
||||||
CompletionItem { name: "while", snippet: Some("while $0 {}") },
|
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
|
||||||
CompletionItem { name: "loop", snippet: Some("loop {$0}") },
|
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
|
||||||
CompletionItem { name: "return", snippet: Some("return $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 }]"#);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,6 +682,28 @@ impl<'a> AstNode<'a> for IndexExpr<'a> {
|
||||||
|
|
||||||
impl<'a> 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<Self> {
|
||||||
|
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<Item = ModuleItem<'a>> + 'a {
|
||||||
|
super::children(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Label<'a> {
|
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::NameOwner<'a> for Module<'a> {}
|
||||||
impl<'a> ast::AttrsOwner<'a> for Module<'a> {}
|
impl<'a> ast::AttrsOwner<'a> for Module<'a> {}
|
||||||
impl<'a> Module<'a> {
|
impl<'a> ast::FnDefOwner<'a> for Module<'a> {}
|
||||||
pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a {
|
impl<'a> Module<'a> {pub fn item_list(self) -> Option<ItemList<'a>> {
|
||||||
super::children(self)
|
super::child_opt(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1593,15 +1615,12 @@ impl<'a> AstNode<'a> for Root<'a> {
|
||||||
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
|
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ast::FnDefOwner<'a> for Root<'a> {}
|
||||||
impl<'a> Root<'a> {
|
impl<'a> Root<'a> {
|
||||||
pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a {
|
pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a {
|
||||||
super::children(self)
|
super::children(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn functions(self) -> impl Iterator<Item = FnDef<'a>> + 'a {
|
|
||||||
super::children(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modules(self) -> impl Iterator<Item = Module<'a>> + 'a {
|
pub fn modules(self) -> impl Iterator<Item = Module<'a>> + 'a {
|
||||||
super::children(self)
|
super::children(self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,12 @@ pub trait ArgListOwner<'a>: AstNode<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FnDefOwner<'a>: AstNode<'a> {
|
||||||
|
fn functions(self) -> Box<Iterator<Item=FnDef<'a>> + 'a> {
|
||||||
|
Box::new(children(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait TypeParamsOwner<'a>: AstNode<'a> {
|
pub trait TypeParamsOwner<'a>: AstNode<'a> {
|
||||||
fn type_param_list(self) -> Option<TypeParamList<'a>> {
|
fn type_param_list(self) -> Option<TypeParamList<'a>> {
|
||||||
child_opt(self)
|
child_opt(self)
|
||||||
|
|
|
@ -238,9 +238,9 @@ Grammar(
|
||||||
],
|
],
|
||||||
ast: {
|
ast: {
|
||||||
"Root": (
|
"Root": (
|
||||||
|
traits: [ "FnDefOwner" ],
|
||||||
collections: [
|
collections: [
|
||||||
["items", "ModuleItem"],
|
["items", "ModuleItem"],
|
||||||
["functions", "FnDef"],
|
|
||||||
["modules", "Module"],
|
["modules", "Module"],
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
@ -271,10 +271,11 @@ Grammar(
|
||||||
] ),
|
] ),
|
||||||
"TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
|
"TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
|
||||||
"Module": (
|
"Module": (
|
||||||
traits: ["NameOwner", "AttrsOwner"],
|
traits: ["NameOwner", "AttrsOwner", "FnDefOwner" ],
|
||||||
collections: [
|
options: [ "ItemList" ]
|
||||||
["items", "ModuleItem"]
|
),
|
||||||
]
|
"ItemList": (
|
||||||
|
collections: [ ["items", "ModuleItem"] ]
|
||||||
),
|
),
|
||||||
"ConstDef": ( traits: [
|
"ConstDef": ( traits: [
|
||||||
"NameOwner",
|
"NameOwner",
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub(super) fn pattern(p: &mut Parser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PAT_RECOVERY_SET: TokenSet =
|
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<CompletedMarker> {
|
fn atom_pat(p: &mut Parser) -> Option<CompletedMarker> {
|
||||||
|
|
|
@ -8,6 +8,9 @@ pub(super) const TYPE_FIRST: TokenSet =
|
||||||
paths::PATH_FIRST,
|
paths::PATH_FIRST,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TYPE_RECOVERY_SET: TokenSet =
|
||||||
|
token_set![R_PAREN, COMMA];
|
||||||
|
|
||||||
pub(super) fn type_(p: &mut Parser) {
|
pub(super) fn type_(p: &mut Parser) {
|
||||||
match p.current() {
|
match p.current() {
|
||||||
L_PAREN => paren_or_tuple_type(p),
|
L_PAREN => paren_or_tuple_type(p),
|
||||||
|
@ -23,7 +26,7 @@ pub(super) fn type_(p: &mut Parser) {
|
||||||
L_ANGLE => path_type(p),
|
L_ANGLE => path_type(p),
|
||||||
_ if paths::is_path_start(p) => 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,168 +11,121 @@ ROOT@[0; 183)
|
||||||
ITEM_LIST@[14; 182)
|
ITEM_LIST@[14; 182)
|
||||||
L_CURLY@[14; 15)
|
L_CURLY@[14; 15)
|
||||||
WHITESPACE@[15; 20)
|
WHITESPACE@[15; 20)
|
||||||
FN_DEF@[20; 180)
|
FN_DEF@[20; 161)
|
||||||
FN_KW@[20; 22)
|
FN_KW@[20; 22)
|
||||||
WHITESPACE@[22; 23)
|
WHITESPACE@[22; 23)
|
||||||
NAME@[23; 32)
|
NAME@[23; 32)
|
||||||
IDENT@[23; 32) "new_scope"
|
IDENT@[23; 32) "new_scope"
|
||||||
PARAM_LIST@[32; 180)
|
PARAM_LIST@[32; 35)
|
||||||
L_PAREN@[32; 33)
|
L_PAREN@[32; 33)
|
||||||
PARAM@[33; 38)
|
PARAM@[33; 34)
|
||||||
REF_PAT@[33; 35)
|
REF_PAT@[33; 34)
|
||||||
AMP@[33; 34)
|
AMP@[33; 34)
|
||||||
err: `expected pattern`
|
err: `expected pattern`
|
||||||
ERROR@[34; 35)
|
err: `expected COLON`
|
||||||
R_PAREN@[34; 35)
|
err: `expected type`
|
||||||
err: `expected COLON`
|
R_PAREN@[34; 35)
|
||||||
WHITESPACE@[35; 36)
|
WHITESPACE@[35; 36)
|
||||||
err: `expected type`
|
RET_TYPE@[36; 46)
|
||||||
ERROR@[36; 38)
|
THIN_ARROW@[36; 38)
|
||||||
THIN_ARROW@[36; 38)
|
|
||||||
err: `expected COMMA`
|
|
||||||
WHITESPACE@[38; 39)
|
WHITESPACE@[38; 39)
|
||||||
PARAM@[39; 169)
|
PATH_TYPE@[39; 46)
|
||||||
STRUCT_PAT@[39; 161)
|
PATH@[39; 46)
|
||||||
PATH@[39; 46)
|
PATH_SEGMENT@[39; 46)
|
||||||
PATH_SEGMENT@[39; 46)
|
NAME_REF@[39; 46)
|
||||||
NAME_REF@[39; 46)
|
IDENT@[39; 46) "ScopeId"
|
||||||
IDENT@[39; 46) "ScopeId"
|
WHITESPACE@[46; 47)
|
||||||
WHITESPACE@[46; 47)
|
BLOCK@[47; 161)
|
||||||
FIELD_PAT_LIST@[47; 161)
|
L_CURLY@[47; 48)
|
||||||
L_CURLY@[47; 48)
|
WHITESPACE@[48; 57)
|
||||||
WHITESPACE@[48; 57)
|
LET_STMT@[57; 85)
|
||||||
err: `expected a name`
|
LET_KW@[57; 60)
|
||||||
BIND_PAT@[57; 60)
|
WHITESPACE@[60; 61)
|
||||||
ERROR@[57; 60)
|
BIND_PAT@[61; 64)
|
||||||
LET_KW@[57; 60)
|
NAME@[61; 64)
|
||||||
err: `expected COMMA`
|
IDENT@[61; 64) "res"
|
||||||
WHITESPACE@[60; 61)
|
WHITESPACE@[64; 65)
|
||||||
BIND_PAT@[61; 64)
|
EQ@[65; 66)
|
||||||
NAME@[61; 64)
|
WHITESPACE@[66; 67)
|
||||||
IDENT@[61; 64) "res"
|
METHOD_CALL_EXPR@[67; 84)
|
||||||
err: `expected COMMA`
|
FIELD_EXPR@[67; 78)
|
||||||
WHITESPACE@[64; 65)
|
PATH_EXPR@[67; 71)
|
||||||
err: `expected a name`
|
PATH@[67; 71)
|
||||||
BIND_PAT@[65; 66)
|
PATH_SEGMENT@[67; 71)
|
||||||
ERROR@[65; 66)
|
SELF_KW@[67; 71)
|
||||||
EQ@[65; 66)
|
DOT@[71; 72)
|
||||||
err: `expected COMMA`
|
NAME_REF@[72; 78)
|
||||||
WHITESPACE@[66; 67)
|
IDENT@[72; 78) "scopes"
|
||||||
err: `expected a name`
|
DOT@[78; 79)
|
||||||
BIND_PAT@[67; 71)
|
NAME_REF@[79; 82)
|
||||||
ERROR@[67; 71)
|
IDENT@[79; 82) "len"
|
||||||
SELF_KW@[67; 71)
|
ARG_LIST@[82; 84)
|
||||||
err: `expected COMMA`
|
L_PAREN@[82; 83)
|
||||||
err: `expected a name`
|
R_PAREN@[83; 84)
|
||||||
BIND_PAT@[71; 72)
|
SEMI@[84; 85)
|
||||||
ERROR@[71; 72)
|
WHITESPACE@[85; 94)
|
||||||
DOT@[71; 72)
|
METHOD_CALL_EXPR@[94; 155)
|
||||||
err: `expected COMMA`
|
FIELD_EXPR@[94; 105)
|
||||||
BIND_PAT@[72; 78)
|
PATH_EXPR@[94; 98)
|
||||||
NAME@[72; 78)
|
PATH@[94; 98)
|
||||||
IDENT@[72; 78) "scopes"
|
PATH_SEGMENT@[94; 98)
|
||||||
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)
|
|
||||||
SELF_KW@[94; 98)
|
SELF_KW@[94; 98)
|
||||||
err: `expected COMMA`
|
DOT@[98; 99)
|
||||||
err: `expected a name`
|
NAME_REF@[99; 105)
|
||||||
BIND_PAT@[98; 99)
|
IDENT@[99; 105) "scopes"
|
||||||
ERROR@[98; 99)
|
DOT@[105; 106)
|
||||||
DOT@[98; 99)
|
NAME_REF@[106; 110)
|
||||||
err: `expected COMMA`
|
IDENT@[106; 110) "push"
|
||||||
BIND_PAT@[99; 105)
|
ARG_LIST@[110; 155)
|
||||||
NAME@[99; 105)
|
L_PAREN@[110; 111)
|
||||||
IDENT@[99; 105) "scopes"
|
STRUCT_LIT@[111; 154)
|
||||||
err: `expected COMMA`
|
PATH@[111; 120)
|
||||||
err: `expected a name`
|
PATH_SEGMENT@[111; 120)
|
||||||
BIND_PAT@[105; 106)
|
NAME_REF@[111; 120)
|
||||||
ERROR@[105; 106)
|
IDENT@[111; 120) "ScopeData"
|
||||||
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`
|
|
||||||
WHITESPACE@[120; 121)
|
WHITESPACE@[120; 121)
|
||||||
err: `expected ident`
|
NAMED_FIELD_LIST@[121; 154)
|
||||||
ERROR@[121; 154)
|
|
||||||
L_CURLY@[121; 122)
|
L_CURLY@[121; 122)
|
||||||
WHITESPACE@[122; 123)
|
WHITESPACE@[122; 123)
|
||||||
IDENT@[123; 129) "parent"
|
NAMED_FIELD@[123; 135)
|
||||||
COLON@[129; 130)
|
NAME_REF@[123; 129)
|
||||||
WHITESPACE@[130; 131)
|
IDENT@[123; 129) "parent"
|
||||||
IDENT@[131; 135) "None"
|
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)
|
COMMA@[135; 136)
|
||||||
WHITESPACE@[136; 137)
|
WHITESPACE@[136; 137)
|
||||||
IDENT@[137; 144) "entries"
|
NAMED_FIELD@[137; 152)
|
||||||
COLON@[144; 145)
|
NAME_REF@[137; 144)
|
||||||
WHITESPACE@[145; 146)
|
IDENT@[137; 144) "entries"
|
||||||
IDENT@[146; 149) "vec"
|
COLON@[144; 145)
|
||||||
EXCL@[149; 150)
|
WHITESPACE@[145; 146)
|
||||||
L_BRACK@[150; 151)
|
MACRO_CALL@[146; 152)
|
||||||
R_BRACK@[151; 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)
|
WHITESPACE@[152; 153)
|
||||||
R_CURLY@[153; 154)
|
R_CURLY@[153; 154)
|
||||||
err: `expected COMMA`
|
R_PAREN@[154; 155)
|
||||||
err: `expected a name`
|
WHITESPACE@[155; 160)
|
||||||
BIND_PAT@[154; 155)
|
R_CURLY@[160; 161)
|
||||||
ERROR@[154; 155)
|
WHITESPACE@[161; 167)
|
||||||
R_PAREN@[154; 155)
|
FN_DEF@[167; 180)
|
||||||
WHITESPACE@[155; 160)
|
FN_KW@[167; 169)
|
||||||
R_CURLY@[160; 161)
|
WHITESPACE@[169; 170)
|
||||||
err: `expected COLON`
|
NAME@[170; 180)
|
||||||
WHITESPACE@[161; 167)
|
IDENT@[170; 180) "set_parent"
|
||||||
FN_POINTER_TYPE@[167; 169)
|
err: `expected function arguments`
|
||||||
FN_KW@[167; 169)
|
err: `expected a block`
|
||||||
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`
|
|
||||||
WHITESPACE@[180; 181)
|
WHITESPACE@[180; 181)
|
||||||
R_CURLY@[181; 182)
|
R_CURLY@[181; 182)
|
||||||
WHITESPACE@[182; 183)
|
WHITESPACE@[182; 183)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
fn foo(x: i32, y) {
|
||||||
|
}
|
|
@ -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)
|
|
@ -345,7 +345,8 @@ pub fn handle_completion(
|
||||||
let items = items.into_iter()
|
let items = items.into_iter()
|
||||||
.map(|item| {
|
.map(|item| {
|
||||||
let mut res = CompletionItem {
|
let mut res = CompletionItem {
|
||||||
label: item.name,
|
label: item.label,
|
||||||
|
filter_text: item.lookup,
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
};
|
};
|
||||||
if let Some(snip) = item.snippet {
|
if let Some(snip) = item.snippet {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue