From e42c448077ca2b7675320da3c5294bf4bebaedeb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 28 May 2021 22:18:52 +0200 Subject: More completion pattern tests --- crates/ide_completion/src/completions/keyword.rs | 2 - crates/ide_completion/src/patterns.rs | 193 +++++++++++++---------- 2 files changed, 109 insertions(+), 86 deletions(-) (limited to 'crates/ide_completion/src') diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 06789b704..e71a04b6e 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -39,8 +39,6 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC } } -trait Foo {} - pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { if ctx.token.kind() == SyntaxKind::COMMENT { cov_mark::hit!(no_keyword_completion_in_comments); diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 8c4bdbed2..caf0ef39f 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -52,7 +52,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option { - let node = it.expr()?.syntax().clone(); + let node = it.expr().filter(|_| it.semicolon_token().is_none())?.syntax().clone(); match_ast! { match node { ast::IfExpr(_it) => ImmediatePrevSibling::IfExpr, @@ -149,59 +149,6 @@ fn maximize_name_ref(name_like: &ast::NameLike) -> Option { Some(node) } -#[cfg(test)] -fn check_location(code: &str, loc: ImmediateLocation) { - check_pattern_is_applicable(code, |e| { - let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); - assert_eq!(determine_location(name), Some(loc)); - true - }); -} - -#[test] -fn test_has_trait_parent() { - check_location(r"trait A { f$0 }", ImmediateLocation::Trait); -} - -#[test] -fn test_has_use_parent() { - check_location(r"use f$0", ImmediateLocation::Use); -} - -#[test] -fn test_has_impl_parent() { - check_location(r"impl A { f$0 }", ImmediateLocation::Impl); -} -#[test] -fn test_has_field_list_parent() { - check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField); - check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField); -} - -#[test] -fn test_has_block_expr_parent() { - check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr); -} - -#[test] -fn test_has_ident_pat_parent() { - check_location(r"fn my_fn(m$0) {}", ImmediateLocation::IdentPat); - check_location(r"fn my_fn() { let m$0 }", ImmediateLocation::IdentPat); - check_location(r"fn my_fn(&m$0) {}", ImmediateLocation::IdentPat); - check_location(r"fn my_fn() { let &m$0 }", ImmediateLocation::IdentPat); -} - -#[test] -fn test_has_ref_expr_parent() { - check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr); -} - -#[test] -fn test_has_item_list_or_source_file_parent() { - check_location(r"i$0", ImmediateLocation::ItemList); - check_location(r"mod foo { f$0 }", ImmediateLocation::ItemList); -} - pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, // where we only check the first parent with different text range. @@ -251,36 +198,6 @@ fn test_for_is_prev2() { check_pattern_is_applicable(r"for i i$0", for_is_prev2); } -#[cfg(test)] -fn check_prev_sibling(code: &str, sibling: impl Into>) { - check_pattern_is_applicable(code, |e| { - let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); - assert_eq!(determine_prev_sibling(name), sibling.into()); - true - }); -} - -#[test] -fn test_has_impl_as_prev_sibling() { - check_prev_sibling(r"impl A w$0 ", ImmediatePrevSibling::ImplDefType); - check_prev_sibling(r"impl A w$0 {}", ImmediatePrevSibling::ImplDefType); - check_prev_sibling(r"impl A for A w$0 ", ImmediatePrevSibling::ImplDefType); - check_prev_sibling(r"impl A for A w$0 {}", ImmediatePrevSibling::ImplDefType); - check_prev_sibling(r"impl A for w$0 {}", None); - check_prev_sibling(r"impl A for w$0", None); -} - -#[test] -fn test_has_trait_as_prev_sibling() { - check_prev_sibling(r"trait A w$0 ", ImmediatePrevSibling::TraitDefName); - check_prev_sibling(r"trait A w$0 {}", ImmediatePrevSibling::TraitDefName); -} - -#[test] -fn test_has_if_expr_as_prev_sibling() { - check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); -} - pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { element .ancestors() @@ -329,3 +246,111 @@ fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option>) { + check_pattern_is_applicable(code, |e| { + let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); + assert_eq!(determine_location(name), loc.into()); + true + }); + } + + fn check_prev_sibling(code: &str, sibling: impl Into>) { + check_pattern_is_applicable(code, |e| { + let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); + assert_eq!(determine_prev_sibling(name), sibling.into()); + true + }); + } + + #[test] + fn test_trait_loc() { + check_location(r"trait A { f$0 }", ImmediateLocation::Trait); + check_location(r"trait A { #[attr] f$0 }", ImmediateLocation::Trait); + check_location(r"trait A { f$0 fn f() {} }", ImmediateLocation::Trait); + check_location(r"trait A { fn f() {} f$0 }", ImmediateLocation::Trait); + check_location(r"trait A$0 {}", None); + check_location(r"trait A { fn f$0 }", None); + } + + #[test] + fn test_impl_loc() { + check_location(r"impl A { f$0 }", ImmediateLocation::Impl); + check_location(r"impl A { #[attr] f$0 }", ImmediateLocation::Impl); + check_location(r"impl A { f$0 fn f() {} }", ImmediateLocation::Impl); + check_location(r"impl A { fn f() {} f$0 }", ImmediateLocation::Impl); + check_location(r"impl A$0 {}", None); + check_location(r"impl A { fn f$0 }", None); + } + + #[test] + fn test_use_loc() { + check_location(r"use f$0", ImmediateLocation::Use); + check_location(r"use f$0;", ImmediateLocation::Use); + check_location(r"use f::{f$0}", None); + check_location(r"use {f$0}", None); + } + + #[test] + fn test_record_field_loc() { + check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField); + check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField); + check_location(r"struct Foo { pub f: i32, f$0 }", ImmediateLocation::RecordField); + } + + #[test] + fn test_block_expr_loc() { + check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr); + check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::BlockExpr); + } + + #[test] + fn test_ident_pat_loc() { + check_location(r"fn my_fn(m$0) {}", ImmediateLocation::IdentPat); + check_location(r"fn my_fn() { let m$0 }", ImmediateLocation::IdentPat); + check_location(r"fn my_fn(&m$0) {}", ImmediateLocation::IdentPat); + check_location(r"fn my_fn() { let &m$0 }", ImmediateLocation::IdentPat); + } + + #[test] + fn test_ref_expr_loc() { + check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr); + } + + #[test] + fn test_item_list_loc() { + check_location(r"i$0", ImmediateLocation::ItemList); + check_location(r"#[attr] i$0", ImmediateLocation::ItemList); + check_location(r"fn f() {} i$0", ImmediateLocation::ItemList); + check_location(r"mod foo { f$0 }", ImmediateLocation::ItemList); + check_location(r"mod foo { #[attr] f$0 }", ImmediateLocation::ItemList); + check_location(r"mod foo { fn f() {} f$0 }", ImmediateLocation::ItemList); + check_location(r"mod foo$0 {}", None); + } + + #[test] + fn test_impl_prev_sibling() { + check_prev_sibling(r"impl A w$0 ", ImmediatePrevSibling::ImplDefType); + check_prev_sibling(r"impl A w$0 {}", ImmediatePrevSibling::ImplDefType); + check_prev_sibling(r"impl A for A w$0 ", ImmediatePrevSibling::ImplDefType); + check_prev_sibling(r"impl A for A w$0 {}", ImmediatePrevSibling::ImplDefType); + check_prev_sibling(r"impl A for w$0 {}", None); + check_prev_sibling(r"impl A for w$0", None); + } + + #[test] + fn test_trait_prev_sibling() { + check_prev_sibling(r"trait A w$0 ", ImmediatePrevSibling::TraitDefName); + check_prev_sibling(r"trait A w$0 {}", ImmediatePrevSibling::TraitDefName); + } + + #[test] + fn test_if_expr_prev_sibling() { + check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); + check_prev_sibling(r"fn foo() { if true {}; w$0", None); + } +} -- cgit v1.2.3