aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/completion')
-rw-r--r--crates/ide/src/completion/complete_keyword.rs8
-rw-r--r--crates/ide/src/completion/complete_mod.rs4
-rw-r--r--crates/ide/src/completion/complete_postfix.rs61
-rw-r--r--crates/ide/src/completion/complete_postfix/format_like.rs277
-rw-r--r--crates/ide/src/completion/complete_qualified_path.rs4
-rw-r--r--crates/ide/src/completion/complete_unqualified_path.rs34
-rw-r--r--crates/ide/src/completion/completion_context.rs7
-rw-r--r--crates/ide/src/completion/presentation.rs4
-rw-r--r--crates/ide/src/completion/test_utils.rs9
9 files changed, 382 insertions, 26 deletions
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index 5645b41fa..e59747095 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -495,13 +495,13 @@ Some multi-line comment<|>
495 fn test_completion_await_impls_future() { 495 fn test_completion_await_impls_future() {
496 check( 496 check(
497 r#" 497 r#"
498//- /main.rs 498//- /main.rs crate:main deps:std
499use std::future::*; 499use std::future::*;
500struct A {} 500struct A {}
501impl Future for A {} 501impl Future for A {}
502fn foo(a: A) { a.<|> } 502fn foo(a: A) { a.<|> }
503 503
504//- /std/lib.rs 504//- /std/lib.rs crate:std
505pub mod future { 505pub mod future {
506 #[lang = "future_trait"] 506 #[lang = "future_trait"]
507 pub trait Future {} 507 pub trait Future {}
@@ -514,14 +514,14 @@ pub mod future {
514 514
515 check( 515 check(
516 r#" 516 r#"
517//- /main.rs 517//- /main.rs crate:main deps:std
518use std::future::*; 518use std::future::*;
519fn foo() { 519fn foo() {
520 let a = async {}; 520 let a = async {};
521 a.<|> 521 a.<|>
522} 522}
523 523
524//- /std/lib.rs 524//- /std/lib.rs crate:std
525pub mod future { 525pub mod future {
526 #[lang = "future_trait"] 526 #[lang = "future_trait"]
527 pub trait Future { 527 pub trait Future {
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/ide/src/completion/complete_mod.rs
index 3cfc2e131..c7a99bdc3 100644
--- a/crates/ide/src/completion/complete_mod.rs
+++ b/crates/ide/src/completion/complete_mod.rs
@@ -300,7 +300,7 @@ mod tests {
300 // "#, 300 // "#,
301 // expect![[r#" 301 // expect![[r#"
302 // md bar; 302 // md bar;
303 // "#]], 303 // "#]],foo
304 // ); 304 // );
305 // } 305 // }
306 306
@@ -308,7 +308,7 @@ mod tests {
308 fn already_declared_bin_module_completion_omitted() { 308 fn already_declared_bin_module_completion_omitted() {
309 check( 309 check(
310 r#" 310 r#"
311 //- /src/bin.rs 311 //- /src/bin.rs crate:main
312 fn main() {} 312 fn main() {}
313 //- /src/bin/foo.rs 313 //- /src/bin/foo.rs
314 mod <|> 314 mod <|>
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/ide/src/completion/complete_postfix.rs
index 26a5af5b9..db5319618 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/ide/src/completion/complete_postfix.rs
@@ -1,11 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3mod format_like;
4
2use assists::utils::TryEnum; 5use assists::utils::TryEnum;
3use syntax::{ 6use syntax::{
4 ast::{self, AstNode}, 7 ast::{self, AstNode, AstToken},
5 TextRange, TextSize, 8 TextRange, TextSize,
6}; 9};
7use text_edit::TextEdit; 10use text_edit::TextEdit;
8 11
12use self::format_like::add_format_like_completions;
9use crate::{ 13use crate::{
10 completion::{ 14 completion::{
11 completion_config::SnippetCap, 15 completion_config::SnippetCap,
@@ -207,6 +211,12 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
207 &format!("${{1}}({})", receiver_text), 211 &format!("${{1}}({})", receiver_text),
208 ) 212 )
209 .add_to(acc); 213 .add_to(acc);
214
215 if let ast::Expr::Literal(literal) = dot_receiver.clone() {
216 if let Some(literal_text) = ast::String::cast(literal.token()) {
217 add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text);
218 }
219 }
210} 220}
211 221
212fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { 222fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
@@ -392,4 +402,53 @@ fn main() {
392 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#); 402 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#);
393 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#); 403 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#);
394 } 404 }
405
406 #[test]
407 fn postfix_completion_for_format_like_strings() {
408 check_edit(
409 "fmt",
410 r#"fn main() { "{some_var:?}".<|> }"#,
411 r#"fn main() { format!("{:?}", some_var) }"#,
412 );
413 check_edit(
414 "panic",
415 r#"fn main() { "Panic with {a}".<|> }"#,
416 r#"fn main() { panic!("Panic with {}", a) }"#,
417 );
418 check_edit(
419 "println",
420 r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".<|> }"#,
421 r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#,
422 );
423 check_edit(
424 "loge",
425 r#"fn main() { "{2+2}".<|> }"#,
426 r#"fn main() { log::error!("{}", 2+2) }"#,
427 );
428 check_edit(
429 "logt",
430 r#"fn main() { "{2+2}".<|> }"#,
431 r#"fn main() { log::trace!("{}", 2+2) }"#,
432 );
433 check_edit(
434 "logd",
435 r#"fn main() { "{2+2}".<|> }"#,
436 r#"fn main() { log::debug!("{}", 2+2) }"#,
437 );
438 check_edit(
439 "logi",
440 r#"fn main() { "{2+2}".<|> }"#,
441 r#"fn main() { log::info!("{}", 2+2) }"#,
442 );
443 check_edit(
444 "logw",
445 r#"fn main() { "{2+2}".<|> }"#,
446 r#"fn main() { log::warn!("{}", 2+2) }"#,
447 );
448 check_edit(
449 "loge",
450 r#"fn main() { "{2+2}".<|> }"#,
451 r#"fn main() { log::error!("{}", 2+2) }"#,
452 );
453 }
395} 454}
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/ide/src/completion/complete_postfix/format_like.rs
new file mode 100644
index 000000000..81c33bf3a
--- /dev/null
+++ b/crates/ide/src/completion/complete_postfix/format_like.rs
@@ -0,0 +1,277 @@
1// Feature: Format String Completion.
2//
3// `"Result {result} is {2 + 2}"` is expanded to the `"Result {} is {}", result, 2 + 2`.
4//
5// The following postfix snippets are available:
6//
7// - `format` -> `format!(...)`
8// - `panic` -> `panic!(...)`
9// - `println` -> `println!(...)`
10// - `log`:
11// + `logd` -> `log::debug!(...)`
12// + `logt` -> `log::trace!(...)`
13// + `logi` -> `log::info!(...)`
14// + `logw` -> `log::warn!(...)`
15// + `loge` -> `log::error!(...)`
16
17use crate::completion::{
18 complete_postfix::postfix_snippet, completion_config::SnippetCap,
19 completion_context::CompletionContext, completion_item::Completions,
20};
21use syntax::ast::{self, AstToken};
22
23/// Mapping ("postfix completion item" => "macro to use")
24static KINDS: &[(&str, &str)] = &[
25 ("fmt", "format!"),
26 ("panic", "panic!"),
27 ("println", "println!"),
28 ("logd", "log::debug!"),
29 ("logt", "log::trace!"),
30 ("logi", "log::info!"),
31 ("logw", "log::warn!"),
32 ("loge", "log::error!"),
33];
34
35pub(super) fn add_format_like_completions(
36 acc: &mut Completions,
37 ctx: &CompletionContext,
38 dot_receiver: &ast::Expr,
39 cap: SnippetCap,
40 receiver_text: &ast::String,
41) {
42 let input = match string_literal_contents(receiver_text) {
43 // It's not a string literal, do not parse input.
44 Some(input) => input,
45 None => return,
46 };
47
48 let mut parser = FormatStrParser::new(input);
49
50 if parser.parse().is_ok() {
51 for (label, macro_name) in KINDS {
52 let snippet = parser.into_suggestion(macro_name);
53
54 postfix_snippet(ctx, cap, &dot_receiver, label, macro_name, &snippet).add_to(acc);
55 }
56 }
57}
58
59/// Checks whether provided item is a string literal.
60fn string_literal_contents(item: &ast::String) -> Option<String> {
61 let item = item.text();
62 if item.len() >= 2 && item.starts_with("\"") && item.ends_with("\"") {
63 return Some(item[1..item.len() - 1].to_owned());
64 }
65
66 None
67}
68
69/// Parser for a format-like string. It is more allowing in terms of string contents,
70/// as we expect variable placeholders to be filled with expressions.
71#[derive(Debug)]
72pub struct FormatStrParser {
73 input: String,
74 output: String,
75 extracted_expressions: Vec<String>,
76 state: State,
77 parsed: bool,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq)]
81enum State {
82 NotExpr,
83 MaybeExpr,
84 Expr,
85 MaybeIncorrect,
86 FormatOpts,
87}
88
89impl FormatStrParser {
90 pub fn new(input: String) -> Self {
91 Self {
92 input: input.into(),
93 output: String::new(),
94 extracted_expressions: Vec::new(),
95 state: State::NotExpr,
96 parsed: false,
97 }
98 }
99
100 pub fn parse(&mut self) -> Result<(), ()> {
101 let mut current_expr = String::new();
102
103 let mut placeholder_id = 1;
104
105 // Count of open braces inside of an expression.
106 // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
107 // "{MyStruct { val_a: 0, val_b: 1 }}".
108 let mut inexpr_open_count = 0;
109
110 for chr in self.input.chars() {
111 match (self.state, chr) {
112 (State::NotExpr, '{') => {
113 self.output.push(chr);
114 self.state = State::MaybeExpr;
115 }
116 (State::NotExpr, '}') => {
117 self.output.push(chr);
118 self.state = State::MaybeIncorrect;
119 }
120 (State::NotExpr, _) => {
121 self.output.push(chr);
122 }
123 (State::MaybeIncorrect, '}') => {
124 // It's okay, we met "}}".
125 self.output.push(chr);
126 self.state = State::NotExpr;
127 }
128 (State::MaybeIncorrect, _) => {
129 // Error in the string.
130 return Err(());
131 }
132 (State::MaybeExpr, '{') => {
133 self.output.push(chr);
134 self.state = State::NotExpr;
135 }
136 (State::MaybeExpr, '}') => {
137 // This is an empty sequence '{}'. Replace it with placeholder.
138 self.output.push(chr);
139 self.extracted_expressions.push(format!("${}", placeholder_id));
140 placeholder_id += 1;
141 self.state = State::NotExpr;
142 }
143 (State::MaybeExpr, _) => {
144 current_expr.push(chr);
145 self.state = State::Expr;
146 }
147 (State::Expr, '}') => {
148 if inexpr_open_count == 0 {
149 self.output.push(chr);
150 self.extracted_expressions.push(current_expr.trim().into());
151 current_expr = String::new();
152 self.state = State::NotExpr;
153 } else {
154 // We're closing one brace met before inside of the expression.
155 current_expr.push(chr);
156 inexpr_open_count -= 1;
157 }
158 }
159 (State::Expr, ':') => {
160 if inexpr_open_count == 0 {
161 // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
162 self.output.push(chr);
163 self.extracted_expressions.push(current_expr.trim().into());
164 current_expr = String::new();
165 self.state = State::FormatOpts;
166 } else {
167 // We're inside of braced expression, assume that it's a struct field name/value delimeter.
168 current_expr.push(chr);
169 }
170 }
171 (State::Expr, '{') => {
172 current_expr.push(chr);
173 inexpr_open_count += 1;
174 }
175 (State::Expr, _) => {
176 current_expr.push(chr);
177 }
178 (State::FormatOpts, '}') => {
179 self.output.push(chr);
180 self.state = State::NotExpr;
181 }
182 (State::FormatOpts, _) => {
183 self.output.push(chr);
184 }
185 }
186 }
187
188 if self.state != State::NotExpr {
189 return Err(());
190 }
191
192 self.parsed = true;
193 Ok(())
194 }
195
196 pub fn into_suggestion(&self, macro_name: &str) -> String {
197 assert!(self.parsed, "Attempt to get a suggestion from not parsed expression");
198
199 let expressions_as_string = self.extracted_expressions.join(", ");
200 format!(r#"{}("{}", {})"#, macro_name, self.output, expressions_as_string)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use expect_test::{expect, Expect};
208
209 fn check(input: &str, expect: &Expect) {
210 let mut parser = FormatStrParser::new((*input).to_owned());
211 let outcome_repr = if parser.parse().is_ok() {
212 // Parsing should be OK, expected repr is "string; expr_1, expr_2".
213 if parser.extracted_expressions.is_empty() {
214 parser.output
215 } else {
216 format!("{}; {}", parser.output, parser.extracted_expressions.join(", "))
217 }
218 } else {
219 // Parsing should fail, expected repr is "-".
220 "-".to_owned()
221 };
222
223 expect.assert_eq(&outcome_repr);
224 }
225
226 #[test]
227 fn format_str_parser() {
228 let test_vector = &[
229 ("no expressions", expect![["no expressions"]]),
230 ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
231 ("{expr:?}", expect![["{:?}; expr"]]),
232 ("{malformed", expect![["-"]]),
233 ("malformed}", expect![["-"]]),
234 ("{{correct", expect![["{{correct"]]),
235 ("correct}}", expect![["correct}}"]]),
236 ("{correct}}}", expect![["{}}}; correct"]]),
237 ("{correct}}}}}", expect![["{}}}}}; correct"]]),
238 ("{incorrect}}", expect![["-"]]),
239 ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
240 ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
241 (
242 "{SomeStruct { val_a: 0, val_b: 1 }}",
243 expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
244 ),
245 ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
246 (
247 "{SomeStruct { val_a: 0, val_b: 1 }:?}",
248 expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
249 ),
250 ("{ 2 + 2 }", expect![["{}; 2 + 2"]]),
251 ];
252
253 for (input, output) in test_vector {
254 check(input, output)
255 }
256 }
257
258 #[test]
259 fn test_into_suggestion() {
260 let test_vector = &[
261 ("println!", "{}", r#"println!("{}", $1)"#),
262 (
263 "log::info!",
264 "{} {expr} {} {2 + 2}",
265 r#"log::info!("{} {} {} {}", $1, expr, $2, 2 + 2)"#,
266 ),
267 ("format!", "{expr:?}", r#"format!("{:?}", expr)"#),
268 ];
269
270 for (kind, input, output) in test_vector {
271 let mut parser = FormatStrParser::new((*input).to_owned());
272 parser.parse().expect("Parsing must succeed");
273
274 assert_eq!(&parser.into_suggestion(*kind), output);
275 }
276 }
277}
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/ide/src/completion/complete_qualified_path.rs
index 00e89f0fd..2fafedd47 100644
--- a/crates/ide/src/completion/complete_qualified_path.rs
+++ b/crates/ide/src/completion/complete_qualified_path.rs
@@ -422,10 +422,10 @@ fn foo() { let _ = U::<|> }
422 fn completes_use_paths_across_crates() { 422 fn completes_use_paths_across_crates() {
423 check( 423 check(
424 r#" 424 r#"
425//- /main.rs 425//- /main.rs crate:main deps:foo
426use foo::<|>; 426use foo::<|>;
427 427
428//- /foo/lib.rs 428//- /foo/lib.rs crate:foo
429pub mod bar { pub struct S; } 429pub mod bar { pub struct S; }
430"#, 430"#,
431 expect![[r#" 431 expect![[r#"
diff --git a/crates/ide/src/completion/complete_unqualified_path.rs b/crates/ide/src/completion/complete_unqualified_path.rs
index 8eda4b64d..8b6757195 100644
--- a/crates/ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ide/src/completion/complete_unqualified_path.rs
@@ -267,14 +267,34 @@ fn quux() { <|> }
267 ); 267 );
268 } 268 }
269 269
270 /// Regression test for issue #6091.
271 #[test]
272 fn correctly_completes_module_items_prefixed_with_underscore() {
273 check_edit(
274 "_alpha",
275 r#"
276fn main() {
277 _<|>
278}
279fn _alpha() {}
280"#,
281 r#"
282fn main() {
283 _alpha()$0
284}
285fn _alpha() {}
286"#,
287 )
288 }
289
270 #[test] 290 #[test]
271 fn completes_extern_prelude() { 291 fn completes_extern_prelude() {
272 check( 292 check(
273 r#" 293 r#"
274//- /lib.rs 294//- /lib.rs crate:main deps:other_crate
275use <|>; 295use <|>;
276 296
277//- /other_crate/lib.rs 297//- /other_crate/lib.rs crate:other_crate
278// nothing here 298// nothing here
279"#, 299"#,
280 expect![[r#" 300 expect![[r#"
@@ -350,10 +370,10 @@ fn foo() {
350 fn completes_prelude() { 370 fn completes_prelude() {
351 check( 371 check(
352 r#" 372 r#"
353//- /main.rs 373//- /main.rs crate:main deps:std
354fn foo() { let x: <|> } 374fn foo() { let x: <|> }
355 375
356//- /std/lib.rs 376//- /std/lib.rs crate:std
357#[prelude_import] 377#[prelude_import]
358use prelude::*; 378use prelude::*;
359 379
@@ -371,16 +391,16 @@ mod prelude { struct Option; }
371 fn completes_std_prelude_if_core_is_defined() { 391 fn completes_std_prelude_if_core_is_defined() {
372 check( 392 check(
373 r#" 393 r#"
374//- /main.rs 394//- /main.rs crate:main deps:core,std
375fn foo() { let x: <|> } 395fn foo() { let x: <|> }
376 396
377//- /core/lib.rs 397//- /core/lib.rs crate:core
378#[prelude_import] 398#[prelude_import]
379use prelude::*; 399use prelude::*;
380 400
381mod prelude { struct Option; } 401mod prelude { struct Option; }
382 402
383//- /std/lib.rs 403//- /std/lib.rs crate:std deps:core
384#[prelude_import] 404#[prelude_import]
385use prelude::*; 405use prelude::*;
386 406
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index 671b13328..8dea8a4bf 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -221,10 +221,11 @@ impl<'a> CompletionContext<'a> {
221 Some(ctx) 221 Some(ctx)
222 } 222 }
223 223
224 // The range of the identifier that is being completed. 224 /// The range of the identifier that is being completed.
225 pub(crate) fn source_range(&self) -> TextRange { 225 pub(crate) fn source_range(&self) -> TextRange {
226 // check kind of macro-expanded token, but use range of original token 226 // check kind of macro-expanded token, but use range of original token
227 if self.token.kind() == IDENT || self.token.kind().is_keyword() { 227 let kind = self.token.kind();
228 if kind == IDENT || kind == UNDERSCORE || kind.is_keyword() {
228 mark::hit!(completes_if_prefix_is_keyword); 229 mark::hit!(completes_if_prefix_is_keyword);
229 self.original_token.text_range() 230 self.original_token.text_range()
230 } else { 231 } else {
@@ -469,7 +470,7 @@ impl<'a> CompletionContext<'a> {
469 } 470 }
470 } else { 471 } else {
471 false 472 false
472 } 473 };
473 } 474 }
474 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 475 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
475 // As above 476 // As above
diff --git a/crates/ide/src/completion/presentation.rs b/crates/ide/src/completion/presentation.rs
index 987cbfa7a..a5172b87e 100644
--- a/crates/ide/src/completion/presentation.rs
+++ b/crates/ide/src/completion/presentation.rs
@@ -1172,9 +1172,9 @@ fn foo(xs: Vec<i128>)
1172 check_edit( 1172 check_edit(
1173 "frobnicate!", 1173 "frobnicate!",
1174 r#" 1174 r#"
1175//- /main.rs 1175//- /main.rs crate:main deps:foo
1176use foo::<|>; 1176use foo::<|>;
1177//- /foo/lib.rs 1177//- /foo/lib.rs crate:foo
1178#[macro_export] 1178#[macro_export]
1179macro_rules frobnicate { () => () } 1179macro_rules frobnicate { () => () }
1180"#, 1180"#,
diff --git a/crates/ide/src/completion/test_utils.rs b/crates/ide/src/completion/test_utils.rs
index 1452d7e9e..feb8cd2a6 100644
--- a/crates/ide/src/completion/test_utils.rs
+++ b/crates/ide/src/completion/test_utils.rs
@@ -8,8 +8,7 @@ use test_utils::assert_eq_text;
8 8
9use crate::{ 9use crate::{
10 completion::{completion_item::CompletionKind, CompletionConfig}, 10 completion::{completion_item::CompletionKind, CompletionConfig},
11 mock_analysis::analysis_and_position, 11 fixture, CompletionItem,
12 CompletionItem,
13}; 12};
14 13
15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 14pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
@@ -80,7 +79,7 @@ pub(crate) fn check_edit_with_config(
80 ra_fixture_after: &str, 79 ra_fixture_after: &str,
81) { 80) {
82 let ra_fixture_after = trim_indent(ra_fixture_after); 81 let ra_fixture_after = trim_indent(ra_fixture_after);
83 let (analysis, position) = analysis_and_position(ra_fixture_before); 82 let (analysis, position) = fixture::position(ra_fixture_before);
84 let completions: Vec<CompletionItem> = 83 let completions: Vec<CompletionItem> =
85 analysis.completions(&config, position).unwrap().unwrap().into(); 84 analysis.completions(&config, position).unwrap().unwrap().into();
86 let (completion,) = completions 85 let (completion,) = completions
@@ -94,7 +93,7 @@ pub(crate) fn check_edit_with_config(
94} 93}
95 94
96pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) { 95pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
97 let (analysis, pos) = analysis_and_position(code); 96 let (analysis, pos) = fixture::position(code);
98 analysis 97 analysis
99 .with_db(|db| { 98 .with_db(|db| {
100 let sema = Semantics::new(db); 99 let sema = Semantics::new(db);
@@ -109,6 +108,6 @@ pub(crate) fn get_all_completion_items(
109 config: CompletionConfig, 108 config: CompletionConfig,
110 code: &str, 109 code: &str,
111) -> Vec<CompletionItem> { 110) -> Vec<CompletionItem> {
112 let (analysis, position) = analysis_and_position(code); 111 let (analysis, position) = fixture::position(code);
113 analysis.completions(&config, position).unwrap().unwrap().into() 112 analysis.completions(&config, position).unwrap().unwrap().into()
114} 113}