diff options
Diffstat (limited to 'crates')
7 files changed, 253 insertions, 19 deletions
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 02966bbda..d3b6aeb36 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -11,6 +11,7 @@ join_to_string = "0.1.3" | |||
11 | itertools = "0.8.0" | 11 | itertools = "0.8.0" |
12 | arrayvec = "0.4.10" | 12 | arrayvec = "0.4.10" |
13 | rustc-hash = "1.0.1" | 13 | rustc-hash = "1.0.1" |
14 | rustc_lexer = "0.1.0" | ||
14 | 15 | ||
15 | ra_syntax = { path = "../ra_syntax" } | 16 | ra_syntax = { path = "../ra_syntax" } |
16 | ra_text_edit = { path = "../ra_text_edit" } | 17 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 388ee7e97..2d2e31e51 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | 4 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; |
5 | use rustc_lexer; | ||
5 | 6 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{Assist, AssistCtx, AssistId}; |
7 | 8 | ||
@@ -10,13 +11,51 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
10 | if literal.token().kind() != ra_syntax::SyntaxKind::STRING { | 11 | if literal.token().kind() != ra_syntax::SyntaxKind::STRING { |
11 | return None; | 12 | return None; |
12 | } | 13 | } |
14 | let token = literal.token(); | ||
15 | let text = token.text().as_str(); | ||
16 | let usual_string_range = find_usual_string_range(text)?; | ||
17 | let start_of_inside = usual_string_range.start().to_usize() + 1; | ||
18 | let end_of_inside = usual_string_range.end().to_usize(); | ||
19 | let inside_str = &text[start_of_inside..end_of_inside]; | ||
20 | let mut unescaped = String::with_capacity(inside_str.len()); | ||
21 | let mut error = Ok(()); | ||
22 | rustc_lexer::unescape::unescape_str( | ||
23 | inside_str, | ||
24 | &mut |_, unescaped_char| match unescaped_char { | ||
25 | Ok(c) => unescaped.push(c), | ||
26 | Err(_) => error = Err(()), | ||
27 | }, | ||
28 | ); | ||
29 | if error.is_err() { | ||
30 | return None; | ||
31 | } | ||
13 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { | 32 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { |
14 | edit.target(literal.syntax().text_range()); | 33 | edit.target(literal.syntax().text_range()); |
15 | edit.insert(literal.syntax().text_range().start(), "r"); | 34 | let max_hash_streak = count_hashes(&unescaped); |
35 | let mut hashes = String::with_capacity(max_hash_streak + 1); | ||
36 | for _ in 0..hashes.capacity() { | ||
37 | hashes.push('#'); | ||
38 | } | ||
39 | edit.replace( | ||
40 | literal.syntax().text_range(), | ||
41 | format!("r{}\"{}\"{}", hashes, unescaped, hashes), | ||
42 | ); | ||
16 | }); | 43 | }); |
17 | ctx.build() | 44 | ctx.build() |
18 | } | 45 | } |
19 | 46 | ||
47 | fn count_hashes(s: &str) -> usize { | ||
48 | let mut max_hash_streak = 0usize; | ||
49 | for idx in s.match_indices("\"#").map(|(i, _)| i) { | ||
50 | let (_, sub) = s.split_at(idx + 1); | ||
51 | let nb_hash = sub.chars().take_while(|c| *c == '#').count(); | ||
52 | if nb_hash > max_hash_streak { | ||
53 | max_hash_streak = nb_hash; | ||
54 | } | ||
55 | } | ||
56 | max_hash_streak | ||
57 | } | ||
58 | |||
20 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | 59 | fn find_usual_string_range(s: &str) -> Option<TextRange> { |
21 | Some(TextRange::from_to( | 60 | Some(TextRange::from_to( |
22 | TextUnit::from(s.find('"')? as u32), | 61 | TextUnit::from(s.find('"')? as u32), |
@@ -94,10 +133,10 @@ mod test { | |||
94 | make_raw_string, | 133 | make_raw_string, |
95 | r#" | 134 | r#" |
96 | fn f() { | 135 | fn f() { |
97 | let s = <|>"random string"; | 136 | let s = <|>"random\nstring"; |
98 | } | 137 | } |
99 | "#, | 138 | "#, |
100 | r#""random string""#, | 139 | r#""random\nstring""#, |
101 | ); | 140 | ); |
102 | } | 141 | } |
103 | 142 | ||
@@ -107,44 +146,69 @@ mod test { | |||
107 | make_raw_string, | 146 | make_raw_string, |
108 | r#" | 147 | r#" |
109 | fn f() { | 148 | fn f() { |
110 | let s = <|>"random string"; | 149 | let s = <|>"random\nstring"; |
111 | } | 150 | } |
112 | "#, | 151 | "#, |
113 | r#" | 152 | r##" |
114 | fn f() { | 153 | fn f() { |
115 | let s = <|>r"random string"; | 154 | let s = <|>r#"random |
155 | string"#; | ||
116 | } | 156 | } |
117 | "#, | 157 | "##, |
118 | ) | 158 | ) |
119 | } | 159 | } |
120 | 160 | ||
121 | #[test] | 161 | #[test] |
122 | fn make_raw_string_with_escaped_works() { | 162 | fn make_raw_string_hashes_inside_works() { |
123 | check_assist( | 163 | check_assist( |
124 | make_raw_string, | 164 | make_raw_string, |
125 | r#" | 165 | r###" |
126 | fn f() { | 166 | fn f() { |
127 | let s = <|>"random\nstring"; | 167 | let s = <|>"#random##\nstring"; |
128 | } | 168 | } |
129 | "#, | 169 | "###, |
130 | r#" | 170 | r####" |
131 | fn f() { | 171 | fn f() { |
132 | let s = <|>r"random\nstring"; | 172 | let s = <|>r#"#random## |
173 | string"#; | ||
133 | } | 174 | } |
134 | "#, | 175 | "####, |
135 | ) | 176 | ) |
136 | } | 177 | } |
137 | 178 | ||
138 | #[test] | 179 | #[test] |
139 | fn make_raw_string_not_works() { | 180 | fn make_raw_string_closing_hashes_inside_works() { |
140 | check_assist_not_applicable( | 181 | check_assist( |
182 | make_raw_string, | ||
183 | r###" | ||
184 | fn f() { | ||
185 | let s = <|>"#random\"##\nstring"; | ||
186 | } | ||
187 | "###, | ||
188 | r####" | ||
189 | fn f() { | ||
190 | let s = <|>r###"#random"## | ||
191 | string"###; | ||
192 | } | ||
193 | "####, | ||
194 | ) | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn make_raw_string_nothing_to_unescape_works() { | ||
199 | check_assist( | ||
141 | make_raw_string, | 200 | make_raw_string, |
142 | r#" | 201 | r#" |
143 | fn f() { | 202 | fn f() { |
144 | let s = <|>r"random string"; | 203 | let s = <|>"random string"; |
145 | } | 204 | } |
146 | "#, | 205 | "#, |
147 | ); | 206 | r##" |
207 | fn f() { | ||
208 | let s = <|>r#"random string"#; | ||
209 | } | ||
210 | "##, | ||
211 | ) | ||
148 | } | 212 | } |
149 | 213 | ||
150 | #[test] | 214 | #[test] |
@@ -369,4 +433,14 @@ mod test { | |||
369 | "#, | 433 | "#, |
370 | ); | 434 | ); |
371 | } | 435 | } |
436 | |||
437 | #[test] | ||
438 | fn count_hashes_test() { | ||
439 | assert_eq!(0, count_hashes("abc")); | ||
440 | assert_eq!(0, count_hashes("###")); | ||
441 | assert_eq!(1, count_hashes("\"#abc")); | ||
442 | assert_eq!(0, count_hashes("#abc")); | ||
443 | assert_eq!(2, count_hashes("#ab\"##c")); | ||
444 | assert_eq!(4, count_hashes("#ab\"##\"####c")); | ||
445 | } | ||
372 | } | 446 | } |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 74b23e2f7..45f2e3de4 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -250,6 +250,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) { | |||
250 | T![!] if p.at(T![!=]) => (5, T![!=]), | 250 | T![!] if p.at(T![!=]) => (5, T![!=]), |
251 | T![-] if p.at(T![-=]) => (1, T![-=]), | 251 | T![-] if p.at(T![-=]) => (1, T![-=]), |
252 | T![-] => (10, T![-]), | 252 | T![-] => (10, T![-]), |
253 | T![as] => (12, T![as]), | ||
253 | 254 | ||
254 | _ => NOT_AN_OP | 255 | _ => NOT_AN_OP |
255 | } | 256 | } |
@@ -278,6 +279,14 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, | |||
278 | if op_bp < bp { | 279 | if op_bp < bp { |
279 | break; | 280 | break; |
280 | } | 281 | } |
282 | // test as_precedence | ||
283 | // fn foo() { | ||
284 | // let _ = &1 as *const i32; | ||
285 | // } | ||
286 | if p.at(T![as]) { | ||
287 | lhs = cast_expr(p, lhs); | ||
288 | continue; | ||
289 | } | ||
281 | let m = lhs.precede(p); | 290 | let m = lhs.precede(p); |
282 | p.bump(op); | 291 | p.bump(op); |
283 | 292 | ||
@@ -344,6 +353,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> | |||
344 | )); | 353 | )); |
345 | } | 354 | } |
346 | }; | 355 | }; |
356 | // parse the interior of the unary expression | ||
347 | expr_bp(p, r, 255); | 357 | expr_bp(p, r, 255); |
348 | Some((m.complete(p, kind), BlockLike::NotBlock)) | 358 | Some((m.complete(p, kind), BlockLike::NotBlock)) |
349 | } | 359 | } |
@@ -378,7 +388,6 @@ fn postfix_expr( | |||
378 | } | 388 | } |
379 | }, | 389 | }, |
380 | T![?] => try_expr(p, lhs), | 390 | T![?] => try_expr(p, lhs), |
381 | T![as] => cast_expr(p, lhs), | ||
382 | _ => break, | 391 | _ => break, |
383 | }; | 392 | }; |
384 | allow_calls = true; | 393 | allow_calls = true; |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs new file mode 100644 index 000000000..a06dec1fa --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | fn foo() { | ||
2 | let _ = &1 as *const i32; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt new file mode 100644 index 000000000..9e3767fb7 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | SOURCE_FILE@[0; 43) | ||
2 | FN_DEF@[0; 42) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | R_PAREN@[7; 8) ")" | ||
10 | WHITESPACE@[8; 9) " " | ||
11 | BLOCK_EXPR@[9; 42) | ||
12 | BLOCK@[9; 42) | ||
13 | L_CURLY@[9; 10) "{" | ||
14 | WHITESPACE@[10; 15) "\n " | ||
15 | LET_STMT@[15; 40) | ||
16 | LET_KW@[15; 18) "let" | ||
17 | WHITESPACE@[18; 19) " " | ||
18 | PLACEHOLDER_PAT@[19; 20) | ||
19 | UNDERSCORE@[19; 20) "_" | ||
20 | WHITESPACE@[20; 21) " " | ||
21 | EQ@[21; 22) "=" | ||
22 | WHITESPACE@[22; 23) " " | ||
23 | CAST_EXPR@[23; 39) | ||
24 | REF_EXPR@[23; 25) | ||
25 | AMP@[23; 24) "&" | ||
26 | LITERAL@[24; 25) | ||
27 | INT_NUMBER@[24; 25) "1" | ||
28 | WHITESPACE@[25; 26) " " | ||
29 | AS_KW@[26; 28) "as" | ||
30 | WHITESPACE@[28; 29) " " | ||
31 | POINTER_TYPE@[29; 39) | ||
32 | STAR@[29; 30) "*" | ||
33 | CONST_KW@[30; 35) "const" | ||
34 | WHITESPACE@[35; 36) " " | ||
35 | PATH_TYPE@[36; 39) | ||
36 | PATH@[36; 39) | ||
37 | PATH_SEGMENT@[36; 39) | ||
38 | NAME_REF@[36; 39) | ||
39 | IDENT@[36; 39) "i32" | ||
40 | SEMI@[39; 40) ";" | ||
41 | WHITESPACE@[40; 41) "\n" | ||
42 | R_CURLY@[41; 42) "}" | ||
43 | WHITESPACE@[42; 43) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs new file mode 100644 index 000000000..100fccc64 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs | |||
@@ -0,0 +1,7 @@ | |||
1 | fn foo() { | ||
2 | 1 + *&2 + 3; | ||
3 | *&1 as u64; | ||
4 | *x(1); | ||
5 | &x[1]; | ||
6 | -1..2; | ||
7 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt new file mode 100644 index 000000000..d30cb63ff --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt | |||
@@ -0,0 +1,97 @@ | |||
1 | SOURCE_FILE@[0; 79) | ||
2 | FN_DEF@[0; 78) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | R_PAREN@[7; 8) ")" | ||
10 | WHITESPACE@[8; 9) " " | ||
11 | BLOCK_EXPR@[9; 78) | ||
12 | BLOCK@[9; 78) | ||
13 | L_CURLY@[9; 10) "{" | ||
14 | WHITESPACE@[10; 15) "\n " | ||
15 | EXPR_STMT@[15; 27) | ||
16 | BIN_EXPR@[15; 26) | ||
17 | BIN_EXPR@[15; 22) | ||
18 | LITERAL@[15; 16) | ||
19 | INT_NUMBER@[15; 16) "1" | ||
20 | WHITESPACE@[16; 17) " " | ||
21 | PLUS@[17; 18) "+" | ||
22 | WHITESPACE@[18; 19) " " | ||
23 | PREFIX_EXPR@[19; 22) | ||
24 | STAR@[19; 20) "*" | ||
25 | REF_EXPR@[20; 22) | ||
26 | AMP@[20; 21) "&" | ||
27 | LITERAL@[21; 22) | ||
28 | INT_NUMBER@[21; 22) "2" | ||
29 | WHITESPACE@[22; 23) " " | ||
30 | PLUS@[23; 24) "+" | ||
31 | WHITESPACE@[24; 25) " " | ||
32 | LITERAL@[25; 26) | ||
33 | INT_NUMBER@[25; 26) "3" | ||
34 | SEMI@[26; 27) ";" | ||
35 | WHITESPACE@[27; 32) "\n " | ||
36 | EXPR_STMT@[32; 43) | ||
37 | CAST_EXPR@[32; 42) | ||
38 | PREFIX_EXPR@[32; 35) | ||
39 | STAR@[32; 33) "*" | ||
40 | REF_EXPR@[33; 35) | ||
41 | AMP@[33; 34) "&" | ||
42 | LITERAL@[34; 35) | ||
43 | INT_NUMBER@[34; 35) "1" | ||
44 | WHITESPACE@[35; 36) " " | ||
45 | AS_KW@[36; 38) "as" | ||
46 | WHITESPACE@[38; 39) " " | ||
47 | PATH_TYPE@[39; 42) | ||
48 | PATH@[39; 42) | ||
49 | PATH_SEGMENT@[39; 42) | ||
50 | NAME_REF@[39; 42) | ||
51 | IDENT@[39; 42) "u64" | ||
52 | SEMI@[42; 43) ";" | ||
53 | WHITESPACE@[43; 48) "\n " | ||
54 | EXPR_STMT@[48; 54) | ||
55 | PREFIX_EXPR@[48; 53) | ||
56 | STAR@[48; 49) "*" | ||
57 | CALL_EXPR@[49; 53) | ||
58 | PATH_EXPR@[49; 50) | ||
59 | PATH@[49; 50) | ||
60 | PATH_SEGMENT@[49; 50) | ||
61 | NAME_REF@[49; 50) | ||
62 | IDENT@[49; 50) "x" | ||
63 | ARG_LIST@[50; 53) | ||
64 | L_PAREN@[50; 51) "(" | ||
65 | LITERAL@[51; 52) | ||
66 | INT_NUMBER@[51; 52) "1" | ||
67 | R_PAREN@[52; 53) ")" | ||
68 | SEMI@[53; 54) ";" | ||
69 | WHITESPACE@[54; 59) "\n " | ||
70 | EXPR_STMT@[59; 65) | ||
71 | REF_EXPR@[59; 64) | ||
72 | AMP@[59; 60) "&" | ||
73 | INDEX_EXPR@[60; 64) | ||
74 | PATH_EXPR@[60; 61) | ||
75 | PATH@[60; 61) | ||
76 | PATH_SEGMENT@[60; 61) | ||
77 | NAME_REF@[60; 61) | ||
78 | IDENT@[60; 61) "x" | ||
79 | L_BRACK@[61; 62) "[" | ||
80 | LITERAL@[62; 63) | ||
81 | INT_NUMBER@[62; 63) "1" | ||
82 | R_BRACK@[63; 64) "]" | ||
83 | SEMI@[64; 65) ";" | ||
84 | WHITESPACE@[65; 70) "\n " | ||
85 | EXPR_STMT@[70; 76) | ||
86 | RANGE_EXPR@[70; 75) | ||
87 | PREFIX_EXPR@[70; 72) | ||
88 | MINUS@[70; 71) "-" | ||
89 | LITERAL@[71; 72) | ||
90 | INT_NUMBER@[71; 72) "1" | ||
91 | DOTDOT@[72; 74) ".." | ||
92 | LITERAL@[74; 75) | ||
93 | INT_NUMBER@[74; 75) "2" | ||
94 | SEMI@[75; 76) ";" | ||
95 | WHITESPACE@[76; 77) "\n" | ||
96 | R_CURLY@[77; 78) "}" | ||
97 | WHITESPACE@[78; 79) "\n" | ||