aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_assists/Cargo.toml1
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs110
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs11
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt97
-rw-r--r--docs/user/README.md2
-rw-r--r--docs/user/features.md7
10 files changed, 259 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a5a43cffc..e9383a89a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -904,6 +904,7 @@ dependencies = [
904 "ra_syntax 0.1.0", 904 "ra_syntax 0.1.0",
905 "ra_text_edit 0.1.0", 905 "ra_text_edit 0.1.0",
906 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 906 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
907 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
907 "test_utils 0.1.0", 908 "test_utils 0.1.0",
908] 909]
909 910
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"
11itertools = "0.8.0" 11itertools = "0.8.0"
12arrayvec = "0.4.10" 12arrayvec = "0.4.10"
13rustc-hash = "1.0.1" 13rustc-hash = "1.0.1"
14rustc_lexer = "0.1.0"
14 15
15ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
16ra_text_edit = { path = "../ra_text_edit" } 17ra_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
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
5use rustc_lexer;
5 6
6use crate::{Assist, AssistCtx, AssistId}; 7use 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
47fn 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
20fn find_usual_string_range(s: &str) -> Option<TextRange> { 59fn 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
155string"#;
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##
173string"#;
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"##
191string"###;
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 @@
1fn 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 @@
1SOURCE_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 @@
1fn 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 @@
1SOURCE_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"
diff --git a/docs/user/README.md b/docs/user/README.md
index 44d6ee739..036b51d58 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -45,7 +45,7 @@ should adapt these manual installation instructions:
45``` 45```
46$ git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1 46$ git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1
47$ cd rust-analyzer 47$ cd rust-analyzer
48$ cargo install --path ./crates/ra_lsp_server/ --force 48$ cargo install --path ./crates/ra_lsp_server/ --force --locked
49$ cd ./editors/code 49$ cd ./editors/code
50$ npm install 50$ npm install
51$ ./node_modules/vsce/out/vsce package 51$ ./node_modules/vsce/out/vsce package
diff --git a/docs/user/features.md b/docs/user/features.md
index 757a02838..8b7a8d7fc 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -459,17 +459,18 @@ fn foo<T: u32, F: FnOnce(T) -> T>() {}
459fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} 459fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
460``` 460```
461 461
462- Make raw string 462- Make raw string unescaped
463 463
464```rust 464```rust
465// before: 465// before:
466fn f() { 466fn f() {
467 let s = <|>"abcd"; 467 let s = <|>"ab\ncd";
468} 468}
469 469
470// after: 470// after:
471fn f() { 471fn f() {
472 let s = <|>r"abcd"; 472 let s = <|>r#"ab
473cd"#;
473} 474}
474``` 475```
475 476