diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated/nodes.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 29 |
3 files changed, 29 insertions, 6 deletions
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 93aa3d45f..ecf74fd36 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -368,12 +368,15 @@ impl ast::BlockExpr { | |||
368 | /// const FOO: () = { stand_alone }; | 368 | /// const FOO: () = { stand_alone }; |
369 | /// ``` | 369 | /// ``` |
370 | pub fn is_standalone(&self) -> bool { | 370 | pub fn is_standalone(&self) -> bool { |
371 | if self.unsafe_token().is_some() || self.async_token().is_some() { | ||
372 | return false; | ||
373 | } | ||
371 | let kind = match self.syntax().parent() { | 374 | let kind = match self.syntax().parent() { |
372 | None => return true, | 375 | None => return true, |
373 | Some(it) => it.kind(), | 376 | Some(it) => it.kind(), |
374 | }; | 377 | }; |
375 | match kind { | 378 | match kind { |
376 | FN_DEF | MATCH_ARM | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false, | 379 | FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false, |
377 | _ => true, | 380 | _ => true, |
378 | } | 381 | } |
379 | } | 382 | } |
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 3b5e05af9..d2253d4af 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -554,6 +554,7 @@ impl ast::AttrsOwner for BlockExpr {} | |||
554 | impl BlockExpr { | 554 | impl BlockExpr { |
555 | pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } | 555 | pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } |
556 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } | 556 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } |
557 | pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } | ||
557 | pub fn block(&self) -> Option<Block> { support::child(&self.syntax) } | 558 | pub fn block(&self) -> Option<Block> { support::child(&self.syntax) } |
558 | } | 559 | } |
559 | 560 | ||
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 | } |