diff options
author | John Renner <[email protected]> | 2020-04-27 18:02:47 +0100 |
---|---|---|
committer | John Renner <[email protected]> | 2020-04-29 19:06:51 +0100 |
commit | 0af727da91e7ff3c8ed5518cb7e005e8d4f939b0 (patch) | |
tree | 4b1b78edb4d28b2ad98e40f054ab3efe58e33eba /crates/ra_syntax/src | |
parent | 7a9ba1657daa9fd90c639dcd937da11b4f526675 (diff) |
Validate the location of `crate` in paths
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/ast/generated/nodes.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 39 |
2 files changed, 40 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 2cb3ad011..3b5e05af9 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -1249,6 +1249,7 @@ pub struct PathSegment { | |||
1249 | } | 1249 | } |
1250 | impl PathSegment { | 1250 | impl PathSegment { |
1251 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } | 1251 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } |
1252 | 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![<]) } | 1253 | 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) } | 1254 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } |
1254 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } | 1255 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 5e93895ec..a30bc97bb 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,41 @@ 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 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 | // We now know that the path variable describes a complete path. | ||
246 | // For expressions and types, validation is complete, but we still have | ||
247 | // to handle UseItems like this: | ||
248 | // use foo:{crate}; | ||
249 | // so we crawl upwards looking for any preceding paths on `UseTree`s | ||
250 | for node in path.syntax().ancestors().skip(1) { | ||
251 | match_ast! { | ||
252 | match node { | ||
253 | ast::UseTree(it) => if let Some(tree_path) = it.path() { | ||
254 | if tree_path != path { | ||
255 | errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); | ||
256 | } | ||
257 | }, | ||
258 | ast::UseTreeList(_it) => continue, | ||
259 | _ => return, | ||
260 | } | ||
261 | }; | ||
262 | } | ||
263 | } | ||