Skip to content

Commit 0af727d

Browse files
committed
Validate the location of crate in paths
1 parent 7a9ba16 commit 0af727d

File tree

5 files changed

+121
-1
lines changed

5 files changed

+121
-1
lines changed

crates/ra_syntax/src/ast/generated/nodes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,7 @@ pub struct PathSegment {
12491249
}
12501250
impl PathSegment {
12511251
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]) }
12521253
pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
12531254
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
12541255
pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) }

crates/ra_syntax/src/validation.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
9696
ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors),
9797
ast::Visibility(it) => validate_visibility(it, &mut errors),
9898
ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
99+
ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors),
99100
_ => (),
100101
}
101102
}
@@ -222,3 +223,41 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
222223
));
223224
}
224225
}
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+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
12+
13+
14+
15+
16+
17+
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
29+
30+
31+
32+
33+
34+
35+
36+
37+
38+
39+
40+
41+
42+
43+
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
56+
57+
58+
59+
60+
61+
62+
63+
64+
65+
66+
67+
68+
69+
70+
71+
72+
73+
error 6..11: The `crate` keyword is only allowed as the first segment of a path
74+
error 31..36: The `crate` keyword is only allowed as the first segment of a path
75+
error 51..56: The `crate` keyword is only allowed as the first segment of a path
76+
error 69..74: The `crate` keyword is only allowed as the first segment of a path
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
use ::crate;
2+
use {crate, foo::{crate}};
3+
use hello::crate;
4+
use hello::crate::there;

xtask/src/ast_src.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
595595
qualifier: Path,
596596
}
597597
struct PathSegment {
598-
T![::], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
598+
T![::], T![crate], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
599599
}
600600
struct TypeArgList {
601601
T![::],

0 commit comments

Comments
 (0)