aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs5
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs1
-rw-r--r--crates/ra_syntax/src/validation.rs29
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 {}
554impl BlockExpr { 554impl 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 }