Add few smoke tests for patterns and refactoring

This commit is contained in:
Mikhail Rakhmanov 2020-06-12 00:17:30 +02:00
parent f46bc12199
commit a2b4385f16
4 changed files with 111 additions and 10 deletions

View File

@ -65,13 +65,13 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
add_keyword(ctx, acc, "use", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent);
add_keyword(ctx, acc, "impl", "impl $0 {}", ctx.is_new_item);
add_keyword(ctx, acc, "trait", "impl $0 {}", ctx.is_new_item);
add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !ctx.after_unsafe);
add_keyword(ctx, acc, "struct", "struct $0 {}", ctx.is_new_item && !ctx.after_unsafe);
add_keyword(ctx, acc, "union", "union $0 {}", ctx.is_new_item && !ctx.after_unsafe);
add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev);
add_keyword(ctx, acc, "struct", "struct $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev);
add_keyword(ctx, acc, "union", "union $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev);
add_keyword(ctx, acc, "match", "match $0 {}", ctx.block_expr_parent);
add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent);
add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent);
add_keyword(ctx, acc, "let", "let ", ctx.after_if || ctx.block_expr_parent);
add_keyword(ctx, acc, "let", "let ", ctx.if_is_prev || ctx.block_expr_parent);
add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if);
add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if);
add_keyword(ctx, acc, "mod", "mod $0 {}", ctx.is_new_item || ctx.block_expr_parent);

View File

@ -12,8 +12,8 @@ use ra_syntax::{
use ra_text_edit::Indel;
use super::patterns::{
goes_after_unsafe, has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling,
has_ref_pat_parent, has_trait_as_prev_sibling, inside_trait, is_in_loop_body,
has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_ref_pat_parent,
has_trait_as_prev_sibling, if_is_prev, inside_trait, is_in_loop_body, unsafe_is_prev,
};
use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition};
use test_utils::mark;
@ -64,7 +64,8 @@ pub(crate) struct CompletionContext<'a> {
pub(super) is_path_type: bool,
pub(super) has_type_args: bool,
pub(super) attribute_under_caret: Option<ast::Attr>,
pub(super) after_unsafe: bool,
pub(super) unsafe_is_prev: bool,
pub(super) if_is_prev: bool,
pub(super) block_expr_parent: bool,
pub(super) bind_pat_parent: bool,
pub(super) ref_pat_parent: bool,
@ -130,7 +131,7 @@ impl<'a> CompletionContext<'a> {
has_type_args: false,
dot_receiver_is_ambiguous_float_literal: false,
attribute_under_caret: None,
after_unsafe: false,
unsafe_is_prev: false,
in_loop_body: false,
ref_pat_parent: false,
bind_pat_parent: false,
@ -138,6 +139,7 @@ impl<'a> CompletionContext<'a> {
inside_trait: false,
trait_as_prev_sibling: false,
impl_as_prev_sibling: false,
if_is_prev: false,
};
let mut original_file = original_file.syntax().clone();
@ -212,7 +214,8 @@ impl<'a> CompletionContext<'a> {
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
let syntax_element = NodeOrToken::Token(fake_ident_token.clone());
self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
self.after_unsafe = goes_after_unsafe(syntax_element.clone());
self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone());
self.if_is_prev = if_is_prev(syntax_element.clone());
self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone());
self.ref_pat_parent = has_ref_pat_parent(syntax_element.clone());
self.in_loop_body = is_in_loop_body(syntax_element.clone());

View File

@ -22,7 +22,7 @@ pub(crate) fn has_ref_pat_parent(element: SyntaxElement) -> bool {
element.ancestors().find(|it| it.kind() == REF_PAT).is_some()
}
pub(crate) fn goes_after_unsafe(element: SyntaxElement) -> bool {
pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
element
.into_token()
.and_then(|it| previous_non_trivia_token(it))
@ -30,6 +30,14 @@ pub(crate) fn goes_after_unsafe(element: SyntaxElement) -> bool {
.is_some()
}
pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
element
.into_token()
.and_then(|it| previous_non_trivia_token(it))
.filter(|it| it.kind() == IF_KW)
.is_some()
}
pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
}
@ -110,3 +118,79 @@ fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<Syntax
non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
}
}
#[cfg(test)]
mod tests {
use super::{
has_block_expr_parent, has_impl_as_prev_sibling, has_trait_as_prev_sibling, if_is_prev,
inside_trait, unsafe_is_prev,
};
use crate::completion::test_utils::check_pattern_is_applicable;
#[test]
fn test_unsafe_is_prev() {
check_pattern_is_applicable(
r"
unsafe i<|>
",
unsafe_is_prev,
);
}
#[test]
fn test_if_is_prev() {
check_pattern_is_applicable(
r"
if l<|>
",
if_is_prev,
);
}
#[test]
fn test_inside_trait() {
check_pattern_is_applicable(
r"
trait A {
fn<|>
}
",
inside_trait,
);
}
#[test]
fn test_has_trait_as_prev_sibling() {
check_pattern_is_applicable(
r"
trait A w<|> {
}
",
has_trait_as_prev_sibling,
);
}
#[test]
fn test_has_impl_as_prev_sibling() {
check_pattern_is_applicable(
r"
impl A w<|> {
}
",
has_impl_as_prev_sibling,
);
}
#[test]
fn test_parent_block_expr() {
check_pattern_is_applicable(
r"
fn my_fn() {
let a = 2;
f<|>
}
",
has_block_expr_parent,
);
}
}

View File

@ -5,6 +5,8 @@ use crate::{
mock_analysis::{analysis_and_position, single_file_with_position},
CompletionItem,
};
use hir::Semantics;
use ra_syntax::{AstNode, NodeOrToken, SyntaxElement, SyntaxToken};
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
do_completion_with_options(code, kind, &CompletionConfig::default())
@ -27,3 +29,15 @@ pub(crate) fn do_completion_with_options(
kind_completions.sort_by_key(|c| c.label().to_owned());
kind_completions
}
pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
let (analysis, pos) = single_file_with_position(code);
analysis
.with_db(|db| {
let sema = Semantics::new(db);
let original_file = sema.parse(pos.file_id);
let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
assert!(check(NodeOrToken::Token(token)));
})
.unwrap();
}