mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
nested mod completion
This commit is contained in:
parent
ff1c82216c
commit
127814d9a7
5 changed files with 68 additions and 46 deletions
|
@ -2,7 +2,7 @@ use std::collections::{HashSet, HashMap};
|
||||||
|
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*,
|
File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*,
|
||||||
ast::{self, LoopBodyOwner},
|
ast::{self, LoopBodyOwner, ModuleItemOwner},
|
||||||
algo::{
|
algo::{
|
||||||
ancestors,
|
ancestors,
|
||||||
visit::{visitor, Visitor, visitor_ctx, VisitorCtx},
|
visit::{visitor, Visitor, visitor_ctx, VisitorCtx},
|
||||||
|
@ -58,13 +58,14 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi
|
||||||
if !is_node::<ast::Path>(name_ref.syntax()) {
|
if !is_node::<ast::Path>(name_ref.syntax()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
|
let mut visited_fn = false;
|
||||||
complete_expr_keywords(&file, fn_def, name_ref, acc);
|
for node in ancestors(name_ref.syntax()) {
|
||||||
let scopes = FnScopes::new(fn_def);
|
if let Some(items) = visitor()
|
||||||
complete_fn(name_ref, &scopes, acc);
|
.visit::<ast::Root, _>(|it| Some(it.items()))
|
||||||
}
|
.visit::<ast::Module, _>(|it| Some(it.item_list()?.items()))
|
||||||
if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
|
.accept(node) {
|
||||||
let scope = ModuleScope::new(root);
|
if let Some(items) = items {
|
||||||
|
let scope = ModuleScope::new(items);
|
||||||
acc.extend(
|
acc.extend(
|
||||||
scope.entries().iter()
|
scope.entries().iter()
|
||||||
.filter(|entry| entry.syntax() != name_ref.syntax())
|
.filter(|entry| entry.syntax() != name_ref.syntax())
|
||||||
|
@ -75,6 +76,17 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if !visited_fn {
|
||||||
|
if let Some(fn_def) = ast::FnDef::cast(node) {
|
||||||
|
visited_fn = true;
|
||||||
|
complete_expr_keywords(&file, fn_def, name_ref, acc);
|
||||||
|
let scopes = FnScopes::new(fn_def);
|
||||||
|
complete_fn(name_ref, &scopes, acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
|
fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
|
||||||
|
@ -299,6 +311,18 @@ mod tests {
|
||||||
", r#"[]"#);
|
", r#"[]"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_completion_mod_scope_nested() {
|
||||||
|
check_scope_completion(r"
|
||||||
|
struct Foo;
|
||||||
|
mod m {
|
||||||
|
struct Bar;
|
||||||
|
fn quux() { <|> }
|
||||||
|
}
|
||||||
|
", r#"[CompletionItem { label: "Bar", lookup: None, snippet: None },
|
||||||
|
CompletionItem { label: "quux", lookup: None, snippet: None }]"#);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complete_type() {
|
fn test_complete_type() {
|
||||||
check_scope_completion(r"
|
check_scope_completion(r"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
AstNode, SyntaxNode, SyntaxNodeRef, SmolStr, ast
|
AstNode, SyntaxNode, SyntaxNodeRef, SmolStr,
|
||||||
|
ast::{self, AstChildren},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ModuleScope {
|
pub struct ModuleScope {
|
||||||
|
@ -16,9 +17,9 @@ enum EntryKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleScope {
|
impl ModuleScope {
|
||||||
pub fn new(m: ast::Root) -> ModuleScope {
|
pub fn new(items: AstChildren<ast::ModuleItem>) -> ModuleScope {
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
for item in m.items() {
|
for item in items {
|
||||||
let entry = match item {
|
let entry = match item {
|
||||||
ast::ModuleItem::StructDef(item) => Entry::new(item),
|
ast::ModuleItem::StructDef(item) => Entry::new(item),
|
||||||
ast::ModuleItem::EnumDef(item) => Entry::new(item),
|
ast::ModuleItem::EnumDef(item) => Entry::new(item),
|
||||||
|
@ -85,11 +86,11 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use libsyntax2::File;
|
use libsyntax2::{File, ast::ModuleItemOwner};
|
||||||
|
|
||||||
fn do_check(code: &str, expected: &[&str]) {
|
fn do_check(code: &str, expected: &[&str]) {
|
||||||
let file = File::parse(&code);
|
let file = File::parse(&code);
|
||||||
let scope = ModuleScope::new(file.ast());
|
let scope = ModuleScope::new(file.ast().items());
|
||||||
let actual = scope.entries
|
let actual = scope.entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|it| it.name())
|
.map(|it| it.name())
|
||||||
|
|
|
@ -699,11 +699,8 @@ impl<'a> AstNode<'a> for ItemList<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {}
|
impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {}
|
||||||
impl<'a> ItemList<'a> {
|
impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {}
|
||||||
pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a {
|
impl<'a> ItemList<'a> {}
|
||||||
super::children(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -979,7 +976,6 @@ 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> ast::FnDefOwner<'a> for Module<'a> {}
|
|
||||||
impl<'a> Module<'a> {pub fn item_list(self) -> Option<ItemList<'a>> {
|
impl<'a> Module<'a> {pub fn item_list(self) -> Option<ItemList<'a>> {
|
||||||
super::child_opt(self)
|
super::child_opt(self)
|
||||||
}
|
}
|
||||||
|
@ -1616,12 +1612,9 @@ impl<'a> AstNode<'a> for Root<'a> {
|
||||||
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
|
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ast::ModuleItemOwner<'a> for Root<'a> {}
|
||||||
impl<'a> ast::FnDefOwner<'a> for Root<'a> {}
|
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 {
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,13 @@ pub trait ArgListOwner<'a>: AstNode<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FnDefOwner<'a>: AstNode<'a> {
|
pub trait FnDefOwner<'a>: AstNode<'a> {
|
||||||
fn functions(self) -> AstNodeChildren<'a, FnDef<'a>> {
|
fn functions(self) -> AstChildren<'a, FnDef<'a>> {
|
||||||
|
children(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ModuleItemOwner<'a>: AstNode<'a> {
|
||||||
|
fn items(self) -> AstChildren<'a, ModuleItem<'a>> {
|
||||||
children(self)
|
children(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +58,7 @@ pub trait TypeParamsOwner<'a>: AstNode<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AttrsOwner<'a>: AstNode<'a> {
|
pub trait AttrsOwner<'a>: AstNode<'a> {
|
||||||
fn attrs(self) -> AstNodeChildren<'a, Attr<'a>> {
|
fn attrs(self) -> AstChildren<'a, Attr<'a>> {
|
||||||
children(self)
|
children(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +164,7 @@ impl<'a> IfExpr<'a> {
|
||||||
pub fn else_branch(self) -> Option<Block<'a>> {
|
pub fn else_branch(self) -> Option<Block<'a>> {
|
||||||
self.blocks().nth(1)
|
self.blocks().nth(1)
|
||||||
}
|
}
|
||||||
fn blocks(self) -> AstNodeChildren<'a, Block<'a>> {
|
fn blocks(self) -> AstChildren<'a, Block<'a>> {
|
||||||
children(self)
|
children(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,27 +173,27 @@ fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> {
|
||||||
children(parent).next()
|
children(parent).next()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstNodeChildren<'a, C> {
|
fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C> {
|
||||||
AstNodeChildren::new(parent.syntax())
|
AstChildren::new(parent.syntax())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AstNodeChildren<'a, N> {
|
pub struct AstChildren<'a, N> {
|
||||||
inner: SyntaxNodeChildren<RefRoot<'a>>,
|
inner: SyntaxNodeChildren<RefRoot<'a>>,
|
||||||
ph: PhantomData<N>,
|
ph: PhantomData<N>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, N> AstNodeChildren<'a, N> {
|
impl<'a, N> AstChildren<'a, N> {
|
||||||
fn new(parent: SyntaxNodeRef<'a>) -> Self {
|
fn new(parent: SyntaxNodeRef<'a>) -> Self {
|
||||||
AstNodeChildren {
|
AstChildren {
|
||||||
inner: parent.children(),
|
inner: parent.children(),
|
||||||
ph: PhantomData,
|
ph: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, N: AstNode<'a>> Iterator for AstNodeChildren<'a, N> {
|
impl<'a, N: AstNode<'a>> Iterator for AstChildren<'a, N> {
|
||||||
type Item = N;
|
type Item = N;
|
||||||
fn next(&mut self) -> Option<N> {
|
fn next(&mut self) -> Option<N> {
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -238,9 +238,8 @@ Grammar(
|
||||||
],
|
],
|
||||||
ast: {
|
ast: {
|
||||||
"Root": (
|
"Root": (
|
||||||
traits: [ "FnDefOwner" ],
|
traits: [ "ModuleItemOwner", "FnDefOwner" ],
|
||||||
collections: [
|
collections: [
|
||||||
["items", "ModuleItem"],
|
|
||||||
["modules", "Module"],
|
["modules", "Module"],
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
@ -271,12 +270,11 @@ Grammar(
|
||||||
] ),
|
] ),
|
||||||
"TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
|
"TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
|
||||||
"Module": (
|
"Module": (
|
||||||
traits: ["NameOwner", "AttrsOwner", "FnDefOwner" ],
|
traits: ["NameOwner", "AttrsOwner" ],
|
||||||
options: [ "ItemList" ]
|
options: [ "ItemList" ]
|
||||||
),
|
),
|
||||||
"ItemList": (
|
"ItemList": (
|
||||||
traits: [ "FnDefOwner" ],
|
traits: [ "FnDefOwner", "ModuleItemOwner" ],
|
||||||
collections: [ ["items", "ModuleItem"] ]
|
|
||||||
),
|
),
|
||||||
"ConstDef": ( traits: [
|
"ConstDef": ( traits: [
|
||||||
"NameOwner",
|
"NameOwner",
|
||||||
|
|
Loading…
Reference in a new issue