aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-03-30 10:25:53 +0000
committerAleksey Kladov <[email protected]>2019-04-01 10:06:24 +0100
commit9e213385c9d06db3c8ca20812779e2b8f8ad2c71 (patch)
treefe57697b54ccfb791fe96c13cb553a8570516270 /crates
parentdec9bde10868b5e459535449476d17a6a0987b3e (diff)
switch to new rowan
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/add_derive.rs6
-rw-r--r--crates/ra_assists/src/add_impl.rs8
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs13
-rw-r--r--crates/ra_assists/src/assist_ctx.rs12
-rw-r--r--crates/ra_assists/src/auto_import.rs13
-rw-r--r--crates/ra_assists/src/change_visibility.rs10
-rw-r--r--crates/ra_assists/src/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/flip_comma.rs10
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs6
-rw-r--r--crates/ra_assists/src/introduce_variable.rs28
-rw-r--r--crates/ra_assists/src/remove_dbg.rs6
-rw-r--r--crates/ra_assists/src/split_import.rs4
-rw-r--r--crates/ra_cli/src/analysis_stats.rs7
-rw-r--r--crates/ra_cli/src/main.rs35
-rw-r--r--crates/ra_fmt/src/lib.rs28
-rw-r--r--crates/ra_hir/src/expr.rs12
-rw-r--r--crates/ra_hir/src/source_binder.rs8
-rw-r--r--crates/ra_hir/src/ty/tests.rs14
-rw-r--r--crates/ra_ide_api/src/completion.rs23
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs8
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs22
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs6
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs144
-rw-r--r--crates/ra_ide_api/src/folding_ranges.rs134
-rw-r--r--crates/ra_ide_api/src/hover.rs14
-rw-r--r--crates/ra_ide_api/src/join_lines.rs79
-rw-r--r--crates/ra_ide_api/src/matching_brace.rs9
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs12
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs33
-rw-r--r--crates/ra_ide_api/src/typing.rs32
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs86
-rw-r--r--crates/ra_parser/src/event.rs6
-rw-r--r--crates/ra_parser/src/lib.rs8
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/algo.rs41
-rw-r--r--crates/ra_syntax/src/ast.rs246
-rw-r--r--crates/ra_syntax/src/ast/generated.rs527
-rw-r--r--crates/ra_syntax/src/grammar.ron35
-rw-r--r--crates/ra_syntax/src/lib.rs34
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs142
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs28
-rw-r--r--crates/ra_syntax/src/syntax_node.rs287
-rw-r--r--crates/ra_syntax/src/syntax_text.rs15
-rw-r--r--crates/ra_syntax/src/validation.rs18
-rw-r--r--crates/ra_syntax/src/validation/byte.rs6
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs6
-rw-r--r--crates/ra_syntax/src/validation/char.rs6
-rw-r--r--crates/ra_syntax/src/validation/string.rs6
49 files changed, 1019 insertions, 1220 deletions
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs
index e91b5eb8d..0c4cf2615 100644
--- a/crates/ra_assists/src/add_derive.rs
+++ b/crates/ra_assists/src/add_derive.rs
@@ -33,8 +33,10 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
33 33
34// Insert `derive` after doc comments. 34// Insert `derive` after doc comments.
35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { 35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
36 let non_ws_child = 36 let non_ws_child = nominal
37 nominal.syntax().children().find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; 37 .syntax()
38 .children_with_tokens()
39 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
38 Some(non_ws_child.range().start()) 40 Some(non_ws_child.range().start())
39} 41}
40 42
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs
index b292f188d..fa1c85890 100644
--- a/crates/ra_assists/src/add_impl.rs
+++ b/crates/ra_assists/src/add_impl.rs
@@ -1,7 +1,7 @@
1use join_to_string::join; 1use join_to_string::join;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, 4 ast::{self, AstNode, NameOwner, TypeParamsOwner},
5 TextUnit, 5 TextUnit,
6}; 6};
7 7
@@ -22,8 +22,10 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 buf.push_str(" "); 22 buf.push_str(" ");
23 buf.push_str(name.text().as_str()); 23 buf.push_str(name.text().as_str());
24 if let Some(type_params) = type_params { 24 if let Some(type_params) = type_params {
25 let lifetime_params = 25 let lifetime_params = type_params
26 type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); 26 .lifetime_params()
27 .filter_map(|it| it.lifetime_token())
28 .map(|it| it.text());
27 let type_params = 29 let type_params =
28 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); 30 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text());
29 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); 31 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
index e13f54c4f..5b01e898e 100644
--- a/crates/ra_assists/src/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -1,3 +1,5 @@
1use std::fmt::Write;
2
1use crate::{Assist, AssistId, AssistCtx}; 3use crate::{Assist, AssistId, AssistCtx};
2 4
3use hir::Resolver; 5use hir::Resolver;
@@ -91,8 +93,9 @@ fn add_missing_impl_members_inner(
91 }; 93 };
92 94
93 let changed_range = { 95 let changed_range = {
94 let children = impl_item_list.syntax().children(); 96 let children = impl_item_list.syntax().children_with_tokens();
95 let last_whitespace = children.filter_map(ast::Whitespace::cast).last(); 97 let last_whitespace =
98 children.filter_map(|it| ast::Whitespace::cast(it.as_token()?)).last();
96 99
97 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| { 100 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| {
98 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}"); 101 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}");
@@ -134,13 +137,13 @@ fn resolve_target_trait_def(
134fn build_func_body(def: &ast::FnDef) -> String { 137fn build_func_body(def: &ast::FnDef) -> String {
135 let mut buf = String::new(); 138 let mut buf = String::new();
136 139
137 for child in def.syntax().children() { 140 for child in def.syntax().children_with_tokens() {
138 match (child.prev_sibling().map(|c| c.kind()), child.kind()) { 141 match (child.prev_sibling_or_token().map(|c| c.kind()), child.kind()) {
139 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"), 142 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"),
140 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {} 143 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {}
141 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE) 144 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE)
142 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {} 145 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {}
143 _ => child.text().push_to(&mut buf), 146 _ => write!(buf, "{}", child).unwrap(),
144 }; 147 };
145 } 148 }
146 149
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 4ad21c74b..bb5742bd9 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -2,8 +2,8 @@ use hir::db::HirDatabase;
2use ra_text_edit::TextEditBuilder; 2use ra_text_edit::TextEditBuilder;
3use ra_db::FileRange; 3use ra_db::FileRange;
4use ra_syntax::{ 4use ra_syntax::{
5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, 5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, SyntaxElement, SyntaxToken,
6 algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, 6 algo::{find_token_at_offset, find_node_at_offset, find_covering_element, TokenAtOffset},
7}; 7};
8use ra_fmt::{leading_indent, reindent}; 8use ra_fmt::{leading_indent, reindent};
9 9
@@ -104,15 +104,15 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
104 Some(self.assist) 104 Some(self.assist)
105 } 105 }
106 106
107 pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> { 107 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken<'a>> {
108 find_leaf_at_offset(self.source_file.syntax(), self.frange.range.start()) 108 find_token_at_offset(self.source_file.syntax(), self.frange.range.start())
109 } 109 }
110 110
111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> { 111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> {
112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) 112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start())
113 } 113 }
114 pub(crate) fn covering_node(&self) -> &'a SyntaxNode { 114 pub(crate) fn covering_element(&self) -> SyntaxElement<'a> {
115 find_covering_node(self.source_file.syntax(), self.frange.range) 115 find_covering_element(self.source_file.syntax(), self.frange.range)
116 } 116 }
117} 117}
118 118
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index 685dbed06..3fdf6b0d9 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -21,7 +21,7 @@ fn collect_path_segments_raw<'a>(
21) -> Option<usize> { 21) -> Option<usize> {
22 let oldlen = segments.len(); 22 let oldlen = segments.len();
23 loop { 23 loop {
24 let mut children = path.syntax().children(); 24 let mut children = path.syntax().children_with_tokens();
25 let (first, second, third) = ( 25 let (first, second, third) = (
26 children.next().map(|n| (n, n.kind())), 26 children.next().map(|n| (n, n.kind())),
27 children.next().map(|n| (n, n.kind())), 27 children.next().map(|n| (n, n.kind())),
@@ -29,11 +29,11 @@ fn collect_path_segments_raw<'a>(
29 ); 29 );
30 match (first, second, third) { 30 match (first, second, third) {
31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => { 31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => {
32 path = ast::Path::cast(subpath)?; 32 path = ast::Path::cast(subpath.as_node()?)?;
33 segments.push(ast::PathSegment::cast(segment)?); 33 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
34 } 34 }
35 (Some((segment, PATH_SEGMENT)), _, _) => { 35 (Some((segment, PATH_SEGMENT)), _, _) => {
36 segments.push(ast::PathSegment::cast(segment)?); 36 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
37 break; 37 break;
38 } 38 }
39 (_, _, _) => return None, 39 (_, _, _) => return None,
@@ -514,8 +514,7 @@ fn apply_auto_import<'a>(
514} 514}
515 515
516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
517 let node = ctx.covering_node(); 517 let path: &ast::Path = ctx.node_at_offset()?;
518 let path = node.ancestors().find_map(ast::Path::cast)?;
519 // We don't want to mess with use statements 518 // We don't want to mess with use statements
520 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 519 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
521 return None; 520 return None;
@@ -537,7 +536,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
537 ); 536 );
538 } 537 }
539 } else { 538 } else {
540 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; 539 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
541 ctx.add_action( 540 ctx.add_action(
542 AssistId("auto_import"), 541 AssistId("auto_import"),
543 format!("import {} in the current file", fmt_segments(&segments)), 542 format!("import {} in the current file", fmt_segments(&segments)),
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs
index 50c1be5ae..c63470726 100644
--- a/crates/ra_assists/src/change_visibility.rs
+++ b/crates/ra_assists/src/change_visibility.rs
@@ -15,13 +15,13 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
15} 15}
16 16
17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() { 18 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, 19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
20 _ => false, 20 _ => false,
21 }); 21 });
22 22
23 let (offset, target) = if let Some(keyword) = item_keyword { 23 let (offset, target) = if let Some(keyword) = item_keyword {
24 let parent = keyword.parent()?; 24 let parent = keyword.parent();
25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
26 // Parent is not a definition, can't add visibility 26 // Parent is not a definition, can't add visibility
27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
@@ -33,8 +33,8 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
33 } 33 }
34 (vis_offset(parent), keyword.range()) 34 (vis_offset(parent), keyword.range())
35 } else { 35 } else {
36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; 36 let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?;
37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; 37 let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?;
38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { 38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
39 return None; 39 return None;
40 } 40 }
@@ -51,7 +51,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
51} 51}
52 52
53fn vis_offset(node: &SyntaxNode) -> TextUnit { 53fn vis_offset(node: &SyntaxNode) -> TextUnit {
54 node.children() 54 node.children_with_tokens()
55 .skip_while(|it| match it.kind() { 55 .skip_while(|it| match it.kind() {
56 WHITESPACE | COMMENT | ATTR => true, 56 WHITESPACE | COMMENT | ATTR => true,
57 _ => false, 57 _ => false,
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs
index ec377642e..02d27f66d 100644
--- a/crates/ra_assists/src/flip_binexpr.rs
+++ b/crates/ra_assists/src/flip_binexpr.rs
@@ -8,7 +8,7 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
8 let expr = ctx.node_at_offset::<BinExpr>()?; 8 let expr = ctx.node_at_offset::<BinExpr>()?;
9 let lhs = expr.lhs()?.syntax(); 9 let lhs = expr.lhs()?.syntax();
10 let rhs = expr.rhs()?.syntax(); 10 let rhs = expr.rhs()?.syntax();
11 let op_range = expr.op()?.range(); 11 let op_range = expr.op_token()?.range();
12 // The assist should be applied only if the cursor is on the operator 12 // The assist should be applied only if the cursor is on the operator
13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range); 13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
14 if !cursor_in_range { 14 if !cursor_in_range {
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs
index 6b98cac68..a9b108111 100644
--- a/crates/ra_assists/src/flip_comma.rs
+++ b/crates/ra_assists/src/flip_comma.rs
@@ -8,13 +8,13 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; 11 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == COMMA)?;
12 let prev = non_trivia_sibling(comma, Direction::Prev)?; 12 let prev = non_trivia_sibling(comma.into(), Direction::Prev)?;
13 let next = non_trivia_sibling(comma, Direction::Next)?; 13 let next = non_trivia_sibling(comma.into(), Direction::Next)?;
14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { 14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
15 edit.target(comma.range()); 15 edit.target(comma.range());
16 edit.replace(prev.range(), next.text()); 16 edit.replace(prev.range(), next.to_string());
17 edit.replace(next.range(), prev.text()); 17 edit.replace(next.range(), prev.to_string());
18 }); 18 });
19 19
20 ctx.build() 20 ctx.build()
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
index bd3cdb970..2258ca139 100644
--- a/crates/ra_assists/src/inline_local_variable.rs
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -46,8 +46,10 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
46 | ExprKind::BlockExpr(_) => false, 46 | ExprKind::BlockExpr(_) => false,
47 }; 47 };
48 48
49 let delete_range = if let Some(whitespace) = 49 let delete_range = if let Some(whitespace) = let_stmt
50 let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast) 50 .syntax()
51 .next_sibling_or_token()
52 .and_then(|it| ast::Whitespace::cast(it.as_token()?))
51 { 53 {
52 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) 54 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
53 } else { 55 } else {
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs
index 353bc4105..fb7333c8c 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -2,9 +2,8 @@ use test_utils::tested_by;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 SyntaxKind::{ 5 SyntaxNode, TextUnit,
6 WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT 6 SyntaxKind::{WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT},
7 }, SyntaxNode, TextUnit,
8}; 7};
9 8
10use crate::{AssistCtx, Assist, AssistId}; 9use crate::{AssistCtx, Assist, AssistId};
@@ -13,14 +12,14 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
13 if ctx.frange.range.is_empty() { 12 if ctx.frange.range.is_empty() {
14 return None; 13 return None;
15 } 14 }
16 let node = ctx.covering_node(); 15 let node = ctx.covering_element();
17 if node.kind() == COMMENT { 16 if node.kind() == COMMENT {
18 tested_by!(introduce_var_in_comment_is_not_applicable); 17 tested_by!(introduce_var_in_comment_is_not_applicable);
19 return None; 18 return None;
20 } 19 }
21 let expr = node.ancestors().find_map(valid_target_expr)?; 20 let expr = node.ancestors().find_map(valid_target_expr)?;
22 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; 21 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?;
23 let indent = anchor_stmt.prev_sibling()?; 22 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?;
24 if indent.kind() != WHITESPACE { 23 if indent.kind() != WHITESPACE {
25 return None; 24 return None;
26 } 25 }
@@ -54,16 +53,15 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
54 // We want to maintain the indent level, 53 // We want to maintain the indent level,
55 // but we do not want to duplicate possible 54 // but we do not want to duplicate possible
56 // extra newlines in the indent block 55 // extra newlines in the indent block
57 for chunk in indent.text().chunks() { 56 let text = indent.text();
58 if chunk.starts_with("\r\n") { 57 if text.starts_with("\r\n") {
59 buf.push_str("\r\n"); 58 buf.push_str("\r\n");
60 buf.push_str(chunk.trim_start_matches("\r\n")); 59 buf.push_str(text.trim_start_matches("\r\n"));
61 } else if chunk.starts_with("\n") { 60 } else if text.starts_with("\n") {
62 buf.push_str("\n"); 61 buf.push_str("\n");
63 buf.push_str(chunk.trim_start_matches("\n")); 62 buf.push_str(text.trim_start_matches("\n"));
64 } else { 63 } else {
65 buf.push_str(chunk); 64 buf.push_str(text);
66 }
67 } 65 }
68 66
69 edit.target(expr.syntax().range()); 67 edit.target(expr.syntax().range());
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index 6ea48d909..ae9958f11 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -62,15 +62,15 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
62 let name_ref = path.segment()?.name_ref()?; 62 let name_ref = path.segment()?.name_ref()?;
63 63
64 // Make sure it is actually a dbg-macro call, dbg followed by ! 64 // Make sure it is actually a dbg-macro call, dbg followed by !
65 let excl = path.syntax().next_sibling()?; 65 let excl = path.syntax().next_sibling_or_token()?;
66 66
67 if name_ref.text() != macro_name || excl.kind() != EXCL { 67 if name_ref.text() != macro_name || excl.kind() != EXCL {
68 return None; 68 return None;
69 } 69 }
70 70
71 let node = macro_call.token_tree()?.syntax(); 71 let node = macro_call.token_tree()?.syntax();
72 let first_child = node.first_child()?; 72 let first_child = node.first_child_or_token()?;
73 let last_child = node.last_child()?; 73 let last_child = node.last_child_or_token()?;
74 74
75 match (first_child.kind(), last_child.kind()) { 75 match (first_child.kind(), last_child.kind()) {
76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), 76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true),
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs
index dd5be4e91..4bf1852db 100644
--- a/crates/ra_assists/src/split_import.rs
+++ b/crates/ra_assists/src/split_import.rs
@@ -8,8 +8,8 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; 11 let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?;
12 let path = colon_colon.parent().and_then(ast::Path::cast)?; 12 let path = ast::Path::cast(colon_colon.parent())?;
13 let top_path = generate(Some(path), |it| it.parent_path()).last()?; 13 let top_path = generate(Some(path), |it| it.parent_path()).last()?;
14 14
15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); 15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index ee410c548..4516ed660 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -1,4 +1,4 @@
1use std::collections::HashSet; 1use std::{collections::HashSet, time::Instant};
2 2
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_batch::BatchDatabase; 4use ra_batch::BatchDatabase;
@@ -8,8 +8,10 @@ use ra_syntax::AstNode;
8use crate::Result; 8use crate::Result;
9 9
10pub fn run(verbose: bool) -> Result<()> { 10pub fn run(verbose: bool) -> Result<()> {
11 let db_load_time = Instant::now();
11 let (db, roots) = BatchDatabase::load_cargo(".")?; 12 let (db, roots) = BatchDatabase::load_cargo(".")?;
12 println!("Database loaded, {} roots", roots.len()); 13 println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
14 let analysis_time = Instant::now();
13 let mut num_crates = 0; 15 let mut num_crates = 0;
14 let mut visited_modules = HashSet::new(); 16 let mut visited_modules = HashSet::new();
15 let mut visit_queue = Vec::new(); 17 let mut visit_queue = Vec::new();
@@ -96,5 +98,6 @@ pub fn run(verbose: bool) -> Result<()> {
96 num_exprs_partially_unknown, 98 num_exprs_partially_unknown,
97 (num_exprs_partially_unknown * 100 / num_exprs) 99 (num_exprs_partially_unknown * 100 / num_exprs)
98 ); 100 );
101 println!("Analysis: {:?}", analysis_time.elapsed());
99 Ok(()) 102 Ok(())
100} 103}
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 11f5541eb..1f2750d89 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -3,10 +3,8 @@ mod analysis_stats;
3use std::{fs, io::Read, path::Path, time::Instant}; 3use std::{fs, io::Read, path::Path, time::Instant};
4 4
5use clap::{App, Arg, SubCommand}; 5use clap::{App, Arg, SubCommand};
6use join_to_string::join;
7use ra_ide_api::{Analysis, FileRange};
8use ra_ide_api::file_structure; 6use ra_ide_api::file_structure;
9use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; 7use ra_syntax::{SourceFile, TreeArc, AstNode};
10use tools::collect_tests; 8use tools::collect_tests;
11use flexi_logger::Logger; 9use flexi_logger::Logger;
12 10
@@ -24,11 +22,6 @@ fn main() -> Result<()> {
24 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) 22 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
25 .subcommand(SubCommand::with_name("symbols")) 23 .subcommand(SubCommand::with_name("symbols"))
26 .subcommand( 24 .subcommand(
27 SubCommand::with_name("extend-selection")
28 .arg(Arg::with_name("start"))
29 .arg(Arg::with_name("end")),
30 )
31 .subcommand(
32 SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), 25 SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")),
33 ) 26 )
34 .get_matches(); 27 .get_matches();
@@ -57,13 +50,6 @@ fn main() -> Result<()> {
57 let (test, tree) = render_test(file, line)?; 50 let (test, tree) = render_test(file, line)?;
58 println!("{}\n{}", test, tree); 51 println!("{}\n{}", test, tree);
59 } 52 }
60 ("extend-selection", Some(matches)) => {
61 let start: u32 = matches.value_of("start").unwrap().parse()?;
62 let end: u32 = matches.value_of("end").unwrap().parse()?;
63 let text = read_stdin()?;
64 let sels = selections(text, start, end);
65 println!("{}", sels)
66 }
67 ("analysis-stats", Some(matches)) => { 53 ("analysis-stats", Some(matches)) => {
68 let verbose = matches.is_present("verbose"); 54 let verbose = matches.is_present("verbose");
69 analysis_stats::run(verbose)?; 55 analysis_stats::run(verbose)?;
@@ -98,22 +84,3 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
98 let tree = file.syntax().debug_dump(); 84 let tree = file.syntax().debug_dump();
99 Ok((test.text, tree)) 85 Ok((test.text, tree))
100} 86}
101
102fn selections(text: String, start: u32, end: u32) -> String {
103 let (analysis, file_id) = Analysis::from_single_file(text);
104 let mut ranges = Vec::new();
105 let mut range = TextRange::from_to((start - 1).into(), (end - 1).into());
106 loop {
107 ranges.push(range);
108 let next = analysis.extend_selection(FileRange { file_id, range }).unwrap();
109 if range == next {
110 break;
111 }
112 range = next;
113 }
114 let ranges = ranges
115 .iter()
116 .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
117 .map(|(s, e)| format!("({} {})", s, e));
118 join(ranges).separator(" ").surround_with("(", ")").to_string()
119}
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs
index 62e6fb9c1..ea90dc2b8 100644
--- a/crates/ra_fmt/src/lib.rs
+++ b/crates/ra_fmt/src/lib.rs
@@ -3,8 +3,8 @@
3use itertools::Itertools; 3use itertools::Itertools;
4use ra_syntax::{ 4use ra_syntax::{
5 AstNode, 5 AstNode,
6 SyntaxNode, SyntaxKind::*, 6 SyntaxNode, SyntaxKind::*, SyntaxToken, SyntaxKind,
7 ast::{self, AstToken}, 7 ast,
8 algo::generate, 8 algo::generate,
9}; 9};
10 10
@@ -15,26 +15,22 @@ pub fn reindent(text: &str, indent: &str) -> String {
15 15
16/// If the node is on the beginning of the line, calculate indent. 16/// If the node is on the beginning of the line, calculate indent.
17pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { 17pub fn leading_indent(node: &SyntaxNode) -> Option<&str> {
18 for leaf in prev_leaves(node) { 18 for token in prev_tokens(node.first_token()?) {
19 if let Some(ws) = ast::Whitespace::cast(leaf) { 19 if let Some(ws) = ast::Whitespace::cast(token) {
20 let ws_text = ws.text(); 20 let ws_text = ws.text();
21 if let Some(pos) = ws_text.rfind('\n') { 21 if let Some(pos) = ws_text.rfind('\n') {
22 return Some(&ws_text[pos + 1..]); 22 return Some(&ws_text[pos + 1..]);
23 } 23 }
24 } 24 }
25 if leaf.leaf_text().unwrap().contains('\n') { 25 if token.text().contains('\n') {
26 break; 26 break;
27 } 27 }
28 } 28 }
29 None 29 None
30} 30}
31 31
32fn prev_leaves(node: &SyntaxNode) -> impl Iterator<Item = &SyntaxNode> { 32fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
33 generate(prev_leaf(node), |&node| prev_leaf(node)) 33 generate(token.prev_token(), |&token| token.prev_token())
34}
35
36fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> {
37 generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| it.last_child()).last()
38} 34}
39 35
40pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { 36pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
@@ -52,20 +48,20 @@ pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
52 Some(expr) 48 Some(expr)
53} 49}
54 50
55pub fn compute_ws(left: &SyntaxNode, right: &SyntaxNode) -> &'static str { 51pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
56 match left.kind() { 52 match left {
57 L_PAREN | L_BRACK => return "", 53 L_PAREN | L_BRACK => return "",
58 L_CURLY => { 54 L_CURLY => {
59 if let USE_TREE = right.kind() { 55 if let USE_TREE = right {
60 return ""; 56 return "";
61 } 57 }
62 } 58 }
63 _ => (), 59 _ => (),
64 } 60 }
65 match right.kind() { 61 match right {
66 R_PAREN | R_BRACK => return "", 62 R_PAREN | R_BRACK => return "",
67 R_CURLY => { 63 R_CURLY => {
68 if let USE_TREE = left.kind() { 64 if let USE_TREE = left {
69 return ""; 65 return "";
70 } 66 }
71 } 67 }
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index a85422955..2ff4139f9 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -726,13 +726,7 @@ impl ExprCollector {
726 self.alloc_expr(Expr::Array { exprs }, syntax_ptr) 726 self.alloc_expr(Expr::Array { exprs }, syntax_ptr)
727 } 727 }
728 ast::ExprKind::Literal(e) => { 728 ast::ExprKind::Literal(e) => {
729 let child = if let Some(child) = e.literal_expr() { 729 let lit = match e.flavor() {
730 child
731 } else {
732 return self.alloc_expr(Expr::Missing, syntax_ptr);
733 };
734
735 let lit = match child.flavor() {
736 LiteralFlavor::IntNumber { suffix } => { 730 LiteralFlavor::IntNumber { suffix } => {
737 let known_name = suffix 731 let known_name = suffix
738 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); 732 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
@@ -874,9 +868,7 @@ impl ExprCollector {
874 fn collect_fn_body(&mut self, node: &ast::FnDef) { 868 fn collect_fn_body(&mut self, node: &ast::FnDef) {
875 if let Some(param_list) = node.param_list() { 869 if let Some(param_list) = node.param_list() {
876 if let Some(self_param) = param_list.self_param() { 870 if let Some(self_param) = param_list.self_param() {
877 let self_param = SyntaxNodePtr::new( 871 let self_param = SyntaxNodePtr::new(self_param.syntax());
878 self_param.self_kw().expect("self param without self keyword").syntax(),
879 );
880 let param_pat = self.alloc_pat( 872 let param_pat = self.alloc_pat(
881 Pat::Bind { 873 Pat::Bind {
882 name: Name::self_param(), 874 name: Name::self_param(),
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 9dae4c3d1..54dc27399 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -9,7 +9,7 @@ use ra_db::{FileId, FilePosition};
9use ra_syntax::{ 9use ra_syntax::{
10 SyntaxNode, 10 SyntaxNode,
11 ast::{self, AstNode, NameOwner}, 11 ast::{self, AstNode, NameOwner},
12 algo::{find_node_at_offset, find_leaf_at_offset}, 12 algo::{find_node_at_offset, find_token_at_offset},
13}; 13};
14 14
15use crate::{ 15use crate::{
@@ -155,9 +155,9 @@ pub fn trait_from_module(
155pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { 155pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver {
156 let file_id = position.file_id; 156 let file_id = position.file_id;
157 let file = db.parse(file_id); 157 let file = db.parse(file_id);
158 find_leaf_at_offset(file.syntax(), position.offset) 158 find_token_at_offset(file.syntax(), position.offset)
159 .find_map(|node| { 159 .find_map(|token| {
160 node.ancestors().find_map(|node| { 160 token.parent().ancestors().find_map(|node| {
161 if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { 161 if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
162 if let Some(func) = function_from_child_node(db, file_id, node) { 162 if let Some(func) = function_from_child_node(db, file_id, node) {
163 let scopes = func.scopes(db); 163 let scopes = func.scopes(db);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 655f3c522..943c5499b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2251,14 +2251,12 @@ fn infer(content: &str) -> String {
2251 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); 2251 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
2252 for (syntax_ptr, ty) in &types { 2252 for (syntax_ptr, ty) in &types {
2253 let node = syntax_ptr.to_node(&source_file); 2253 let node = syntax_ptr.to_node(&source_file);
2254 write!( 2254 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node) {
2255 acc, 2255 (self_param.self_kw_token().range(), "self".to_string())
2256 "{} '{}': {}\n", 2256 } else {
2257 syntax_ptr.range(), 2257 (syntax_ptr.range(), node.text().to_string().replace("\n", " "))
2258 ellipsize(node.text().to_string().replace("\n", " "), 15), 2258 };
2259 ty.display(&db) 2259 write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap();
2260 )
2261 .unwrap();
2262 } 2260 }
2263 } 2261 }
2264 acc.truncate(acc.trim_end().len()); 2262 acc.truncate(acc.trim_end().len());
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 639942f7b..a846a7a3c 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -13,7 +13,7 @@ mod complete_scope;
13mod complete_postfix; 13mod complete_postfix;
14 14
15use ra_db::SourceDatabase; 15use ra_db::SourceDatabase;
16use ra_syntax::ast::{self, AstNode}; 16use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}};
17 17
18use crate::{ 18use crate::{
19 db, 19 db,
@@ -76,11 +76,10 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
76 let body_range = body.syntax().range(); 76 let body_range = body.syntax().range();
77 let label: String = node 77 let label: String = node
78 .syntax() 78 .syntax()
79 .children() 79 .children_with_tokens()
80 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 80 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
81 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments 81 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) // Filter out comments and attrs
82 .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes 82 .map(|node| node.to_string())
83 .map(|node| node.text().to_string())
84 .collect(); 83 .collect();
85 label 84 label
86 } else { 85 } else {
@@ -93,10 +92,9 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
93pub fn const_label(node: &ast::ConstDef) -> String { 92pub fn const_label(node: &ast::ConstDef) -> String {
94 let label: String = node 93 let label: String = node
95 .syntax() 94 .syntax()
96 .children() 95 .children_with_tokens()
97 .filter(|child| ast::Comment::cast(child).is_none()) 96 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
98 .filter(|child| ast::Attr::cast(child).is_none()) 97 .map(|node| node.to_string())
99 .map(|node| node.text().to_string())
100 .collect(); 98 .collect();
101 99
102 label.trim().to_owned() 100 label.trim().to_owned()
@@ -105,10 +103,9 @@ pub fn const_label(node: &ast::ConstDef) -> String {
105pub fn type_label(node: &ast::TypeAliasDef) -> String { 103pub fn type_label(node: &ast::TypeAliasDef) -> String {
106 let label: String = node 104 let label: String = node
107 .syntax() 105 .syntax()
108 .children() 106 .children_with_tokens()
109 .filter(|child| ast::Comment::cast(child).is_none()) 107 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
110 .filter(|child| ast::Attr::cast(child).is_none()) 108 .map(|node| node.to_string())
111 .map(|node| node.text().to_string())
112 .collect(); 109 .collect();
113 110
114 label.trim().to_owned() 111 label.trim().to_owned()
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index ffdc744b2..f87ccdeb9 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -17,7 +17,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
17 } 17 }
18 18
19 let mut params = FxHashMap::default(); 19 let mut params = FxHashMap::default();
20 for node in ctx.leaf.ancestors() { 20 for node in ctx.token.parent().ancestors() {
21 let _ = visitor_ctx(&mut params) 21 let _ = visitor_ctx(&mut params)
22 .visit::<ast::SourceFile, _>(process) 22 .visit::<ast::SourceFile, _>(process)
23 .visit::<ast::ItemList, _>(process) 23 .visit::<ast::ItemList, _>(process)
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs
index 841c0c554..718b83418 100644
--- a/crates/ra_ide_api/src/completion/complete_keyword.rs
+++ b/crates/ra_ide_api/src/completion/complete_keyword.rs
@@ -2,7 +2,7 @@ use ra_syntax::{
2 algo::visit::{visitor, Visitor}, 2 algo::visit::{visitor, Visitor},
3 AstNode, 3 AstNode,
4 ast::{self, LoopBodyOwner}, 4 ast::{self, LoopBodyOwner},
5 SyntaxKind::*, SyntaxNode, 5 SyntaxKind::*, SyntaxToken,
6}; 6};
7 7
8use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind}; 8use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind};
@@ -62,7 +62,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
62 acc.add(keyword(ctx, "else", "else {$0}")); 62 acc.add(keyword(ctx, "else", "else {$0}"));
63 acc.add(keyword(ctx, "else if", "else if $0 {}")); 63 acc.add(keyword(ctx, "else if", "else if $0 {}"));
64 } 64 }
65 if is_in_loop_body(ctx.leaf) { 65 if is_in_loop_body(ctx.token) {
66 if ctx.can_be_stmt { 66 if ctx.can_be_stmt {
67 acc.add(keyword(ctx, "continue", "continue;")); 67 acc.add(keyword(ctx, "continue", "continue;"));
68 acc.add(keyword(ctx, "break", "break;")); 68 acc.add(keyword(ctx, "break", "break;"));
@@ -74,8 +74,8 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
74 acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt)); 74 acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt));
75} 75}
76 76
77fn is_in_loop_body(leaf: &SyntaxNode) -> bool { 77fn is_in_loop_body(leaf: SyntaxToken) -> bool {
78 for node in leaf.ancestors() { 78 for node in leaf.parent().ancestors() {
79 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { 79 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
80 break; 80 break;
81 } 81 }
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 724d0dfbf..65dffa470 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -1,8 +1,8 @@
1use ra_text_edit::AtomTextEdit; 1use ra_text_edit::AtomTextEdit;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, 3 AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, SyntaxToken,
4 ast, 4 ast,
5 algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, 5 algo::{find_token_at_offset, find_covering_element, find_node_at_offset},
6 SyntaxKind::*, 6 SyntaxKind::*,
7}; 7};
8use hir::{source_binder, Resolver}; 8use hir::{source_binder, Resolver};
@@ -15,7 +15,7 @@ use crate::{db, FilePosition};
15pub(crate) struct CompletionContext<'a> { 15pub(crate) struct CompletionContext<'a> {
16 pub(super) db: &'a db::RootDatabase, 16 pub(super) db: &'a db::RootDatabase,
17 pub(super) offset: TextUnit, 17 pub(super) offset: TextUnit,
18 pub(super) leaf: &'a SyntaxNode, 18 pub(super) token: SyntaxToken<'a>,
19 pub(super) resolver: Resolver, 19 pub(super) resolver: Resolver,
20 pub(super) module: Option<hir::Module>, 20 pub(super) module: Option<hir::Module>,
21 pub(super) function: Option<hir::Function>, 21 pub(super) function: Option<hir::Function>,
@@ -49,10 +49,10 @@ impl<'a> CompletionContext<'a> {
49 ) -> Option<CompletionContext<'a>> { 49 ) -> Option<CompletionContext<'a>> {
50 let resolver = source_binder::resolver_for_position(db, position); 50 let resolver = source_binder::resolver_for_position(db, position);
51 let module = source_binder::module_from_position(db, position); 51 let module = source_binder::module_from_position(db, position);
52 let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; 52 let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?;
53 let mut ctx = CompletionContext { 53 let mut ctx = CompletionContext {
54 db, 54 db,
55 leaf, 55 token,
56 offset: position.offset, 56 offset: position.offset,
57 resolver, 57 resolver,
58 module, 58 module,
@@ -76,9 +76,9 @@ impl<'a> CompletionContext<'a> {
76 76
77 // The range of the identifier that is being completed. 77 // The range of the identifier that is being completed.
78 pub(crate) fn source_range(&self) -> TextRange { 78 pub(crate) fn source_range(&self) -> TextRange {
79 match self.leaf.kind() { 79 match self.token.kind() {
80 // workaroud when completion is triggered by trigger characters. 80 // workaroud when completion is triggered by trigger characters.
81 IDENT => self.leaf.range(), 81 IDENT => self.token.range(),
82 _ => TextRange::offset_len(self.offset, 0.into()), 82 _ => TextRange::offset_len(self.offset, 0.into()),
83 } 83 }
84 } 84 }
@@ -139,10 +139,11 @@ impl<'a> CompletionContext<'a> {
139 _ => (), 139 _ => (),
140 } 140 }
141 141
142 self.use_item_syntax = self.leaf.ancestors().find_map(ast::UseItem::cast); 142 self.use_item_syntax = self.token.parent().ancestors().find_map(ast::UseItem::cast);
143 143
144 self.function_syntax = self 144 self.function_syntax = self
145 .leaf 145 .token
146 .parent()
146 .ancestors() 147 .ancestors()
147 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 148 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
148 .find_map(ast::FnDef::cast); 149 .find_map(ast::FnDef::cast);
@@ -224,8 +225,7 @@ impl<'a> CompletionContext<'a> {
224} 225}
225 226
226fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> { 227fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> {
227 let node = find_covering_node(syntax, range); 228 find_covering_element(syntax, range).ancestors().find_map(N::cast)
228 node.ancestors().find_map(N::cast)
229} 229}
230 230
231fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { 231fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 5a78e94d8..2dfaa0045 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -106,8 +106,10 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
106 single_use_tree: &ast::UseTree, 106 single_use_tree: &ast::UseTree,
107) -> Option<TextEdit> { 107) -> Option<TextEdit> {
108 let use_tree_list_node = single_use_tree.syntax().parent()?; 108 let use_tree_list_node = single_use_tree.syntax().parent()?;
109 if single_use_tree.path()?.segment()?.syntax().first_child()?.kind() == SyntaxKind::SELF_KW { 109 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind()
110 let start = use_tree_list_node.prev_sibling()?.range().start(); 110 == SyntaxKind::SELF_KW
111 {
112 let start = use_tree_list_node.prev_sibling_or_token()?.range().start();
111 let end = use_tree_list_node.range().end(); 113 let end = use_tree_list_node.range().end();
112 let range = TextRange::from_to(start, end); 114 let range = TextRange::from_to(start, end);
113 let mut edit_builder = TextEditBuilder::default(); 115 let mut edit_builder = TextEditBuilder::default();
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 63879a0b5..e743bf0fe 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -1,8 +1,9 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 Direction, SyntaxNode, TextRange, TextUnit, AstNode, 3 Direction, SyntaxNode, TextRange, TextUnit, AstNode, SyntaxElement,
4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 4 algo::{find_covering_element, find_token_at_offset, TokenAtOffset},
5 SyntaxKind::*, 5 SyntaxKind::*, SyntaxToken,
6 ast::Comment,
6}; 7};
7 8
8use crate::{FileRange, db::RootDatabase}; 9use crate::{FileRange, db::RootDatabase};
@@ -32,53 +33,58 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
32 33
33 if range.is_empty() { 34 if range.is_empty() {
34 let offset = range.start(); 35 let offset = range.start();
35 let mut leaves = find_leaf_at_offset(root, offset); 36 let mut leaves = find_token_at_offset(root, offset);
36 if leaves.clone().all(|it| it.kind() == WHITESPACE) { 37 if leaves.clone().all(|it| it.kind() == WHITESPACE) {
37 return Some(extend_ws(root, leaves.next()?, offset)); 38 return Some(extend_ws(root, leaves.next()?, offset));
38 } 39 }
39 let leaf_range = match leaves { 40 let leaf_range = match leaves {
40 LeafAtOffset::None => return None, 41 TokenAtOffset::None => return None,
41 LeafAtOffset::Single(l) => { 42 TokenAtOffset::Single(l) => {
42 if string_kinds.contains(&l.kind()) { 43 if string_kinds.contains(&l.kind()) {
43 extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range()) 44 extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range())
44 } else { 45 } else {
45 l.range() 46 l.range()
46 } 47 }
47 } 48 }
48 LeafAtOffset::Between(l, r) => pick_best(l, r).range(), 49 TokenAtOffset::Between(l, r) => pick_best(l, r).range(),
49 }; 50 };
50 return Some(leaf_range); 51 return Some(leaf_range);
51 }; 52 };
52 let node = find_covering_node(root, range); 53 let node = match find_covering_element(root, range) {
54 SyntaxElement::Token(token) => {
55 if token.range() != range {
56 return Some(token.range());
57 }
58 if let Some(comment) = Comment::cast(token) {
59 if let Some(range) = extend_comments(comment) {
60 return Some(range);
61 }
62 }
63 token.parent()
64 }
65 SyntaxElement::Node(node) => node,
66 };
67 if node.range() != range {
68 return Some(node.range());
69 }
53 70
54 // Using shallowest node with same range allows us to traverse siblings. 71 // Using shallowest node with same range allows us to traverse siblings.
55 let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap(); 72 let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap();
56 73
57 if range == node.range() { 74 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
58 if string_kinds.contains(&node.kind()) { 75 if let Some(range) = extend_list_item(node) {
59 if let Some(range) = extend_comments(node) { 76 return Some(range);
60 return Some(range);
61 }
62 }
63
64 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
65 if let Some(range) = extend_list_item(node) {
66 return Some(range);
67 }
68 } 77 }
69 } 78 }
70 79
71 match node.ancestors().skip_while(|n| n.range() == range).next() { 80 node.parent().map(|it| it.range())
72 None => None,
73 Some(parent) => Some(parent.range()),
74 }
75} 81}
76 82
77fn extend_single_word_in_comment_or_string( 83fn extend_single_word_in_comment_or_string(
78 leaf: &SyntaxNode, 84 leaf: SyntaxToken,
79 offset: TextUnit, 85 offset: TextUnit,
80) -> Option<TextRange> { 86) -> Option<TextRange> {
81 let text: &str = leaf.leaf_text()?; 87 let text: &str = leaf.text();
82 let cursor_position: u32 = (offset - leaf.range().start()).into(); 88 let cursor_position: u32 = (offset - leaf.range().start()).into();
83 89
84 let (before, after) = text.split_at(cursor_position as usize); 90 let (before, after) = text.split_at(cursor_position as usize);
@@ -101,14 +107,14 @@ fn extend_single_word_in_comment_or_string(
101 } 107 }
102} 108}
103 109
104fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange { 110fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange {
105 let ws_text = ws.leaf_text().unwrap(); 111 let ws_text = ws.text();
106 let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start(); 112 let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start();
107 let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start(); 113 let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start();
108 let ws_suffix = &ws_text.as_str()[suffix]; 114 let ws_suffix = &ws_text.as_str()[suffix];
109 let ws_prefix = &ws_text.as_str()[prefix]; 115 let ws_prefix = &ws_text.as_str()[prefix];
110 if ws_text.contains('\n') && !ws_suffix.contains('\n') { 116 if ws_text.contains('\n') && !ws_suffix.contains('\n') {
111 if let Some(node) = ws.next_sibling() { 117 if let Some(node) = ws.next_sibling_or_token() {
112 let start = match ws_prefix.rfind('\n') { 118 let start = match ws_prefix.rfind('\n') {
113 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), 119 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32),
114 None => node.range().start(), 120 None => node.range().start(),
@@ -124,9 +130,9 @@ fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange
124 ws.range() 130 ws.range()
125} 131}
126 132
127fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { 133fn pick_best<'a>(l: SyntaxToken<'a>, r: SyntaxToken<'a>) -> SyntaxToken<'a> {
128 return if priority(r) > priority(l) { r } else { l }; 134 return if priority(r) > priority(l) { r } else { l };
129 fn priority(n: &SyntaxNode) -> usize { 135 fn priority(n: SyntaxToken) -> usize {
130 match n.kind() { 136 match n.kind() {
131 WHITESPACE => 0, 137 WHITESPACE => 0,
132 IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2, 138 IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2,
@@ -137,54 +143,60 @@ fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode {
137 143
138/// Extend list item selection to include nearby comma and whitespace. 144/// Extend list item selection to include nearby comma and whitespace.
139fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> { 145fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
140 fn is_single_line_ws(node: &SyntaxNode) -> bool { 146 fn is_single_line_ws(node: &SyntaxToken) -> bool {
141 node.kind() == WHITESPACE && !node.leaf_text().unwrap().contains('\n') 147 node.kind() == WHITESPACE && !node.text().contains('\n')
142 } 148 }
143 149
144 fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<&SyntaxNode> { 150 fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<SyntaxToken> {
145 node.siblings(dir) 151 node.siblings_with_tokens(dir)
146 .skip(1) 152 .skip(1)
147 .skip_while(|node| is_single_line_ws(node)) 153 .skip_while(|node| match node {
154 SyntaxElement::Node(_) => false,
155 SyntaxElement::Token(it) => is_single_line_ws(it),
156 })
148 .next() 157 .next()
158 .and_then(|it| it.as_token())
149 .filter(|node| node.kind() == COMMA) 159 .filter(|node| node.kind() == COMMA)
150 } 160 }
151 161
152 if let Some(comma_node) = nearby_comma(node, Direction::Prev) { 162 if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
153 return Some(TextRange::from_to(comma_node.range().start(), node.range().end())); 163 return Some(TextRange::from_to(comma_node.range().start(), node.range().end()));
154 } 164 }
155
156 if let Some(comma_node) = nearby_comma(node, Direction::Next) { 165 if let Some(comma_node) = nearby_comma(node, Direction::Next) {
157 // Include any following whitespace when comma if after list item. 166 // Include any following whitespace when comma if after list item.
158 let final_node = comma_node 167 let final_node = comma_node
159 .siblings(Direction::Next) 168 .next_sibling_or_token()
160 .skip(1) 169 .and_then(|it| it.as_token())
161 .next()
162 .filter(|node| is_single_line_ws(node)) 170 .filter(|node| is_single_line_ws(node))
163 .unwrap_or(comma_node); 171 .unwrap_or(comma_node);
164 172
165 return Some(TextRange::from_to(node.range().start(), final_node.range().end())); 173 return Some(TextRange::from_to(node.range().start(), final_node.range().end()));
166 } 174 }
167 175
168 return None; 176 None
169} 177}
170 178
171fn extend_comments(node: &SyntaxNode) -> Option<TextRange> { 179fn extend_comments(comment: Comment) -> Option<TextRange> {
172 let prev = adj_comments(node, Direction::Prev); 180 let prev = adj_comments(comment, Direction::Prev);
173 let next = adj_comments(node, Direction::Next); 181 let next = adj_comments(comment, Direction::Next);
174 if prev != next { 182 if prev != next {
175 Some(TextRange::from_to(prev.range().start(), next.range().end())) 183 Some(TextRange::from_to(prev.syntax().range().start(), next.syntax().range().end()))
176 } else { 184 } else {
177 None 185 None
178 } 186 }
179} 187}
180 188
181fn adj_comments(node: &SyntaxNode, dir: Direction) -> &SyntaxNode { 189fn adj_comments(comment: Comment, dir: Direction) -> Comment {
182 let mut res = node; 190 let mut res = comment;
183 for node in node.siblings(dir) { 191 for element in comment.syntax().siblings_with_tokens(dir) {
184 match node.kind() { 192 let token = match element.as_token() {
185 COMMENT => res = node, 193 None => break,
186 WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), 194 Some(token) => token,
187 _ => break, 195 };
196 if let Some(c) = Comment::cast(token) {
197 res = c
198 } else if token.kind() != WHITESPACE || token.text().contains("\n\n") {
199 break;
188 } 200 }
189 } 201 }
190 res 202 res
@@ -308,23 +320,13 @@ fn bar(){}
308/* 320/*
309foo 321foo
310_bar1<|>*/ 322_bar1<|>*/
311 "#, 323"#,
312 &["_bar1", "/*\nfoo\n_bar1*/"], 324 &["_bar1", "/*\nfoo\n_bar1*/"],
313 ); 325 );
314 326
315 do_check( 327 do_check(r#"//!<|>foo_2 bar"#, &["foo_2", "//!foo_2 bar"]);
316 r#"
317//!<|>foo_2 bar
318 "#,
319 &["foo_2", "//!foo_2 bar"],
320 );
321 328
322 do_check( 329 do_check(r#"/<|>/foo bar"#, &["//foo bar"]);
323 r#"
324/<|>/foo bar
325 "#,
326 &["//foo bar"],
327 );
328 } 330 }
329 331
330 #[test] 332 #[test]
@@ -332,13 +334,13 @@ _bar1<|>*/
332 do_check( 334 do_check(
333 r#" 335 r#"
334fn main() { foo<|>+bar;} 336fn main() { foo<|>+bar;}
335 "#, 337"#,
336 &["foo", "foo+bar"], 338 &["foo", "foo+bar"],
337 ); 339 );
338 do_check( 340 do_check(
339 r#" 341 r#"
340fn main() { foo+<|>bar;} 342fn main() { foo+<|>bar;}
341 "#, 343"#,
342 &["bar", "foo+bar"], 344 &["bar", "foo+bar"],
343 ); 345 );
344 } 346 }
@@ -355,11 +357,11 @@ fn main() { foo+<|>bar;}
355 do_check( 357 do_check(
356 r#" 358 r#"
357impl S { 359impl S {
358 fn foo() { 360fn foo() {
359 // hel<|>lo world 361// hel<|>lo world
360 }
361} 362}
362 "#, 363}
364"#,
363 &["hello", "// hello world"], 365 &["hello", "// hello world"],
364 ); 366 );
365 } 367 }
@@ -371,7 +373,7 @@ impl S {
371fn bar(){} 373fn bar(){}
372 374
373" fn f<|>oo() {" 375" fn f<|>oo() {"
374 "#, 376"#,
375 &["foo", "\" fn foo() {\""], 377 &["foo", "\" fn foo() {\""],
376 ); 378 );
377 } 379 }
diff --git a/crates/ra_ide_api/src/folding_ranges.rs b/crates/ra_ide_api/src/folding_ranges.rs
index b96145f05..a6fe8a5d5 100644
--- a/crates/ra_ide_api/src/folding_ranges.rs
+++ b/crates/ra_ide_api/src/folding_ranges.rs
@@ -1,9 +1,9 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, Direction, SourceFile, SyntaxNode, TextRange, 4 AstNode, SourceFile, SyntaxNode, TextRange, Direction, SyntaxElement,
5 SyntaxKind::{self, *}, 5 SyntaxKind::{self, *},
6 ast::{self, VisibilityOwner}, 6 ast::{self, VisibilityOwner, Comment},
7}; 7};
8 8
9#[derive(Debug, PartialEq, Eq)] 9#[derive(Debug, PartialEq, Eq)]
@@ -26,34 +26,49 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
26 let mut visited_imports = FxHashSet::default(); 26 let mut visited_imports = FxHashSet::default();
27 let mut visited_mods = FxHashSet::default(); 27 let mut visited_mods = FxHashSet::default();
28 28
29 for node in file.syntax().descendants() { 29 for element in file.syntax().descendants_with_tokens() {
30 // Fold items that span multiple lines 30 // Fold items that span multiple lines
31 if let Some(kind) = fold_kind(node.kind()) { 31 if let Some(kind) = fold_kind(element.kind()) {
32 if node.text().contains('\n') { 32 let is_multiline = match element {
33 res.push(Fold { range: node.range(), kind }); 33 SyntaxElement::Node(node) => node.text().contains('\n'),
34 SyntaxElement::Token(token) => token.text().contains('\n'),
35 };
36 if is_multiline {
37 res.push(Fold { range: element.range(), kind });
38 continue;
34 } 39 }
35 } 40 }
36 41
37 // Fold groups of comments 42 match element {
38 if node.kind() == COMMENT && !visited_comments.contains(&node) { 43 SyntaxElement::Token(token) => {
39 if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) { 44 // Fold groups of comments
40 res.push(Fold { range, kind: FoldKind::Comment }) 45 if let Some(comment) = ast::Comment::cast(token) {
46 if !visited_comments.contains(&comment) {
47 if let Some(range) =
48 contiguous_range_for_comment(comment, &mut visited_comments)
49 {
50 res.push(Fold { range, kind: FoldKind::Comment })
51 }
52 }
53 }
41 } 54 }
42 } 55 SyntaxElement::Node(node) => {
43 56 // Fold groups of imports
44 // Fold groups of imports 57 if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
45 if node.kind() == USE_ITEM && !visited_imports.contains(&node) { 58 if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) {
46 if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) { 59 res.push(Fold { range, kind: FoldKind::Imports })
47 res.push(Fold { range, kind: FoldKind::Imports }) 60 }
48 } 61 }
49 } 62
50 63 // Fold groups of mods
51 // Fold groups of mods 64 if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
52 if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) { 65 {
53 if let Some(range) = 66 if let Some(range) =
54 contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods) 67 contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods)
55 { 68 {
56 res.push(Fold { range, kind: FoldKind::Mods }) 69 res.push(Fold { range, kind: FoldKind::Mods })
70 }
71 }
57 } 72 }
58 } 73 }
59 } 74 }
@@ -90,16 +105,21 @@ fn contiguous_range_for_group_unless<'a>(
90 visited.insert(first); 105 visited.insert(first);
91 106
92 let mut last = first; 107 let mut last = first;
93 for node in first.siblings(Direction::Next) { 108 for element in first.siblings_with_tokens(Direction::Next) {
94 if let Some(ws) = ast::Whitespace::cast(node) { 109 let node = match element {
95 // There is a blank line, which means that the group ends here 110 SyntaxElement::Token(token) => {
96 if ws.count_newlines_lazy().take(2).count() == 2 { 111 if let Some(ws) = ast::Whitespace::cast(token) {
112 if !ws.spans_multiple_lines() {
113 // Ignore whitespace without blank lines
114 continue;
115 }
116 }
117 // There is a blank line or another token, which means that the
118 // group ends here
97 break; 119 break;
98 } 120 }
99 121 SyntaxElement::Node(node) => node,
100 // Ignore whitespace without blank lines 122 };
101 continue;
102 }
103 123
104 // Stop if we find a node that doesn't belong to the group 124 // Stop if we find a node that doesn't belong to the group
105 if node.kind() != first.kind() || unless(node) { 125 if node.kind() != first.kind() || unless(node) {
@@ -119,40 +139,42 @@ fn contiguous_range_for_group_unless<'a>(
119} 139}
120 140
121fn contiguous_range_for_comment<'a>( 141fn contiguous_range_for_comment<'a>(
122 first: &'a SyntaxNode, 142 first: Comment<'a>,
123 visited: &mut FxHashSet<&'a SyntaxNode>, 143 visited: &mut FxHashSet<Comment<'a>>,
124) -> Option<TextRange> { 144) -> Option<TextRange> {
125 visited.insert(first); 145 visited.insert(first);
126 146
127 // Only fold comments of the same flavor 147 // Only fold comments of the same flavor
128 let group_flavor = ast::Comment::cast(first)?.flavor(); 148 let group_flavor = first.flavor();
129 149
130 let mut last = first; 150 let mut last = first;
131 for node in first.siblings(Direction::Next) { 151 for element in first.syntax().siblings_with_tokens(Direction::Next) {
132 if let Some(ws) = ast::Whitespace::cast(node) { 152 match element {
133 // There is a blank line, which means the group ends here 153 SyntaxElement::Token(token) => {
134 if ws.count_newlines_lazy().take(2).count() == 2 { 154 if let Some(ws) = ast::Whitespace::cast(token) {
155 if !ws.spans_multiple_lines() {
156 // Ignore whitespace without blank lines
157 continue;
158 }
159 }
160 if let Some(c) = Comment::cast(token) {
161 if c.flavor() == group_flavor {
162 visited.insert(c);
163 last = c;
164 continue;
165 }
166 }
167 // The comment group ends because either:
168 // * An element of a different kind was reached
169 // * A comment of a different flavor was reached
135 break; 170 break;
136 } 171 }
137 172 SyntaxElement::Node(_) => break,
138 // Ignore whitespace without blank lines 173 };
139 continue;
140 }
141
142 match ast::Comment::cast(node) {
143 Some(next_comment) if next_comment.flavor() == group_flavor => {
144 visited.insert(node);
145 last = node;
146 }
147 // The comment group ends because either:
148 // * An element of a different kind was reached
149 // * A comment of a different flavor was reached
150 _ => break,
151 }
152 } 174 }
153 175
154 if first != last { 176 if first != last {
155 Some(TextRange::from_to(first.range().start(), last.range().end())) 177 Some(TextRange::from_to(first.syntax().range().start(), last.syntax().range().end()))
156 } else { 178 } else {
157 // The group consists of only one element, therefore it cannot be folded 179 // The group consists of only one element, therefore it cannot be folded
158 None 180 None
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 3206e68b9..bfa7cd67a 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,7 +1,7 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, 3 AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner},
4 algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, 4 algo::{find_covering_element, find_node_at_offset, find_token_at_offset, visit::{visitor, Visitor}},
5}; 5};
6use hir::HirDisplay; 6use hir::HirDisplay;
7 7
@@ -104,8 +104,11 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
104 } 104 }
105 105
106 if range.is_none() { 106 if range.is_none() {
107 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| { 107 let node = find_token_at_offset(file.syntax(), position.offset).find_map(|token| {
108 leaf.ancestors().find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) 108 token
109 .parent()
110 .ancestors()
111 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
109 })?; 112 })?;
110 let frange = FileRange { file_id: position.file_id, range: node.range() }; 113 let frange = FileRange { file_id: position.file_id, range: node.range() };
111 res.extend(type_of(db, frange).map(rust_code_markup)); 114 res.extend(type_of(db, frange).map(rust_code_markup));
@@ -123,13 +126,12 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
123pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 126pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
124 let file = db.parse(frange.file_id); 127 let file = db.parse(frange.file_id);
125 let syntax = file.syntax(); 128 let syntax = file.syntax();
126 let leaf_node = find_covering_node(syntax, frange.range); 129 let leaf_node = find_covering_element(syntax, frange.range);
127 // if we picked identifier, expand to pattern/expression 130 // if we picked identifier, expand to pattern/expression
128 let node = leaf_node 131 let node = leaf_node
129 .ancestors() 132 .ancestors()
130 .take_while(|it| it.range() == leaf_node.range()) 133 .take_while(|it| it.range() == leaf_node.range())
131 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some()) 134 .find(|&it| ast::Expr::cast(it).is_some() || ast::Pat::cast(it).is_some())?;
132 .unwrap_or(leaf_node);
133 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?; 135 let parent_fn = node.ancestors().find_map(ast::FnDef::cast)?;
134 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?; 136 let function = hir::source_binder::function_from_source(db, frange.file_id, parent_fn)?;
135 let infer = function.infer(db); 137 let infer = function.infer(db);
diff --git a/crates/ra_ide_api/src/join_lines.rs b/crates/ra_ide_api/src/join_lines.rs
index 8fb3eaa06..57b6f8384 100644
--- a/crates/ra_ide_api/src/join_lines.rs
+++ b/crates/ra_ide_api/src/join_lines.rs
@@ -1,8 +1,8 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use ra_syntax::{ 2use ra_syntax::{
3 SourceFile, TextRange, TextUnit, AstNode, SyntaxNode, 3 SourceFile, TextRange, TextUnit, AstNode, SyntaxNode, SyntaxElement, SyntaxToken,
4 SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK}, 4 SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK},
5 algo::{find_covering_node, non_trivia_sibling}, 5 algo::{find_covering_element, non_trivia_sibling},
6 ast, 6 ast,
7 Direction, 7 Direction,
8}; 8};
@@ -24,22 +24,22 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
24 range 24 range
25 }; 25 };
26 26
27 let node = find_covering_node(file.syntax(), range); 27 let node = match find_covering_element(file.syntax(), range) {
28 SyntaxElement::Node(node) => node,
29 SyntaxElement::Token(token) => token.parent(),
30 };
28 let mut edit = TextEditBuilder::default(); 31 let mut edit = TextEditBuilder::default();
29 for node in node.descendants() { 32 for token in node.descendants_with_tokens().filter_map(|it| it.as_token()) {
30 let text = match node.leaf_text() { 33 let range = match range.intersection(&token.range()) {
31 Some(text) => text,
32 None => continue,
33 };
34 let range = match range.intersection(&node.range()) {
35 Some(range) => range, 34 Some(range) => range,
36 None => continue, 35 None => continue,
37 } - node.range().start(); 36 } - token.range().start();
37 let text = token.text();
38 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { 38 for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
39 let pos: TextUnit = (pos as u32).into(); 39 let pos: TextUnit = (pos as u32).into();
40 let off = node.range().start() + range.start() + pos; 40 let off = token.range().start() + range.start() + pos;
41 if !edit.invalidates_offset(off) { 41 if !edit.invalidates_offset(off) {
42 remove_newline(&mut edit, node, text.as_str(), off); 42 remove_newline(&mut edit, token, off);
43 } 43 }
44 } 44 }
45 } 45 }
@@ -47,17 +47,12 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
47 edit.finish() 47 edit.finish()
48} 48}
49 49
50fn remove_newline( 50fn remove_newline(edit: &mut TextEditBuilder, token: SyntaxToken, offset: TextUnit) {
51 edit: &mut TextEditBuilder, 51 if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 {
52 node: &SyntaxNode,
53 node_text: &str,
54 offset: TextUnit,
55) {
56 if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 {
57 // The node is either the first or the last in the file 52 // The node is either the first or the last in the file
58 let suff = &node_text[TextRange::from_to( 53 let suff = &token.text()[TextRange::from_to(
59 offset - node.range().start() + TextUnit::of_char('\n'), 54 offset - token.range().start() + TextUnit::of_char('\n'),
60 TextUnit::of_str(node_text), 55 TextUnit::of_str(token.text()),
61 )]; 56 )];
62 let spaces = suff.bytes().take_while(|&b| b == b' ').count(); 57 let spaces = suff.bytes().take_while(|&b| b == b' ').count();
63 58
@@ -74,7 +69,7 @@ fn remove_newline(
74 // ``` 69 // ```
75 // 70 //
76 // into `my_function(<some-expr>)` 71 // into `my_function(<some-expr>)`
77 if join_single_expr_block(edit, node).is_some() { 72 if join_single_expr_block(edit, token).is_some() {
78 return; 73 return;
79 } 74 }
80 // ditto for 75 // ditto for
@@ -84,44 +79,50 @@ fn remove_newline(
84 // bar 79 // bar
85 // }; 80 // };
86 // ``` 81 // ```
87 if join_single_use_tree(edit, node).is_some() { 82 if join_single_use_tree(edit, token).is_some() {
88 return; 83 return;
89 } 84 }
90 85
91 // The node is between two other nodes 86 // The node is between two other nodes
92 let prev = node.prev_sibling().unwrap(); 87 let prev = token.prev_sibling_or_token().unwrap();
93 let next = node.next_sibling().unwrap(); 88 let next = token.next_sibling_or_token().unwrap();
94 if is_trailing_comma(prev.kind(), next.kind()) { 89 if is_trailing_comma(prev.kind(), next.kind()) {
95 // Removes: trailing comma, newline (incl. surrounding whitespace) 90 // Removes: trailing comma, newline (incl. surrounding whitespace)
96 edit.delete(TextRange::from_to(prev.range().start(), node.range().end())); 91 edit.delete(TextRange::from_to(prev.range().start(), token.range().end()));
97 } else if prev.kind() == COMMA && next.kind() == R_CURLY { 92 } else if prev.kind() == COMMA && next.kind() == R_CURLY {
98 // Removes: comma, newline (incl. surrounding whitespace) 93 // Removes: comma, newline (incl. surrounding whitespace)
99 let space = if let Some(left) = prev.prev_sibling() { compute_ws(left, next) } else { " " }; 94 let space = if let Some(left) = prev.prev_sibling_or_token() {
95 compute_ws(left.kind(), next.kind())
96 } else {
97 " "
98 };
100 edit.replace( 99 edit.replace(
101 TextRange::from_to(prev.range().start(), node.range().end()), 100 TextRange::from_to(prev.range().start(), token.range().end()),
102 space.to_string(), 101 space.to_string(),
103 ); 102 );
104 } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) { 103 } else if let (Some(_), Some(next)) =
104 (prev.as_token().and_then(ast::Comment::cast), next.as_token().and_then(ast::Comment::cast))
105 {
105 // Removes: newline (incl. surrounding whitespace), start of the next comment 106 // Removes: newline (incl. surrounding whitespace), start of the next comment
106 edit.delete(TextRange::from_to( 107 edit.delete(TextRange::from_to(
107 node.range().start(), 108 token.range().start(),
108 next.syntax().range().start() + TextUnit::of_str(next.prefix()), 109 next.syntax().range().start() + TextUnit::of_str(next.prefix()),
109 )); 110 ));
110 } else { 111 } else {
111 // Remove newline but add a computed amount of whitespace characters 112 // Remove newline but add a computed amount of whitespace characters
112 edit.replace(node.range(), compute_ws(prev, next).to_string()); 113 edit.replace(token.range(), compute_ws(prev.kind(), next.kind()).to_string());
113 } 114 }
114} 115}
115 116
116fn has_comma_after(node: &SyntaxNode) -> bool { 117fn has_comma_after(node: &SyntaxNode) -> bool {
117 match non_trivia_sibling(node, Direction::Next) { 118 match non_trivia_sibling(node.into(), Direction::Next) {
118 Some(n) => n.kind() == COMMA, 119 Some(n) => n.kind() == COMMA,
119 _ => false, 120 _ => false,
120 } 121 }
121} 122}
122 123
123fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { 124fn join_single_expr_block(edit: &mut TextEditBuilder, token: SyntaxToken) -> Option<()> {
124 let block = ast::Block::cast(node.parent()?)?; 125 let block = ast::Block::cast(token.parent())?;
125 let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; 126 let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
126 let expr = extract_trivial_expression(block)?; 127 let expr = extract_trivial_expression(block)?;
127 128
@@ -140,8 +141,8 @@ fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Opti
140 Some(()) 141 Some(())
141} 142}
142 143
143fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { 144fn join_single_use_tree(edit: &mut TextEditBuilder, token: SyntaxToken) -> Option<()> {
144 let use_tree_list = ast::UseTreeList::cast(node.parent()?)?; 145 let use_tree_list = ast::UseTreeList::cast(token.parent())?;
145 let (tree,) = use_tree_list.use_trees().collect_tuple()?; 146 let (tree,) = use_tree_list.use_trees().collect_tuple()?;
146 edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string()); 147 edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string());
147 Some(()) 148 Some(())
@@ -401,13 +402,13 @@ use ra_syntax::{
401 r" 402 r"
402use ra_syntax::{ 403use ra_syntax::{
403 algo::<|>{ 404 algo::<|>{
404 find_leaf_at_offset, 405 find_token_at_offset,
405 }, 406 },
406 ast, 407 ast,
407};", 408};",
408 r" 409 r"
409use ra_syntax::{ 410use ra_syntax::{
410 algo::<|>find_leaf_at_offset, 411 algo::<|>find_token_at_offset,
411 ast, 412 ast,
412};", 413};",
413 ); 414 );
diff --git a/crates/ra_ide_api/src/matching_brace.rs b/crates/ra_ide_api/src/matching_brace.rs
index d1405f14f..bebd16a69 100644
--- a/crates/ra_ide_api/src/matching_brace.rs
+++ b/crates/ra_ide_api/src/matching_brace.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 SourceFile, TextUnit, 2 SourceFile, TextUnit,
3 algo::find_leaf_at_offset, 3 algo::find_token_at_offset,
4 SyntaxKind::{self, *}, 4 SyntaxKind::{self, *},
5 ast::AstNode, 5 ast::AstNode,
6}; 6};
@@ -8,15 +8,15 @@ use ra_syntax::{
8pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> { 8pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> {
9 const BRACES: &[SyntaxKind] = 9 const BRACES: &[SyntaxKind] =
10 &[L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE]; 10 &[L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE];
11 let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) 11 let (brace_node, brace_idx) = find_token_at_offset(file.syntax(), offset)
12 .filter_map(|node| { 12 .filter_map(|node| {
13 let idx = BRACES.iter().position(|&brace| brace == node.kind())?; 13 let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
14 Some((node, idx)) 14 Some((node, idx))
15 }) 15 })
16 .next()?; 16 .next()?;
17 let parent = brace_node.parent()?; 17 let parent = brace_node.parent();
18 let matching_kind = BRACES[brace_idx ^ 1]; 18 let matching_kind = BRACES[brace_idx ^ 1];
19 let matching_node = parent.children().find(|node| node.kind() == matching_kind)?; 19 let matching_node = parent.children_with_tokens().find(|node| node.kind() == matching_kind)?;
20 Some(matching_node.range().start()) 20 Some(matching_node.range().start())
21} 21}
22 22
@@ -41,5 +41,4 @@ mod tests {
41 41
42 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }"); 42 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }");
43 } 43 }
44
45} 44}
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index a0c5e78ad..d9a28d2b5 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -1,6 +1,6 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ast, AstNode, TextRange, Direction, SyntaxKind::*}; 3use ra_syntax::{ast, AstNode, TextRange, Direction, SyntaxKind::*, SyntaxElement};
4use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
5 5
6use crate::{FileId, db::RootDatabase}; 6use crate::{FileId, db::RootDatabase};
@@ -15,9 +15,9 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
15 let source_file = db.parse(file_id); 15 let source_file = db.parse(file_id);
16 16
17 // Visited nodes to handle highlighting priorities 17 // Visited nodes to handle highlighting priorities
18 let mut highlighted = FxHashSet::default(); 18 let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
19 let mut res = Vec::new(); 19 let mut res = Vec::new();
20 for node in source_file.syntax().descendants() { 20 for node in source_file.syntax().descendants_with_tokens() {
21 if highlighted.contains(&node) { 21 if highlighted.contains(&node) {
22 continue; 22 continue;
23 } 23 }
@@ -31,14 +31,14 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
31 LIFETIME => "parameter", 31 LIFETIME => "parameter",
32 k if k.is_keyword() => "keyword", 32 k if k.is_keyword() => "keyword",
33 _ => { 33 _ => {
34 if let Some(macro_call) = ast::MacroCall::cast(node) { 34 if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) {
35 if let Some(path) = macro_call.path() { 35 if let Some(path) = macro_call.path() {
36 if let Some(segment) = path.segment() { 36 if let Some(segment) = path.segment() {
37 if let Some(name_ref) = segment.name_ref() { 37 if let Some(name_ref) = segment.name_ref() {
38 highlighted.insert(name_ref.syntax()); 38 highlighted.insert(name_ref.syntax().into());
39 let range_start = name_ref.syntax().range().start(); 39 let range_start = name_ref.syntax().range().start();
40 let mut range_end = name_ref.syntax().range().end(); 40 let mut range_end = name_ref.syntax().range().end();
41 for sibling in path.syntax().siblings(Direction::Next) { 41 for sibling in path.syntax().siblings_with_tokens(Direction::Next) {
42 match sibling.kind() { 42 match sibling.kind() {
43 EXCL | IDENT => range_end = sibling.range().end(), 43 EXCL | IDENT => range_end = sibling.range().end(),
44 _ => (), 44 _ => (),
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs
index 276f8a8c8..a4e4c3dbe 100644
--- a/crates/ra_ide_api/src/syntax_tree.rs
+++ b/crates/ra_ide_api/src/syntax_tree.rs
@@ -1,8 +1,9 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use crate::db::RootDatabase; 2use crate::db::RootDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 SourceFile, SyntaxNode, TextRange, AstNode, 4 SourceFile, TextRange, AstNode, SyntaxToken, SyntaxElement,
5 algo::{self, visit::{visitor, Visitor}}, ast::{self, AstToken} 5 algo,
6 SyntaxKind::{STRING, RAW_STRING},
6}; 7};
7 8
8pub use ra_db::FileId; 9pub use ra_db::FileId;
@@ -14,11 +15,15 @@ pub(crate) fn syntax_tree(
14) -> String { 15) -> String {
15 if let Some(text_range) = text_range { 16 if let Some(text_range) = text_range {
16 let file = db.parse(file_id); 17 let file = db.parse(file_id);
17 let node = algo::find_covering_node(file.syntax(), text_range); 18 let node = match algo::find_covering_element(file.syntax(), text_range) {
18 19 SyntaxElement::Node(node) => node,
19 if let Some(tree) = syntax_tree_for_string(node, text_range) { 20 SyntaxElement::Token(token) => {
20 return tree; 21 if let Some(tree) = syntax_tree_for_string(token, text_range) {
21 } 22 return tree;
23 }
24 token.parent()
25 }
26 };
22 27
23 node.debug_dump() 28 node.debug_dump()
24 } else { 29 } else {
@@ -28,19 +33,19 @@ pub(crate) fn syntax_tree(
28 33
29/// Attempts parsing the selected contents of a string literal 34/// Attempts parsing the selected contents of a string literal
30/// as rust syntax and returns its syntax tree 35/// as rust syntax and returns its syntax tree
31fn syntax_tree_for_string(node: &SyntaxNode, text_range: TextRange) -> Option<String> { 36fn syntax_tree_for_string(token: SyntaxToken, text_range: TextRange) -> Option<String> {
32 // When the range is inside a string 37 // When the range is inside a string
33 // we'll attempt parsing it as rust syntax 38 // we'll attempt parsing it as rust syntax
34 // to provide the syntax tree of the contents of the string 39 // to provide the syntax tree of the contents of the string
35 visitor() 40 match token.kind() {
36 .visit(|node: &ast::String| syntax_tree_for_token(node, text_range)) 41 STRING | RAW_STRING => syntax_tree_for_token(token, text_range),
37 .visit(|node: &ast::RawString| syntax_tree_for_token(node, text_range)) 42 _ => None,
38 .accept(node)? 43 }
39} 44}
40 45
41fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option<String> { 46fn syntax_tree_for_token(node: SyntaxToken, text_range: TextRange) -> Option<String> {
42 // Range of the full node 47 // Range of the full node
43 let node_range = node.syntax().range(); 48 let node_range = node.range();
44 let text = node.text().to_string(); 49 let text = node.text().to_string();
45 50
46 // We start at some point inside the node 51 // We start at some point inside the node
diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs
index 501d44dbb..4510d663d 100644
--- a/crates/ra_ide_api/src/typing.rs
+++ b/crates/ra_ide_api/src/typing.rs
@@ -1,8 +1,8 @@
1use ra_syntax::{ 1use ra_syntax::{
2 AstNode, SourceFile, SyntaxKind::*, 2 AstNode, SourceFile, SyntaxKind::*,
3 SyntaxNode, TextUnit, TextRange, 3 TextUnit, TextRange, SyntaxToken,
4 algo::{find_node_at_offset, find_leaf_at_offset, LeafAtOffset}, 4 algo::{find_node_at_offset, find_token_at_offset, TokenAtOffset},
5 ast::{self, AstToken}, 5 ast::{self},
6}; 6};
7use ra_fmt::leading_indent; 7use ra_fmt::leading_indent;
8use ra_text_edit::{TextEdit, TextEditBuilder}; 8use ra_text_edit::{TextEdit, TextEditBuilder};
@@ -11,11 +11,11 @@ use crate::{db::RootDatabase, SourceChange, SourceFileEdit};
11 11
12pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { 12pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> {
13 let file = db.parse(position.file_id); 13 let file = db.parse(position.file_id);
14 let comment = find_leaf_at_offset(file.syntax(), position.offset) 14 let comment = find_token_at_offset(file.syntax(), position.offset)
15 .left_biased() 15 .left_biased()
16 .and_then(ast::Comment::cast)?; 16 .and_then(ast::Comment::cast)?;
17 17
18 if let ast::CommentFlavor::Multiline = comment.flavor() { 18 if comment.flavor() == ast::CommentFlavor::Multiline {
19 return None; 19 return None;
20 } 20 }
21 21
@@ -41,23 +41,23 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour
41 ) 41 )
42} 42}
43 43
44fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> { 44fn node_indent<'a>(file: &'a SourceFile, token: SyntaxToken) -> Option<&'a str> {
45 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) { 45 let ws = match find_token_at_offset(file.syntax(), token.range().start()) {
46 LeafAtOffset::Between(l, r) => { 46 TokenAtOffset::Between(l, r) => {
47 assert!(r == node); 47 assert!(r == token);
48 l 48 l
49 } 49 }
50 LeafAtOffset::Single(n) => { 50 TokenAtOffset::Single(n) => {
51 assert!(n == node); 51 assert!(n == token);
52 return Some(""); 52 return Some("");
53 } 53 }
54 LeafAtOffset::None => unreachable!(), 54 TokenAtOffset::None => unreachable!(),
55 }; 55 };
56 if ws.kind() != WHITESPACE { 56 if ws.kind() != WHITESPACE {
57 return None; 57 return None;
58 } 58 }
59 let text = ws.leaf_text().unwrap(); 59 let text = ws.text();
60 let pos = text.as_str().rfind('\n').map(|it| it + 1).unwrap_or(0); 60 let pos = text.rfind('\n').map(|it| it + 1).unwrap_or(0);
61 Some(&text[pos..]) 61 Some(&text[pos..])
62} 62}
63 63
@@ -88,7 +88,7 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option<
88 let file = db.parse(position.file_id); 88 let file = db.parse(position.file_id);
89 assert_eq!(file.syntax().text().char_at(position.offset), Some('.')); 89 assert_eq!(file.syntax().text().char_at(position.offset), Some('.'));
90 90
91 let whitespace = find_leaf_at_offset(file.syntax(), position.offset) 91 let whitespace = find_token_at_offset(file.syntax(), position.offset)
92 .left_biased() 92 .left_biased()
93 .and_then(ast::Whitespace::cast)?; 93 .and_then(ast::Whitespace::cast)?;
94 94
@@ -100,7 +100,7 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option<
100 let current_indent_len = TextUnit::of_str(current_indent); 100 let current_indent_len = TextUnit::of_str(current_indent);
101 101
102 // Make sure dot is a part of call chain 102 // Make sure dot is a part of call chain
103 let field_expr = whitespace.syntax().parent().and_then(ast::FieldExpr::cast)?; 103 let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?;
104 let prev_indent = leading_indent(field_expr.syntax())?; 104 let prev_indent = leading_indent(field_expr.syntax())?;
105 let target_indent = format!(" {}", prev_indent); 105 let target_indent = format!(" {}", prev_indent);
106 let target_indent_len = TextUnit::of_str(&target_indent); 106 let target_indent_len = TextUnit::of_str(&target_indent);
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 4b1d1d3ca..05f9817da 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -1,6 +1,6 @@
1use ra_parser::{TokenSource, TreeSink, ParseError}; 1use ra_parser::{TokenSource, TreeSink, ParseError};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc, 3 AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc, SyntaxElement,
4 ast, SyntaxKind::*, TextUnit 4 ast, SyntaxKind::*, TextUnit
5}; 5};
6 6
@@ -47,8 +47,8 @@ fn convert_tt(
47 global_offset: TextUnit, 47 global_offset: TextUnit,
48 tt: &SyntaxNode, 48 tt: &SyntaxNode,
49) -> Option<tt::Subtree> { 49) -> Option<tt::Subtree> {
50 let first_child = tt.first_child()?; 50 let first_child = tt.first_child_or_token()?;
51 let last_child = tt.last_child()?; 51 let last_child = tt.last_child_or_token()?;
52 let delimiter = match (first_child.kind(), last_child.kind()) { 52 let delimiter = match (first_child.kind(), last_child.kind()) {
53 (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis, 53 (L_PAREN, R_PAREN) => tt::Delimiter::Parenthesis,
54 (L_CURLY, R_CURLY) => tt::Delimiter::Brace, 54 (L_CURLY, R_CURLY) => tt::Delimiter::Brace,
@@ -56,39 +56,47 @@ fn convert_tt(
56 _ => return None, 56 _ => return None,
57 }; 57 };
58 let mut token_trees = Vec::new(); 58 let mut token_trees = Vec::new();
59 for child in tt.children().skip(1) { 59 for child in tt.children_with_tokens().skip(1) {
60 if child == first_child || child == last_child || child.kind().is_trivia() { 60 if child == first_child || child == last_child || child.kind().is_trivia() {
61 continue; 61 continue;
62 } 62 }
63 if child.kind().is_punct() { 63 match child {
64 let mut prev = None; 64 SyntaxElement::Token(token) => {
65 for char in child.leaf_text().unwrap().chars() { 65 if token.kind().is_punct() {
66 if let Some(char) = prev { 66 let mut prev = None;
67 token_trees.push( 67 for char in token.text().chars() {
68 tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Joint }).into(), 68 if let Some(char) = prev {
69 ); 69 token_trees.push(
70 tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Joint })
71 .into(),
72 );
73 }
74 prev = Some(char)
75 }
76 if let Some(char) = prev {
77 token_trees.push(
78 tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Alone }).into(),
79 );
80 }
81 } else {
82 let child = if token.kind().is_keyword() || token.kind() == IDENT {
83 let relative_range = token.range() - global_offset;
84 let id = token_map.alloc(relative_range);
85 let text = token.text().clone();
86 tt::Leaf::from(tt::Ident { text, id }).into()
87 } else if token.kind().is_literal() {
88 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into()
89 } else {
90 return None;
91 };
92 token_trees.push(child);
70 } 93 }
71 prev = Some(char)
72 } 94 }
73 if let Some(char) = prev { 95 SyntaxElement::Node(node) => {
74 token_trees 96 let child = convert_tt(token_map, global_offset, node)?.into();
75 .push(tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Alone }).into()); 97 token_trees.push(child);
76 } 98 }
77 } else { 99 };
78 let child: tt::TokenTree = if child.kind() == TOKEN_TREE {
79 convert_tt(token_map, global_offset, child)?.into()
80 } else if child.kind().is_keyword() || child.kind() == IDENT {
81 let relative_range = child.range() - global_offset;
82 let id = token_map.alloc(relative_range);
83 let text = child.leaf_text().unwrap().clone();
84 tt::Leaf::from(tt::Ident { text, id }).into()
85 } else if child.kind().is_literal() {
86 tt::Leaf::from(tt::Literal { text: child.leaf_text().unwrap().clone() }).into()
87 } else {
88 return None;
89 };
90 token_trees.push(child)
91 }
92 } 100 }
93 101
94 let res = tt::Subtree { delimiter, token_trees }; 102 let res = tt::Subtree { delimiter, token_trees };
@@ -118,12 +126,12 @@ impl TtTokenSource {
118 } 126 }
119 fn convert_tt(&mut self, tt: &tt::TokenTree) { 127 fn convert_tt(&mut self, tt: &tt::TokenTree) {
120 match tt { 128 match tt {
121 tt::TokenTree::Leaf(leaf) => self.convert_leaf(leaf), 129 tt::TokenTree::Leaf(token) => self.convert_token(token),
122 tt::TokenTree::Subtree(sub) => self.convert_subtree(sub), 130 tt::TokenTree::Subtree(sub) => self.convert_subtree(sub),
123 } 131 }
124 } 132 }
125 fn convert_leaf(&mut self, leaf: &tt::Leaf) { 133 fn convert_token(&mut self, token: &tt::Leaf) {
126 let tok = match leaf { 134 let tok = match token {
127 tt::Leaf::Literal(l) => TtToken { 135 tt::Leaf::Literal(l) => TtToken {
128 kind: SyntaxKind::INT_NUMBER, // FIXME 136 kind: SyntaxKind::INT_NUMBER, // FIXME
129 is_joint_to_next: false, 137 is_joint_to_next: false,
@@ -206,7 +214,7 @@ impl<'a> TtTreeSink<'a> {
206} 214}
207 215
208impl<'a> TreeSink for TtTreeSink<'a> { 216impl<'a> TreeSink for TtTreeSink<'a> {
209 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { 217 fn token(&mut self, kind: SyntaxKind, n_tokens: u8) {
210 for _ in 0..n_tokens { 218 for _ in 0..n_tokens {
211 self.buf += self.tokens[self.token_pos].text.as_str(); 219 self.buf += self.tokens[self.token_pos].text.as_str();
212 self.token_pos += 1; 220 self.token_pos += 1;
@@ -214,15 +222,15 @@ impl<'a> TreeSink for TtTreeSink<'a> {
214 self.text_pos += TextUnit::of_str(&self.buf); 222 self.text_pos += TextUnit::of_str(&self.buf);
215 let text = SmolStr::new(self.buf.as_str()); 223 let text = SmolStr::new(self.buf.as_str());
216 self.buf.clear(); 224 self.buf.clear();
217 self.inner.leaf(kind, text) 225 self.inner.token(kind, text)
218 } 226 }
219 227
220 fn start_branch(&mut self, kind: SyntaxKind) { 228 fn start_node(&mut self, kind: SyntaxKind) {
221 self.inner.start_branch(kind); 229 self.inner.start_node(kind);
222 } 230 }
223 231
224 fn finish_branch(&mut self) { 232 fn finish_node(&mut self) {
225 self.inner.finish_branch(); 233 self.inner.finish_node();
226 } 234 }
227 235
228 fn error(&mut self, error: ParseError) { 236 fn error(&mut self, error: ParseError) {
diff --git a/crates/ra_parser/src/event.rs b/crates/ra_parser/src/event.rs
index c1773e8e0..87cf4eca0 100644
--- a/crates/ra_parser/src/event.rs
+++ b/crates/ra_parser/src/event.rs
@@ -116,12 +116,12 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
116 } 116 }
117 117
118 for kind in forward_parents.drain(..).rev() { 118 for kind in forward_parents.drain(..).rev() {
119 sink.start_branch(kind); 119 sink.start_node(kind);
120 } 120 }
121 } 121 }
122 Event::Finish => sink.finish_branch(), 122 Event::Finish => sink.finish_node(),
123 Event::Token { kind, n_raw_tokens } => { 123 Event::Token { kind, n_raw_tokens } => {
124 sink.leaf(kind, n_raw_tokens); 124 sink.token(kind, n_raw_tokens);
125 } 125 }
126 Event::Error { msg } => sink.error(msg), 126 Event::Error { msg } => sink.error(msg),
127 } 127 }
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index ddc08e462..30ba06aac 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -40,15 +40,15 @@ pub trait TokenSource {
40 40
41/// `TreeSink` abstracts details of a particular syntax tree implementation. 41/// `TreeSink` abstracts details of a particular syntax tree implementation.
42pub trait TreeSink { 42pub trait TreeSink {
43 /// Adds new leaf to the current branch. 43 /// Adds new token to the current branch.
44 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8); 44 fn token(&mut self, kind: SyntaxKind, n_tokens: u8);
45 45
46 /// Start new branch and make it current. 46 /// Start new branch and make it current.
47 fn start_branch(&mut self, kind: SyntaxKind); 47 fn start_node(&mut self, kind: SyntaxKind);
48 48
49 /// Finish current branch and restore previous 49 /// Finish current branch and restore previous
50 /// branch as current. 50 /// branch as current.
51 fn finish_branch(&mut self); 51 fn finish_node(&mut self);
52 52
53 fn error(&mut self, error: ParseError); 53 fn error(&mut self, error: ParseError);
54} 54}
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 7e70dad3f..1a763fb47 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -13,7 +13,7 @@ unicode-xid = "0.1.0"
13itertools = "0.8.0" 13itertools = "0.8.0"
14drop_bomb = "0.1.4" 14drop_bomb = "0.1.4"
15parking_lot = "0.7.0" 15parking_lot = "0.7.0"
16rowan = "0.3.3" 16rowan = "0.4.0"
17 17
18# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 18# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
19# to reduce number of compilations 19# to reduce number of compilations
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index e2b4f0388..06b45135c 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -1,18 +1,14 @@
1pub mod visit; 1pub mod visit;
2 2
3use rowan::TransparentNewType; 3use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement};
4 4
5use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction}; 5pub use rowan::TokenAtOffset;
6 6
7pub use rowan::LeafAtOffset; 7pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset<SyntaxToken> {
8 8 match node.0.token_at_offset(offset) {
9pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<&SyntaxNode> { 9 TokenAtOffset::None => TokenAtOffset::None,
10 match node.0.leaf_at_offset(offset) { 10 TokenAtOffset::Single(n) => TokenAtOffset::Single(n.into()),
11 LeafAtOffset::None => LeafAtOffset::None, 11 TokenAtOffset::Between(l, r) => TokenAtOffset::Between(l.into(), r.into()),
12 LeafAtOffset::Single(n) => LeafAtOffset::Single(SyntaxNode::from_repr(n)),
13 LeafAtOffset::Between(l, r) => {
14 LeafAtOffset::Between(SyntaxNode::from_repr(l), SyntaxNode::from_repr(r))
15 }
16 } 12 }
17} 13}
18 14
@@ -26,16 +22,29 @@ pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<
26/// 22///
27/// then the left node will be silently preferred. 23/// then the left node will be silently preferred.
28pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { 24pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> {
29 find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) 25 find_token_at_offset(syntax, offset)
26 .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast))
30} 27}
31 28
32/// Finds the first sibling in the given direction which is not `trivia` 29/// Finds the first sibling in the given direction which is not `trivia`
33pub fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> { 30pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> {
34 node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia()) 31 return match element {
32 SyntaxElement::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia),
33 SyntaxElement::Token(token) => {
34 token.siblings_with_tokens(direction).skip(1).find(not_trivia)
35 }
36 };
37
38 fn not_trivia(element: &SyntaxElement) -> bool {
39 match element {
40 SyntaxElement::Node(_) => true,
41 SyntaxElement::Token(token) => !token.kind().is_trivia(),
42 }
43 }
35} 44}
36 45
37pub fn find_covering_node(root: &SyntaxNode, range: TextRange) -> &SyntaxNode { 46pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement {
38 SyntaxNode::from_repr(root.0.covering_node(range)) 47 root.0.covering_node(range).into()
39} 48}
40 49
41// Replace with `std::iter::successors` in `1.34.0` 50// Replace with `std::iter::successors` in `1.34.0`
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index fd7e63f84..9a44afc67 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
7 7
8pub use self::generated::*; 8pub use self::generated::*;
9use crate::{ 9use crate::{
10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, 10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren},
11 SmolStr, 11 SmolStr,
12 SyntaxKind::*, 12 SyntaxKind::*,
13}; 13};
@@ -27,7 +27,8 @@ pub trait AstNode:
27 27
28pub trait AstToken: AstNode { 28pub trait AstToken: AstNode {
29 fn text(&self) -> &SmolStr { 29 fn text(&self) -> &SmolStr {
30 self.syntax().leaf_text().unwrap() 30 // self.syntax().leaf_text().unwrap()
31 unimplemented!()
31 } 32 }
32} 33}
33 34
@@ -126,8 +127,8 @@ pub trait AttrsOwner: AstNode {
126} 127}
127 128
128pub trait DocCommentsOwner: AstNode { 129pub trait DocCommentsOwner: AstNode {
129 fn doc_comments(&self) -> AstChildren<Comment> { 130 fn doc_comments(&self) -> CommentIter {
130 children(self) 131 CommentIter { iter: self.syntax().children_with_tokens() }
131 } 132 }
132 133
133 /// Returns the textual content of a doc comment block as a single string. 134 /// Returns the textual content of a doc comment block as a single string.
@@ -179,9 +180,9 @@ impl Attr {
179 180
180 pub fn as_atom(&self) -> Option<SmolStr> { 181 pub fn as_atom(&self) -> Option<SmolStr> {
181 let tt = self.value()?; 182 let tt = self.value()?;
182 let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; 183 let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
183 if attr.kind() == IDENT { 184 if attr.kind() == IDENT {
184 Some(attr.leaf_text().unwrap().clone()) 185 Some(attr.as_token()?.text().clone())
185 } else { 186 } else {
186 None 187 None
187 } 188 }
@@ -189,10 +190,10 @@ impl Attr {
189 190
190 pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { 191 pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> {
191 let tt = self.value()?; 192 let tt = self.value()?;
192 let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; 193 let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
193 let args = TokenTree::cast(args)?; 194 let args = TokenTree::cast(args.as_node()?)?;
194 if attr.kind() == IDENT { 195 if attr.kind() == IDENT {
195 Some((attr.leaf_text().unwrap().clone(), args)) 196 Some((attr.as_token()?.text().clone(), args))
196 } else { 197 } else {
197 None 198 None
198 } 199 }
@@ -200,16 +201,35 @@ impl Attr {
200 201
201 pub fn as_named(&self) -> Option<SmolStr> { 202 pub fn as_named(&self) -> Option<SmolStr> {
202 let tt = self.value()?; 203 let tt = self.value()?;
203 let attr = tt.syntax().children().nth(1)?; 204 let attr = tt.syntax().children_with_tokens().nth(1)?;
204 if attr.kind() == IDENT { 205 if attr.kind() == IDENT {
205 Some(attr.leaf_text().unwrap().clone()) 206 Some(attr.as_token()?.text().clone())
206 } else { 207 } else {
207 None 208 None
208 } 209 }
209 } 210 }
210} 211}
211 212
212impl Comment { 213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
214pub struct Comment<'a>(SyntaxToken<'a>);
215
216impl<'a> Comment<'a> {
217 pub fn cast(token: SyntaxToken<'a>) -> Option<Self> {
218 if token.kind() == COMMENT {
219 Some(Comment(token))
220 } else {
221 None
222 }
223 }
224
225 pub fn syntax(&self) -> SyntaxToken<'a> {
226 self.0
227 }
228
229 pub fn text(&self) -> &'a SmolStr {
230 self.0.text()
231 }
232
213 pub fn flavor(&self) -> CommentFlavor { 233 pub fn flavor(&self) -> CommentFlavor {
214 let text = self.text(); 234 let text = self.text();
215 if text.starts_with("///") { 235 if text.starts_with("///") {
@@ -230,13 +250,16 @@ impl Comment {
230 pub fn prefix(&self) -> &'static str { 250 pub fn prefix(&self) -> &'static str {
231 self.flavor().prefix() 251 self.flavor().prefix()
232 } 252 }
253}
233 254
234 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { 255pub struct CommentIter<'a> {
235 self.text().chars().filter(|&c| c == '\n').map(|_| &()) 256 iter: SyntaxElementChildren<'a>,
236 } 257}
237 258
238 pub fn has_newlines(&self) -> bool { 259impl<'a> Iterator for CommentIter<'a> {
239 self.count_newlines_lazy().count() > 0 260 type Item = Comment<'a>;
261 fn next(&mut self) -> Option<Comment<'a>> {
262 self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast))
240 } 263 }
241} 264}
242 265
@@ -267,27 +290,42 @@ impl CommentFlavor {
267 } 290 }
268} 291}
269 292
270impl Whitespace { 293pub struct Whitespace<'a>(SyntaxToken<'a>);
271 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { 294
272 self.text().chars().filter(|&c| c == '\n').map(|_| &()) 295impl<'a> Whitespace<'a> {
296 pub fn cast(token: SyntaxToken<'a>) -> Option<Self> {
297 if token.kind() == WHITESPACE {
298 Some(Whitespace(token))
299 } else {
300 None
301 }
302 }
303
304 pub fn syntax(&self) -> SyntaxToken<'a> {
305 self.0
273 } 306 }
274 307
275 pub fn has_newlines(&self) -> bool { 308 pub fn text(&self) -> &'a SmolStr {
276 self.text().contains('\n') 309 self.0.text()
310 }
311
312 pub fn spans_multiple_lines(&self) -> bool {
313 let text = self.text();
314 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
277 } 315 }
278} 316}
279 317
280impl Name { 318impl Name {
281 pub fn text(&self) -> &SmolStr { 319 pub fn text(&self) -> &SmolStr {
282 let ident = self.syntax().first_child().unwrap(); 320 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
283 ident.leaf_text().unwrap() 321 ident.text()
284 } 322 }
285} 323}
286 324
287impl NameRef { 325impl NameRef {
288 pub fn text(&self) -> &SmolStr { 326 pub fn text(&self) -> &SmolStr {
289 let ident = self.syntax().first_child().unwrap(); 327 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
290 ident.leaf_text().unwrap() 328 ident.text()
291 } 329 }
292} 330}
293 331
@@ -316,7 +354,7 @@ impl ImplBlock {
316 354
317impl Module { 355impl Module {
318 pub fn has_semi(&self) -> bool { 356 pub fn has_semi(&self) -> bool {
319 match self.syntax().last_child() { 357 match self.syntax().last_child_or_token() {
320 None => false, 358 None => false,
321 Some(node) => node.kind() == SEMI, 359 Some(node) => node.kind() == SEMI,
322 } 360 }
@@ -325,7 +363,7 @@ impl Module {
325 363
326impl LetStmt { 364impl LetStmt {
327 pub fn has_semi(&self) -> bool { 365 pub fn has_semi(&self) -> bool {
328 match self.syntax().last_child() { 366 match self.syntax().last_child_or_token() {
329 None => false, 367 None => false,
330 Some(node) => node.kind() == SEMI, 368 Some(node) => node.kind() == SEMI,
331 } 369 }
@@ -360,7 +398,7 @@ impl IfExpr {
360 398
361impl ExprStmt { 399impl ExprStmt {
362 pub fn has_semi(&self) -> bool { 400 pub fn has_semi(&self) -> bool {
363 match self.syntax().last_child() { 401 match self.syntax().last_child_or_token() {
364 None => false, 402 None => false,
365 Some(node) => node.kind() == SEMI, 403 Some(node) => node.kind() == SEMI,
366 } 404 }
@@ -384,7 +422,7 @@ impl PathSegment {
384 let res = if let Some(name_ref) = self.name_ref() { 422 let res = if let Some(name_ref) = self.name_ref() {
385 PathSegmentKind::Name(name_ref) 423 PathSegmentKind::Name(name_ref)
386 } else { 424 } else {
387 match self.syntax().first_child()?.kind() { 425 match self.syntax().first_child_or_token()?.kind() {
388 SELF_KW => PathSegmentKind::SelfKw, 426 SELF_KW => PathSegmentKind::SelfKw,
389 SUPER_KW => PathSegmentKind::SuperKw, 427 SUPER_KW => PathSegmentKind::SuperKw,
390 CRATE_KW => PathSegmentKind::CrateKw, 428 CRATE_KW => PathSegmentKind::CrateKw,
@@ -395,7 +433,7 @@ impl PathSegment {
395 } 433 }
396 434
397 pub fn has_colon_colon(&self) -> bool { 435 pub fn has_colon_colon(&self) -> bool {
398 match self.syntax.first_child().map(|s| s.kind()) { 436 match self.syntax.first_child_or_token().map(|s| s.kind()) {
399 Some(COLONCOLON) => true, 437 Some(COLONCOLON) => true,
400 _ => false, 438 _ => false,
401 } 439 }
@@ -410,7 +448,7 @@ impl Path {
410 448
411impl UseTree { 449impl UseTree {
412 pub fn has_star(&self) -> bool { 450 pub fn has_star(&self) -> bool {
413 self.syntax().children().any(|it| it.kind() == STAR) 451 self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
414 } 452 }
415} 453}
416 454
@@ -425,7 +463,7 @@ impl UseTreeList {
425 463
426impl RefPat { 464impl RefPat {
427 pub fn is_mut(&self) -> bool { 465 pub fn is_mut(&self) -> bool {
428 self.syntax().children().any(|n| n.kind() == MUT_KW) 466 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
429 } 467 }
430} 468}
431 469
@@ -500,19 +538,19 @@ impl EnumVariant {
500 538
501impl PointerType { 539impl PointerType {
502 pub fn is_mut(&self) -> bool { 540 pub fn is_mut(&self) -> bool {
503 self.syntax().children().any(|n| n.kind() == MUT_KW) 541 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
504 } 542 }
505} 543}
506 544
507impl ReferenceType { 545impl ReferenceType {
508 pub fn is_mut(&self) -> bool { 546 pub fn is_mut(&self) -> bool {
509 self.syntax().children().any(|n| n.kind() == MUT_KW) 547 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
510 } 548 }
511} 549}
512 550
513impl RefExpr { 551impl RefExpr {
514 pub fn is_mut(&self) -> bool { 552 pub fn is_mut(&self) -> bool {
515 self.syntax().children().any(|n| n.kind() == MUT_KW) 553 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
516 } 554 }
517} 555}
518 556
@@ -528,7 +566,7 @@ pub enum PrefixOp {
528 566
529impl PrefixExpr { 567impl PrefixExpr {
530 pub fn op_kind(&self) -> Option<PrefixOp> { 568 pub fn op_kind(&self) -> Option<PrefixOp> {
531 match self.syntax().first_child()?.kind() { 569 match self.op_token()?.kind() {
532 STAR => Some(PrefixOp::Deref), 570 STAR => Some(PrefixOp::Deref),
533 EXCL => Some(PrefixOp::Not), 571 EXCL => Some(PrefixOp::Not),
534 MINUS => Some(PrefixOp::Neg), 572 MINUS => Some(PrefixOp::Neg),
@@ -536,8 +574,8 @@ impl PrefixExpr {
536 } 574 }
537 } 575 }
538 576
539 pub fn op(&self) -> Option<&SyntaxNode> { 577 pub fn op_token(&self) -> Option<SyntaxToken> {
540 self.syntax().first_child() 578 self.syntax().first_child_or_token()?.as_token()
541 } 579 }
542} 580}
543 581
@@ -608,40 +646,42 @@ pub enum BinOp {
608} 646}
609 647
610impl BinExpr { 648impl BinExpr {
611 fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> { 649 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
612 self.syntax().children().find_map(|c| match c.kind() { 650 self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| {
613 PIPEPIPE => Some((c, BinOp::BooleanOr)), 651 match c.kind() {
614 AMPAMP => Some((c, BinOp::BooleanAnd)), 652 PIPEPIPE => Some((c, BinOp::BooleanOr)),
615 EQEQ => Some((c, BinOp::EqualityTest)), 653 AMPAMP => Some((c, BinOp::BooleanAnd)),
616 NEQ => Some((c, BinOp::NegatedEqualityTest)), 654 EQEQ => Some((c, BinOp::EqualityTest)),
617 LTEQ => Some((c, BinOp::LesserEqualTest)), 655 NEQ => Some((c, BinOp::NegatedEqualityTest)),
618 GTEQ => Some((c, BinOp::GreaterEqualTest)), 656 LTEQ => Some((c, BinOp::LesserEqualTest)),
619 L_ANGLE => Some((c, BinOp::LesserTest)), 657 GTEQ => Some((c, BinOp::GreaterEqualTest)),
620 R_ANGLE => Some((c, BinOp::GreaterTest)), 658 L_ANGLE => Some((c, BinOp::LesserTest)),
621 PLUS => Some((c, BinOp::Addition)), 659 R_ANGLE => Some((c, BinOp::GreaterTest)),
622 STAR => Some((c, BinOp::Multiplication)), 660 PLUS => Some((c, BinOp::Addition)),
623 MINUS => Some((c, BinOp::Subtraction)), 661 STAR => Some((c, BinOp::Multiplication)),
624 SLASH => Some((c, BinOp::Division)), 662 MINUS => Some((c, BinOp::Subtraction)),
625 PERCENT => Some((c, BinOp::Remainder)), 663 SLASH => Some((c, BinOp::Division)),
626 SHL => Some((c, BinOp::LeftShift)), 664 PERCENT => Some((c, BinOp::Remainder)),
627 SHR => Some((c, BinOp::RightShift)), 665 SHL => Some((c, BinOp::LeftShift)),
628 CARET => Some((c, BinOp::BitwiseXor)), 666 SHR => Some((c, BinOp::RightShift)),
629 PIPE => Some((c, BinOp::BitwiseOr)), 667 CARET => Some((c, BinOp::BitwiseXor)),
630 AMP => Some((c, BinOp::BitwiseAnd)), 668 PIPE => Some((c, BinOp::BitwiseOr)),
631 DOTDOT => Some((c, BinOp::RangeRightOpen)), 669 AMP => Some((c, BinOp::BitwiseAnd)),
632 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), 670 DOTDOT => Some((c, BinOp::RangeRightOpen)),
633 EQ => Some((c, BinOp::Assignment)), 671 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
634 PLUSEQ => Some((c, BinOp::AddAssign)), 672 EQ => Some((c, BinOp::Assignment)),
635 SLASHEQ => Some((c, BinOp::DivAssign)), 673 PLUSEQ => Some((c, BinOp::AddAssign)),
636 STAREQ => Some((c, BinOp::MulAssign)), 674 SLASHEQ => Some((c, BinOp::DivAssign)),
637 PERCENTEQ => Some((c, BinOp::RemAssign)), 675 STAREQ => Some((c, BinOp::MulAssign)),
638 SHREQ => Some((c, BinOp::ShrAssign)), 676 PERCENTEQ => Some((c, BinOp::RemAssign)),
639 SHLEQ => Some((c, BinOp::ShlAssign)), 677 SHREQ => Some((c, BinOp::ShrAssign)),
640 MINUSEQ => Some((c, BinOp::SubAssign)), 678 SHLEQ => Some((c, BinOp::ShlAssign)),
641 PIPEEQ => Some((c, BinOp::BitOrAssign)), 679 MINUSEQ => Some((c, BinOp::SubAssign)),
642 AMPEQ => Some((c, BinOp::BitAndAssign)), 680 PIPEEQ => Some((c, BinOp::BitOrAssign)),
643 CARETEQ => Some((c, BinOp::BitXorAssign)), 681 AMPEQ => Some((c, BinOp::BitAndAssign)),
644 _ => None, 682 CARETEQ => Some((c, BinOp::BitXorAssign)),
683 _ => None,
684 }
645 }) 685 })
646 } 686 }
647 687
@@ -649,7 +689,7 @@ impl BinExpr {
649 self.op_details().map(|t| t.1) 689 self.op_details().map(|t| t.1)
650 } 690 }
651 691
652 pub fn op(&self) -> Option<&SyntaxNode> { 692 pub fn op_token(&self) -> Option<SyntaxToken> {
653 self.op_details().map(|t| t.0) 693 self.op_details().map(|t| t.0)
654 } 694 }
655 695
@@ -680,11 +720,23 @@ pub enum SelfParamFlavor {
680} 720}
681 721
682impl SelfParam { 722impl SelfParam {
723 pub fn self_kw_token(&self) -> SyntaxToken {
724 self.syntax()
725 .children_with_tokens()
726 .filter_map(|it| it.as_token())
727 .find(|it| it.kind() == SELF_KW)
728 .expect("invalid tree: self param must have self")
729 }
730
683 pub fn flavor(&self) -> SelfParamFlavor { 731 pub fn flavor(&self) -> SelfParamFlavor {
684 let borrowed = self.syntax().children().any(|n| n.kind() == AMP); 732 let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP);
685 if borrowed { 733 if borrowed {
686 // check for a `mut` coming after the & -- `mut &self` != `&mut self` 734 // check for a `mut` coming after the & -- `mut &self` != `&mut self`
687 if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW) 735 if self
736 .syntax()
737 .children_with_tokens()
738 .skip_while(|n| n.kind() != AMP)
739 .any(|n| n.kind() == MUT_KW)
688 { 740 {
689 SelfParamFlavor::MutRef 741 SelfParamFlavor::MutRef
690 } else { 742 } else {
@@ -707,25 +759,31 @@ pub enum LiteralFlavor {
707 Bool, 759 Bool,
708} 760}
709 761
710impl LiteralExpr { 762impl Literal {
763 pub fn token(&self) -> SyntaxToken {
764 match self.syntax().first_child_or_token().unwrap() {
765 SyntaxElement::Token(token) => token,
766 _ => unreachable!(),
767 }
768 }
769
711 pub fn flavor(&self) -> LiteralFlavor { 770 pub fn flavor(&self) -> LiteralFlavor {
712 let syntax = self.syntax(); 771 match self.token().kind() {
713 match syntax.kind() {
714 INT_NUMBER => { 772 INT_NUMBER => {
715 let allowed_suffix_list = [ 773 let allowed_suffix_list = [
716 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", 774 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
717 "u16", "u8", 775 "u16", "u8",
718 ]; 776 ];
719 let text = syntax.text().to_string(); 777 let text = self.token().text().to_string();
720 let suffix = allowed_suffix_list 778 let suffix = allowed_suffix_list
721 .iter() 779 .iter()
722 .find(|&s| text.ends_with(s)) 780 .find(|&s| text.ends_with(s))
723 .map(|&suf| SmolStr::new(suf)); 781 .map(|&suf| SmolStr::new(suf));
724 LiteralFlavor::IntNumber { suffix: suffix } 782 LiteralFlavor::IntNumber { suffix }
725 } 783 }
726 FLOAT_NUMBER => { 784 FLOAT_NUMBER => {
727 let allowed_suffix_list = ["f64", "f32"]; 785 let allowed_suffix_list = ["f64", "f32"];
728 let text = syntax.text().to_string(); 786 let text = self.token().text().to_string();
729 let suffix = allowed_suffix_list 787 let suffix = allowed_suffix_list
730 .iter() 788 .iter()
731 .find(|&s| text.ends_with(s)) 789 .find(|&s| text.ends_with(s))
@@ -750,11 +808,29 @@ impl NamedField {
750 808
751impl BindPat { 809impl BindPat {
752 pub fn is_mutable(&self) -> bool { 810 pub fn is_mutable(&self) -> bool {
753 self.syntax().children().any(|n| n.kind() == MUT_KW) 811 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
754 } 812 }
755 813
756 pub fn is_ref(&self) -> bool { 814 pub fn is_ref(&self) -> bool {
757 self.syntax().children().any(|n| n.kind() == REF_KW) 815 self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW)
816 }
817}
818
819impl LifetimeParam {
820 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
821 self.syntax()
822 .children_with_tokens()
823 .filter_map(|it| it.as_token())
824 .find(|it| it.kind() == LIFETIME)
825 }
826}
827
828impl WherePred {
829 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
830 self.syntax()
831 .children_with_tokens()
832 .filter_map(|it| it.as_token())
833 .find(|it| it.kind() == LIFETIME)
758 } 834 }
759} 835}
760 836
@@ -835,7 +911,7 @@ where
835 let pred = predicates.next().unwrap(); 911 let pred = predicates.next().unwrap();
836 let mut bounds = pred.type_bound_list().unwrap().bounds(); 912 let mut bounds = pred.type_bound_list().unwrap().bounds();
837 913
838 assert_eq!("'a", pred.lifetime().unwrap().syntax().text().to_string()); 914 assert_eq!("'a", pred.lifetime_token().unwrap().text());
839 915
840 assert_bound("'b", bounds.next()); 916 assert_bound("'b", bounds.next());
841 assert_bound("'c", bounds.next()); 917 assert_bound("'c", bounds.next());
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c51b4caa4..4afe1a146 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -376,64 +376,6 @@ impl BreakExpr {
376 } 376 }
377} 377}
378 378
379// Byte
380#[derive(Debug, PartialEq, Eq, Hash)]
381#[repr(transparent)]
382pub struct Byte {
383 pub(crate) syntax: SyntaxNode,
384}
385unsafe impl TransparentNewType for Byte {
386 type Repr = rowan::SyntaxNode<RaTypes>;
387}
388
389impl AstNode for Byte {
390 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
391 match syntax.kind() {
392 BYTE => Some(Byte::from_repr(syntax.into_repr())),
393 _ => None,
394 }
395 }
396 fn syntax(&self) -> &SyntaxNode { &self.syntax }
397}
398
399impl ToOwned for Byte {
400 type Owned = TreeArc<Byte>;
401 fn to_owned(&self) -> TreeArc<Byte> { TreeArc::cast(self.syntax.to_owned()) }
402}
403
404
405impl ast::AstToken for Byte {}
406impl Byte {}
407
408// ByteString
409#[derive(Debug, PartialEq, Eq, Hash)]
410#[repr(transparent)]
411pub struct ByteString {
412 pub(crate) syntax: SyntaxNode,
413}
414unsafe impl TransparentNewType for ByteString {
415 type Repr = rowan::SyntaxNode<RaTypes>;
416}
417
418impl AstNode for ByteString {
419 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
420 match syntax.kind() {
421 BYTE_STRING => Some(ByteString::from_repr(syntax.into_repr())),
422 _ => None,
423 }
424 }
425 fn syntax(&self) -> &SyntaxNode { &self.syntax }
426}
427
428impl ToOwned for ByteString {
429 type Owned = TreeArc<ByteString>;
430 fn to_owned(&self) -> TreeArc<ByteString> { TreeArc::cast(self.syntax.to_owned()) }
431}
432
433
434impl ast::AstToken for ByteString {}
435impl ByteString {}
436
437// CallExpr 379// CallExpr
438#[derive(Debug, PartialEq, Eq, Hash)] 380#[derive(Debug, PartialEq, Eq, Hash)]
439#[repr(transparent)] 381#[repr(transparent)]
@@ -503,64 +445,6 @@ impl CastExpr {
503 } 445 }
504} 446}
505 447
506// Char
507#[derive(Debug, PartialEq, Eq, Hash)]
508#[repr(transparent)]
509pub struct Char {
510 pub(crate) syntax: SyntaxNode,
511}
512unsafe impl TransparentNewType for Char {
513 type Repr = rowan::SyntaxNode<RaTypes>;
514}
515
516impl AstNode for Char {
517 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
518 match syntax.kind() {
519 CHAR => Some(Char::from_repr(syntax.into_repr())),
520 _ => None,
521 }
522 }
523 fn syntax(&self) -> &SyntaxNode { &self.syntax }
524}
525
526impl ToOwned for Char {
527 type Owned = TreeArc<Char>;
528 fn to_owned(&self) -> TreeArc<Char> { TreeArc::cast(self.syntax.to_owned()) }
529}
530
531
532impl ast::AstToken for Char {}
533impl Char {}
534
535// Comment
536#[derive(Debug, PartialEq, Eq, Hash)]
537#[repr(transparent)]
538pub struct Comment {
539 pub(crate) syntax: SyntaxNode,
540}
541unsafe impl TransparentNewType for Comment {
542 type Repr = rowan::SyntaxNode<RaTypes>;
543}
544
545impl AstNode for Comment {
546 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
547 match syntax.kind() {
548 COMMENT => Some(Comment::from_repr(syntax.into_repr())),
549 _ => None,
550 }
551 }
552 fn syntax(&self) -> &SyntaxNode { &self.syntax }
553}
554
555impl ToOwned for Comment {
556 type Owned = TreeArc<Comment>;
557 fn to_owned(&self) -> TreeArc<Comment> { TreeArc::cast(self.syntax.to_owned()) }
558}
559
560
561impl ast::AstToken for Comment {}
562impl Comment {}
563
564// Condition 448// Condition
565#[derive(Debug, PartialEq, Eq, Hash)] 449#[derive(Debug, PartialEq, Eq, Hash)]
566#[repr(transparent)] 450#[repr(transparent)]
@@ -1115,35 +999,6 @@ impl ExternCrateItem {
1115 } 999 }
1116} 1000}
1117 1001
1118// FalseKw
1119#[derive(Debug, PartialEq, Eq, Hash)]
1120#[repr(transparent)]
1121pub struct FalseKw {
1122 pub(crate) syntax: SyntaxNode,
1123}
1124unsafe impl TransparentNewType for FalseKw {
1125 type Repr = rowan::SyntaxNode<RaTypes>;
1126}
1127
1128impl AstNode for FalseKw {
1129 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1130 match syntax.kind() {
1131 FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())),
1132 _ => None,
1133 }
1134 }
1135 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1136}
1137
1138impl ToOwned for FalseKw {
1139 type Owned = TreeArc<FalseKw>;
1140 fn to_owned(&self) -> TreeArc<FalseKw> { TreeArc::cast(self.syntax.to_owned()) }
1141}
1142
1143
1144impl ast::AstToken for FalseKw {}
1145impl FalseKw {}
1146
1147// FieldExpr 1002// FieldExpr
1148#[derive(Debug, PartialEq, Eq, Hash)] 1003#[derive(Debug, PartialEq, Eq, Hash)]
1149#[repr(transparent)] 1004#[repr(transparent)]
@@ -1249,35 +1104,6 @@ impl FieldPatList {
1249 } 1104 }
1250} 1105}
1251 1106
1252// FloatNumber
1253#[derive(Debug, PartialEq, Eq, Hash)]
1254#[repr(transparent)]
1255pub struct FloatNumber {
1256 pub(crate) syntax: SyntaxNode,
1257}
1258unsafe impl TransparentNewType for FloatNumber {
1259 type Repr = rowan::SyntaxNode<RaTypes>;
1260}
1261
1262impl AstNode for FloatNumber {
1263 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1264 match syntax.kind() {
1265 FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())),
1266 _ => None,
1267 }
1268 }
1269 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1270}
1271
1272impl ToOwned for FloatNumber {
1273 type Owned = TreeArc<FloatNumber>;
1274 fn to_owned(&self) -> TreeArc<FloatNumber> { TreeArc::cast(self.syntax.to_owned()) }
1275}
1276
1277
1278impl ast::AstToken for FloatNumber {}
1279impl FloatNumber {}
1280
1281// FnDef 1107// FnDef
1282#[derive(Debug, PartialEq, Eq, Hash)] 1108#[derive(Debug, PartialEq, Eq, Hash)]
1283#[repr(transparent)] 1109#[repr(transparent)]
@@ -1613,35 +1439,6 @@ impl ToOwned for IndexExpr {
1613 1439
1614impl IndexExpr {} 1440impl IndexExpr {}
1615 1441
1616// IntNumber
1617#[derive(Debug, PartialEq, Eq, Hash)]
1618#[repr(transparent)]
1619pub struct IntNumber {
1620 pub(crate) syntax: SyntaxNode,
1621}
1622unsafe impl TransparentNewType for IntNumber {
1623 type Repr = rowan::SyntaxNode<RaTypes>;
1624}
1625
1626impl AstNode for IntNumber {
1627 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1628 match syntax.kind() {
1629 INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())),
1630 _ => None,
1631 }
1632 }
1633 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1634}
1635
1636impl ToOwned for IntNumber {
1637 type Owned = TreeArc<IntNumber>;
1638 fn to_owned(&self) -> TreeArc<IntNumber> { TreeArc::cast(self.syntax.to_owned()) }
1639}
1640
1641
1642impl ast::AstToken for IntNumber {}
1643impl IntNumber {}
1644
1645// ItemList 1442// ItemList
1646#[derive(Debug, PartialEq, Eq, Hash)] 1443#[derive(Debug, PartialEq, Eq, Hash)]
1647#[repr(transparent)] 1444#[repr(transparent)]
@@ -1777,35 +1574,6 @@ impl LetStmt {
1777 } 1574 }
1778} 1575}
1779 1576
1780// Lifetime
1781#[derive(Debug, PartialEq, Eq, Hash)]
1782#[repr(transparent)]
1783pub struct Lifetime {
1784 pub(crate) syntax: SyntaxNode,
1785}
1786unsafe impl TransparentNewType for Lifetime {
1787 type Repr = rowan::SyntaxNode<RaTypes>;
1788}
1789
1790impl AstNode for Lifetime {
1791 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1792 match syntax.kind() {
1793 LIFETIME => Some(Lifetime::from_repr(syntax.into_repr())),
1794 _ => None,
1795 }
1796 }
1797 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1798}
1799
1800impl ToOwned for Lifetime {
1801 type Owned = TreeArc<Lifetime>;
1802 fn to_owned(&self) -> TreeArc<Lifetime> { TreeArc::cast(self.syntax.to_owned()) }
1803}
1804
1805
1806impl ast::AstToken for Lifetime {}
1807impl Lifetime {}
1808
1809// LifetimeArg 1577// LifetimeArg
1810#[derive(Debug, PartialEq, Eq, Hash)] 1578#[derive(Debug, PartialEq, Eq, Hash)]
1811#[repr(transparent)] 1579#[repr(transparent)]
@@ -1832,11 +1600,7 @@ impl ToOwned for LifetimeArg {
1832} 1600}
1833 1601
1834 1602
1835impl LifetimeArg { 1603impl LifetimeArg {}
1836 pub fn lifetime(&self) -> Option<&Lifetime> {
1837 super::child_opt(self)
1838 }
1839}
1840 1604
1841// LifetimeParam 1605// LifetimeParam
1842#[derive(Debug, PartialEq, Eq, Hash)] 1606#[derive(Debug, PartialEq, Eq, Hash)]
@@ -1865,11 +1629,7 @@ impl ToOwned for LifetimeParam {
1865 1629
1866 1630
1867impl ast::AttrsOwner for LifetimeParam {} 1631impl ast::AttrsOwner for LifetimeParam {}
1868impl LifetimeParam { 1632impl LifetimeParam {}
1869 pub fn lifetime(&self) -> Option<&Lifetime> {
1870 super::child_opt(self)
1871 }
1872}
1873 1633
1874// Literal 1634// Literal
1875#[derive(Debug, PartialEq, Eq, Hash)] 1635#[derive(Debug, PartialEq, Eq, Hash)]
@@ -1897,130 +1657,7 @@ impl ToOwned for Literal {
1897} 1657}
1898 1658
1899 1659
1900impl Literal { 1660impl Literal {}
1901 pub fn literal_expr(&self) -> Option<&LiteralExpr> {
1902 super::child_opt(self)
1903 }
1904}
1905
1906// LiteralExpr
1907#[derive(Debug, PartialEq, Eq, Hash)]
1908#[repr(transparent)]
1909pub struct LiteralExpr {
1910 pub(crate) syntax: SyntaxNode,
1911}
1912unsafe impl TransparentNewType for LiteralExpr {
1913 type Repr = rowan::SyntaxNode<RaTypes>;
1914}
1915
1916#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1917pub enum LiteralExprKind<'a> {
1918 String(&'a String),
1919 ByteString(&'a ByteString),
1920 RawString(&'a RawString),
1921 RawByteString(&'a RawByteString),
1922 Char(&'a Char),
1923 Byte(&'a Byte),
1924 IntNumber(&'a IntNumber),
1925 FloatNumber(&'a FloatNumber),
1926 TrueKw(&'a TrueKw),
1927 FalseKw(&'a FalseKw),
1928}
1929impl<'a> From<&'a String> for &'a LiteralExpr {
1930 fn from(n: &'a String) -> &'a LiteralExpr {
1931 LiteralExpr::cast(&n.syntax).unwrap()
1932 }
1933}
1934impl<'a> From<&'a ByteString> for &'a LiteralExpr {
1935 fn from(n: &'a ByteString) -> &'a LiteralExpr {
1936 LiteralExpr::cast(&n.syntax).unwrap()
1937 }
1938}
1939impl<'a> From<&'a RawString> for &'a LiteralExpr {
1940 fn from(n: &'a RawString) -> &'a LiteralExpr {
1941 LiteralExpr::cast(&n.syntax).unwrap()
1942 }
1943}
1944impl<'a> From<&'a RawByteString> for &'a LiteralExpr {
1945 fn from(n: &'a RawByteString) -> &'a LiteralExpr {
1946 LiteralExpr::cast(&n.syntax).unwrap()
1947 }
1948}
1949impl<'a> From<&'a Char> for &'a LiteralExpr {
1950 fn from(n: &'a Char) -> &'a LiteralExpr {
1951 LiteralExpr::cast(&n.syntax).unwrap()
1952 }
1953}
1954impl<'a> From<&'a Byte> for &'a LiteralExpr {
1955 fn from(n: &'a Byte) -> &'a LiteralExpr {
1956 LiteralExpr::cast(&n.syntax).unwrap()
1957 }
1958}
1959impl<'a> From<&'a IntNumber> for &'a LiteralExpr {
1960 fn from(n: &'a IntNumber) -> &'a LiteralExpr {
1961 LiteralExpr::cast(&n.syntax).unwrap()
1962 }
1963}
1964impl<'a> From<&'a FloatNumber> for &'a LiteralExpr {
1965 fn from(n: &'a FloatNumber) -> &'a LiteralExpr {
1966 LiteralExpr::cast(&n.syntax).unwrap()
1967 }
1968}
1969impl<'a> From<&'a TrueKw> for &'a LiteralExpr {
1970 fn from(n: &'a TrueKw) -> &'a LiteralExpr {
1971 LiteralExpr::cast(&n.syntax).unwrap()
1972 }
1973}
1974impl<'a> From<&'a FalseKw> for &'a LiteralExpr {
1975 fn from(n: &'a FalseKw) -> &'a LiteralExpr {
1976 LiteralExpr::cast(&n.syntax).unwrap()
1977 }
1978}
1979
1980
1981impl AstNode for LiteralExpr {
1982 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1983 match syntax.kind() {
1984 | STRING
1985 | BYTE_STRING
1986 | RAW_STRING
1987 | RAW_BYTE_STRING
1988 | CHAR
1989 | BYTE
1990 | INT_NUMBER
1991 | FLOAT_NUMBER
1992 | TRUE_KW
1993 | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())),
1994 _ => None,
1995 }
1996 }
1997 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1998}
1999
2000impl ToOwned for LiteralExpr {
2001 type Owned = TreeArc<LiteralExpr>;
2002 fn to_owned(&self) -> TreeArc<LiteralExpr> { TreeArc::cast(self.syntax.to_owned()) }
2003}
2004
2005impl LiteralExpr {
2006 pub fn kind(&self) -> LiteralExprKind {
2007 match self.syntax.kind() {
2008 STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()),
2009 BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()),
2010 RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()),
2011 RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()),
2012 CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()),
2013 BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()),
2014 INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()),
2015 FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()),
2016 TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()),
2017 FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()),
2018 _ => unreachable!(),
2019 }
2020 }
2021}
2022
2023impl LiteralExpr {}
2024 1661
2025// LiteralPat 1662// LiteralPat
2026#[derive(Debug, PartialEq, Eq, Hash)] 1663#[derive(Debug, PartialEq, Eq, Hash)]
@@ -3404,64 +3041,6 @@ impl ToOwned for RangePat {
3404 3041
3405impl RangePat {} 3042impl RangePat {}
3406 3043
3407// RawByteString
3408#[derive(Debug, PartialEq, Eq, Hash)]
3409#[repr(transparent)]
3410pub struct RawByteString {
3411 pub(crate) syntax: SyntaxNode,
3412}
3413unsafe impl TransparentNewType for RawByteString {
3414 type Repr = rowan::SyntaxNode<RaTypes>;
3415}
3416
3417impl AstNode for RawByteString {
3418 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
3419 match syntax.kind() {
3420 RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())),
3421 _ => None,
3422 }
3423 }
3424 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3425}
3426
3427impl ToOwned for RawByteString {
3428 type Owned = TreeArc<RawByteString>;
3429 fn to_owned(&self) -> TreeArc<RawByteString> { TreeArc::cast(self.syntax.to_owned()) }
3430}
3431
3432
3433impl ast::AstToken for RawByteString {}
3434impl RawByteString {}
3435
3436// RawString
3437#[derive(Debug, PartialEq, Eq, Hash)]
3438#[repr(transparent)]
3439pub struct RawString {
3440 pub(crate) syntax: SyntaxNode,
3441}
3442unsafe impl TransparentNewType for RawString {
3443 type Repr = rowan::SyntaxNode<RaTypes>;
3444}
3445
3446impl AstNode for RawString {
3447 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
3448 match syntax.kind() {
3449 RAW_STRING => Some(RawString::from_repr(syntax.into_repr())),
3450 _ => None,
3451 }
3452 }
3453 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3454}
3455
3456impl ToOwned for RawString {
3457 type Owned = TreeArc<RawString>;
3458 fn to_owned(&self) -> TreeArc<RawString> { TreeArc::cast(self.syntax.to_owned()) }
3459}
3460
3461
3462impl ast::AstToken for RawString {}
3463impl RawString {}
3464
3465// RefExpr 3044// RefExpr
3466#[derive(Debug, PartialEq, Eq, Hash)] 3045#[derive(Debug, PartialEq, Eq, Hash)]
3467#[repr(transparent)] 3046#[repr(transparent)]
@@ -3622,34 +3201,6 @@ impl ReturnExpr {
3622 } 3201 }
3623} 3202}
3624 3203
3625// SelfKw
3626#[derive(Debug, PartialEq, Eq, Hash)]
3627#[repr(transparent)]
3628pub struct SelfKw {
3629 pub(crate) syntax: SyntaxNode,
3630}
3631unsafe impl TransparentNewType for SelfKw {
3632 type Repr = rowan::SyntaxNode<RaTypes>;
3633}
3634
3635impl AstNode for SelfKw {
3636 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
3637 match syntax.kind() {
3638 SELF_KW => Some(SelfKw::from_repr(syntax.into_repr())),
3639 _ => None,
3640 }
3641 }
3642 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3643}
3644
3645impl ToOwned for SelfKw {
3646 type Owned = TreeArc<SelfKw>;
3647 fn to_owned(&self) -> TreeArc<SelfKw> { TreeArc::cast(self.syntax.to_owned()) }
3648}
3649
3650
3651impl SelfKw {}
3652
3653// SelfParam 3204// SelfParam
3654#[derive(Debug, PartialEq, Eq, Hash)] 3205#[derive(Debug, PartialEq, Eq, Hash)]
3655#[repr(transparent)] 3206#[repr(transparent)]
@@ -3677,11 +3228,7 @@ impl ToOwned for SelfParam {
3677 3228
3678 3229
3679impl ast::TypeAscriptionOwner for SelfParam {} 3230impl ast::TypeAscriptionOwner for SelfParam {}
3680impl SelfParam { 3231impl SelfParam {}