aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
authorJohn Renner <[email protected]>2020-04-30 18:41:24 +0100
committerJohn Renner <[email protected]>2020-04-30 19:16:09 +0100
commit513a3615f6d462852c0135dc4ac30a2086e25c5a (patch)
tree31b5de91f47cf315074dcf7b1a7282accdbfad1d /crates/ra_syntax/src
parentfec1e7c8e10e1c592642fac0c497cd57bd3f003c (diff)
Report invalid, nested, multi-segment crate-paths
Specifically, things like: use foo::{crate::bar}; Are now being caught, when before we only caught: use foo::{crate};
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/validation.rs29
1 files changed, 24 insertions, 5 deletions
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 }