diff options
Diffstat (limited to 'crates/ra_syntax')
9 files changed, 179 insertions, 12 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 7fca5661e..a716e525b 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -243,6 +243,21 @@ fn test_comments_preserve_trailing_whitespace() { | |||
243 | } | 243 | } |
244 | 244 | ||
245 | #[test] | 245 | #[test] |
246 | fn test_four_slash_line_comment() { | ||
247 | let file = SourceFile::parse( | ||
248 | r#" | ||
249 | //// too many slashes to be a doc comment | ||
250 | /// doc comment | ||
251 | mod foo {} | ||
252 | "#, | ||
253 | ) | ||
254 | .ok() | ||
255 | .unwrap(); | ||
256 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
257 | assert_eq!("doc comment", module.doc_comment_text().unwrap()); | ||
258 | } | ||
259 | |||
260 | #[test] | ||
246 | fn test_where_predicates() { | 261 | fn test_where_predicates() { |
247 | fn assert_bound(text: &str, bound: Option<TypeBound>) { | 262 | fn assert_bound(text: &str, bound: Option<TypeBound>) { |
248 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); | 263 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); |
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/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..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 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast new file mode 100644 index 000000000..8306f7361 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast | |||
@@ -0,0 +1,76 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "use" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] "::" | ||
9 | [email protected] "crate" | ||
10 | [email protected] ";" | ||
11 | [email protected] "\n" | ||
12 | [email protected] | ||
13 | [email protected] "use" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "{" | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "crate" | ||
22 | [email protected] "," | ||
23 | [email protected] " " | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] "foo" | ||
29 | [email protected] "::" | ||
30 | [email protected] | ||
31 | [email protected] "{" | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "crate" | ||
36 | [email protected] "}" | ||
37 | [email protected] "}" | ||
38 | [email protected] ";" | ||
39 | [email protected] "\n" | ||
40 | [email protected] | ||
41 | [email protected] "use" | ||
42 | [email protected] " " | ||
43 | [email protected] | ||
44 | [email protected] | ||
45 | [email protected] | ||
46 | [email protected] | ||
47 | [email protected] | ||
48 | [email protected] "hello" | ||
49 | [email protected] "::" | ||
50 | [email protected] | ||
51 | [email protected] "crate" | ||
52 | [email protected] ";" | ||
53 | [email protected] "\n" | ||
54 | [email protected] | ||
55 | [email protected] "use" | ||
56 | [email protected] " " | ||
57 | [email protected] | ||
58 | [email protected] | ||
59 | [email protected] | ||
60 | [email protected] | ||
61 | [email protected] | ||
62 | [email protected] | ||
63 | [email protected] "hello" | ||
64 | [email protected] "::" | ||
65 | [email protected] | ||
66 | [email protected] "crate" | ||
67 | [email protected] "::" | ||
68 | [email protected] | ||
69 | [email protected] | ||
70 | [email protected] "there" | ||
71 | [email protected] ";" | ||
72 | [email protected] "\n" | ||
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 | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs new file mode 100644 index 000000000..bead4c0b6 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | use ::crate; | ||
2 | use {crate, foo::{crate}}; | ||
3 | use hello::crate; | ||
4 | use hello::crate::there; | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast new file mode 100644 index 000000000..beb6d8010 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast | |||
@@ -0,0 +1,35 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "foo" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] "{" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] "try" | ||
21 | [email protected] "!" | ||
22 | [email protected] | ||
23 | [email protected] "(" | ||
24 | [email protected] "Ok" | ||
25 | [email protected] | ||
26 | [email protected] "(" | ||
27 | [email protected] | ||
28 | [email protected] "(" | ||
29 | [email protected] ")" | ||
30 | [email protected] ")" | ||
31 | [email protected] ")" | ||
32 | [email protected] ";" | ||
33 | [email protected] " " | ||
34 | [email protected] "}" | ||
35 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rs b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rs new file mode 100644 index 000000000..61a6b46a0 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rs | |||
@@ -0,0 +1 @@ | |||
fn foo() { try!(Ok(())); } | |||