diff options
author | Benjamin Coenen <[email protected]> | 2020-05-01 15:26:30 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-05-01 15:26:30 +0100 |
commit | dc34162450797f5756ce2b44f1a3fe73d8e2dce4 (patch) | |
tree | 0883abc2d87f8b9704b49f5662da04b73ffedbf6 /crates/ra_syntax/src | |
parent | bbe22640b8d52354c3de3e126c9fcda5b1b174fd (diff) | |
parent | a5f2b16366f027ad60c58266a66eb7fbdcbda9f9 (diff) |
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 19 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 28 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated/nodes.rs | 39 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 17 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 58 |
6 files changed, 111 insertions, 53 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 7fca5661e..521ca8ab8 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -16,7 +16,9 @@ use crate::{ | |||
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub use self::{ | 18 | pub use self::{ |
19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, | 19 | expr_extensions::{ |
20 | ArrayExprKind, BinOp, BlockModifier, ElseBranch, LiteralKind, PrefixOp, RangeOp, | ||
21 | }, | ||
20 | extensions::{ | 22 | extensions::{ |
21 | AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, | 23 | AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, |
22 | StructKind, TypeBoundKind, VisibilityKind, | 24 | StructKind, TypeBoundKind, VisibilityKind, |
@@ -243,6 +245,21 @@ fn test_comments_preserve_trailing_whitespace() { | |||
243 | } | 245 | } |
244 | 246 | ||
245 | #[test] | 247 | #[test] |
248 | fn test_four_slash_line_comment() { | ||
249 | let file = SourceFile::parse( | ||
250 | r#" | ||
251 | //// too many slashes to be a doc comment | ||
252 | /// doc comment | ||
253 | mod foo {} | ||
254 | "#, | ||
255 | ) | ||
256 | .ok() | ||
257 | .unwrap(); | ||
258 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
259 | assert_eq!("doc comment", module.doc_comment_text().unwrap()); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
246 | fn test_where_predicates() { | 263 | fn test_where_predicates() { |
247 | fn assert_bound(text: &str, bound: Option<TypeBound>) { | 264 | fn assert_bound(text: &str, bound: Option<TypeBound>) { |
248 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); | 265 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 1c1134bc5..329c80749 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -16,7 +16,7 @@ impl ast::Expr { | |||
16 | | ast::Expr::WhileExpr(_) | 16 | | ast::Expr::WhileExpr(_) |
17 | | ast::Expr::BlockExpr(_) | 17 | | ast::Expr::BlockExpr(_) |
18 | | ast::Expr::MatchExpr(_) | 18 | | ast::Expr::MatchExpr(_) |
19 | | ast::Expr::TryBlockExpr(_) => true, | 19 | | ast::Expr::TryExpr(_) => true, |
20 | _ => false, | 20 | _ => false, |
21 | } | 21 | } |
22 | } | 22 | } |
@@ -359,7 +359,22 @@ impl ast::Literal { | |||
359 | } | 359 | } |
360 | } | 360 | } |
361 | 361 | ||
362 | pub enum BlockModifier { | ||
363 | Async(SyntaxToken), | ||
364 | Unsafe(SyntaxToken), | ||
365 | } | ||
366 | |||
362 | impl ast::BlockExpr { | 367 | impl ast::BlockExpr { |
368 | pub fn modifier(&self) -> Option<BlockModifier> { | ||
369 | if let Some(token) = self.async_token() { | ||
370 | return Some(BlockModifier::Async(token)); | ||
371 | } | ||
372 | if let Some(token) = self.unsafe_token() { | ||
373 | return Some(BlockModifier::Unsafe(token)); | ||
374 | } | ||
375 | None | ||
376 | } | ||
377 | |||
363 | /// false if the block is an intrinsic part of the syntax and can't be | 378 | /// false if the block is an intrinsic part of the syntax and can't be |
364 | /// replaced with arbitrary expression. | 379 | /// replaced with arbitrary expression. |
365 | /// | 380 | /// |
@@ -368,12 +383,15 @@ impl ast::BlockExpr { | |||
368 | /// const FOO: () = { stand_alone }; | 383 | /// const FOO: () = { stand_alone }; |
369 | /// ``` | 384 | /// ``` |
370 | pub fn is_standalone(&self) -> bool { | 385 | pub fn is_standalone(&self) -> bool { |
371 | let kind = match self.syntax().parent() { | 386 | if self.modifier().is_some() { |
387 | return false; | ||
388 | } | ||
389 | let parent = match self.syntax().parent() { | ||
390 | Some(it) => it, | ||
372 | None => return true, | 391 | None => return true, |
373 | Some(it) => it.kind(), | ||
374 | }; | 392 | }; |
375 | match kind { | 393 | match parent.kind() { |
376 | FN_DEF | MATCH_ARM | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false, | 394 | FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR => false, |
377 | _ => true, | 395 | _ => true, |
378 | } | 396 | } |
379 | } | 397 | } |
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 2cb3ad011..81260680f 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -476,16 +476,6 @@ impl LoopExpr { | |||
476 | } | 476 | } |
477 | 477 | ||
478 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 478 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
479 | pub struct TryBlockExpr { | ||
480 | pub(crate) syntax: SyntaxNode, | ||
481 | } | ||
482 | impl ast::AttrsOwner for TryBlockExpr {} | ||
483 | impl TryBlockExpr { | ||
484 | pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } | ||
485 | pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) } | ||
486 | } | ||
487 | |||
488 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
489 | pub struct ForExpr { | 479 | pub struct ForExpr { |
490 | pub(crate) syntax: SyntaxNode, | 480 | pub(crate) syntax: SyntaxNode, |
491 | } | 481 | } |
@@ -554,6 +544,7 @@ impl ast::AttrsOwner for BlockExpr {} | |||
554 | impl BlockExpr { | 544 | impl BlockExpr { |
555 | pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } | 545 | pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } |
556 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } | 546 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } |
547 | pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } | ||
557 | pub fn block(&self) -> Option<Block> { support::child(&self.syntax) } | 548 | pub fn block(&self) -> Option<Block> { support::child(&self.syntax) } |
558 | } | 549 | } |
559 | 550 | ||
@@ -1249,6 +1240,7 @@ pub struct PathSegment { | |||
1249 | } | 1240 | } |
1250 | impl PathSegment { | 1241 | impl PathSegment { |
1251 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } | 1242 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } |
1243 | pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } | ||
1252 | pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } | 1244 | pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } |
1253 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } | 1245 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } |
1254 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } | 1246 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } |
@@ -1473,7 +1465,6 @@ pub enum Expr { | |||
1473 | FieldExpr(FieldExpr), | 1465 | FieldExpr(FieldExpr), |
1474 | AwaitExpr(AwaitExpr), | 1466 | AwaitExpr(AwaitExpr), |
1475 | TryExpr(TryExpr), | 1467 | TryExpr(TryExpr), |
1476 | TryBlockExpr(TryBlockExpr), | ||
1477 | CastExpr(CastExpr), | 1468 | CastExpr(CastExpr), |
1478 | RefExpr(RefExpr), | 1469 | RefExpr(RefExpr), |
1479 | PrefixExpr(PrefixExpr), | 1470 | PrefixExpr(PrefixExpr), |
@@ -1956,17 +1947,6 @@ impl AstNode for LoopExpr { | |||
1956 | } | 1947 | } |
1957 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 1948 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
1958 | } | 1949 | } |
1959 | impl AstNode for TryBlockExpr { | ||
1960 | fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_BLOCK_EXPR } | ||
1961 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
1962 | if Self::can_cast(syntax.kind()) { | ||
1963 | Some(Self { syntax }) | ||
1964 | } else { | ||
1965 | None | ||
1966 | } | ||
1967 | } | ||
1968 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1969 | } | ||
1970 | impl AstNode for ForExpr { | 1950 | impl AstNode for ForExpr { |
1971 | fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR } | 1951 | fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR } |
1972 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 1952 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
@@ -3308,9 +3288,6 @@ impl From<AwaitExpr> for Expr { | |||
3308 | impl From<TryExpr> for Expr { | 3288 | impl From<TryExpr> for Expr { |
3309 | fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) } | 3289 | fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) } |
3310 | } | 3290 | } |
3311 | impl From<TryBlockExpr> for Expr { | ||
3312 | fn from(node: TryBlockExpr) -> Expr { Expr::TryBlockExpr(node) } | ||
3313 | } | ||
3314 | impl From<CastExpr> for Expr { | 3291 | impl From<CastExpr> for Expr { |
3315 | fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) } | 3292 | fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) } |
3316 | } | 3293 | } |
@@ -3341,9 +3318,8 @@ impl AstNode for Expr { | |||
3341 | TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR | 3318 | TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR |
3342 | | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL | 3319 | | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL |
3343 | | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR | 3320 | | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR |
3344 | | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_EXPR | 3321 | | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | CAST_EXPR | REF_EXPR |
3345 | | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | 3322 | | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | BOX_EXPR => true, |
3346 | | BOX_EXPR => true, | ||
3347 | _ => false, | 3323 | _ => false, |
3348 | } | 3324 | } |
3349 | } | 3325 | } |
@@ -3371,7 +3347,6 @@ impl AstNode for Expr { | |||
3371 | FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }), | 3347 | FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }), |
3372 | AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }), | 3348 | AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }), |
3373 | TRY_EXPR => Expr::TryExpr(TryExpr { syntax }), | 3349 | TRY_EXPR => Expr::TryExpr(TryExpr { syntax }), |
3374 | TRY_BLOCK_EXPR => Expr::TryBlockExpr(TryBlockExpr { syntax }), | ||
3375 | CAST_EXPR => Expr::CastExpr(CastExpr { syntax }), | 3350 | CAST_EXPR => Expr::CastExpr(CastExpr { syntax }), |
3376 | REF_EXPR => Expr::RefExpr(RefExpr { syntax }), | 3351 | REF_EXPR => Expr::RefExpr(RefExpr { syntax }), |
3377 | PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }), | 3352 | PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }), |
@@ -3408,7 +3383,6 @@ impl AstNode for Expr { | |||
3408 | Expr::FieldExpr(it) => &it.syntax, | 3383 | Expr::FieldExpr(it) => &it.syntax, |
3409 | Expr::AwaitExpr(it) => &it.syntax, | 3384 | Expr::AwaitExpr(it) => &it.syntax, |
3410 | Expr::TryExpr(it) => &it.syntax, | 3385 | Expr::TryExpr(it) => &it.syntax, |
3411 | Expr::TryBlockExpr(it) => &it.syntax, | ||
3412 | Expr::CastExpr(it) => &it.syntax, | 3386 | Expr::CastExpr(it) => &it.syntax, |
3413 | Expr::RefExpr(it) => &it.syntax, | 3387 | Expr::RefExpr(it) => &it.syntax, |
3414 | Expr::PrefixExpr(it) => &it.syntax, | 3388 | Expr::PrefixExpr(it) => &it.syntax, |
@@ -3889,11 +3863,6 @@ impl std::fmt::Display for LoopExpr { | |||
3889 | std::fmt::Display::fmt(self.syntax(), f) | 3863 | std::fmt::Display::fmt(self.syntax(), f) |
3890 | } | 3864 | } |
3891 | } | 3865 | } |
3892 | impl std::fmt::Display for TryBlockExpr { | ||
3893 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
3894 | std::fmt::Display::fmt(self.syntax(), f) | ||
3895 | } | ||
3896 | } | ||
3897 | impl std::fmt::Display for ForExpr { | 3866 | impl std::fmt::Display for ForExpr { |
3898 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 3867 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
3899 | std::fmt::Display::fmt(self.syntax(), f) | 3868 | std::fmt::Display::fmt(self.syntax(), f) |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index ee0f5cc40..492088353 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -22,8 +22,7 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { | |||
22 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { | 22 | pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { |
23 | path_from_text(&format!("{}::{}", qual, segment)) | 23 | path_from_text(&format!("{}::{}", qual, segment)) |
24 | } | 24 | } |
25 | 25 | fn path_from_text(text: &str) -> ast::Path { | |
26 | pub fn path_from_text(text: &str) -> ast::Path { | ||
27 | ast_from_text(text) | 26 | ast_from_text(text) |
28 | } | 27 | } |
29 | 28 | ||
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 3865729b8..74906d8a6 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -13,7 +13,12 @@ impl Comment { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | pub fn prefix(&self) -> &'static str { | 15 | pub fn prefix(&self) -> &'static str { |
16 | prefix_by_kind(self.kind()) | 16 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { |
17 | if *k == self.kind() && self.text().starts_with(prefix) { | ||
18 | return prefix; | ||
19 | } | ||
20 | } | ||
21 | unreachable!() | ||
17 | } | 22 | } |
18 | } | 23 | } |
19 | 24 | ||
@@ -48,6 +53,7 @@ pub enum CommentPlacement { | |||
48 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { | 53 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { |
49 | use {CommentPlacement::*, CommentShape::*}; | 54 | use {CommentPlacement::*, CommentShape::*}; |
50 | &[ | 55 | &[ |
56 | ("////", CommentKind { shape: Line, doc: None }), | ||
51 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), | 57 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), |
52 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), | 58 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), |
53 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), | 59 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), |
@@ -69,15 +75,6 @@ fn kind_by_prefix(text: &str) -> CommentKind { | |||
69 | panic!("bad comment text: {:?}", text) | 75 | panic!("bad comment text: {:?}", text) |
70 | } | 76 | } |
71 | 77 | ||
72 | fn prefix_by_kind(kind: CommentKind) -> &'static str { | ||
73 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { | ||
74 | if *k == kind { | ||
75 | return prefix; | ||
76 | } | ||
77 | } | ||
78 | unreachable!() | ||
79 | } | ||
80 | |||
81 | impl Whitespace { | 78 | impl Whitespace { |
82 | pub fn spans_multiple_lines(&self) -> bool { | 79 | pub fn spans_multiple_lines(&self) -> bool { |
83 | let text = self.text(); | 80 | let text = self.text(); |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 5e93895ec..f0b3dec63 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -96,6 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
96 | ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), | 96 | ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), |
97 | ast::Visibility(it) => validate_visibility(it, &mut errors), | 97 | ast::Visibility(it) => validate_visibility(it, &mut errors), |
98 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), | 98 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), |
99 | ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors), | ||
99 | _ => (), | 100 | _ => (), |
100 | } | 101 | } |
101 | } | 102 | } |
@@ -222,3 +223,60 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { | |||
222 | )); | 223 | )); |
223 | } | 224 | } |
224 | } | 225 | } |
226 | |||
227 | fn validate_crate_keyword_in_path_segment( | ||
228 | segment: ast::PathSegment, | ||
229 | errors: &mut Vec<SyntaxError>, | ||
230 | ) { | ||
231 | const ERR_MSG: &str = "The `crate` keyword is only allowed as the first segment of a path"; | ||
232 | |||
233 | let crate_token = match segment.crate_token() { | ||
234 | None => return, | ||
235 | Some(it) => it, | ||
236 | }; | ||
237 | |||
238 | // Disallow both ::crate and foo::crate | ||
239 | let mut path = segment.parent_path(); | ||
240 | if segment.coloncolon_token().is_some() || path.qualifier().is_some() { | ||
241 | errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | // For expressions and types, validation is complete, but we still have | ||
246 | // to handle invalid UseItems like this: | ||
247 | // | ||
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}}}}}; | ||
267 | for node in path.syntax().ancestors().skip(1) { | ||
268 | match_ast! { | ||
269 | match node { | ||
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 | ||
273 | if tree_path != path { | ||
274 | errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); | ||
275 | } | ||
276 | }, | ||
277 | ast::UseTreeList(_it) => continue, | ||
278 | _ => return, | ||
279 | } | ||
280 | }; | ||
281 | } | ||
282 | } | ||