aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock16
-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
50 files changed, 1027 insertions, 1228 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9a5630db6..ddd508b0a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1077,8 +1077,8 @@ dependencies = [
1077 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1077 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1078 "ra_parser 0.1.0", 1078 "ra_parser 0.1.0",
1079 "ra_text_edit 0.1.0", 1079 "ra_text_edit 0.1.0",
1080 "rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1080 "rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1081 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1081 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1082 "test_utils 0.1.0", 1082 "test_utils 0.1.0",
1083 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1083 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1084 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1084 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1098,7 +1098,7 @@ dependencies = [
1098name = "ra_tt" 1098name = "ra_tt"
1099version = "0.1.0" 1099version = "0.1.0"
1100dependencies = [ 1100dependencies = [
1101 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1101 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1102] 1102]
1103 1103
1104[[package]] 1104[[package]]
@@ -1298,12 +1298,12 @@ dependencies = [
1298 1298
1299[[package]] 1299[[package]]
1300name = "rowan" 1300name = "rowan"
1301version = "0.3.3" 1301version = "0.4.0"
1302source = "registry+https://github.com/rust-lang/crates.io-index" 1302source = "registry+https://github.com/rust-lang/crates.io-index"
1303dependencies = [ 1303dependencies = [
1304 "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 1304 "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
1305 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1305 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1306 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1306 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1307 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1307 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1308] 1308]
1309 1309
@@ -1456,7 +1456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1456 1456
1457[[package]] 1457[[package]]
1458name = "smol_str" 1458name = "smol_str"
1459version = "0.1.9" 1459version = "0.1.10"
1460source = "registry+https://github.com/rust-lang/crates.io-index" 1460source = "registry+https://github.com/rust-lang/crates.io-index"
1461dependencies = [ 1461dependencies = [
1462 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1462 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1964,7 +1964,7 @@ dependencies = [
1964"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 1964"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c"
1965"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" 1965"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
1966"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f" 1966"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f"
1967"checksum rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74d41f779e2c893339e34bebf035652c58214823cd412550111886c06632f89d" 1967"checksum rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "397cd19c109641f10f3c66433440285e232d8cbd37406cf8f944a15ab1e63a8e"
1968"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" 1968"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
1969"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1969"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
1970"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1970"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
@@ -1983,7 +1983,7 @@ dependencies = [
1983"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1983"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1984"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1984"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
1985"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 1985"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
1986"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" 1986"checksum smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d077b3367211e9c6e2e012fb804c444e0d80ab5a51ae4137739b58e6446dcaef"
1987"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1987"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
1988"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1988"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
1989"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1989"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
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 {}
3681 pub fn self_kw(&self) -> Option<&SelfKw> {
3682 super::child_opt(self)
3683 }
3684}
3685 3232
3686// SlicePat 3233// SlicePat
3687#[derive(Debug, PartialEq, Eq, Hash)] 3234#[derive(Debug, PartialEq, Eq, Hash)]
@@ -3866,35 +3413,6 @@ impl Stmt {
3866 3413
3867impl Stmt {} 3414impl Stmt {}
3868 3415
3869// String
3870#[derive(Debug, PartialEq, Eq, Hash)]
3871#[repr(transparent)]
3872pub struct String {
3873 pub(crate) syntax: SyntaxNode,
3874}
3875unsafe impl TransparentNewType for String {
3876 type Repr = rowan::SyntaxNode<RaTypes>;
3877}
3878
3879impl AstNode for String {
3880 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
3881 match syntax.kind() {
3882 STRING => Some(String::from_repr(syntax.into_repr())),
3883 _ => None,
3884 }
3885 }
3886 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3887}
3888
3889impl ToOwned for String {
3890 type Owned = TreeArc<String>;
3891 fn to_owned(&self) -> TreeArc<String> { TreeArc::cast(self.syntax.to_owned()) }
3892}
3893
3894
3895impl ast::AstToken for String {}
3896impl String {}
3897
3898// StructDef 3416// StructDef
3899#[derive(Debug, PartialEq, Eq, Hash)] 3417#[derive(Debug, PartialEq, Eq, Hash)]
3900#[repr(transparent)] 3418#[repr(transparent)]
@@ -4070,35 +3588,6 @@ impl TraitDef {
4070 } 3588 }
4071} 3589}
4072 3590
4073// TrueKw
4074#[derive(Debug, PartialEq, Eq, Hash)]
4075#[repr(transparent)]
4076pub struct TrueKw {
4077 pub(crate) syntax: SyntaxNode,
4078}
4079unsafe impl TransparentNewType for TrueKw {
4080 type Repr = rowan::SyntaxNode<RaTypes>;
4081}
4082
4083impl AstNode for TrueKw {
4084 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
4085 match syntax.kind() {
4086 TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())),
4087 _ => None,
4088 }
4089 }
4090 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4091}
4092
4093impl ToOwned for TrueKw {
4094 type Owned = TreeArc<TrueKw>;
4095 fn to_owned(&self) -> TreeArc<TrueKw> { TreeArc::cast(self.syntax.to_owned()) }
4096}
4097
4098
4099impl ast::AstToken for TrueKw {}
4100impl TrueKw {}
4101
4102// TryExpr 3591// TryExpr
4103#[derive(Debug, PartialEq, Eq, Hash)] 3592#[derive(Debug, PartialEq, Eq, Hash)]
4104#[repr(transparent)] 3593#[repr(transparent)]
@@ -4403,10 +3892,6 @@ impl TypeBound {
4403 pub fn type_ref(&self) -> Option<&TypeRef> { 3892 pub fn type_ref(&self) -> Option<&TypeRef> {
4404 super::child_opt(self) 3893 super::child_opt(self)
4405 } 3894 }
4406
4407 pub fn lifetime(&self) -> Option<&Lifetime> {
4408 super::child_opt(self)
4409 }
4410} 3895}
4411 3896
4412// TypeBoundList 3897// TypeBoundList
@@ -4847,10 +4332,6 @@ impl WherePred {
4847 pub fn type_ref(&self) -> Option<&TypeRef> { 4332 pub fn type_ref(&self) -> Option<&TypeRef> {
4848 super::child_opt(self) 4333 super::child_opt(self)
4849 } 4334 }
4850
4851 pub fn lifetime(&self) -> Option<&Lifetime> {
4852 super::child_opt(self)
4853 }
4854} 4335}
4855 4336
4856// WhileExpr 4337// WhileExpr
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 1123c2e95..6d7a5a1cb 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -463,31 +463,7 @@ Grammar(
463 "RangeExpr": (), 463 "RangeExpr": (),
464 "BinExpr": (), 464 "BinExpr": (),
465 465
466 "IntNumber": ( traits: ["AstToken"] ), 466 "Literal": (),
467 "FloatNumber": ( traits: ["AstToken"] ),
468 "String": ( traits: ["AstToken"] ),
469 "RawString": ( traits: ["AstToken"] ),
470 "Byte": ( traits: ["AstToken"] ),
471 "RawByteString": ( traits: ["AstToken"] ),
472 "ByteString": ( traits: ["AstToken"] ),
473 "Char": ( traits: ["AstToken"] ),
474 "TrueKw": ( traits: ["AstToken"] ),
475 "FalseKw": ( traits: ["AstToken"] ),
476 "LiteralExpr": (
477 enum: [
478 "String",
479 "ByteString",
480 "RawString",
481 "RawByteString",
482 "Char",
483 "Byte",
484 "IntNumber",
485 "FloatNumber",
486 "TrueKw",
487 "FalseKw",
488 ]
489 ),
490 "Literal": (options: ["LiteralExpr"]),
491 467
492 "Expr": ( 468 "Expr": (
493 enum: [ 469 enum: [
@@ -580,14 +556,11 @@ Grammar(
580 ), 556 ),
581 "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ), 557 "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ),
582 "LifetimeParam": ( 558 "LifetimeParam": (
583 options: [ "Lifetime"],
584 traits: ["AttrsOwner"], 559 traits: ["AttrsOwner"],
585 ), 560 ),
586 "Lifetime": ( traits: ["AstToken"] ),
587 "TypeBound": ( 561 "TypeBound": (
588 options: [ 562 options: [
589 "TypeRef", 563 "TypeRef",
590 "Lifetime",
591 ] 564 ]
592 ), 565 ),
593 "TypeBoundList": ( 566 "TypeBoundList": (
@@ -598,7 +571,6 @@ Grammar(
598 "WherePred": ( 571 "WherePred": (
599 options: [ 572 options: [
600 "TypeRef", 573 "TypeRef",
601 "Lifetime",
602 ], 574 ],
603 traits: [ 575 traits: [
604 "TypeBoundsOwner", 576 "TypeBoundsOwner",
@@ -643,12 +615,10 @@ Grammar(
643 ] 615 ]
644 ), 616 ),
645 "SelfParam": ( 617 "SelfParam": (
646 options: ["SelfKw"],
647 traits: [ 618 traits: [
648 "TypeAscriptionOwner", 619 "TypeAscriptionOwner",
649 ] 620 ]
650 ), 621 ),
651 "SelfKw": (),
652 "Param": ( 622 "Param": (
653 options: [ "Pat" ], 623 options: [ "Pat" ],
654 traits: [ 624 traits: [
@@ -692,8 +662,7 @@ Grammar(
692 ]), 662 ]),
693 "TypeArg": (options: ["TypeRef"]), 663 "TypeArg": (options: ["TypeRef"]),
694 "AssocTypeArg": (options: ["NameRef", "TypeRef"]), 664 "AssocTypeArg": (options: ["NameRef", "TypeRef"]),
695 "LifetimeArg": (options: ["Lifetime"]), 665 "LifetimeArg": (),
696 "Comment": ( traits: ["AstToken"] ),
697 "Whitespace": ( traits: ["AstToken"] ), 666 "Whitespace": ( traits: ["AstToken"] ),
698 }, 667 },
699) 668)
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 4f3020440..e1088e296 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -38,7 +38,7 @@ pub use crate::{
38 ast::AstNode, 38 ast::AstNode,
39 syntax_error::{SyntaxError, SyntaxErrorKind, Location}, 39 syntax_error::{SyntaxError, SyntaxErrorKind, Location},
40 syntax_text::SyntaxText, 40 syntax_text::SyntaxText,
41 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder}, 41 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken},
42 ptr::{SyntaxNodePtr, AstPtr}, 42 ptr::{SyntaxNodePtr, AstPtr},
43 parsing::{tokenize, Token}, 43 parsing::{tokenize, Token},
44}; 44};
@@ -70,7 +70,7 @@ impl SourceFile {
70 70
71 pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { 71 pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> {
72 parsing::incremental_reparse(self.syntax(), edit, self.errors()) 72 parsing::incremental_reparse(self.syntax(), edit, self.errors())
73 .map(|(green_node, errors)| SourceFile::new(green_node, errors)) 73 .map(|(green_node, errors, _reparsed_range)| SourceFile::new(green_node, errors))
74 } 74 }
75 75
76 fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { 76 fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> {
@@ -179,15 +179,23 @@ fn api_walkthrough() {
179 179
180 // There's a bunch of traversal methods on `SyntaxNode`: 180 // There's a bunch of traversal methods on `SyntaxNode`:
181 assert_eq!(expr_syntax.parent(), Some(block.syntax())); 181 assert_eq!(expr_syntax.parent(), Some(block.syntax()));
182 assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY)); 182 assert_eq!(
183 assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE)); 183 block.syntax().first_child_or_token().map(|it| it.kind()),
184 Some(SyntaxKind::L_CURLY)
185 );
186 assert_eq!(
187 expr_syntax.next_sibling_or_token().map(|it| it.kind()),
188 Some(SyntaxKind::WHITESPACE)
189 );
184 190
185 // As well as some iterator helpers: 191 // As well as some iterator helpers:
186 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); 192 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast);
187 assert_eq!(f, Some(&*func)); 193 assert_eq!(f, Some(&*func));
188 assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY)); 194 assert!(expr_syntax
195 .siblings_with_tokens(Direction::Next)
196 .any(|it| it.kind() == SyntaxKind::R_CURLY));
189 assert_eq!( 197 assert_eq!(
190 expr_syntax.descendants().count(), 198 expr_syntax.descendants_with_tokens().count(),
191 8, // 5 tokens `1`, ` `, `+`, ` `, `!` 199 8, // 5 tokens `1`, ` `, `+`, ` `, `!`
192 // 2 child literal expressions: `1`, `1` 200 // 2 child literal expressions: `1`, `1`
193 // 1 the node itself: `1 + 1` 201 // 1 the node itself: `1 + 1`
@@ -196,16 +204,14 @@ fn api_walkthrough() {
196 // There's also a `preorder` method with a more fine-grained iteration control: 204 // There's also a `preorder` method with a more fine-grained iteration control:
197 let mut buf = String::new(); 205 let mut buf = String::new();
198 let mut indent = 0; 206 let mut indent = 0;
199 for event in expr_syntax.preorder() { 207 for event in expr_syntax.preorder_with_tokens() {
200 match event { 208 match event {
201 WalkEvent::Enter(node) => { 209 WalkEvent::Enter(node) => {
202 buf += &format!( 210 let text = match node {
203 "{:indent$}{:?} {:?}\n", 211 SyntaxElement::Node(it) => it.text().to_string(),
204 " ", 212 SyntaxElement::Token(it) => it.text().to_string(),
205 node.text(), 213 };
206 node.kind(), 214 buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
207 indent = indent
208 );
209 indent += 2; 215 indent += 2;
210 } 216 }
211 WalkEvent::Leave(_) => indent -= 2, 217 WalkEvent::Leave(_) => indent -= 2,
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index 7e7f914f5..69887f500 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -12,7 +12,7 @@ use ra_parser::Reparser;
12use crate::{ 12use crate::{
13 SyntaxKind::*, TextRange, TextUnit, SyntaxError, 13 SyntaxKind::*, TextRange, TextUnit, SyntaxError,
14 algo, 14 algo,
15 syntax_node::{GreenNode, SyntaxNode}, 15 syntax_node::{GreenNode, SyntaxNode, GreenToken, SyntaxElement},
16 parsing::{ 16 parsing::{
17 text_token_source::TextTokenSource, 17 text_token_source::TextTokenSource,
18 text_tree_sink::TextTreeSink, 18 text_tree_sink::TextTreeSink,
@@ -24,60 +24,62 @@ pub(crate) fn incremental_reparse(
24 node: &SyntaxNode, 24 node: &SyntaxNode,
25 edit: &AtomTextEdit, 25 edit: &AtomTextEdit,
26 errors: Vec<SyntaxError>, 26 errors: Vec<SyntaxError>,
27) -> Option<(GreenNode, Vec<SyntaxError>)> { 27) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
28 let (node, green, new_errors) = 28 if let Some((green, old_range)) = reparse_token(node, &edit) {
29 reparse_leaf(node, &edit).or_else(|| reparse_block(node, &edit))?; 29 return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range));
30 let green_root = node.replace_with(green); 30 }
31 let errors = merge_errors(errors, new_errors, node, edit); 31
32 Some((green_root, errors)) 32 if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
33 return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
34 }
35 None
33} 36}
34 37
35fn reparse_leaf<'node>( 38fn reparse_token<'node>(
36 root: &'node SyntaxNode, 39 root: &'node SyntaxNode,
37 edit: &AtomTextEdit, 40 edit: &AtomTextEdit,
38) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { 41) -> Option<(GreenNode, TextRange)> {
39 let node = algo::find_covering_node(root, edit.delete); 42 let token = algo::find_covering_element(root, edit.delete).as_token()?;
40 match node.kind() { 43 match token.kind() {
41 WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { 44 WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
42 if node.kind() == WHITESPACE || node.kind() == COMMENT { 45 if token.kind() == WHITESPACE || token.kind() == COMMENT {
43 // removing a new line may extends previous token 46 // removing a new line may extends previous token
44 if node.text().to_string()[edit.delete - node.range().start()].contains('\n') { 47 if token.text().to_string()[edit.delete - token.range().start()].contains('\n') {
45 return None; 48 return None;
46 } 49 }
47 } 50 }
48 51
49 let text = get_text_after_edit(node, &edit); 52 let text = get_text_after_edit(token.into(), &edit);
50 let tokens = tokenize(&text); 53 let lex_tokens = tokenize(&text);
51 let token = match tokens[..] { 54 let lex_token = match lex_tokens[..] {
52 [token] if token.kind == node.kind() => token, 55 [lex_token] if lex_token.kind == token.kind() => lex_token,
53 _ => return None, 56 _ => return None,
54 }; 57 };
55 58
56 if token.kind == IDENT && is_contextual_kw(&text) { 59 if lex_token.kind == IDENT && is_contextual_kw(&text) {
57 return None; 60 return None;
58 } 61 }
59 62
60 if let Some(next_char) = root.text().char_at(node.range().end()) { 63 if let Some(next_char) = root.text().char_at(token.range().end()) {
61 let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); 64 let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char));
62 if tokens_with_next_char.len() == 1 { 65 if tokens_with_next_char.len() == 1 {
63 return None; 66 return None;
64 } 67 }
65 } 68 }
66 69
67 let green = GreenNode::new_leaf(node.kind(), text.into()); 70 let new_token = GreenToken::new(token.kind(), text.into());
68 let new_errors = vec![]; 71 Some((token.replace_with(new_token), token.range()))
69 Some((node, green, new_errors))
70 } 72 }
71 _ => None, 73 _ => None,
72 } 74 }
73} 75}
74 76
75fn reparse_block<'node>( 77fn reparse_block<'node>(
76 node: &'node SyntaxNode, 78 root: &'node SyntaxNode,
77 edit: &AtomTextEdit, 79 edit: &AtomTextEdit,
78) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { 80) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
79 let (node, reparser) = find_reparsable_node(node, edit.delete)?; 81 let (node, reparser) = find_reparsable_node(root, edit.delete)?;
80 let text = get_text_after_edit(node, &edit); 82 let text = get_text_after_edit(node.into(), &edit);
81 let tokens = tokenize(&text); 83 let tokens = tokenize(&text);
82 if !is_balanced(&tokens) { 84 if !is_balanced(&tokens) {
83 return None; 85 return None;
@@ -86,12 +88,16 @@ fn reparse_block<'node>(
86 let mut tree_sink = TextTreeSink::new(&text, &tokens); 88 let mut tree_sink = TextTreeSink::new(&text, &tokens);
87 reparser.parse(&token_source, &mut tree_sink); 89 reparser.parse(&token_source, &mut tree_sink);
88 let (green, new_errors) = tree_sink.finish(); 90 let (green, new_errors) = tree_sink.finish();
89 Some((node, green, new_errors)) 91 Some((node.replace_with(green), new_errors, node.range()))
90} 92}
91 93
92fn get_text_after_edit(node: &SyntaxNode, edit: &AtomTextEdit) -> String { 94fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
93 let edit = AtomTextEdit::replace(edit.delete - node.range().start(), edit.insert.clone()); 95 let edit = AtomTextEdit::replace(edit.delete - element.range().start(), edit.insert.clone());
94 edit.apply(node.text().to_string()) 96 let text = match element {
97 SyntaxElement::Token(token) => token.text().to_string(),
98 SyntaxElement::Node(node) => node.text().to_string(),
99 };
100 edit.apply(text)
95} 101}
96 102
97fn is_contextual_kw(text: &str) -> bool { 103fn is_contextual_kw(text: &str) -> bool {
@@ -102,9 +108,13 @@ fn is_contextual_kw(text: &str) -> bool {
102} 108}
103 109
104fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { 110fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> {
105 let node = algo::find_covering_node(node, range); 111 let node = algo::find_covering_element(node, range);
106 node.ancestors().find_map(|node| { 112 let mut ancestors = match node {
107 let first_child = node.first_child().map(|it| it.kind()); 113 SyntaxElement::Token(it) => it.parent().ancestors(),
114 SyntaxElement::Node(it) => it.ancestors(),
115 };
116 ancestors.find_map(|node| {
117 let first_child = node.first_child_or_token().map(|it| it.kind());
108 let parent = node.parent().map(|it| it.kind()); 118 let parent = node.parent().map(|it| it.kind());
109 Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) 119 Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
110 }) 120 })
@@ -136,19 +146,19 @@ fn is_balanced(tokens: &[Token]) -> bool {
136fn merge_errors( 146fn merge_errors(
137 old_errors: Vec<SyntaxError>, 147 old_errors: Vec<SyntaxError>,
138 new_errors: Vec<SyntaxError>, 148 new_errors: Vec<SyntaxError>,
139 old_node: &SyntaxNode, 149 old_range: TextRange,
140 edit: &AtomTextEdit, 150 edit: &AtomTextEdit,
141) -> Vec<SyntaxError> { 151) -> Vec<SyntaxError> {
142 let mut res = Vec::new(); 152 let mut res = Vec::new();
143 for e in old_errors { 153 for e in old_errors {
144 if e.offset() <= old_node.range().start() { 154 if e.offset() <= old_range.start() {
145 res.push(e) 155 res.push(e)
146 } else if e.offset() >= old_node.range().end() { 156 } else if e.offset() >= old_range.end() {
147 res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); 157 res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len()));
148 } 158 }
149 } 159 }
150 for e in new_errors { 160 for e in new_errors {
151 res.push(e.add_offset(old_node.range().start(), 0.into())); 161 res.push(e.add_offset(old_range.start(), 0.into()));
152 } 162 }
153 res 163 res
154} 164}
@@ -160,13 +170,7 @@ mod tests {
160 use crate::{SourceFile, AstNode}; 170 use crate::{SourceFile, AstNode};
161 use super::*; 171 use super::*;
162 172
163 fn do_check<F>(before: &str, replace_with: &str, reparser: F) 173 fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
164 where
165 for<'a> F: Fn(
166 &'a SyntaxNode,
167 &AtomTextEdit,
168 ) -> Option<(&'a SyntaxNode, GreenNode, Vec<SyntaxError>)>,
169 {
170 let (range, before) = extract_range(before); 174 let (range, before) = extract_range(before);
171 let edit = AtomTextEdit::replace(range, replace_with.to_owned()); 175 let edit = AtomTextEdit::replace(range, replace_with.to_owned());
172 let after = edit.apply(before.clone()); 176 let after = edit.apply(before.clone());
@@ -175,23 +179,20 @@ mod tests {
175 let incrementally_reparsed = { 179 let incrementally_reparsed = {
176 let f = SourceFile::parse(&before); 180 let f = SourceFile::parse(&before);
177 let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; 181 let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() };
178 let (node, green, new_errors) = 182 let (green, new_errors, range) =
179 reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); 183 incremental_reparse(f.syntax(), &edit, f.errors()).unwrap();
180 let green_root = node.replace_with(green); 184 assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
181 let errors = super::merge_errors(f.errors(), new_errors, node, &edit); 185 SourceFile::new(green, new_errors)
182 SourceFile::new(green_root, errors)
183 }; 186 };
184 187
185 assert_eq_text!( 188 assert_eq_text!(
186 &fully_reparsed.syntax().debug_dump(), 189 &fully_reparsed.syntax().debug_dump(),
187 &incrementally_reparsed.syntax().debug_dump(), 190 &incrementally_reparsed.syntax().debug_dump(),
188 ) 191 );
189 } 192 }
190 193
191 #[test] 194 #[test] // FIXME: some test here actually test token reparsing
192 fn reparse_block_tests() { 195 fn reparse_block_tests() {
193 let do_check = |before, replace_to| do_check(before, replace_to, reparse_block);
194
195 do_check( 196 do_check(
196 r" 197 r"
197fn foo() { 198fn foo() {
@@ -199,6 +200,7 @@ fn foo() {
199} 200}
200", 201",
201 "baz", 202 "baz",
203 3,
202 ); 204 );
203 do_check( 205 do_check(
204 r" 206 r"
@@ -207,6 +209,7 @@ fn foo() {
207} 209}
208", 210",
209 "baz", 211 "baz",
212 25,
210 ); 213 );
211 do_check( 214 do_check(
212 r" 215 r"
@@ -215,6 +218,7 @@ struct Foo {
215} 218}
216", 219",
217 ",\n g: (),", 220 ",\n g: (),",
221 14,
218 ); 222 );
219 do_check( 223 do_check(
220 r" 224 r"
@@ -225,6 +229,7 @@ fn foo {
225} 229}
226", 230",
227 "62", 231 "62",
232 31, // FIXME: reparse only int literal here
228 ); 233 );
229 do_check( 234 do_check(
230 r" 235 r"
@@ -233,7 +238,9 @@ mod foo {
233} 238}
234", 239",
235 "bar", 240 "bar",
241 11,
236 ); 242 );
243
237 do_check( 244 do_check(
238 r" 245 r"
239trait Foo { 246trait Foo {
@@ -241,6 +248,7 @@ trait Foo {
241} 248}
242", 249",
243 "Output", 250 "Output",
251 3,
244 ); 252 );
245 do_check( 253 do_check(
246 r" 254 r"
@@ -249,13 +257,9 @@ impl IntoIterator<Item=i32> for Foo {
249} 257}
250", 258",
251 "n next(", 259 "n next(",
260 9,
252 ); 261 );
253 do_check( 262 do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10);
254 r"
255use a::b::{foo,<|>,bar<|>};
256 ",
257 "baz",
258 );
259 do_check( 263 do_check(
260 r" 264 r"
261pub enum A { 265pub enum A {
@@ -263,12 +267,14 @@ pub enum A {
263} 267}
264", 268",
265 "\nBar;\n", 269 "\nBar;\n",
270 11,
266 ); 271 );
267 do_check( 272 do_check(
268 r" 273 r"
269foo!{a, b<|><|> d} 274foo!{a, b<|><|> d}
270", 275",
271 ", c[3]", 276 ", c[3]",
277 8,
272 ); 278 );
273 do_check( 279 do_check(
274 r" 280 r"
@@ -277,6 +283,7 @@ fn foo() {
277} 283}
278", 284",
279 "123", 285 "123",
286 14,
280 ); 287 );
281 do_check( 288 do_check(
282 r" 289 r"
@@ -285,54 +292,60 @@ extern {
285} 292}
286", 293",
287 " exit(code: c_int)", 294 " exit(code: c_int)",
295 11,
288 ); 296 );
289 } 297 }
290 298
291 #[test] 299 #[test]
292 fn reparse_leaf_tests() { 300 fn reparse_token_tests() {
293 let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf);
294
295 do_check( 301 do_check(
296 r"<|><|> 302 r"<|><|>
297fn foo() -> i32 { 1 } 303fn foo() -> i32 { 1 }
298", 304",
299 "\n\n\n \n", 305 "\n\n\n \n",
306 1,
300 ); 307 );
301 do_check( 308 do_check(
302 r" 309 r"
303fn foo() -> <|><|> {} 310fn foo() -> <|><|> {}
304", 311",
305 " \n", 312 " \n",
313 2,
306 ); 314 );
307 do_check( 315 do_check(
308 r" 316 r"
309fn <|>foo<|>() -> i32 { 1 } 317fn <|>foo<|>() -> i32 { 1 }
310", 318",
311 "bar", 319 "bar",
320 3,
312 ); 321 );
313 do_check( 322 do_check(
314 r" 323 r"
315fn foo<|><|>foo() { } 324fn foo<|><|>foo() { }
316", 325",
317 "bar", 326 "bar",
327 6,
318 ); 328 );
319 do_check( 329 do_check(
320 r" 330 r"
321fn foo /* <|><|> */ () {} 331fn foo /* <|><|> */ () {}
322", 332",
323 "some comment", 333 "some comment",
334 6,
324 ); 335 );
325 do_check( 336 do_check(
326 r" 337 r"
327fn baz <|><|> () {} 338fn baz <|><|> () {}
328", 339",
329 " \t\t\n\n", 340 " \t\t\n\n",
341 2,
330 ); 342 );
331 do_check( 343 do_check(
332 r" 344 r"
333fn baz <|><|> () {} 345fn baz <|><|> () {}
334", 346",
335 " \t\t\n\n", 347 " \t\t\n\n",
348 2,
336 ); 349 );
337 do_check( 350 do_check(
338 r" 351 r"
@@ -340,24 +353,28 @@ fn baz <|><|> () {}
340mod { } 353mod { }
341", 354",
342 "c", 355 "c",
356 14,
343 ); 357 );
344 do_check( 358 do_check(
345 r#" 359 r#"
346fn -> &str { "Hello<|><|>" } 360fn -> &str { "Hello<|><|>" }
347"#, 361"#,
348 ", world", 362 ", world",
363 7,
349 ); 364 );
350 do_check( 365 do_check(
351 r#" 366 r#"
352fn -> &str { // "Hello<|><|>" 367fn -> &str { // "Hello<|><|>"
353"#, 368"#,
354 ", world", 369 ", world",
370 10,
355 ); 371 );
356 do_check( 372 do_check(
357 r##" 373 r##"
358fn -> &str { r#"Hello<|><|>"# 374fn -> &str { r#"Hello<|><|>"#
359"##, 375"##,
360 ", world", 376 ", world",
377 10,
361 ); 378 );
362 do_check( 379 do_check(
363 r" 380 r"
@@ -367,6 +384,7 @@ enum Foo {
367} 384}
368", 385",
369 "Clone", 386 "Clone",
387 4,
370 ); 388 );
371 } 389 }
372} 390}
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index b17d06c61..71fc515f2 100644
--- a/crates/ra_syntax/src/parsing/text_tree_sink.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -28,10 +28,10 @@ enum State {
28} 28}
29 29
30impl<'a> TreeSink for TextTreeSink<'a> { 30impl<'a> TreeSink for TextTreeSink<'a> {
31 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { 31 fn token(&mut self, kind: SyntaxKind, n_tokens: u8) {
32 match mem::replace(&mut self.state, State::Normal) { 32 match mem::replace(&mut self.state, State::Normal) {
33 State::PendingStart => unreachable!(), 33 State::PendingStart => unreachable!(),
34 State::PendingFinish => self.inner.finish_branch(), 34 State::PendingFinish => self.inner.finish_node(),
35 State::Normal => (), 35 State::Normal => (),
36 } 36 }
37 self.eat_trivias(); 37 self.eat_trivias();
@@ -40,18 +40,18 @@ impl<'a> TreeSink for TextTreeSink<'a> {
40 .iter() 40 .iter()
41 .map(|it| it.len) 41 .map(|it| it.len)
42 .sum::<TextUnit>(); 42 .sum::<TextUnit>();
43 self.do_leaf(kind, len, n_tokens); 43 self.do_token(kind, len, n_tokens);
44 } 44 }
45 45
46 fn start_branch(&mut self, kind: SyntaxKind) { 46 fn start_node(&mut self, kind: SyntaxKind) {
47 match mem::replace(&mut self.state, State::Normal) { 47 match mem::replace(&mut self.state, State::Normal) {
48 State::PendingStart => { 48 State::PendingStart => {
49 self.inner.start_branch(kind); 49 self.inner.start_node(kind);
50 // No need to attach trivias to previous node: there is no 50 // No need to attach trivias to previous node: there is no
51 // previous node. 51 // previous node.
52 return; 52 return;
53 } 53 }
54 State::PendingFinish => self.inner.finish_branch(), 54 State::PendingFinish => self.inner.finish_node(),
55 State::Normal => (), 55 State::Normal => (),
56 } 56 }
57 57
@@ -71,14 +71,14 @@ impl<'a> TreeSink for TextTreeSink<'a> {
71 n_attached_trivias(kind, leading_trivias) 71 n_attached_trivias(kind, leading_trivias)
72 }; 72 };
73 self.eat_n_trivias(n_trivias - n_attached_trivias); 73 self.eat_n_trivias(n_trivias - n_attached_trivias);
74 self.inner.start_branch(kind); 74 self.inner.start_node(kind);
75 self.eat_n_trivias(n_attached_trivias); 75 self.eat_n_trivias(n_attached_trivias);
76 } 76 }
77 77
78 fn finish_branch(&mut self) { 78 fn finish_node(&mut self) {
79 match mem::replace(&mut self.state, State::PendingFinish) { 79 match mem::replace(&mut self.state, State::PendingFinish) {
80 State::PendingStart => unreachable!(), 80 State::PendingStart => unreachable!(),
81 State::PendingFinish => self.inner.finish_branch(), 81 State::PendingFinish => self.inner.finish_node(),
82 State::Normal => (), 82 State::Normal => (),
83 } 83 }
84 } 84 }
@@ -104,7 +104,7 @@ impl<'a> TextTreeSink<'a> {
104 match mem::replace(&mut self.state, State::Normal) { 104 match mem::replace(&mut self.state, State::Normal) {
105 State::PendingFinish => { 105 State::PendingFinish => {
106 self.eat_trivias(); 106 self.eat_trivias();
107 self.inner.finish_branch() 107 self.inner.finish_node()
108 } 108 }
109 State::PendingStart | State::Normal => unreachable!(), 109 State::PendingStart | State::Normal => unreachable!(),
110 } 110 }
@@ -117,7 +117,7 @@ impl<'a> TextTreeSink<'a> {
117 if !token.kind.is_trivia() { 117 if !token.kind.is_trivia() {
118 break; 118 break;
119 } 119 }
120 self.do_leaf(token.kind, token.len, 1); 120 self.do_token(token.kind, token.len, 1);
121 } 121 }
122 } 122 }
123 123
@@ -125,16 +125,16 @@ impl<'a> TextTreeSink<'a> {
125 for _ in 0..n { 125 for _ in 0..n {
126 let token = self.tokens[self.token_pos]; 126 let token = self.tokens[self.token_pos];
127 assert!(token.kind.is_trivia()); 127 assert!(token.kind.is_trivia());
128 self.do_leaf(token.kind, token.len, 1); 128 self.do_token(token.kind, token.len, 1);
129 } 129 }
130 } 130 }
131 131
132 fn do_leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { 132 fn do_token(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) {
133 let range = TextRange::offset_len(self.text_pos, len); 133 let range = TextRange::offset_len(self.text_pos, len);
134 let text: SmolStr = self.text[range].into(); 134 let text: SmolStr = self.text[range].into();
135 self.text_pos += len; 135 self.text_pos += len;
136 self.token_pos += n_tokens; 136 self.token_pos += n_tokens;
137 self.inner.leaf(kind, text); 137 self.inner.token(kind, text);
138 } 138 }
139} 139}
140 140
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index e5b4cdb11..be181d0ae 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -29,6 +29,9 @@ impl Types for RaTypes {
29} 29}
30 30
31pub(crate) type GreenNode = rowan::GreenNode<RaTypes>; 31pub(crate) type GreenNode = rowan::GreenNode<RaTypes>;
32pub(crate) type GreenToken = rowan::GreenToken<RaTypes>;
33#[allow(unused)]
34pub(crate) type GreenElement = rowan::GreenElement<RaTypes>;
32 35
33/// Marker trait for CST and AST nodes 36/// Marker trait for CST and AST nodes
34pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {} 37pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {}
@@ -113,11 +116,13 @@ impl ToOwned for SyntaxNode {
113 116
114impl fmt::Debug for SyntaxNode { 117impl fmt::Debug for SyntaxNode {
115 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 118 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
116 write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; 119 write!(fmt, "{:?}@{:?}", self.kind(), self.range())
117 if has_short_text(self.kind()) { 120 }
118 write!(fmt, " \"{}\"", self.text())?; 121}
119 } 122
120 Ok(()) 123impl fmt::Display for SyntaxNode {
124 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
125 fmt::Display::fmt(&self.text(), fmt)
121 } 126 }
122} 127}
123 128
@@ -145,14 +150,6 @@ impl SyntaxNode {
145 SyntaxText::new(self) 150 SyntaxText::new(self)
146 } 151 }
147 152
148 pub fn is_leaf(&self) -> bool {
149 self.0.is_leaf()
150 }
151
152 pub fn leaf_text(&self) -> Option<&SmolStr> {
153 self.0.leaf_text()
154 }
155
156 pub fn parent(&self) -> Option<&SyntaxNode> { 153 pub fn parent(&self) -> Option<&SyntaxNode> {
157 self.0.parent().map(SyntaxNode::from_repr) 154 self.0.parent().map(SyntaxNode::from_repr)
158 } 155 }
@@ -161,22 +158,50 @@ impl SyntaxNode {
161 self.0.first_child().map(SyntaxNode::from_repr) 158 self.0.first_child().map(SyntaxNode::from_repr)
162 } 159 }
163 160
161 pub fn first_child_or_token(&self) -> Option<SyntaxElement> {
162 self.0.first_child_or_token().map(SyntaxElement::from)
163 }
164
164 pub fn last_child(&self) -> Option<&SyntaxNode> { 165 pub fn last_child(&self) -> Option<&SyntaxNode> {
165 self.0.last_child().map(SyntaxNode::from_repr) 166 self.0.last_child().map(SyntaxNode::from_repr)
166 } 167 }
167 168
169 pub fn last_child_or_token(&self) -> Option<SyntaxElement> {
170 self.0.last_child_or_token().map(SyntaxElement::from)
171 }
172
168 pub fn next_sibling(&self) -> Option<&SyntaxNode> { 173 pub fn next_sibling(&self) -> Option<&SyntaxNode> {
169 self.0.next_sibling().map(SyntaxNode::from_repr) 174 self.0.next_sibling().map(SyntaxNode::from_repr)
170 } 175 }
171 176
177 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> {
178 self.0.next_sibling_or_token().map(SyntaxElement::from)
179 }
180
172 pub fn prev_sibling(&self) -> Option<&SyntaxNode> { 181 pub fn prev_sibling(&self) -> Option<&SyntaxNode> {
173 self.0.prev_sibling().map(SyntaxNode::from_repr) 182 self.0.prev_sibling().map(SyntaxNode::from_repr)
174 } 183 }
175 184
185 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> {
186 self.0.prev_sibling_or_token().map(SyntaxElement::from)
187 }
188
176 pub fn children(&self) -> SyntaxNodeChildren { 189 pub fn children(&self) -> SyntaxNodeChildren {
177 SyntaxNodeChildren(self.0.children()) 190 SyntaxNodeChildren(self.0.children())
178 } 191 }
179 192
193 pub fn children_with_tokens(&self) -> SyntaxElementChildren {
194 SyntaxElementChildren(self.0.children_with_tokens())
195 }
196
197 pub fn first_token(&self) -> Option<SyntaxToken> {
198 self.0.first_token().map(SyntaxToken::from)
199 }
200
201 pub fn last_token(&self) -> Option<SyntaxToken> {
202 self.0.last_token().map(SyntaxToken::from)
203 }
204
180 pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> { 205 pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> {
181 crate::algo::generate(Some(self), |&node| node.parent()) 206 crate::algo::generate(Some(self), |&node| node.parent())
182 } 207 }
@@ -188,6 +213,13 @@ impl SyntaxNode {
188 }) 213 })
189 } 214 }
190 215
216 pub fn descendants_with_tokens(&self) -> impl Iterator<Item = SyntaxElement> {
217 self.preorder_with_tokens().filter_map(|event| match event {
218 WalkEvent::Enter(it) => Some(it),
219 WalkEvent::Leave(_) => None,
220 })
221 }
222
191 pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> { 223 pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> {
192 crate::algo::generate(Some(self), move |&node| match direction { 224 crate::algo::generate(Some(self), move |&node| match direction {
193 Direction::Next => node.next_sibling(), 225 Direction::Next => node.next_sibling(),
@@ -195,6 +227,17 @@ impl SyntaxNode {
195 }) 227 })
196 } 228 }
197 229
230 pub fn siblings_with_tokens(
231 &self,
232 direction: Direction,
233 ) -> impl Iterator<Item = SyntaxElement> {
234 let me: SyntaxElement = self.into();
235 crate::algo::generate(Some(me), move |el| match direction {
236 Direction::Next => el.next_sibling_or_token(),
237 Direction::Prev => el.prev_sibling_or_token(),
238 })
239 }
240
198 pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> { 241 pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> {
199 self.0.preorder().map(|event| match event { 242 self.0.preorder().map(|event| match event {
200 WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), 243 WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)),
@@ -202,6 +245,13 @@ impl SyntaxNode {
202 }) 245 })
203 } 246 }
204 247
248 pub fn preorder_with_tokens(&self) -> impl Iterator<Item = WalkEvent<SyntaxElement>> {
249 self.0.preorder_with_tokens().map(|event| match event {
250 WalkEvent::Enter(n) => WalkEvent::Enter(n.into()),
251 WalkEvent::Leave(n) => WalkEvent::Leave(n.into()),
252 })
253 }
254
205 pub fn memory_size_of_subtree(&self) -> usize { 255 pub fn memory_size_of_subtree(&self) -> usize {
206 self.0.memory_size_of_subtree() 256 self.0.memory_size_of_subtree()
207 } 257 }
@@ -223,17 +273,20 @@ impl SyntaxNode {
223 }; 273 };
224 } 274 }
225 275
226 for event in self.preorder() { 276 for event in self.preorder_with_tokens() {
227 match event { 277 match event {
228 WalkEvent::Enter(node) => { 278 WalkEvent::Enter(element) => {
229 indent!(); 279 indent!();
230 writeln!(buf, "{:?}", node).unwrap(); 280 match element {
231 if node.first_child().is_none() { 281 SyntaxElement::Node(node) => writeln!(buf, "{:?}", node).unwrap(),
232 let off = node.range().end(); 282 SyntaxElement::Token(token) => {
233 while err_pos < errors.len() && errors[err_pos].offset() <= off { 283 writeln!(buf, "{:?}", token).unwrap();
234 indent!(); 284 let off = token.range().end();
235 writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); 285 while err_pos < errors.len() && errors[err_pos].offset() <= off {
236 err_pos += 1; 286 indent!();
287 writeln!(buf, "err: `{}`", errors[err_pos]).unwrap();
288 err_pos += 1;
289 }
237 } 290 }
238 } 291 }
239 level += 1; 292 level += 1;
@@ -255,7 +308,172 @@ impl SyntaxNode {
255 } 308 }
256 309
257 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { 310 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
258 self.0.replace_self(replacement) 311 self.0.replace_with(replacement)
312 }
313}
314
315#[derive(Clone, Copy, PartialEq, Eq, Hash)]
316pub struct SyntaxToken<'a>(pub(crate) rowan::SyntaxToken<'a, RaTypes>);
317
318//FIXME: always output text
319impl<'a> fmt::Debug for SyntaxToken<'a> {
320 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
321 write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
322 if has_short_text(self.kind()) {
323 write!(fmt, " \"{}\"", self.text())?;
324 }
325 Ok(())
326 }
327}
328
329impl<'a> fmt::Display for SyntaxToken<'a> {
330 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
331 fmt::Display::fmt(self.text(), fmt)
332 }
333}
334
335impl<'a> From<rowan::SyntaxToken<'a, RaTypes>> for SyntaxToken<'a> {
336 fn from(t: rowan::SyntaxToken<'a, RaTypes>) -> Self {
337 SyntaxToken(t)
338 }
339}
340
341impl<'a> SyntaxToken<'a> {
342 pub fn kind(&self) -> SyntaxKind {
343 self.0.kind()
344 }
345
346 pub fn text(&self) -> &'a SmolStr {
347 self.0.text()
348 }
349
350 pub fn range(&self) -> TextRange {
351 self.0.range()
352 }
353
354 pub fn parent(&self) -> &'a SyntaxNode {
355 SyntaxNode::from_repr(self.0.parent())
356 }
357
358 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> {
359 self.0.next_sibling_or_token().map(SyntaxElement::from)
360 }
361
362 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> {
363 self.0.prev_sibling_or_token().map(SyntaxElement::from)
364 }
365
366 pub fn siblings_with_tokens(
367 &self,
368 direction: Direction,
369 ) -> impl Iterator<Item = SyntaxElement<'a>> {
370 let me: SyntaxElement = (*self).into();
371 crate::algo::generate(Some(me), move |el| match direction {
372 Direction::Next => el.next_sibling_or_token(),
373 Direction::Prev => el.prev_sibling_or_token(),
374 })
375 }
376
377 pub fn next_token(&self) -> Option<SyntaxToken<'a>> {
378 self.0.next_token().map(SyntaxToken::from)
379 }
380
381 pub fn prev_token(&self) -> Option<SyntaxToken<'a>> {
382 self.0.prev_token().map(SyntaxToken::from)
383 }
384
385 pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode {
386 self.0.replace_with(new_token)
387 }
388}
389
390#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
391pub enum SyntaxElement<'a> {
392 Node(&'a SyntaxNode),
393 Token(SyntaxToken<'a>),
394}
395
396impl<'a> fmt::Display for SyntaxElement<'a> {
397 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
398 match self {
399 SyntaxElement::Node(it) => fmt::Display::fmt(it, fmt),
400 SyntaxElement::Token(it) => fmt::Display::fmt(it, fmt),
401 }
402 }
403}
404
405impl<'a> SyntaxElement<'a> {
406 pub fn kind(&self) -> SyntaxKind {
407 match self {
408 SyntaxElement::Node(it) => it.kind(),
409 SyntaxElement::Token(it) => it.kind(),
410 }
411 }
412
413 pub fn as_node(&self) -> Option<&'a SyntaxNode> {
414 match self {
415 SyntaxElement::Node(node) => Some(*node),
416 SyntaxElement::Token(_) => None,
417 }
418 }
419
420 pub fn as_token(&self) -> Option<SyntaxToken<'a>> {
421 match self {
422 SyntaxElement::Node(_) => None,
423 SyntaxElement::Token(token) => Some(*token),
424 }
425 }
426
427 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> {
428 match self {
429 SyntaxElement::Node(it) => it.next_sibling_or_token(),
430 SyntaxElement::Token(it) => it.next_sibling_or_token(),
431 }
432 }
433
434 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> {
435 match self {
436 SyntaxElement::Node(it) => it.prev_sibling_or_token(),
437 SyntaxElement::Token(it) => it.prev_sibling_or_token(),
438 }
439 }
440
441 pub fn ancestors(&self) -> impl Iterator<Item = &'a SyntaxNode> {
442 match self {
443 SyntaxElement::Node(it) => it,
444 SyntaxElement::Token(it) => it.parent(),
445 }
446 .ancestors()
447 }
448}
449
450impl<'a> From<rowan::SyntaxElement<'a, RaTypes>> for SyntaxElement<'a> {
451 fn from(el: rowan::SyntaxElement<'a, RaTypes>) -> Self {
452 match el {
453 rowan::SyntaxElement::Node(n) => SyntaxElement::Node(SyntaxNode::from_repr(n)),
454 rowan::SyntaxElement::Token(t) => SyntaxElement::Token(t.into()),
455 }
456 }
457}
458
459impl<'a> From<&'a SyntaxNode> for SyntaxElement<'a> {
460 fn from(node: &'a SyntaxNode) -> SyntaxElement<'a> {
461 SyntaxElement::Node(node)
462 }
463}
464
465impl<'a> From<SyntaxToken<'a>> for SyntaxElement<'a> {
466 fn from(token: SyntaxToken<'a>) -> SyntaxElement<'a> {
467 SyntaxElement::Token(token)
468 }
469}
470
471impl<'a> SyntaxElement<'a> {
472 pub fn range(&self) -> TextRange {
473 match self {
474 SyntaxElement::Node(it) => it.range(),
475 SyntaxElement::Token(it) => it.range(),
476 }
259 } 477 }
260} 478}
261 479
@@ -270,6 +488,17 @@ impl<'a> Iterator for SyntaxNodeChildren<'a> {
270 } 488 }
271} 489}
272 490
491#[derive(Debug)]
492pub struct SyntaxElementChildren<'a>(rowan::SyntaxElementChildren<'a, RaTypes>);
493
494impl<'a> Iterator for SyntaxElementChildren<'a> {
495 type Item = SyntaxElement<'a>;
496
497 fn next(&mut self) -> Option<SyntaxElement<'a>> {
498 self.0.next().map(SyntaxElement::from)
499 }
500}
501
273fn has_short_text(kind: SyntaxKind) -> bool { 502fn has_short_text(kind: SyntaxKind) -> bool {
274 use crate::SyntaxKind::*; 503 use crate::SyntaxKind::*;
275 match kind { 504 match kind {
@@ -304,16 +533,16 @@ impl SyntaxTreeBuilder {
304 node 533 node
305 } 534 }
306 535
307 pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) { 536 pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) {
308 self.inner.leaf(kind, text) 537 self.inner.token(kind, text)
309 } 538 }
310 539
311 pub fn start_branch(&mut self, kind: SyntaxKind) { 540 pub fn start_node(&mut self, kind: SyntaxKind) {
312 self.inner.start_internal(kind) 541 self.inner.start_node(kind)
313 } 542 }
314 543
315 pub fn finish_branch(&mut self) { 544 pub fn finish_node(&mut self) {
316 self.inner.finish_internal() 545 self.inner.finish_node()
317 } 546 }
318 547
319 pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { 548 pub fn error(&mut self, error: ParseError, text_pos: TextUnit) {
diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs
index 84e5b231a..6bb2ff461 100644
--- a/crates/ra_syntax/src/syntax_text.rs
+++ b/crates/ra_syntax/src/syntax_text.rs
@@ -1,6 +1,6 @@
1use std::{fmt, ops}; 1use std::{fmt, ops};
2 2
3use crate::{SyntaxNode, TextRange, TextUnit}; 3use crate::{SyntaxNode, TextRange, TextUnit, SyntaxElement};
4 4
5#[derive(Clone)] 5#[derive(Clone)]
6pub struct SyntaxText<'a> { 6pub struct SyntaxText<'a> {
@@ -15,11 +15,14 @@ impl<'a> SyntaxText<'a> {
15 15
16 pub fn chunks(&self) -> impl Iterator<Item = &'a str> { 16 pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
17 let range = self.range; 17 let range = self.range;
18 self.node.descendants().filter_map(move |node| { 18 self.node.descendants_with_tokens().filter_map(move |el| match el {
19 let text = node.leaf_text()?; 19 SyntaxElement::Token(t) => {
20 let range = range.intersection(&node.range())?; 20 let text = t.text();
21 let range = range - node.range().start(); 21 let range = range.intersection(&t.range())?;
22 Some(&text[range]) 22 let range = range - t.range().start();
23 Some(&text[range])
24 }
25 SyntaxElement::Node(_) => None,
23 }) 26 })
24 } 27 }
25 28
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 69f344d65..fc534df83 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -6,7 +6,7 @@ mod block;
6 6
7use crate::{ 7use crate::{
8 SourceFile, SyntaxError, AstNode, SyntaxNode, 8 SourceFile, SyntaxError, AstNode, SyntaxNode,
9 SyntaxKind::{L_CURLY, R_CURLY}, 9 SyntaxKind::{L_CURLY, R_CURLY, BYTE, BYTE_STRING, STRING, CHAR},
10 ast, 10 ast,
11 algo::visit::{visitor_ctx, VisitorCtx}, 11 algo::visit::{visitor_ctx, VisitorCtx},
12}; 12};
@@ -15,16 +15,24 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> {
15 let mut errors = Vec::new(); 15 let mut errors = Vec::new();
16 for node in file.syntax().descendants() { 16 for node in file.syntax().descendants() {
17 let _ = visitor_ctx(&mut errors) 17 let _ = visitor_ctx(&mut errors)
18 .visit::<ast::Byte, _>(byte::validate_byte_node) 18 .visit::<ast::Literal, _>(validate_literal)
19 .visit::<ast::ByteString, _>(byte_string::validate_byte_string_node)
20 .visit::<ast::Char, _>(char::validate_char_node)
21 .visit::<ast::String, _>(string::validate_string_node)
22 .visit::<ast::Block, _>(block::validate_block_node) 19 .visit::<ast::Block, _>(block::validate_block_node)
23 .accept(node); 20 .accept(node);
24 } 21 }
25 errors 22 errors
26} 23}
27 24
25// FIXME: kill duplication
26fn validate_literal(literal: &ast::Literal, acc: &mut Vec<SyntaxError>) {
27 match literal.token().kind() {
28 BYTE => byte::validate_byte_node(literal.token(), acc),
29 BYTE_STRING => byte_string::validate_byte_string_node(literal.token(), acc),
30 STRING => string::validate_string_node(literal.token(), acc),
31 CHAR => char::validate_char_node(literal.token(), acc),
32 _ => (),
33 }
34}
35
28pub(crate) fn validate_block_structure(root: &SyntaxNode) { 36pub(crate) fn validate_block_structure(root: &SyntaxNode) {
29 let mut stack = Vec::new(); 37 let mut stack = Vec::new();
30 for node in root.descendants() { 38 for node in root.descendants() {
diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs
index 838e7a65f..290f80fc6 100644
--- a/crates/ra_syntax/src/validation/byte.rs
+++ b/crates/ra_syntax/src/validation/byte.rs
@@ -1,17 +1,17 @@
1//! Validation of byte literals 1//! Validation of byte literals
2 2
3use crate::{ 3use crate::{
4 ast::{self, AstNode, AstToken},
5 string_lexing::{self, StringComponentKind}, 4 string_lexing::{self, StringComponentKind},
6 TextRange, 5 TextRange,
7 validation::char, 6 validation::char,
8 SyntaxError, 7 SyntaxError,
9 SyntaxErrorKind::*, 8 SyntaxErrorKind::*,
9 SyntaxToken,
10}; 10};
11 11
12pub(super) fn validate_byte_node(node: &ast::Byte, errors: &mut Vec<SyntaxError>) { 12pub(super) fn validate_byte_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) {
13 let literal_text = node.text(); 13 let literal_text = node.text();
14 let literal_range = node.syntax().range(); 14 let literal_range = node.range();
15 let mut components = string_lexing::parse_byte_literal(literal_text); 15 let mut components = string_lexing::parse_byte_literal(literal_text);
16 let mut len = 0; 16 let mut len = 0;
17 for component in &mut components { 17 for component in &mut components {
diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs
index 64c7054a1..eae395e9d 100644
--- a/crates/ra_syntax/src/validation/byte_string.rs
+++ b/crates/ra_syntax/src/validation/byte_string.rs
@@ -1,15 +1,15 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken},
3 string_lexing::{self, StringComponentKind}, 2 string_lexing::{self, StringComponentKind},
4 SyntaxError, 3 SyntaxError,
5 SyntaxErrorKind::*, 4 SyntaxErrorKind::*,
5 SyntaxToken,
6}; 6};
7 7
8use super::byte; 8use super::byte;
9 9
10pub(crate) fn validate_byte_string_node(node: &ast::ByteString, errors: &mut Vec<SyntaxError>) { 10pub(crate) fn validate_byte_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) {
11 let literal_text = node.text(); 11 let literal_text = node.text();
12 let literal_range = node.syntax().range(); 12 let literal_range = node.range();
13 let mut components = string_lexing::parse_byte_string_literal(literal_text); 13 let mut components = string_lexing::parse_byte_string_literal(literal_text);
14 for component in &mut components { 14 for component in &mut components {
15 let range = component.range + literal_range.start(); 15 let range = component.range + literal_range.start();
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs
index c874e5d08..a385accdd 100644
--- a/crates/ra_syntax/src/validation/char.rs
+++ b/crates/ra_syntax/src/validation/char.rs
@@ -5,16 +5,16 @@ use std::u32;
5use arrayvec::ArrayString; 5use arrayvec::ArrayString;
6 6
7use crate::{ 7use crate::{
8 ast::{self, AstNode, AstToken},
9 string_lexing::{self, StringComponentKind}, 8 string_lexing::{self, StringComponentKind},
10 TextRange, 9 TextRange,
11 SyntaxError, 10 SyntaxError,
12 SyntaxErrorKind::*, 11 SyntaxErrorKind::*,
12 SyntaxToken,
13}; 13};
14 14
15pub(super) fn validate_char_node(node: &ast::Char, errors: &mut Vec<SyntaxError>) { 15pub(super) fn validate_char_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) {
16 let literal_text = node.text(); 16 let literal_text = node.text();
17 let literal_range = node.syntax().range(); 17 let literal_range = node.range();
18 let mut components = string_lexing::parse_char_literal(literal_text); 18 let mut components = string_lexing::parse_char_literal(literal_text);
19 let mut len = 0; 19 let mut len = 0;
20 for component in &mut components { 20 for component in &mut components {
diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs
index d857d088c..f7f5c02c0 100644
--- a/crates/ra_syntax/src/validation/string.rs
+++ b/crates/ra_syntax/src/validation/string.rs
@@ -1,15 +1,15 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken},
3 string_lexing, 2 string_lexing,
4 SyntaxError, 3 SyntaxError,
5 SyntaxErrorKind::*, 4 SyntaxErrorKind::*,
5 SyntaxToken,
6}; 6};
7 7
8use super::char; 8use super::char;
9 9
10pub(crate) fn validate_string_node(node: &ast::String, errors: &mut Vec<SyntaxError>) { 10pub(crate) fn validate_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) {
11 let literal_text = node.text(); 11 let literal_text = node.text();
12 let literal_range = node.syntax().range(); 12 let literal_range = node.range();
13 let mut components = string_lexing::parse_string_literal(literal_text); 13 let mut components = string_lexing::parse_string_literal(literal_text);
14 for component in &mut components { 14 for component in &mut components {
15 let range = component.range + literal_range.start(); 15 let range = component.range + literal_range.start();