aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-04-30 19:37:35 +0100
committerGitHub <[email protected]>2020-04-30 19:37:35 +0100
commit745bd45ddb2f8b6165ab7eacfd482d8530cab05a (patch)
tree9e36b55112d3ea5f9d913d36597884b82aa87f68
parent861652ffa6b6440a022a353d2e6b9f5ca780d2ec (diff)
parent513a3615f6d462852c0135dc4ac30a2086e25c5a (diff)
Merge #4227
4227: Report invalid, nested, multi-segment crate-paths r=matklad a=djrenren There was a bug in the previous path-validating code that didn't detect multi-segment paths that started with `crate`. ```rust // Successfully reported use foo::{crate}; // BUG: was not being reported use foo::{crate::bar}; ``` This was due to my confusion about path-associativity. That is, the path with no qualifier is the innermost path, not the outermost. I've updated the code with a lot of comments to explain what's going on. This bug was discovered when I found an erroneous `ok` test which I reported here: https://github.com/rust-analyzer/rust-analyzer/issues/4226 This test now fails and has been modified, hopefully in the spirit of the original test, to be correct. Sorry about submitting the bug in the first place! Co-authored-by: John Renner <[email protected]>
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs2
-rw-r--r--crates/ra_syntax/src/validation.rs29
-rw-r--r--crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast113
-rw-r--r--crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast49
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rs2
6 files changed, 116 insertions, 81 deletions
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index e3b991c8c..3a0c7a31a 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -47,7 +47,7 @@ fn use_tree(p: &mut Parser, top_level: bool) {
47 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) 47 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
48 // use {path::from::root}; // Rust 2015 48 // use {path::from::root}; // Rust 2015
49 // use ::{some::arbritrary::path}; // Rust 2015 49 // use ::{some::arbritrary::path}; // Rust 2015
50 // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig 50 // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting
51 T!['{'] => { 51 T!['{'] => {
52 use_tree_list(p); 52 use_tree_list(p);
53 } 53 }
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index a30bc97bb..f0b3dec63 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -236,21 +236,40 @@ fn validate_crate_keyword_in_path_segment(
236 }; 236 };
237 237
238 // Disallow both ::crate and foo::crate 238 // Disallow both ::crate and foo::crate
239 let path = segment.parent_path(); 239 let mut path = segment.parent_path();
240 if segment.coloncolon_token().is_some() || path.qualifier().is_some() { 240 if segment.coloncolon_token().is_some() || path.qualifier().is_some() {
241 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); 241 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
242 return; 242 return;
243 } 243 }
244 244
245 // We now know that the path variable describes a complete path.
246 // For expressions and types, validation is complete, but we still have 245 // For expressions and types, validation is complete, but we still have
247 // to handle UseItems like this: 246 // to handle invalid UseItems like this:
248 // use foo:{crate}; 247 //
249 // so we crawl upwards looking for any preceding paths on `UseTree`s 248 // use foo:{crate::bar::baz};
249 //
250 // To handle this we must inspect the parent `UseItem`s and `UseTree`s
251 // but right now we're looking deep inside the nested `Path` nodes because
252 // `Path`s are left-associative:
253 //
254 // ((crate)::bar)::baz)
255 // ^ current value of path
256 //
257 // So we need to climb to the top
258 while let Some(parent) = path.parent_path() {
259 path = parent;
260 }
261
262 // Now that we've found the whole path we need to see if there's a prefix
263 // somewhere in the UseTree hierarchy. This check is arbitrarily deep
264 // because rust allows arbitrary nesting like so:
265 //
266 // use {foo::{{{{crate::bar::baz}}}}};
250 for node in path.syntax().ancestors().skip(1) { 267 for node in path.syntax().ancestors().skip(1) {
251 match_ast! { 268 match_ast! {
252 match node { 269 match node {
253 ast::UseTree(it) => if let Some(tree_path) = it.path() { 270 ast::UseTree(it) => if let Some(tree_path) = it.path() {
271 // Even a top-level path exists within a `UseTree` so we must explicitly
272 // allow our path but disallow anything else
254 if tree_path != path { 273 if tree_path != path {
255 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); 274 errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
256 } 275 }
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
index 8306f7361..d2a549273 100644
--- a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
@@ -1,4 +1,4 @@
1[email protected]3 1SOURCE_FILE@0..98
2 [email protected] 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
@@ -9,11 +9,11 @@ [email protected]
9 [email protected] "crate" 9 [email protected] "crate"
10 [email protected] ";" 10 [email protected] ";"
11 [email protected] "\n" 11 [email protected] "\n"
12 USE_ITEM@13..39 12 USE_ITEM@13..54
13 [email protected] "use" 13 [email protected] "use"
14 [email protected] " " 14 [email protected] " "
15 [email protected]8 15 USE_TREE@17..53
16 [email protected]8 16 USE_TREE_LIST@17..53
17 [email protected] "{" 17 [email protected] "{"
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
@@ -21,56 +21,71 @@ [email protected]
21 [email protected] "crate" 21 [email protected] "crate"
22 [email protected] "," 22 [email protected] ","
23 [email protected] " " 23 [email protected] " "
24 USE_TREE@25..37 24 USE_TREE@25..52
25 [email protected] 25 [email protected]
26 [email protected] 26 [email protected]
27 [email protected] 27 [email protected]
28 [email protected] "foo" 28 [email protected] "foo"
29 [email protected] "::" 29 [email protected] "::"
30 USE_TREE_LIST@30..37 30 USE_TREE_LIST@30..52
31 [email protected] "{" 31 [email protected] "{"
32 [email protected] 32 [email protected]
33 [email protected] 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "crate" 35 [email protected]
36 [email protected] "}" 36 [email protected]
37 [email protected] "}" 37 [email protected]
38 [email protected] ";" 38 [email protected] "crate"
39 [email protected] "\n" 39 [email protected] "::"
40 [email protected] 40 [email protected]
41 [email protected] "use" 41 [email protected]
42 [email protected] " " 42 [email protected] "foo"
43 [email protected] 43 [email protected] "::"
44 [email protected] 44 [email protected]
45 [email protected] 45 [email protected]
46 [email protected] 46 [email protected] "bar"
47 [email protected] 47 [email protected] "::"
48 [email protected] "hello" 48 [email protected]
49 [email protected] "::" 49 [email protected]
50 [email protected] 50 [email protected] "baz"
51 [email protected] "crate" 51 [email protected] "}"
52 [email protected] ";" 52 [email protected] "}"
53 [email protected] "\n" 53 [email protected] ";"
54 [email protected] 54 [email protected] "\n"
55 [email protected] "use" 55 [email protected]
56 [email protected] " " 56 [email protected] "use"
57 [email protected] 57 [email protected] " "
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
60 [email protected] 60 [email protected]
61 [email protected] 61 [email protected]
62 [email protected] 62 [email protected]
63 [email protected] "hello" 63 [email protected] "hello"
64 [email protected] "::" 64 [email protected] "::"
65 [email protected] 65 [email protected]
66 [email protected] "crate" 66 [email protected] "crate"
67 [email protected] "::" 67 [email protected] ";"
68 [email protected] 68 [email protected] "\n"
69 [email protected] 69 [email protected]
70 [email protected] "there" 70 [email protected] "use"
71 [email protected] ";" 71 [email protected] " "
72 [email protected] "\n" 72 [email protected]
73 [email protected]
74 [email protected]
75 [email protected]
76 [email protected]
77 [email protected]
78 [email protected] "hello"
79 [email protected] "::"
80 [email protected]
81 [email protected] "crate"
82 [email protected] "::"
83 [email protected]
84 [email protected]
85 [email protected] "there"
86 [email protected] ";"
87 [email protected] "\n"
73error 6..11: The `crate` keyword is only allowed as the first segment of a path 88error 6..11: The `crate` keyword is only allowed as the first segment of a path
74error 31..36: The `crate` keyword is only allowed as the first segment of a path 89error 31..36: The `crate` keyword is only allowed as the first segment of a path
75error 51..56: The `crate` keyword is only allowed as the first segment of a path 90error 66..71: The `crate` keyword is only allowed as the first segment of a path
76error 69..74: The `crate` keyword is only allowed as the first segment of a path 91error 84..89: The `crate` keyword is only allowed as the first segment of a path
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs
index bead4c0b6..508def2c7 100644
--- a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs
@@ -1,4 +1,4 @@
1use ::crate; 1use ::crate;
2use {crate, foo::{crate}}; 2use {crate, foo::{crate::foo::bar::baz}};
3use hello::crate; 3use hello::crate;
4use hello::crate::there; 4use hello::crate::there;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
index bd74b44a6..cf3a90400 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
@@ -1,4 +1,4 @@
1[email protected]50 1[email protected]49
2 [email protected] 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
@@ -104,32 +104,33 @@ [email protected]
104 [email protected] " " 104 [email protected] " "
105 [email protected] "// Rust 2015" 105 [email protected] "// Rust 2015"
106 [email protected] "\n" 106 [email protected] "\n"
107 [email protected]6 107 [email protected]5
108 [email protected] "use" 108 [email protected] "use"
109 [email protected] " " 109 [email protected] " "
110 [email protected]5 110 [email protected]4
111 [email protected] "::" 111 [email protected] "::"
112 [email protected]5 112 [email protected]4
113 [email protected] "{" 113 [email protected] "{"
114 [email protected]4 114 [email protected]3
115 [email protected]4 115 [email protected]3
116 [email protected] "{" 116 [email protected] "{"
117 [email protected]3 117 [email protected]2
118 [email protected]3 118 [email protected]2
119 [email protected] "{" 119 [email protected] "{"
120 [email protected] 120 [email protected]
121 [email protected] 121 [email protected]
122 [email protected] 122 [email protected]
123 [email protected] 123 [email protected]
124 [email protected] "crate" 124 [email protected]
125 [email protected] "::" 125 [email protected] "root"
126 [email protected] 126 [email protected] "::"
127 [email protected] 127 [email protected]
128 [email protected] "export" 128 [email protected]
129 [email protected] "}" 129 [email protected] "export"
130 [email protected] "}" 130 [email protected] "}"
131 [email protected] "}" 131 [email protected] "}"
132 [email protected] ";" 132 [email protected] "}"
133 [email protected] " " 133 [email protected] ";"
134 [email protected] "// Nonsensical but pe ..." 134 [email protected] " "
135 [email protected] "\n" 135 [email protected] "// Nonsensical but pe ..."
136 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rs b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rs
index 06c387cee..381cba1e2 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rs
@@ -1,4 +1,4 @@
1use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) 1use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
2use {path::from::root}; // Rust 2015 2use {path::from::root}; // Rust 2015
3use ::{some::arbritrary::path}; // Rust 2015 3use ::{some::arbritrary::path}; // Rust 2015
4use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig 4use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting