aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs25
-rw-r--r--crates/ra_assists/src/handlers/add_turbo_fish.rs29
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs16
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs210
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs158
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs2
6 files changed, 225 insertions, 215 deletions
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index d6aaf53f1..f185e61e5 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -158,6 +158,9 @@ fn add_missing_impl_members_inner(
158 .map(|it| ast_transform::apply(&*ast_transform, it)) 158 .map(|it| ast_transform::apply(&*ast_transform, it))
159 .map(|it| match it { 159 .map(|it| match it {
160 ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)), 160 ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)),
161 ast::AssocItem::TypeAliasDef(def) => {
162 ast::AssocItem::TypeAliasDef(def.remove_bounds())
163 }
161 _ => it, 164 _ => it,
162 }) 165 })
163 .map(|it| edit::remove_attrs_and_docs(&it)); 166 .map(|it| edit::remove_attrs_and_docs(&it));
@@ -684,4 +687,26 @@ impl Foo<T> for S<T> {
684}"#, 687}"#,
685 ) 688 )
686 } 689 }
690
691 #[test]
692 fn test_assoc_type_bounds_are_removed() {
693 check_assist(
694 add_missing_impl_members,
695 r#"
696trait Tr {
697 type Ty: Copy + 'static;
698}
699
700impl Tr for ()<|> {
701}"#,
702 r#"
703trait Tr {
704 type Ty: Copy + 'static;
705}
706
707impl Tr for () {
708 $0type Ty;
709}"#,
710 )
711 }
687} 712}
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs
index f7e1a7b05..0c565e89a 100644
--- a/crates/ra_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs
@@ -25,7 +25,14 @@ use crate::{
25// } 25// }
26// ``` 26// ```
27pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 27pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; 28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT).or_else(|| {
29 let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
30 if arg_list.args().count() > 0 {
31 return None;
32 }
33 mark::hit!(add_turbo_fish_after_call);
34 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
35 })?;
29 let next_token = ident.next_token()?; 36 let next_token = ident.next_token()?;
30 if next_token.kind() == T![::] { 37 if next_token.kind() == T![::] {
31 mark::hit!(add_turbo_fish_one_fish_is_enough); 38 mark::hit!(add_turbo_fish_one_fish_is_enough);
@@ -83,6 +90,26 @@ fn main() {
83 } 90 }
84 91
85 #[test] 92 #[test]
93 fn add_turbo_fish_after_call() {
94 mark::check!(add_turbo_fish_after_call);
95 check_assist(
96 add_turbo_fish,
97 r#"
98fn make<T>() -> T {}
99fn main() {
100 make()<|>;
101}
102"#,
103 r#"
104fn make<T>() -> T {}
105fn main() {
106 make::<${0:_}>();
107}
108"#,
109 );
110 }
111
112 #[test]
86 fn add_turbo_fish_method() { 113 fn add_turbo_fish_method() {
87 check_assist( 114 check_assist(
88 add_turbo_fish, 115 add_turbo_fish,
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 703ee2143..4343b423c 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -1,7 +1,9 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY}, 4 SyntaxKind::{
5 CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STATIC_DEF, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
6 },
5 T, 7 T,
6}; 8};
7use test_utils::mark; 9use test_utils::mark;
@@ -28,12 +30,15 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
28 30
29fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let item_keyword = ctx.token_at_offset().find(|leaf| { 32 let item_keyword = ctx.token_at_offset().find(|leaf| {
31 matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]) 33 matches!(
34 leaf.kind(),
35 T![const] | T![static] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]
36 )
32 }); 37 });
33 38
34 let (offset, target) = if let Some(keyword) = item_keyword { 39 let (offset, target) = if let Some(keyword) = item_keyword {
35 let parent = keyword.parent(); 40 let parent = keyword.parent();
36 let def_kws = vec![CONST_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 41 let def_kws = vec![CONST_DEF, STATIC_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
37 // Parent is not a definition, can't add visibility 42 // Parent is not a definition, can't add visibility
38 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 43 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
39 return None; 44 return None;
@@ -152,6 +157,11 @@ mod tests {
152 } 157 }
153 158
154 #[test] 159 #[test]
160 fn change_visibility_static() {
161 check_assist(change_visibility, "<|>static FOO = 3u8;", "pub(crate) static FOO = 3u8;");
162 }
163
164 #[test]
155 fn change_visibility_handles_comment_attrs() { 165 fn change_visibility_handles_comment_attrs() {
156 check_assist( 166 check_assist(
157 change_visibility, 167 change_visibility,
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 511355e07..708e1bc6c 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -115,11 +115,19 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
115 let old_range = match_arm_list.syntax().text_range(); 115 let old_range = match_arm_list.syntax().text_range();
116 match (first_new_arm, ctx.config.snippet_cap) { 116 match (first_new_arm, ctx.config.snippet_cap) {
117 (Some(first_new_arm), Some(cap)) => { 117 (Some(first_new_arm), Some(cap)) => {
118 let snippet = render_snippet( 118 let extend_lifetime;
119 cap, 119 let cursor = match first_new_arm
120 new_arm_list.syntax(), 120 .syntax()
121 Cursor::Before(first_new_arm.syntax()), 121 .descendants()
122 ); 122 .find_map(ast::PlaceholderPat::cast)
123 {
124 Some(it) => {
125 extend_lifetime = it.syntax().clone();
126 Cursor::Replace(&extend_lifetime)
127 }
128 None => Cursor::Before(first_new_arm.syntax()),
129 };
130 let snippet = render_snippet(cap, new_arm_list.syntax(), cursor);
123 builder.replace_snippet(cap, old_range, snippet); 131 builder.replace_snippet(cap, old_range, snippet);
124 } 132 }
125 _ => builder.replace(old_range, new_arm_list.to_string()), 133 _ => builder.replace(old_range, new_arm_list.to_string()),
@@ -291,30 +299,22 @@ mod tests {
291 check_assist( 299 check_assist(
292 fill_match_arms, 300 fill_match_arms,
293 r#" 301 r#"
294 enum A { 302enum A { As, Bs, Cs(Option<i32>) }
295 As, 303fn main() {
296 Bs, 304 match A::As<|> {
297 Cs(Option<i32>), 305 A::Cs(_) | A::Bs => {}
298 } 306 }
299 fn main() { 307}
300 match A::As<|> { 308"#,
301 A::Cs(_) | A::Bs => {}
302 }
303 }
304 "#,
305 r#" 309 r#"
306 enum A { 310enum A { As, Bs, Cs(Option<i32>) }
307 As, 311fn main() {
308 Bs, 312 match A::As {
309 Cs(Option<i32>), 313 A::Cs(_) | A::Bs => {}
310 } 314 $0A::As => {}
311 fn main() { 315 }
312 match A::As { 316}
313 A::Cs(_) | A::Bs => {} 317"#,
314 $0A::As => {}
315 }
316 }
317 "#,
318 ); 318 );
319 } 319 }
320 320
@@ -323,47 +323,29 @@ mod tests {
323 check_assist( 323 check_assist(
324 fill_match_arms, 324 fill_match_arms,
325 r#" 325 r#"
326 enum A { 326enum A { As, Bs, Cs, Ds(String), Es(B) }
327 As, 327enum B { Xs, Ys }
328 Bs, 328fn main() {
329 Cs, 329 match A::As<|> {
330 Ds(String), 330 A::Bs if 0 < 1 => {}
331 Es(B), 331 A::Ds(_value) => { let x = 1; }
332 } 332 A::Es(B::Xs) => (),
333 enum B { 333 }
334 Xs, 334}
335 Ys, 335"#,
336 }
337 fn main() {
338 match A::As<|> {
339 A::Bs if 0 < 1 => {}
340 A::Ds(_value) => { let x = 1; }
341 A::Es(B::Xs) => (),
342 }
343 }
344 "#,
345 r#" 336 r#"
346 enum A { 337enum A { As, Bs, Cs, Ds(String), Es(B) }
347 As, 338enum B { Xs, Ys }
348 Bs, 339fn main() {
349 Cs, 340 match A::As {
350 Ds(String), 341 A::Bs if 0 < 1 => {}
351 Es(B), 342 A::Ds(_value) => { let x = 1; }
352 } 343 A::Es(B::Xs) => (),
353 enum B { 344 $0A::As => {}
354 Xs, 345 A::Cs => {}
355 Ys, 346 }
356 } 347}
357 fn main() { 348"#,
358 match A::As {
359 A::Bs if 0 < 1 => {}
360 A::Ds(_value) => { let x = 1; }
361 A::Es(B::Xs) => (),
362 $0A::As => {}
363 A::Cs => {}
364 }
365 }
366 "#,
367 ); 349 );
368 } 350 }
369 351
@@ -372,32 +354,24 @@ mod tests {
372 check_assist( 354 check_assist(
373 fill_match_arms, 355 fill_match_arms,
374 r#" 356 r#"
375 enum A { 357enum A { As, Bs, Cs(Option<i32>) }
376 As, 358fn main() {
377 Bs, 359 match A::As<|> {
378 Cs(Option<i32>), 360 A::As(_) => {}
379 } 361 a @ A::Bs(_) => {}
380 fn main() { 362 }
381 match A::As<|> { 363}
382 A::As(_) => {} 364"#,
383 a @ A::Bs(_) => {}
384 }
385 }
386 "#,
387 r#" 365 r#"
388 enum A { 366enum A { As, Bs, Cs(Option<i32>) }
389 As, 367fn main() {
390 Bs, 368 match A::As {
391 Cs(Option<i32>), 369 A::As(_) => {}
392 } 370 a @ A::Bs(_) => {}
393 fn main() { 371 A::Cs(${0:_}) => {}
394 match A::As { 372 }
395 A::As(_) => {} 373}
396 a @ A::Bs(_) => {} 374"#,
397 $0A::Cs(_) => {}
398 }
399 }
400 "#,
401 ); 375 );
402 } 376 }
403 377
@@ -406,39 +380,27 @@ mod tests {
406 check_assist( 380 check_assist(
407 fill_match_arms, 381 fill_match_arms,
408 r#" 382 r#"
409 enum A { 383enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
410 As,
411 Bs,
412 Cs(String),
413 Ds(String, String),
414 Es { x: usize, y: usize }
415 }
416 384
417 fn main() { 385fn main() {
418 let a = A::As; 386 let a = A::As;
419 match a<|> {} 387 match a<|> {}
420 } 388}
421 "#, 389"#,
422 r#" 390 r#"
423 enum A { 391enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
424 As,
425 Bs,
426 Cs(String),
427 Ds(String, String),
428 Es { x: usize, y: usize }
429 }
430 392
431 fn main() { 393fn main() {
432 let a = A::As; 394 let a = A::As;
433 match a { 395 match a {
434 $0A::As => {} 396 $0A::As => {}
435 A::Bs => {} 397 A::Bs => {}
436 A::Cs(_) => {} 398 A::Cs(_) => {}
437 A::Ds(_, _) => {} 399 A::Ds(_, _) => {}
438 A::Es { x, y } => {} 400 A::Es { x, y } => {}
439 } 401 }
440 } 402}
441 "#, 403"#,
442 ); 404 );
443 } 405 }
444 406
@@ -778,7 +740,7 @@ fn foo(opt: Option<i32>) {
778 r#" 740 r#"
779fn foo(opt: Option<i32>) { 741fn foo(opt: Option<i32>) {
780 match opt { 742 match opt {
781 $0Some(_) => {} 743 Some(${0:_}) => {}
782 None => {} 744 None => {}
783 } 745 }
784} 746}
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index 96679e160..4e8a0c2db 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -1,9 +1,12 @@
1use std::borrow::Cow;
2
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, HasStringValue}, 4 ast::{self, HasQuotes, HasStringValue},
3 AstToken, 5 AstToken,
4 SyntaxKind::{RAW_STRING, STRING}, 6 SyntaxKind::{RAW_STRING, STRING},
5 TextSize, 7 TextRange, TextSize,
6}; 8};
9use test_utils::mark;
7 10
8use crate::{AssistContext, AssistId, AssistKind, Assists}; 11use crate::{AssistContext, AssistId, AssistKind, Assists};
9 12
@@ -31,15 +34,17 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<
31 "Rewrite as raw string", 34 "Rewrite as raw string",
32 target, 35 target,
33 |edit| { 36 |edit| {
34 let max_hash_streak = count_hashes(&value); 37 let hashes = "#".repeat(required_hashes(&value).max(1));
35 let mut hashes = String::with_capacity(max_hash_streak + 1); 38 if matches!(value, Cow::Borrowed(_)) {
36 for _ in 0..hashes.capacity() { 39 // Avoid replacing the whole string to better position the cursor.
37 hashes.push('#'); 40 edit.insert(token.syntax().text_range().start(), format!("r{}", hashes));
41 edit.insert(token.syntax().text_range().end(), format!("{}", hashes));
42 } else {
43 edit.replace(
44 token.syntax().text_range(),
45 format!("r{}\"{}\"{}", hashes, value, hashes),
46 );
38 } 47 }
39 edit.replace(
40 token.syntax().text_range(),
41 format!("r{}\"{}\"{}", hashes, value, hashes),
42 );
43 }, 48 },
44 ) 49 )
45} 50}
@@ -70,6 +75,14 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio
70 |edit| { 75 |edit| {
71 // parse inside string to escape `"` 76 // parse inside string to escape `"`
72 let escaped = value.escape_default().to_string(); 77 let escaped = value.escape_default().to_string();
78 if let Some(offsets) = token.quote_offsets() {
79 if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped {
80 edit.replace(offsets.quotes.0, "\"");
81 edit.replace(offsets.quotes.1, "\"");
82 return;
83 }
84 }
85
73 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); 86 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
74 }, 87 },
75 ) 88 )
@@ -93,7 +106,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio
93pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 106pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
94 let token = ctx.find_token_at_offset(RAW_STRING)?; 107 let token = ctx.find_token_at_offset(RAW_STRING)?;
95 let target = token.text_range(); 108 let target = token.text_range();
96 acc.add(AssistId("add_hash", AssistKind::Refactor), "Add # to raw string", target, |edit| { 109 acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| {
97 edit.insert(token.text_range().start() + TextSize::of('r'), "#"); 110 edit.insert(token.text_range().start() + TextSize::of('r'), "#");
98 edit.insert(token.text_range().end(), "#"); 111 edit.insert(token.text_range().end(), "#");
99 }) 112 })
@@ -115,49 +128,58 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
115// } 128// }
116// ``` 129// ```
117pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 130pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
118 let token = ctx.find_token_at_offset(RAW_STRING)?; 131 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
132
119 let text = token.text().as_str(); 133 let text = token.text().as_str();
120 if text.starts_with("r\"") { 134 if !text.starts_with("r#") && text.ends_with('#') {
121 // no hash to remove
122 return None; 135 return None;
123 } 136 }
124 let target = token.text_range(); 137
125 acc.add( 138 let existing_hashes = text.chars().skip(1).take_while(|&it| it == '#').count();
126 AssistId("remove_hash", AssistKind::RefactorRewrite), 139
127 "Remove hash from raw string", 140 let text_range = token.syntax().text_range();
128 target, 141 let internal_text = &text[token.text_range_between_quotes()? - text_range.start()];
129 |edit| { 142
130 let result = &text[2..text.len() - 1]; 143 if existing_hashes == required_hashes(internal_text) {
131 let result = if result.starts_with('\"') { 144 mark::hit!(cant_remove_required_hash);
132 // FIXME: this logic is wrong, not only the last has has to handled specially 145 return None;
133 // no more hash, escape 146 }
134 let internal_str = &result[1..result.len() - 1]; 147
135 format!("\"{}\"", internal_str.escape_default().to_string()) 148 acc.add(AssistId("remove_hash", AssistKind::RefactorRewrite), "Remove #", text_range, |edit| {
136 } else { 149 edit.delete(TextRange::at(text_range.start() + TextSize::of('r'), TextSize::of('#')));
137 result.to_owned() 150 edit.delete(TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()));
138 }; 151 })
139 edit.replace(token.text_range(), format!("r{}", result));
140 },
141 )
142} 152}
143 153
144fn count_hashes(s: &str) -> usize { 154fn required_hashes(s: &str) -> usize {
145 let mut max_hash_streak = 0usize; 155 let mut res = 0usize;
146 for idx in s.match_indices("\"#").map(|(i, _)| i) { 156 for idx in s.match_indices('"').map(|(i, _)| i) {
147 let (_, sub) = s.split_at(idx + 1); 157 let (_, sub) = s.split_at(idx + 1);
148 let nb_hash = sub.chars().take_while(|c| *c == '#').count(); 158 let n_hashes = sub.chars().take_while(|c| *c == '#').count();
149 if nb_hash > max_hash_streak { 159 res = res.max(n_hashes + 1)
150 max_hash_streak = nb_hash;
151 }
152 } 160 }
153 max_hash_streak 161 res
162}
163
164#[test]
165fn test_required_hashes() {
166 assert_eq!(0, required_hashes("abc"));
167 assert_eq!(0, required_hashes("###"));
168 assert_eq!(1, required_hashes("\""));
169 assert_eq!(2, required_hashes("\"#abc"));
170 assert_eq!(0, required_hashes("#abc"));
171 assert_eq!(3, required_hashes("#ab\"##c"));
172 assert_eq!(5, required_hashes("#ab\"##\"####c"));
154} 173}
155 174
156#[cfg(test)] 175#[cfg(test)]
157mod test { 176mod test {
158 use super::*; 177 use test_utils::mark;
178
159 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 179 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
160 180
181 use super::*;
182
161 #[test] 183 #[test]
162 fn make_raw_string_target() { 184 fn make_raw_string_target() {
163 check_assist_target( 185 check_assist_target(
@@ -359,33 +381,21 @@ string"###;
359 fn remove_hash_works() { 381 fn remove_hash_works() {
360 check_assist( 382 check_assist(
361 remove_hash, 383 remove_hash,
362 r##" 384 r##"fn f() { let s = <|>r#"random string"#; }"##,
363 fn f() { 385 r#"fn f() { let s = r"random string"; }"#,
364 let s = <|>r#"random string"#;
365 }
366 "##,
367 r#"
368 fn f() {
369 let s = r"random string";
370 }
371 "#,
372 ) 386 )
373 } 387 }
374 388
375 #[test] 389 #[test]
376 fn remove_hash_with_quote_works() { 390 fn cant_remove_required_hash() {
377 check_assist( 391 mark::check!(cant_remove_required_hash);
392 check_assist_not_applicable(
378 remove_hash, 393 remove_hash,
379 r##" 394 r##"
380 fn f() { 395 fn f() {
381 let s = <|>r#"random"str"ing"#; 396 let s = <|>r#"random"str"ing"#;
382 } 397 }
383 "##, 398 "##,
384 r#"
385 fn f() {
386 let s = r"random\"str\"ing";
387 }
388 "#,
389 ) 399 )
390 } 400 }
391 401
@@ -407,27 +417,13 @@ string"###;
407 } 417 }
408 418
409 #[test] 419 #[test]
410 fn remove_hash_not_works() { 420 fn remove_hash_doesnt_work() {
411 check_assist_not_applicable( 421 check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>"random string"; }"#);
412 remove_hash,
413 r#"
414 fn f() {
415 let s = <|>"random string";
416 }
417 "#,
418 );
419 } 422 }
420 423
421 #[test] 424 #[test]
422 fn remove_hash_no_hash_not_works() { 425 fn remove_hash_no_hash_doesnt_work() {
423 check_assist_not_applicable( 426 check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>r"random string"; }"#);
424 remove_hash,
425 r#"
426 fn f() {
427 let s = <|>r"random string";
428 }
429 "#,
430 );
431 } 427 }
432 428
433 #[test] 429 #[test]
@@ -505,14 +501,4 @@ string"###;
505 "#, 501 "#,
506 ); 502 );
507 } 503 }
508
509 #[test]
510 fn count_hashes_test() {
511 assert_eq!(0, count_hashes("abc"));
512 assert_eq!(0, count_hashes("###"));
513 assert_eq!(1, count_hashes("\"#abc"));
514 assert_eq!(0, count_hashes("#abc"));
515 assert_eq!(2, count_hashes("#ab\"##c"));
516 assert_eq!(4, count_hashes("#ab\"##\"####c"));
517 }
518} 504}
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index dfd314abf..3d51faa54 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -106,7 +106,7 @@ fn maybe_replace_path(
106 path: ast::Path, 106 path: ast::Path,
107 target: ast::Path, 107 target: ast::Path,
108) -> Option<()> { 108) -> Option<()> {
109 if !path_eq(path.clone(), target.clone()) { 109 if !path_eq(path.clone(), target) {
110 return None; 110 return None;
111 } 111 }
112 112