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.rs19
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs28
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs39
-rw-r--r--crates/ra_syntax/src/ast/make.rs3
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs17
-rw-r--r--crates/ra_syntax/src/validation.rs58
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
18pub use self::{ 18pub 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]
248fn 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]
246fn test_where_predicates() { 263fn 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
362pub enum BlockModifier {
363 Async(SyntaxToken),
364 Unsafe(SyntaxToken),
365}
366
362impl ast::BlockExpr { 367impl 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)]
479pub struct TryBlockExpr {
480 pub(crate) syntax: SyntaxNode,
481}
482impl ast::AttrsOwner for TryBlockExpr {}
483impl 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)]
489pub struct ForExpr { 479pub struct ForExpr {
490 pub(crate) syntax: SyntaxNode, 480 pub(crate) syntax: SyntaxNode,
491} 481}
@@ -554,6 +544,7 @@ impl ast::AttrsOwner for BlockExpr {}
554impl BlockExpr { 544impl 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}
1250impl PathSegment { 1241impl 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}
1959impl 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}
1970impl AstNode for ForExpr { 1950impl 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 {
3308impl From<TryExpr> for Expr { 3288impl From<TryExpr> for Expr {
3309 fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) } 3289 fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
3310} 3290}
3311impl From<TryBlockExpr> for Expr {
3312 fn from(node: TryBlockExpr) -> Expr { Expr::TryBlockExpr(node) }
3313}
3314impl From<CastExpr> for Expr { 3291impl 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}
3892impl 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}
3897impl std::fmt::Display for ForExpr { 3866impl 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 {
22pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { 22pub 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 25fn path_from_text(text: &str) -> ast::Path {
26pub 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 {
48const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { 53const 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
72fn 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
81impl Whitespace { 78impl 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
227fn 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}