diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-10-18 11:41:46 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-18 11:41:46 +0100 |
commit | 886cfd68212bb0b4487d6a822476c350a6eb114f (patch) | |
tree | 5b144eabe1eaf62aa1ec5b804ee6fff00f5f84e9 /crates/completion/src/test_utils.rs | |
parent | 2067a410f31810f6e1941a86cdea0247c3b7d6f4 (diff) | |
parent | 9e7c952bbddc2e6763c49f0511a295362e9893d6 (diff) |
Merge #6276
6276: Extract call_info and completion into separate crates r=matklad a=popzxc
As it was discussed in [zulip](https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Completion.20refactoring), we need to move `completions` into a separate crate.
Unfortunately, the dependency on `call_info::ActiveParameter` doesn't look easy to get rid of, and it seems to be a topic for a separate PR, thus I also extracted `call_info` into a separate crate (on which both `ide` and `completion` crates depend).
Additionally, a few `FIXME`s in doc-comments were resolved in order to make `tidy` happy.
Co-authored-by: Igor Aleksanov <[email protected]>
Diffstat (limited to 'crates/completion/src/test_utils.rs')
-rw-r--r-- | crates/completion/src/test_utils.rs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs new file mode 100644 index 000000000..f2cf2561f --- /dev/null +++ b/crates/completion/src/test_utils.rs | |||
@@ -0,0 +1,130 @@ | |||
1 | //! Runs completion for testing purposes. | ||
2 | |||
3 | use base_db::{fixture::ChangeFixture, FileLoader, FilePosition}; | ||
4 | use hir::Semantics; | ||
5 | use ide_db::RootDatabase; | ||
6 | use itertools::Itertools; | ||
7 | use stdx::{format_to, trim_indent}; | ||
8 | use syntax::{AstNode, NodeOrToken, SyntaxElement}; | ||
9 | use test_utils::{assert_eq_text, RangeOrOffset}; | ||
10 | |||
11 | use crate::{completion_item::CompletionKind, CompletionConfig, CompletionItem}; | ||
12 | |||
13 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | ||
14 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | ||
15 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
16 | let mut database = RootDatabase::default(); | ||
17 | database.apply_change(change_fixture.change); | ||
18 | let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); | ||
19 | let offset = match range_or_offset { | ||
20 | RangeOrOffset::Range(_) => panic!(), | ||
21 | RangeOrOffset::Offset(it) => it, | ||
22 | }; | ||
23 | (database, FilePosition { file_id, offset }) | ||
24 | } | ||
25 | |||
26 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | ||
27 | do_completion_with_config(CompletionConfig::default(), code, kind) | ||
28 | } | ||
29 | |||
30 | pub(crate) fn do_completion_with_config( | ||
31 | config: CompletionConfig, | ||
32 | code: &str, | ||
33 | kind: CompletionKind, | ||
34 | ) -> Vec<CompletionItem> { | ||
35 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code) | ||
36 | .into_iter() | ||
37 | .filter(|c| c.completion_kind == kind) | ||
38 | .collect(); | ||
39 | kind_completions.sort_by(|l, r| l.label().cmp(r.label())); | ||
40 | kind_completions | ||
41 | } | ||
42 | |||
43 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { | ||
44 | completion_list_with_config(CompletionConfig::default(), code, kind) | ||
45 | } | ||
46 | |||
47 | pub(crate) fn completion_list_with_config( | ||
48 | config: CompletionConfig, | ||
49 | code: &str, | ||
50 | kind: CompletionKind, | ||
51 | ) -> String { | ||
52 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code) | ||
53 | .into_iter() | ||
54 | .filter(|c| c.completion_kind == kind) | ||
55 | .collect(); | ||
56 | kind_completions.sort_by_key(|c| c.label().to_owned()); | ||
57 | let label_width = kind_completions | ||
58 | .iter() | ||
59 | .map(|it| monospace_width(it.label())) | ||
60 | .max() | ||
61 | .unwrap_or_default() | ||
62 | .min(16); | ||
63 | kind_completions | ||
64 | .into_iter() | ||
65 | .map(|it| { | ||
66 | let tag = it.kind().unwrap().tag(); | ||
67 | let var_name = format!("{} {}", tag, it.label()); | ||
68 | let mut buf = var_name; | ||
69 | if let Some(detail) = it.detail() { | ||
70 | let width = label_width.saturating_sub(monospace_width(it.label())); | ||
71 | format_to!(buf, "{:width$} {}", "", detail, width = width); | ||
72 | } | ||
73 | format_to!(buf, "\n"); | ||
74 | buf | ||
75 | }) | ||
76 | .collect() | ||
77 | } | ||
78 | |||
79 | fn monospace_width(s: &str) -> usize { | ||
80 | s.chars().count() | ||
81 | } | ||
82 | |||
83 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
84 | check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after) | ||
85 | } | ||
86 | |||
87 | pub(crate) fn check_edit_with_config( | ||
88 | config: CompletionConfig, | ||
89 | what: &str, | ||
90 | ra_fixture_before: &str, | ||
91 | ra_fixture_after: &str, | ||
92 | ) { | ||
93 | let ra_fixture_after = trim_indent(ra_fixture_after); | ||
94 | let (db, position) = position(ra_fixture_before); | ||
95 | let completions: Vec<CompletionItem> = | ||
96 | crate::completions(&db, &config, position).unwrap().into(); | ||
97 | let (completion,) = completions | ||
98 | .iter() | ||
99 | .filter(|it| it.lookup() == what) | ||
100 | .collect_tuple() | ||
101 | .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions)); | ||
102 | let mut actual = db.file_text(position.file_id).to_string(); | ||
103 | completion.text_edit().apply(&mut actual); | ||
104 | assert_eq_text!(&ra_fixture_after, &actual) | ||
105 | } | ||
106 | |||
107 | pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) { | ||
108 | let (db, pos) = position(code); | ||
109 | |||
110 | let sema = Semantics::new(&db); | ||
111 | let original_file = sema.parse(pos.file_id); | ||
112 | let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); | ||
113 | assert!(check(NodeOrToken::Token(token))); | ||
114 | } | ||
115 | |||
116 | pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElement) -> bool) { | ||
117 | let (db, pos) = position(code); | ||
118 | let sema = Semantics::new(&db); | ||
119 | let original_file = sema.parse(pos.file_id); | ||
120 | let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); | ||
121 | assert!(!check(NodeOrToken::Token(token))); | ||
122 | } | ||
123 | |||
124 | pub(crate) fn get_all_completion_items( | ||
125 | config: CompletionConfig, | ||
126 | code: &str, | ||
127 | ) -> Vec<CompletionItem> { | ||
128 | let (db, position) = position(code); | ||
129 | crate::completions(&db, &config, position).unwrap().into() | ||
130 | } | ||