diff options
319 files changed, 13161 insertions, 11728 deletions
diff --git a/Cargo.lock b/Cargo.lock index 669977163..06117ceaf 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1087,8 +1087,8 @@ dependencies = [ | |||
1087 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1087 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1088 | "ra_parser 0.1.0", | 1088 | "ra_parser 0.1.0", |
1089 | "ra_text_edit 0.1.0", | 1089 | "ra_text_edit 0.1.0", |
1090 | "rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | 1090 | "rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1091 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1091 | "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", |
1092 | "test_utils 0.1.0", | 1092 | "test_utils 0.1.0", |
1093 | "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1093 | "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1094 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1094 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -1108,7 +1108,7 @@ dependencies = [ | |||
1108 | name = "ra_tt" | 1108 | name = "ra_tt" |
1109 | version = "0.1.0" | 1109 | version = "0.1.0" |
1110 | dependencies = [ | 1110 | dependencies = [ |
1111 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1111 | "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", |
1112 | ] | 1112 | ] |
1113 | 1113 | ||
1114 | [[package]] | 1114 | [[package]] |
@@ -1308,12 +1308,12 @@ dependencies = [ | |||
1308 | 1308 | ||
1309 | [[package]] | 1309 | [[package]] |
1310 | name = "rowan" | 1310 | name = "rowan" |
1311 | version = "0.3.3" | 1311 | version = "0.4.0" |
1312 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1313 | dependencies = [ | 1313 | dependencies = [ |
1314 | "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1314 | "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", |
1315 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1315 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1316 | "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | 1316 | "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", |
1317 | "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1317 | "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1318 | ] | 1318 | ] |
1319 | 1319 | ||
@@ -1466,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1466 | 1466 | ||
1467 | [[package]] | 1467 | [[package]] |
1468 | name = "smol_str" | 1468 | name = "smol_str" |
1469 | version = "0.1.9" | 1469 | version = "0.1.10" |
1470 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1470 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1471 | dependencies = [ | 1471 | dependencies = [ |
1472 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", | 1472 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -1974,7 +1974,7 @@ dependencies = [ | |||
1974 | "checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" | 1974 | "checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" |
1975 | "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" | 1975 | "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" |
1976 | "checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f" | 1976 | "checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f" |
1977 | "checksum rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74d41f779e2c893339e34bebf035652c58214823cd412550111886c06632f89d" | 1977 | "checksum rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "397cd19c109641f10f3c66433440285e232d8cbd37406cf8f944a15ab1e63a8e" |
1978 | "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" | 1978 | "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" |
1979 | "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" | 1979 | "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" |
1980 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" | 1980 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" |
@@ -1993,7 +1993,7 @@ dependencies = [ | |||
1993 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | 1993 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" |
1994 | "checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" | 1994 | "checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" |
1995 | "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" | 1995 | "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" |
1996 | "checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" | 1996 | "checksum smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d077b3367211e9c6e2e012fb804c444e0d80ab5a51ae4137739b58e6446dcaef" |
1997 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" | 1997 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" |
1998 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" | 1998 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" |
1999 | "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | 1999 | "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. |
35 | fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { | 35 | fn 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 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 3 | use 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..19a2d05bc 100644 --- a/crates/ra_assists/src/add_missing_impl_members.rs +++ b/crates/ra_assists/src/add_missing_impl_members.rs | |||
@@ -1,9 +1,11 @@ | |||
1 | use std::fmt::Write; | ||
2 | |||
1 | use crate::{Assist, AssistId, AssistCtx}; | 3 | use crate::{Assist, AssistId, AssistCtx}; |
2 | 4 | ||
3 | use hir::Resolver; | 5 | use hir::Resolver; |
4 | use hir::db::HirDatabase; | 6 | use hir::db::HirDatabase; |
5 | use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; | 7 | use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; |
6 | use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner}; | 8 | use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner}; |
7 | use ra_db::FilePosition; | 9 | use ra_db::FilePosition; |
8 | use ra_fmt::{leading_indent, reindent}; | 10 | use ra_fmt::{leading_indent, reindent}; |
9 | 11 | ||
@@ -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( | |||
134 | fn build_func_body(def: &ast::FnDef) -> String { | 137 | fn 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..e80e35738 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; | |||
2 | use ra_text_edit::TextEditBuilder; | 2 | use ra_text_edit::TextEditBuilder; |
3 | use ra_db::FileRange; | 3 | use ra_db::FileRange; |
4 | use ra_syntax::{ | 4 | use 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 | }; |
8 | use ra_fmt::{leading_indent, reindent}; | 8 | use ra_fmt::{leading_indent, reindent}; |
9 | 9 | ||
@@ -104,15 +104,19 @@ 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 | } | ||
117 | |||
118 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement<'a> { | ||
119 | find_covering_element(self.source_file.syntax(), range) | ||
116 | } | 120 | } |
117 | } | 121 | } |
118 | 122 | ||
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 | ||
516 | pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 516 | pub(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 | ||
17 | fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 17 | fn 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 | ||
53 | fn vis_offset(node: &SyntaxNode) -> TextUnit { | 53 | fn 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::{ | |||
8 | use crate::{AssistCtx, Assist, AssistId}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(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..950c2910b 100644 --- a/crates/ra_assists/src/inline_local_variable.rs +++ b/crates/ra_assists/src/inline_local_variable.rs | |||
@@ -1,7 +1,11 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::{ |
2 | use hir::source_binder::function_from_child_node; | 2 | db::HirDatabase, |
3 | use ra_syntax::{ast::{self, AstNode}, TextRange}; | 3 | source_binder::function_from_child_node, |
4 | use ra_syntax::ast::{PatKind, ExprKind}; | 4 | }; |
5 | use ra_syntax::{ | ||
6 | ast::{self, AstNode, AstToken, PatKind, ExprKind}, | ||
7 | TextRange, | ||
8 | }; | ||
5 | 9 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 10 | use crate::{Assist, AssistCtx, AssistId}; |
7 | use crate::assist_ctx::AssistBuilder; | 11 | use crate::assist_ctx::AssistBuilder; |
@@ -15,61 +19,77 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
15 | if bind_pat.is_mutable() { | 19 | if bind_pat.is_mutable() { |
16 | return None; | 20 | return None; |
17 | } | 21 | } |
18 | let initializer = let_stmt.initializer()?; | 22 | let initializer_expr = let_stmt.initializer(); |
19 | let wrap_in_parens = match initializer.kind() { | 23 | let delete_range = if let Some(whitespace) = let_stmt |
20 | ExprKind::LambdaExpr(_) | 24 | .syntax() |
21 | | ExprKind::IfExpr(_) | 25 | .next_sibling_or_token() |
22 | | ExprKind::LoopExpr(_) | 26 | .and_then(|it| ast::Whitespace::cast(it.as_token()?)) |
23 | | ExprKind::ForExpr(_) | ||
24 | | ExprKind::WhileExpr(_) | ||
25 | | ExprKind::ContinueExpr(_) | ||
26 | | ExprKind::BreakExpr(_) | ||
27 | | ExprKind::Label(_) | ||
28 | | ExprKind::ReturnExpr(_) | ||
29 | | ExprKind::MatchExpr(_) | ||
30 | | ExprKind::StructLit(_) | ||
31 | | ExprKind::CastExpr(_) | ||
32 | | ExprKind::PrefixExpr(_) | ||
33 | | ExprKind::RangeExpr(_) | ||
34 | | ExprKind::BinExpr(_) => true, | ||
35 | ExprKind::CallExpr(_) | ||
36 | | ExprKind::IndexExpr(_) | ||
37 | | ExprKind::MethodCallExpr(_) | ||
38 | | ExprKind::FieldExpr(_) | ||
39 | | ExprKind::TryExpr(_) | ||
40 | | ExprKind::RefExpr(_) | ||
41 | | ExprKind::Literal(_) | ||
42 | | ExprKind::TupleExpr(_) | ||
43 | | ExprKind::ArrayExpr(_) | ||
44 | | ExprKind::ParenExpr(_) | ||
45 | | ExprKind::PathExpr(_) | ||
46 | | ExprKind::BlockExpr(_) => false, | ||
47 | }; | ||
48 | |||
49 | let delete_range = if let Some(whitespace) = | ||
50 | let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast) | ||
51 | { | 27 | { |
52 | TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) | 28 | TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) |
53 | } else { | 29 | } else { |
54 | let_stmt.syntax().range() | 30 | let_stmt.syntax().range() |
55 | }; | 31 | }; |
56 | 32 | ||
57 | let init_str = if wrap_in_parens { | ||
58 | format!("({})", initializer.syntax().text().to_string()) | ||
59 | } else { | ||
60 | initializer.syntax().text().to_string() | ||
61 | }; | ||
62 | let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; | 33 | let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; |
63 | let scope = function.scopes(ctx.db); | 34 | let scope = function.scopes(ctx.db); |
64 | let refs = scope.find_all_refs(bind_pat); | 35 | let refs = scope.find_all_refs(bind_pat); |
65 | 36 | ||
37 | let mut wrap_in_parens = vec![true; refs.len()]; | ||
38 | |||
39 | for (i, desc) in refs.iter().enumerate() { | ||
40 | let usage_node = ctx | ||
41 | .covering_node_for_range(desc.range) | ||
42 | .ancestors() | ||
43 | .find_map(|node| ast::PathExpr::cast(node))?; | ||
44 | let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); | ||
45 | let usage_parent = match usage_parent_option { | ||
46 | Some(u) => u, | ||
47 | None => { | ||
48 | wrap_in_parens[i] = false; | ||
49 | continue; | ||
50 | } | ||
51 | }; | ||
52 | |||
53 | wrap_in_parens[i] = match (initializer_expr?.kind(), usage_parent.kind()) { | ||
54 | (ExprKind::CallExpr(_), _) | ||
55 | | (ExprKind::IndexExpr(_), _) | ||
56 | | (ExprKind::MethodCallExpr(_), _) | ||
57 | | (ExprKind::FieldExpr(_), _) | ||
58 | | (ExprKind::TryExpr(_), _) | ||
59 | | (ExprKind::RefExpr(_), _) | ||
60 | | (ExprKind::Literal(_), _) | ||
61 | | (ExprKind::TupleExpr(_), _) | ||
62 | | (ExprKind::ArrayExpr(_), _) | ||
63 | | (ExprKind::ParenExpr(_), _) | ||
64 | | (ExprKind::PathExpr(_), _) | ||
65 | | (ExprKind::BlockExpr(_), _) | ||
66 | | (_, ExprKind::CallExpr(_)) | ||
67 | | (_, ExprKind::TupleExpr(_)) | ||
68 | | (_, ExprKind::ArrayExpr(_)) | ||
69 | | (_, ExprKind::ParenExpr(_)) | ||
70 | | (_, ExprKind::ForExpr(_)) | ||
71 | | (_, ExprKind::WhileExpr(_)) | ||
72 | | (_, ExprKind::BreakExpr(_)) | ||
73 | | (_, ExprKind::ReturnExpr(_)) | ||
74 | | (_, ExprKind::MatchExpr(_)) => false, | ||
75 | _ => true, | ||
76 | }; | ||
77 | } | ||
78 | |||
79 | let init_str = initializer_expr?.syntax().text().to_string(); | ||
80 | let init_in_paren = format!("({})", &init_str); | ||
81 | |||
66 | ctx.add_action( | 82 | ctx.add_action( |
67 | AssistId("inline_local_variable"), | 83 | AssistId("inline_local_variable"), |
68 | "inline local variable", | 84 | "inline local variable", |
69 | move |edit: &mut AssistBuilder| { | 85 | move |edit: &mut AssistBuilder| { |
70 | edit.delete(delete_range); | 86 | edit.delete(delete_range); |
71 | for desc in refs { | 87 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { |
72 | edit.replace(desc.range, init_str.clone()) | 88 | if should_wrap { |
89 | edit.replace(desc.range, init_in_paren.clone()) | ||
90 | } else { | ||
91 | edit.replace(desc.range, init_str.clone()) | ||
92 | } | ||
73 | } | 93 | } |
74 | edit.set_cursor(delete_range.start()) | 94 | edit.set_cursor(delete_range.start()) |
75 | }, | 95 | }, |
@@ -147,7 +167,7 @@ fn foo() { | |||
147 | 167 | ||
148 | } | 168 | } |
149 | let b = (1 + 1) * 10; | 169 | let b = (1 + 1) * 10; |
150 | bar((1 + 1)); | 170 | bar(1 + 1); |
151 | }", | 171 | }", |
152 | ); | 172 | ); |
153 | } | 173 | } |
@@ -215,7 +235,7 @@ fn foo() { | |||
215 | 235 | ||
216 | } | 236 | } |
217 | let b = (bar(1) as u64) * 10; | 237 | let b = (bar(1) as u64) * 10; |
218 | bar((bar(1) as u64)); | 238 | bar(bar(1) as u64); |
219 | }", | 239 | }", |
220 | ); | 240 | ); |
221 | } | 241 | } |
@@ -295,4 +315,324 @@ fn foo() { | |||
295 | }", | 315 | }", |
296 | ); | 316 | ); |
297 | } | 317 | } |
318 | |||
319 | #[test] | ||
320 | fn test_call_expr() { | ||
321 | check_assist( | ||
322 | inline_local_varialbe, | ||
323 | " | ||
324 | fn foo() { | ||
325 | let a<|> = bar(10 + 1); | ||
326 | let b = a * 10; | ||
327 | let c = a as usize; | ||
328 | }", | ||
329 | " | ||
330 | fn foo() { | ||
331 | <|>let b = bar(10 + 1) * 10; | ||
332 | let c = bar(10 + 1) as usize; | ||
333 | }", | ||
334 | ); | ||
335 | } | ||
336 | |||
337 | #[test] | ||
338 | fn test_index_expr() { | ||
339 | check_assist( | ||
340 | inline_local_varialbe, | ||
341 | " | ||
342 | fn foo() { | ||
343 | let x = vec![1, 2, 3]; | ||
344 | let a<|> = x[0]; | ||
345 | let b = a * 10; | ||
346 | let c = a as usize; | ||
347 | }", | ||
348 | " | ||
349 | fn foo() { | ||
350 | let x = vec![1, 2, 3]; | ||
351 | <|>let b = x[0] * 10; | ||
352 | let c = x[0] as usize; | ||
353 | }", | ||
354 | ); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
358 | fn test_method_call_expr() { | ||
359 | check_assist( | ||
360 | inline_local_varialbe, | ||
361 | " | ||
362 | fn foo() { | ||
363 | let bar = vec![1]; | ||
364 | let a<|> = bar.len(); | ||
365 | let b = a * 10; | ||
366 | let c = a as usize; | ||
367 | }", | ||
368 | " | ||
369 | fn foo() { | ||
370 | let bar = vec![1]; | ||
371 | <|>let b = bar.len() * 10; | ||
372 | let c = bar.len() as usize; | ||
373 | }", | ||
374 | ); | ||
375 | } | ||
376 | |||
377 | #[test] | ||
378 | fn test_field_expr() { | ||
379 | check_assist( | ||
380 | inline_local_varialbe, | ||
381 | " | ||
382 | struct Bar { | ||
383 | foo: usize | ||
384 | } | ||
385 | |||
386 | fn foo() { | ||
387 | let bar = Bar { foo: 1 }; | ||
388 | let a<|> = bar.foo; | ||
389 | let b = a * 10; | ||
390 | let c = a as usize; | ||
391 | }", | ||
392 | " | ||
393 | struct Bar { | ||
394 | foo: usize | ||
395 | } | ||
396 | |||
397 | fn foo() { | ||
398 | let bar = Bar { foo: 1 }; | ||
399 | <|>let b = bar.foo * 10; | ||
400 | let c = bar.foo as usize; | ||
401 | }", | ||
402 | ); | ||
403 | } | ||
404 | |||
405 | #[test] | ||
406 | fn test_try_expr() { | ||
407 | check_assist( | ||
408 | inline_local_varialbe, | ||
409 | " | ||
410 | fn foo() -> Option<usize> { | ||
411 | let bar = Some(1); | ||
412 | let a<|> = bar?; | ||
413 | let b = a * 10; | ||
414 | let c = a as usize; | ||
415 | None | ||
416 | }", | ||
417 | " | ||
418 | fn foo() -> Option<usize> { | ||
419 | let bar = Some(1); | ||
420 | <|>let b = bar? * 10; | ||
421 | let c = bar? as usize; | ||
422 | None | ||
423 | }", | ||
424 | ); | ||
425 | } | ||
426 | |||
427 | #[test] | ||
428 | fn test_ref_expr() { | ||
429 | check_assist( | ||
430 | inline_local_varialbe, | ||
431 | " | ||
432 | fn foo() { | ||
433 | let bar = 10; | ||
434 | let a<|> = &bar; | ||
435 | let b = a * 10; | ||
436 | }", | ||
437 | " | ||
438 | fn foo() { | ||
439 | let bar = 10; | ||
440 | <|>let b = &bar * 10; | ||
441 | }", | ||
442 | ); | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn test_tuple_expr() { | ||
447 | check_assist( | ||
448 | inline_local_varialbe, | ||
449 | " | ||
450 | fn foo() { | ||
451 | let a<|> = (10, 20); | ||
452 | let b = a[0]; | ||
453 | }", | ||
454 | " | ||
455 | fn foo() { | ||
456 | <|>let b = (10, 20)[0]; | ||
457 | }", | ||
458 | ); | ||
459 | } | ||
460 | |||
461 | #[test] | ||
462 | fn test_array_expr() { | ||
463 | check_assist( | ||
464 | inline_local_varialbe, | ||
465 | " | ||
466 | fn foo() { | ||
467 | let a<|> = [1, 2, 3]; | ||
468 | let b = a.len(); | ||
469 | }", | ||
470 | " | ||
471 | fn foo() { | ||
472 | <|>let b = [1, 2, 3].len(); | ||
473 | }", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
478 | fn test_paren() { | ||
479 | check_assist( | ||
480 | inline_local_varialbe, | ||
481 | " | ||
482 | fn foo() { | ||
483 | let a<|> = (10 + 20); | ||
484 | let b = a * 10; | ||
485 | let c = a as usize; | ||
486 | }", | ||
487 | " | ||
488 | fn foo() { | ||
489 | <|>let b = (10 + 20) * 10; | ||
490 | let c = (10 + 20) as usize; | ||
491 | }", | ||
492 | ); | ||
493 | } | ||
494 | |||
495 | #[test] | ||
496 | fn test_path_expr() { | ||
497 | check_assist( | ||
498 | inline_local_varialbe, | ||
499 | " | ||
500 | fn foo() { | ||
501 | let d = 10; | ||
502 | let a<|> = d; | ||
503 | let b = a * 10; | ||
504 | let c = a as usize; | ||
505 | }", | ||
506 | " | ||
507 | fn foo() { | ||
508 | let d = 10; | ||
509 | <|>let b = d * 10; | ||
510 | let c = d as usize; | ||
511 | }", | ||
512 | ); | ||
513 | } | ||
514 | |||
515 | #[test] | ||
516 | fn test_block_expr() { | ||
517 | check_assist( | ||
518 | inline_local_varialbe, | ||
519 | " | ||
520 | fn foo() { | ||
521 | let a<|> = { 10 }; | ||
522 | let b = a * 10; | ||
523 | let c = a as usize; | ||
524 | }", | ||
525 | " | ||
526 | fn foo() { | ||
527 | <|>let b = { 10 } * 10; | ||
528 | let c = { 10 } as usize; | ||
529 | }", | ||
530 | ); | ||
531 | } | ||
532 | |||
533 | #[test] | ||
534 | fn test_used_in_different_expr1() { | ||
535 | check_assist( | ||
536 | inline_local_varialbe, | ||
537 | " | ||
538 | fn foo() { | ||
539 | let a<|> = 10 + 20; | ||
540 | let b = a * 10; | ||
541 | let c = (a, 20); | ||
542 | let d = [a, 10]; | ||
543 | let e = (a); | ||
544 | }", | ||
545 | " | ||
546 | fn foo() { | ||
547 | <|>let b = (10 + 20) * 10; | ||
548 | let c = (10 + 20, 20); | ||
549 | let d = [10 + 20, 10]; | ||
550 | let e = (10 + 20); | ||
551 | }", | ||
552 | ); | ||
553 | } | ||
554 | |||
555 | #[test] | ||
556 | fn test_used_in_for_expr() { | ||
557 | check_assist( | ||
558 | inline_local_varialbe, | ||
559 | " | ||
560 | fn foo() { | ||
561 | let a<|> = vec![10, 20]; | ||
562 | for i in a {} | ||
563 | }", | ||
564 | " | ||
565 | fn foo() { | ||
566 | <|>for i in vec![10, 20] {} | ||
567 | }", | ||
568 | ); | ||
569 | } | ||
570 | |||
571 | #[test] | ||
572 | fn test_used_in_while_expr() { | ||
573 | check_assist( | ||
574 | inline_local_varialbe, | ||
575 | " | ||
576 | fn foo() { | ||
577 | let a<|> = 1 > 0; | ||
578 | while a {} | ||
579 | }", | ||
580 | " | ||
581 | fn foo() { | ||
582 | <|>while 1 > 0 {} | ||
583 | }", | ||
584 | ); | ||
585 | } | ||
586 | |||
587 | #[test] | ||
588 | fn test_used_in_break_expr() { | ||
589 | check_assist( | ||
590 | inline_local_varialbe, | ||
591 | " | ||
592 | fn foo() { | ||
593 | let a<|> = 1 + 1; | ||
594 | loop { | ||
595 | break a; | ||
596 | } | ||
597 | }", | ||
598 | " | ||
599 | fn foo() { | ||
600 | <|>loop { | ||
601 | break 1 + 1; | ||
602 | } | ||
603 | }", | ||
604 | ); | ||
605 | } | ||
606 | |||
607 | #[test] | ||
608 | fn test_used_in_return_expr() { | ||
609 | check_assist( | ||
610 | inline_local_varialbe, | ||
611 | " | ||
612 | fn foo() { | ||
613 | let a<|> = 1 > 0; | ||
614 | return a; | ||
615 | }", | ||
616 | " | ||
617 | fn foo() { | ||
618 | <|>return 1 > 0; | ||
619 | }", | ||
620 | ); | ||
621 | } | ||
622 | |||
623 | #[test] | ||
624 | fn test_used_in_match_expr() { | ||
625 | check_assist( | ||
626 | inline_local_varialbe, | ||
627 | " | ||
628 | fn foo() { | ||
629 | let a<|> = 1 > 0; | ||
630 | match a {} | ||
631 | }", | ||
632 | " | ||
633 | fn foo() { | ||
634 | <|>match 1 > 0 {} | ||
635 | }", | ||
636 | ); | ||
637 | } | ||
298 | } | 638 | } |
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; | |||
2 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 3 | use 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 | ||
10 | use crate::{AssistCtx, Assist, AssistId}; | 9 | use 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/replace_if_let_with_match.rs b/crates/ra_assists/src/replace_if_let_with_match.rs index 230573499..2b451f08d 100644 --- a/crates/ra_assists/src/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/replace_if_let_with_match.rs | |||
@@ -11,8 +11,8 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> | |||
11 | let expr = cond.expr()?; | 11 | let expr = cond.expr()?; |
12 | let then_block = if_expr.then_branch()?; | 12 | let then_block = if_expr.then_branch()?; |
13 | let else_block = match if_expr.else_branch()? { | 13 | let else_block = match if_expr.else_branch()? { |
14 | ast::ElseBranchFlavor::Block(it) => it, | 14 | ast::ElseBranch::Block(it) => it, |
15 | ast::ElseBranchFlavor::IfExpr(_) => return None, | 15 | ast::ElseBranch::IfExpr(_) => return None, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { | 18 | ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { |
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::{ | |||
8 | use crate::{AssistCtx, Assist, AssistId}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(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 @@ | |||
1 | use std::collections::HashSet; | 1 | use std::{collections::HashSet, time::Instant}; |
2 | 2 | ||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_batch::BatchDatabase; | 4 | use ra_batch::BatchDatabase; |
@@ -8,8 +8,10 @@ use ra_syntax::AstNode; | |||
8 | use crate::Result; | 8 | use crate::Result; |
9 | 9 | ||
10 | pub fn run(verbose: bool) -> Result<()> { | 10 | pub 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 ecea516f1..45555be6e 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -3,10 +3,8 @@ mod analysis_stats; | |||
3 | use std::{fs, io::Read, path::Path}; | 3 | use std::{fs, io::Read, path::Path}; |
4 | 4 | ||
5 | use clap::{App, Arg, SubCommand}; | 5 | use clap::{App, Arg, SubCommand}; |
6 | use join_to_string::join; | ||
7 | use ra_ide_api::{Analysis, FileRange}; | ||
8 | use ra_ide_api::file_structure; | 6 | use ra_ide_api::file_structure; |
9 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; | 7 | use ra_syntax::{SourceFile, TreeArc, AstNode}; |
10 | use tools::collect_tests; | 8 | use tools::collect_tests; |
11 | use flexi_logger::Logger; | 9 | use flexi_logger::Logger; |
12 | use ra_prof::profile; | 10 | use ra_prof::profile; |
@@ -25,11 +23,6 @@ fn main() -> Result<()> { | |||
25 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) | 23 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) |
26 | .subcommand(SubCommand::with_name("symbols")) | 24 | .subcommand(SubCommand::with_name("symbols")) |
27 | .subcommand( | 25 | .subcommand( |
28 | SubCommand::with_name("extend-selection") | ||
29 | .arg(Arg::with_name("start")) | ||
30 | .arg(Arg::with_name("end")), | ||
31 | ) | ||
32 | .subcommand( | ||
33 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), | 26 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), |
34 | ) | 27 | ) |
35 | .get_matches(); | 28 | .get_matches(); |
@@ -56,13 +49,6 @@ fn main() -> Result<()> { | |||
56 | let (test, tree) = render_test(file, line)?; | 49 | let (test, tree) = render_test(file, line)?; |
57 | println!("{}\n{}", test, tree); | 50 | println!("{}\n{}", test, tree); |
58 | } | 51 | } |
59 | ("extend-selection", Some(matches)) => { | ||
60 | let start: u32 = matches.value_of("start").unwrap().parse()?; | ||
61 | let end: u32 = matches.value_of("end").unwrap().parse()?; | ||
62 | let text = read_stdin()?; | ||
63 | let sels = selections(text, start, end); | ||
64 | println!("{}", sels) | ||
65 | } | ||
66 | ("analysis-stats", Some(matches)) => { | 52 | ("analysis-stats", Some(matches)) => { |
67 | let verbose = matches.is_present("verbose"); | 53 | let verbose = matches.is_present("verbose"); |
68 | analysis_stats::run(verbose)?; | 54 | analysis_stats::run(verbose)?; |
@@ -97,22 +83,3 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> { | |||
97 | let tree = file.syntax().debug_dump(); | 83 | let tree = file.syntax().debug_dump(); |
98 | Ok((test.text, tree)) | 84 | Ok((test.text, tree)) |
99 | } | 85 | } |
100 | |||
101 | fn selections(text: String, start: u32, end: u32) -> String { | ||
102 | let (analysis, file_id) = Analysis::from_single_file(text); | ||
103 | let mut ranges = Vec::new(); | ||
104 | let mut range = TextRange::from_to((start - 1).into(), (end - 1).into()); | ||
105 | loop { | ||
106 | ranges.push(range); | ||
107 | let next = analysis.extend_selection(FileRange { file_id, range }).unwrap(); | ||
108 | if range == next { | ||
109 | break; | ||
110 | } | ||
111 | range = next; | ||
112 | } | ||
113 | let ranges = ranges | ||
114 | .iter() | ||
115 | .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end()))) | ||
116 | .map(|(s, e)| format!("({} {})", s, e)); | ||
117 | join(ranges).separator(" ").surround_with("(", ")").to_string() | ||
118 | } | ||
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index 62e6fb9c1..85b7ce250 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs | |||
@@ -2,9 +2,8 @@ | |||
2 | //! | 2 | //! |
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | AstNode, | 5 | SyntaxNode, SyntaxKind::*, SyntaxToken, SyntaxKind, |
6 | SyntaxNode, SyntaxKind::*, | 6 | ast::{self, AstNode, AstToken}, |
7 | ast::{self, AstToken}, | ||
8 | algo::generate, | 7 | algo::generate, |
9 | }; | 8 | }; |
10 | 9 | ||
@@ -15,26 +14,22 @@ pub fn reindent(text: &str, indent: &str) -> String { | |||
15 | 14 | ||
16 | /// If the node is on the beginning of the line, calculate indent. | 15 | /// If the node is on the beginning of the line, calculate indent. |
17 | pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { | 16 | pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { |
18 | for leaf in prev_leaves(node) { | 17 | for token in prev_tokens(node.first_token()?) { |
19 | if let Some(ws) = ast::Whitespace::cast(leaf) { | 18 | if let Some(ws) = ast::Whitespace::cast(token) { |
20 | let ws_text = ws.text(); | 19 | let ws_text = ws.text(); |
21 | if let Some(pos) = ws_text.rfind('\n') { | 20 | if let Some(pos) = ws_text.rfind('\n') { |
22 | return Some(&ws_text[pos + 1..]); | 21 | return Some(&ws_text[pos + 1..]); |
23 | } | 22 | } |
24 | } | 23 | } |
25 | if leaf.leaf_text().unwrap().contains('\n') { | 24 | if token.text().contains('\n') { |
26 | break; | 25 | break; |
27 | } | 26 | } |
28 | } | 27 | } |
29 | None | 28 | None |
30 | } | 29 | } |
31 | 30 | ||
32 | fn prev_leaves(node: &SyntaxNode) -> impl Iterator<Item = &SyntaxNode> { | 31 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { |
33 | generate(prev_leaf(node), |&node| prev_leaf(node)) | 32 | generate(token.prev_token(), |&token| token.prev_token()) |
34 | } | ||
35 | |||
36 | fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> { | ||
37 | generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| it.last_child()).last() | ||
38 | } | 33 | } |
39 | 34 | ||
40 | pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { | 35 | pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { |
@@ -52,20 +47,20 @@ pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { | |||
52 | Some(expr) | 47 | Some(expr) |
53 | } | 48 | } |
54 | 49 | ||
55 | pub fn compute_ws(left: &SyntaxNode, right: &SyntaxNode) -> &'static str { | 50 | pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { |
56 | match left.kind() { | 51 | match left { |
57 | L_PAREN | L_BRACK => return "", | 52 | L_PAREN | L_BRACK => return "", |
58 | L_CURLY => { | 53 | L_CURLY => { |
59 | if let USE_TREE = right.kind() { | 54 | if let USE_TREE = right { |
60 | return ""; | 55 | return ""; |
61 | } | 56 | } |
62 | } | 57 | } |
63 | _ => (), | 58 | _ => (), |
64 | } | 59 | } |
65 | match right.kind() { | 60 | match right { |
66 | R_PAREN | R_BRACK => return "", | 61 | R_PAREN | R_BRACK => return "", |
67 | R_CURLY => { | 62 | R_CURLY => { |
68 | if let USE_TREE = left.kind() { | 63 | if let USE_TREE = left { |
69 | return ""; | 64 | return ""; |
70 | } | 65 | } |
71 | } | 66 | } |
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 78ea8976b..e027eedd9 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs | |||
@@ -6,7 +6,7 @@ use std::sync::Arc; | |||
6 | use ra_arena::{RawId, Arena, impl_arena_id}; | 6 | use ra_arena::{RawId, Arena, impl_arena_id}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | TreeArc, | 8 | TreeArc, |
9 | ast::{self, NameOwner, StructFlavor, TypeAscriptionOwner} | 9 | ast::{self, NameOwner, StructKind, TypeAscriptionOwner} |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -47,7 +47,7 @@ pub struct StructData { | |||
47 | impl StructData { | 47 | impl StructData { |
48 | fn new(struct_def: &ast::StructDef) -> StructData { | 48 | fn new(struct_def: &ast::StructDef) -> StructData { |
49 | let name = struct_def.name().map(|n| n.as_name()); | 49 | let name = struct_def.name().map(|n| n.as_name()); |
50 | let variant_data = VariantData::new(struct_def.flavor()); | 50 | let variant_data = VariantData::new(struct_def.kind()); |
51 | let variant_data = Arc::new(variant_data); | 51 | let variant_data = Arc::new(variant_data); |
52 | StructData { name, variant_data } | 52 | StructData { name, variant_data } |
53 | } | 53 | } |
@@ -94,7 +94,7 @@ impl EnumData { | |||
94 | let variants = variants(&*enum_def) | 94 | let variants = variants(&*enum_def) |
95 | .map(|var| EnumVariantData { | 95 | .map(|var| EnumVariantData { |
96 | name: var.name().map(|it| it.as_name()), | 96 | name: var.name().map(|it| it.as_name()), |
97 | variant_data: Arc::new(VariantData::new(var.flavor())), | 97 | variant_data: Arc::new(VariantData::new(var.kind())), |
98 | }) | 98 | }) |
99 | .collect(); | 99 | .collect(); |
100 | Arc::new(EnumData { name, variants }) | 100 | Arc::new(EnumData { name, variants }) |
@@ -143,9 +143,9 @@ impl VariantData { | |||
143 | } | 143 | } |
144 | 144 | ||
145 | impl VariantData { | 145 | impl VariantData { |
146 | fn new(flavor: StructFlavor) -> Self { | 146 | fn new(flavor: StructKind) -> Self { |
147 | let inner = match flavor { | 147 | let inner = match flavor { |
148 | ast::StructFlavor::Tuple(fl) => { | 148 | ast::StructKind::Tuple(fl) => { |
149 | let fields = fl | 149 | let fields = fl |
150 | .fields() | 150 | .fields() |
151 | .enumerate() | 151 | .enumerate() |
@@ -156,7 +156,7 @@ impl VariantData { | |||
156 | .collect(); | 156 | .collect(); |
157 | VariantDataInner::Tuple(fields) | 157 | VariantDataInner::Tuple(fields) |
158 | } | 158 | } |
159 | ast::StructFlavor::Named(fl) => { | 159 | ast::StructKind::Named(fl) => { |
160 | let fields = fl | 160 | let fields = fl |
161 | .fields() | 161 | .fields() |
162 | .map(|fd| StructFieldData { | 162 | .map(|fd| StructFieldData { |
@@ -166,7 +166,7 @@ impl VariantData { | |||
166 | .collect(); | 166 | .collect(); |
167 | VariantDataInner::Struct(fields) | 167 | VariantDataInner::Struct(fields) |
168 | } | 168 | } |
169 | ast::StructFlavor::Unit => VariantDataInner::Unit, | 169 | ast::StructKind::Unit => VariantDataInner::Unit, |
170 | }; | 170 | }; |
171 | VariantData(inner) | 171 | VariantData(inner) |
172 | } | 172 | } |
@@ -200,27 +200,27 @@ impl StructField { | |||
200 | let fields = var_data.fields().unwrap(); | 200 | let fields = var_data.fields().unwrap(); |
201 | let ss; | 201 | let ss; |
202 | let es; | 202 | let es; |
203 | let (file_id, struct_flavor) = match self.parent { | 203 | let (file_id, struct_kind) = match self.parent { |
204 | VariantDef::Struct(s) => { | 204 | VariantDef::Struct(s) => { |
205 | let (file_id, source) = s.source(db); | 205 | let (file_id, source) = s.source(db); |
206 | ss = source; | 206 | ss = source; |
207 | (file_id, ss.flavor()) | 207 | (file_id, ss.kind()) |
208 | } | 208 | } |
209 | VariantDef::EnumVariant(e) => { | 209 | VariantDef::EnumVariant(e) => { |
210 | let (file_id, source) = e.source(db); | 210 | let (file_id, source) = e.source(db); |
211 | es = source; | 211 | es = source; |
212 | (file_id, es.flavor()) | 212 | (file_id, es.kind()) |
213 | } | 213 | } |
214 | }; | 214 | }; |
215 | 215 | ||
216 | let field_sources = match struct_flavor { | 216 | let field_sources = match struct_kind { |
217 | ast::StructFlavor::Tuple(fl) => { | 217 | ast::StructKind::Tuple(fl) => { |
218 | fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect() | 218 | fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect() |
219 | } | 219 | } |
220 | ast::StructFlavor::Named(fl) => { | 220 | ast::StructKind::Named(fl) => { |
221 | fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect() | 221 | fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect() |
222 | } | 222 | } |
223 | ast::StructFlavor::Unit => Vec::new(), | 223 | ast::StructKind::Unit => Vec::new(), |
224 | }; | 224 | }; |
225 | let field = field_sources | 225 | let field = field_sources |
226 | .into_iter() | 226 | .into_iter() |
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 624c25c4d..9e6170440 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -4,7 +4,7 @@ use ra_db::{CrateId, SourceRootId, Edition}; | |||
4 | use ra_syntax::{ast::self, TreeArc}; | 4 | use ra_syntax::{ast::self, TreeArc}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | Name, ScopesWithSourceMap, Ty, HirFileId, | 7 | Name, ScopesWithSourceMap, Ty, HirFileId, ImportSource, |
8 | HirDatabase, DefDatabase, | 8 | HirDatabase, DefDatabase, |
9 | type_ref::TypeRef, | 9 | type_ref::TypeRef, |
10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, | 10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, |
@@ -117,11 +117,7 @@ impl Module { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | /// Returns the syntax of the last path segment corresponding to this import | 119 | /// Returns the syntax of the last path segment corresponding to this import |
120 | pub fn import_source( | 120 | pub fn import_source(&self, db: &impl HirDatabase, import: ImportId) -> ImportSource { |
121 | &self, | ||
122 | db: &impl HirDatabase, | ||
123 | import: ImportId, | ||
124 | ) -> TreeArc<ast::PathSegment> { | ||
125 | self.import_source_impl(db, import) | 121 | self.import_source_impl(db, import) |
126 | } | 122 | } |
127 | 123 | ||
@@ -433,6 +429,45 @@ impl Docs for EnumVariant { | |||
433 | } | 429 | } |
434 | } | 430 | } |
435 | 431 | ||
432 | /// The defs which have a body. | ||
433 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
434 | pub enum DefWithBody { | ||
435 | Function(Function), | ||
436 | Const(Const), | ||
437 | Static(Static), | ||
438 | } | ||
439 | |||
440 | impl_froms!(DefWithBody: Function, Const, Static); | ||
441 | |||
442 | impl DefWithBody { | ||
443 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
444 | db.infer(*self) | ||
445 | } | ||
446 | |||
447 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
448 | db.body_with_source_map(*self).1 | ||
449 | } | ||
450 | |||
451 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | ||
452 | db.body_hir(*self) | ||
453 | } | ||
454 | |||
455 | /// Builds a resolver for code inside this item. | ||
456 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
457 | match *self { | ||
458 | DefWithBody::Const(ref c) => c.resolver(db), | ||
459 | DefWithBody::Function(ref f) => f.resolver(db), | ||
460 | DefWithBody::Static(ref s) => s.resolver(db), | ||
461 | } | ||
462 | } | ||
463 | |||
464 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
465 | let scopes = db.expr_scopes(*self); | ||
466 | let source_map = db.body_with_source_map(*self).1; | ||
467 | ScopesWithSourceMap { scopes, source_map } | ||
468 | } | ||
469 | } | ||
470 | |||
436 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 471 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
437 | pub struct Function { | 472 | pub struct Function { |
438 | pub(crate) id: FunctionId, | 473 | pub(crate) id: FunctionId, |
@@ -483,11 +518,11 @@ impl Function { | |||
483 | } | 518 | } |
484 | 519 | ||
485 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 520 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
486 | db.body_with_source_map(*self).1 | 521 | db.body_with_source_map((*self).into()).1 |
487 | } | 522 | } |
488 | 523 | ||
489 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | 524 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { |
490 | db.body_hir(*self) | 525 | db.body_hir((*self).into()) |
491 | } | 526 | } |
492 | 527 | ||
493 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 528 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
@@ -495,8 +530,8 @@ impl Function { | |||
495 | } | 530 | } |
496 | 531 | ||
497 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | 532 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { |
498 | let scopes = db.expr_scopes(*self); | 533 | let scopes = db.expr_scopes((*self).into()); |
499 | let source_map = db.body_with_source_map(*self).1; | 534 | let source_map = db.body_with_source_map((*self).into()).1; |
500 | ScopesWithSourceMap { scopes, source_map } | 535 | ScopesWithSourceMap { scopes, source_map } |
501 | } | 536 | } |
502 | 537 | ||
@@ -505,7 +540,7 @@ impl Function { | |||
505 | } | 540 | } |
506 | 541 | ||
507 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 542 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
508 | db.infer(*self) | 543 | db.infer((*self).into()) |
509 | } | 544 | } |
510 | 545 | ||
511 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | 546 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { |
@@ -561,6 +596,14 @@ impl Const { | |||
561 | db.const_signature(*self) | 596 | db.const_signature(*self) |
562 | } | 597 | } |
563 | 598 | ||
599 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
600 | db.infer((*self).into()) | ||
601 | } | ||
602 | |||
603 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
604 | db.body_with_source_map((*self).into()).1 | ||
605 | } | ||
606 | |||
564 | /// The containing impl block, if this is a method. | 607 | /// The containing impl block, if this is a method. |
565 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { | 608 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { |
566 | let module_impls = db.impls_in_module(self.module(db)); | 609 | let module_impls = db.impls_in_module(self.module(db)); |
@@ -625,6 +668,14 @@ impl Static { | |||
625 | // take the outer scope... | 668 | // take the outer scope... |
626 | self.module(db).resolver(db) | 669 | self.module(db).resolver(db) |
627 | } | 670 | } |
671 | |||
672 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
673 | db.infer((*self).into()) | ||
674 | } | ||
675 | |||
676 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
677 | db.body_with_source_map((*self).into()).1 | ||
678 | } | ||
628 | } | 679 | } |
629 | 680 | ||
630 | impl Docs for Static { | 681 | impl Docs for Static { |
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs index 334cb302b..f8bd0f784 100644 --- a/crates/ra_hir/src/code_model_impl/function.rs +++ b/crates/ra_hir/src/code_model_impl/function.rs | |||
@@ -20,12 +20,12 @@ impl FnSignature { | |||
20 | TypeRef::from_ast(type_ref) | 20 | TypeRef::from_ast(type_ref) |
21 | } else { | 21 | } else { |
22 | let self_type = TypeRef::Path(Name::self_type().into()); | 22 | let self_type = TypeRef::Path(Name::self_type().into()); |
23 | match self_param.flavor() { | 23 | match self_param.kind() { |
24 | ast::SelfParamFlavor::Owned => self_type, | 24 | ast::SelfParamKind::Owned => self_type, |
25 | ast::SelfParamFlavor::Ref => { | 25 | ast::SelfParamKind::Ref => { |
26 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | 26 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) |
27 | } | 27 | } |
28 | ast::SelfParamFlavor::MutRef => { | 28 | ast::SelfParamKind::MutRef => { |
29 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | 29 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) |
30 | } | 30 | } |
31 | } | 31 | } |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 0edb8ade5..88dee3a69 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -5,7 +5,7 @@ use crate::{ | |||
5 | Module, ModuleSource, Name, AstId, | 5 | Module, ModuleSource, Name, AstId, |
6 | nameres::{CrateModuleId, ImportId}, | 6 | nameres::{CrateModuleId, ImportId}, |
7 | HirDatabase, DefDatabase, | 7 | HirDatabase, DefDatabase, |
8 | HirFileId, | 8 | HirFileId, ImportSource, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | impl ModuleSource { | 11 | impl ModuleSource { |
@@ -72,7 +72,7 @@ impl Module { | |||
72 | &self, | 72 | &self, |
73 | db: &impl HirDatabase, | 73 | db: &impl HirDatabase, |
74 | import: ImportId, | 74 | import: ImportId, |
75 | ) -> TreeArc<ast::PathSegment> { | 75 | ) -> ImportSource { |
76 | let (file_id, source) = self.definition_source(db); | 76 | let (file_id, source) = self.definition_source(db); |
77 | let (_, source_map) = db.raw_items_with_source_map(file_id); | 77 | let (_, source_map) = db.raw_items_with_source_map(file_id); |
78 | source_map.get(&source, import) | 78 | source_map.get(&source, import) |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 147005848..be8a8c98b 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -8,6 +8,7 @@ use crate::{ | |||
8 | Function, FnSignature, ExprScopes, TypeAlias, | 8 | Function, FnSignature, ExprScopes, TypeAlias, |
9 | Struct, Enum, StructField, | 9 | Struct, Enum, StructField, |
10 | Const, ConstSignature, Static, | 10 | Const, ConstSignature, Static, |
11 | DefWithBody, | ||
11 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, | 12 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, |
12 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, | 13 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, |
13 | adt::{StructData, EnumData}, | 14 | adt::{StructData, EnumData}, |
@@ -83,10 +84,10 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | |||
83 | #[salsa::query_group(HirDatabaseStorage)] | 84 | #[salsa::query_group(HirDatabaseStorage)] |
84 | pub trait HirDatabase: DefDatabase { | 85 | pub trait HirDatabase: DefDatabase { |
85 | #[salsa::invoke(ExprScopes::expr_scopes_query)] | 86 | #[salsa::invoke(ExprScopes::expr_scopes_query)] |
86 | fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>; | 87 | fn expr_scopes(&self, def: DefWithBody) -> Arc<ExprScopes>; |
87 | 88 | ||
88 | #[salsa::invoke(crate::ty::infer)] | 89 | #[salsa::invoke(crate::ty::infer)] |
89 | fn infer(&self, func: Function) -> Arc<InferenceResult>; | 90 | fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; |
90 | 91 | ||
91 | #[salsa::invoke(crate::ty::type_for_def)] | 92 | #[salsa::invoke(crate::ty::type_for_def)] |
92 | fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; | 93 | fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; |
@@ -100,11 +101,11 @@ pub trait HirDatabase: DefDatabase { | |||
100 | #[salsa::invoke(crate::expr::body_with_source_map_query)] | 101 | #[salsa::invoke(crate::expr::body_with_source_map_query)] |
101 | fn body_with_source_map( | 102 | fn body_with_source_map( |
102 | &self, | 103 | &self, |
103 | func: Function, | 104 | def: DefWithBody, |
104 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); | 105 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); |
105 | 106 | ||
106 | #[salsa::invoke(crate::expr::body_hir_query)] | 107 | #[salsa::invoke(crate::expr::body_hir_query)] |
107 | fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>; | 108 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; |
108 | 109 | ||
109 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 110 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
110 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 111 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index a85422955..b2a237ece 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -6,11 +6,11 @@ use rustc_hash::FxHashMap; | |||
6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | SyntaxNodePtr, AstPtr, AstNode, | 8 | SyntaxNodePtr, AstPtr, AstNode, |
9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner} | 9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind, TypeAscriptionOwner} |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, HirDatabase, Function, Resolver, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, |
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
@@ -27,9 +27,8 @@ impl_arena_id!(ExprId); | |||
27 | /// The body of an item (function, const etc.). | 27 | /// The body of an item (function, const etc.). |
28 | #[derive(Debug, Eq, PartialEq)] | 28 | #[derive(Debug, Eq, PartialEq)] |
29 | pub struct Body { | 29 | pub struct Body { |
30 | // FIXME: this should be more general, consts & statics also have bodies | 30 | /// The def of the item this body belongs to |
31 | /// The Function of the item this body belongs to | 31 | owner: DefWithBody, |
32 | owner: Function, | ||
33 | exprs: Arena<ExprId, Expr>, | 32 | exprs: Arena<ExprId, Expr>, |
34 | pats: Arena<PatId, Pat>, | 33 | pats: Arena<PatId, Pat>, |
35 | /// The patterns for the function's parameters. While the parameter types are | 34 | /// The patterns for the function's parameters. While the parameter types are |
@@ -66,7 +65,7 @@ impl Body { | |||
66 | self.body_expr | 65 | self.body_expr |
67 | } | 66 | } |
68 | 67 | ||
69 | pub fn owner(&self) -> Function { | 68 | pub fn owner(&self) -> DefWithBody { |
70 | self.owner | 69 | self.owner |
71 | } | 70 | } |
72 | 71 | ||
@@ -463,8 +462,8 @@ impl Pat { | |||
463 | 462 | ||
464 | // Queries | 463 | // Queries |
465 | 464 | ||
466 | struct ExprCollector { | 465 | pub(crate) struct ExprCollector { |
467 | owner: Function, | 466 | owner: DefWithBody, |
468 | exprs: Arena<ExprId, Expr>, | 467 | exprs: Arena<ExprId, Expr>, |
469 | pats: Arena<PatId, Pat>, | 468 | pats: Arena<PatId, Pat>, |
470 | source_map: BodySourceMap, | 469 | source_map: BodySourceMap, |
@@ -473,7 +472,7 @@ struct ExprCollector { | |||
473 | } | 472 | } |
474 | 473 | ||
475 | impl ExprCollector { | 474 | impl ExprCollector { |
476 | fn new(owner: Function) -> Self { | 475 | fn new(owner: DefWithBody) -> Self { |
477 | ExprCollector { | 476 | ExprCollector { |
478 | owner, | 477 | owner, |
479 | exprs: Arena::default(), | 478 | exprs: Arena::default(), |
@@ -516,8 +515,8 @@ impl ExprCollector { | |||
516 | let else_branch = e | 515 | let else_branch = e |
517 | .else_branch() | 516 | .else_branch() |
518 | .map(|b| match b { | 517 | .map(|b| match b { |
519 | ast::ElseBranchFlavor::Block(it) => self.collect_block(it), | 518 | ast::ElseBranch::Block(it) => self.collect_block(it), |
520 | ast::ElseBranchFlavor::IfExpr(elif) => { | 519 | ast::ElseBranch::IfExpr(elif) => { |
521 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); | 520 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); |
522 | self.collect_expr(expr) | 521 | self.collect_expr(expr) |
523 | } | 522 | } |
@@ -533,8 +532,8 @@ impl ExprCollector { | |||
533 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); | 532 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); |
534 | let then_branch = self.collect_block_opt(e.then_branch()); | 533 | let then_branch = self.collect_block_opt(e.then_branch()); |
535 | let else_branch = e.else_branch().map(|b| match b { | 534 | let else_branch = e.else_branch().map(|b| match b { |
536 | ast::ElseBranchFlavor::Block(it) => self.collect_block(it), | 535 | ast::ElseBranch::Block(it) => self.collect_block(it), |
537 | ast::ElseBranchFlavor::IfExpr(elif) => { | 536 | ast::ElseBranch::IfExpr(elif) => { |
538 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); | 537 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); |
539 | self.collect_expr(expr) | 538 | self.collect_expr(expr) |
540 | } | 539 | } |
@@ -726,14 +725,8 @@ impl ExprCollector { | |||
726 | self.alloc_expr(Expr::Array { exprs }, syntax_ptr) | 725 | self.alloc_expr(Expr::Array { exprs }, syntax_ptr) |
727 | } | 726 | } |
728 | ast::ExprKind::Literal(e) => { | 727 | ast::ExprKind::Literal(e) => { |
729 | let child = if let Some(child) = e.literal_expr() { | 728 | let lit = match e.kind() { |
730 | child | 729 | LiteralKind::IntNumber { suffix } => { |
731 | } else { | ||
732 | return self.alloc_expr(Expr::Missing, syntax_ptr); | ||
733 | }; | ||
734 | |||
735 | let lit = match child.flavor() { | ||
736 | LiteralFlavor::IntNumber { suffix } => { | ||
737 | let known_name = suffix | 730 | let known_name = suffix |
738 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); | 731 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); |
739 | 732 | ||
@@ -742,7 +735,7 @@ impl ExprCollector { | |||
742 | known_name.unwrap_or(UncertainIntTy::Unknown), | 735 | known_name.unwrap_or(UncertainIntTy::Unknown), |
743 | ) | 736 | ) |
744 | } | 737 | } |
745 | LiteralFlavor::FloatNumber { suffix } => { | 738 | LiteralKind::FloatNumber { suffix } => { |
746 | let known_name = suffix | 739 | let known_name = suffix |
747 | .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); | 740 | .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); |
748 | 741 | ||
@@ -751,13 +744,13 @@ impl ExprCollector { | |||
751 | known_name.unwrap_or(UncertainFloatTy::Unknown), | 744 | known_name.unwrap_or(UncertainFloatTy::Unknown), |
752 | ) | 745 | ) |
753 | } | 746 | } |
754 | LiteralFlavor::ByteString => Literal::ByteString(Default::default()), | 747 | LiteralKind::ByteString => Literal::ByteString(Default::default()), |
755 | LiteralFlavor::String => Literal::String(Default::default()), | 748 | LiteralKind::String => Literal::String(Default::default()), |
756 | LiteralFlavor::Byte => { | 749 | LiteralKind::Byte => { |
757 | Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) | 750 | Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) |
758 | } | 751 | } |
759 | LiteralFlavor::Bool => Literal::Bool(Default::default()), | 752 | LiteralKind::Bool => Literal::Bool(Default::default()), |
760 | LiteralFlavor::Char => Literal::Char(Default::default()), | 753 | LiteralKind::Char => Literal::Char(Default::default()), |
761 | }; | 754 | }; |
762 | self.alloc_expr(Expr::Literal(lit), syntax_ptr) | 755 | self.alloc_expr(Expr::Literal(lit), syntax_ptr) |
763 | } | 756 | } |
@@ -766,6 +759,7 @@ impl ExprCollector { | |||
766 | ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 759 | ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
767 | ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 760 | ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
768 | ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 761 | ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
762 | ast::ExprKind::MacroCall(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
769 | } | 763 | } |
770 | } | 764 | } |
771 | 765 | ||
@@ -871,12 +865,20 @@ impl ExprCollector { | |||
871 | } | 865 | } |
872 | } | 866 | } |
873 | 867 | ||
868 | fn collect_const_body(&mut self, node: &ast::ConstDef) { | ||
869 | let body = self.collect_expr_opt(node.body()); | ||
870 | self.body_expr = Some(body); | ||
871 | } | ||
872 | |||
873 | fn collect_static_body(&mut self, node: &ast::StaticDef) { | ||
874 | let body = self.collect_expr_opt(node.body()); | ||
875 | self.body_expr = Some(body); | ||
876 | } | ||
877 | |||
874 | fn collect_fn_body(&mut self, node: &ast::FnDef) { | 878 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
875 | if let Some(param_list) = node.param_list() { | 879 | if let Some(param_list) = node.param_list() { |
876 | if let Some(self_param) = param_list.self_param() { | 880 | if let Some(self_param) = param_list.self_param() { |
877 | let self_param = SyntaxNodePtr::new( | 881 | 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( | 882 | let param_pat = self.alloc_pat( |
881 | Pat::Bind { | 883 | Pat::Bind { |
882 | name: Name::self_param(), | 884 | name: Name::self_param(), |
@@ -917,24 +919,20 @@ impl ExprCollector { | |||
917 | 919 | ||
918 | pub(crate) fn body_with_source_map_query( | 920 | pub(crate) fn body_with_source_map_query( |
919 | db: &impl HirDatabase, | 921 | db: &impl HirDatabase, |
920 | func: Function, | 922 | def: DefWithBody, |
921 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | 923 | ) -> (Arc<Body>, Arc<BodySourceMap>) { |
922 | let mut collector = ExprCollector::new(func); | 924 | let mut collector = ExprCollector::new(def); |
923 | 925 | ||
924 | // FIXME: consts, etc. | 926 | match def { |
925 | collector.collect_fn_body(&func.source(db).1); | 927 | DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1), |
928 | DefWithBody::Function(ref f) => collector.collect_fn_body(&f.source(db).1), | ||
929 | DefWithBody::Static(ref s) => collector.collect_static_body(&s.source(db).1), | ||
930 | } | ||
926 | 931 | ||
927 | let (body, source_map) = collector.finish(); | 932 | let (body, source_map) = collector.finish(); |
928 | (Arc::new(body), Arc::new(source_map)) | 933 | (Arc::new(body), Arc::new(source_map)) |
929 | } | 934 | } |
930 | 935 | ||
931 | pub(crate) fn body_hir_query(db: &impl HirDatabase, func: Function) -> Arc<Body> { | 936 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { |
932 | db.body_with_source_map(func).0 | 937 | db.body_with_source_map(def).0 |
933 | } | ||
934 | |||
935 | #[cfg(test)] | ||
936 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
937 | let mut collector = ExprCollector::new(function); | ||
938 | collector.collect_fn_body(node); | ||
939 | collector.finish() | ||
940 | } | 938 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index ed005c9f7..48283907b 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | use ra_arena::{Arena, RawId, impl_arena_id}; | 10 | use ra_arena::{Arena, RawId, impl_arena_id}; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Name, AsName, Function, | 13 | Name, AsName,DefWithBody, |
14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, | 14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, |
15 | HirDatabase, | 15 | HirDatabase, |
16 | }; | 16 | }; |
@@ -40,8 +40,8 @@ pub struct ScopeData { | |||
40 | 40 | ||
41 | impl ExprScopes { | 41 | impl ExprScopes { |
42 | // FIXME: This should take something more general than Function | 42 | // FIXME: This should take something more general than Function |
43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, function: Function) -> Arc<ExprScopes> { | 43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { |
44 | let body = db.body_hir(function); | 44 | let body = db.body_hir(def); |
45 | let res = ExprScopes::new(body); | 45 | let res = ExprScopes::new(body); |
46 | Arc::new(res) | 46 | Arc::new(res) |
47 | } | 47 | } |
@@ -297,8 +297,9 @@ mod tests { | |||
297 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; | 297 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; |
298 | use test_utils::{extract_offset, assert_eq_text}; | 298 | use test_utils::{extract_offset, assert_eq_text}; |
299 | use ra_arena::ArenaId; | 299 | use ra_arena::ArenaId; |
300 | use crate::Function; | ||
300 | 301 | ||
301 | use crate::expr; | 302 | use crate::expr::{ExprCollector}; |
302 | 303 | ||
303 | use super::*; | 304 | use super::*; |
304 | 305 | ||
@@ -316,7 +317,7 @@ mod tests { | |||
316 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 317 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
317 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 318 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
318 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 319 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; |
319 | let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | 320 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); |
320 | let scopes = ExprScopes::new(Arc::new(body)); | 321 | let scopes = ExprScopes::new(Arc::new(body)); |
321 | let scopes = | 322 | let scopes = |
322 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 323 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; |
@@ -405,6 +406,12 @@ mod tests { | |||
405 | ); | 406 | ); |
406 | } | 407 | } |
407 | 408 | ||
409 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
410 | let mut collector = ExprCollector::new(DefWithBody::Function(function)); | ||
411 | collector.collect_fn_body(node); | ||
412 | collector.finish() | ||
413 | } | ||
414 | |||
408 | fn do_check_local_name(code: &str, expected_offset: u32) { | 415 | fn do_check_local_name(code: &str, expected_offset: u32) { |
409 | let (off, code) = extract_offset(code); | 416 | let (off, code) = extract_offset(code); |
410 | let file = SourceFile::parse(&code); | 417 | let file = SourceFile::parse(&code); |
@@ -415,7 +422,7 @@ mod tests { | |||
415 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 422 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
416 | 423 | ||
417 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 424 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; |
418 | let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | 425 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); |
419 | let scopes = ExprScopes::new(Arc::new(body)); | 426 | let scopes = ExprScopes::new(Arc::new(body)); |
420 | let scopes = | 427 | let scopes = |
421 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 428 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 7c603bbd3..c19450f39 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -56,7 +56,7 @@ pub use self::{ | |||
56 | name::Name, | 56 | name::Name, |
57 | source_id::{AstIdMap, ErasedFileAstId}, | 57 | source_id::{AstIdMap, ErasedFileAstId}, |
58 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, | 58 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, |
59 | nameres::{PerNs, Namespace}, | 59 | nameres::{PerNs, Namespace, ImportId, ImportSource}, |
60 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, | 60 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, |
61 | impl_block::{ImplBlock, ImplItem}, | 61 | impl_block::{ImplBlock, ImplItem}, |
62 | docs::{Docs, Documentation}, | 62 | docs::{Docs, Documentation}, |
@@ -67,6 +67,7 @@ pub use self::{ | |||
67 | 67 | ||
68 | pub use self::code_model_api::{ | 68 | pub use self::code_model_api::{ |
69 | Crate, CrateDependency, | 69 | Crate, CrateDependency, |
70 | DefWithBody, | ||
70 | Module, ModuleDef, ModuleSource, | 71 | Module, ModuleDef, ModuleSource, |
71 | Struct, Enum, EnumVariant, | 72 | Struct, Enum, EnumVariant, |
72 | Function, FnSignature, | 73 | Function, FnSignature, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 8adc6d368..4ae04514a 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -71,9 +71,12 @@ use crate::{ | |||
71 | AstId, | 71 | AstId, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; | 74 | pub(crate) use self::raw::{RawItems, ImportSourceMap}; |
75 | 75 | ||
76 | pub use self::per_ns::{PerNs, Namespace}; | 76 | pub use self::{ |
77 | per_ns::{PerNs, Namespace}, | ||
78 | raw::{ImportId, ImportSource}, | ||
79 | }; | ||
77 | 80 | ||
78 | /// Contans all top-level defs from a macro-expanded crate | 81 | /// Contans all top-level defs from a macro-expanded crate |
79 | #[derive(Debug, PartialEq, Eq)] | 82 | #[derive(Debug, PartialEq, Eq)] |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 0936229ac..b7416ede6 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -31,21 +31,43 @@ pub struct RawItems { | |||
31 | 31 | ||
32 | #[derive(Debug, Default, PartialEq, Eq)] | 32 | #[derive(Debug, Default, PartialEq, Eq)] |
33 | pub struct ImportSourceMap { | 33 | pub struct ImportSourceMap { |
34 | map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>, | 34 | map: ArenaMap<ImportId, ImportSourcePtr>, |
35 | } | ||
36 | |||
37 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
38 | enum ImportSourcePtr { | ||
39 | UseTree(AstPtr<ast::UseTree>), | ||
40 | ExternCrate(AstPtr<ast::ExternCrateItem>), | ||
41 | } | ||
42 | |||
43 | impl ImportSourcePtr { | ||
44 | fn to_node(self, file: &SourceFile) -> ImportSource { | ||
45 | match self { | ||
46 | ImportSourcePtr::UseTree(ptr) => ImportSource::UseTree(ptr.to_node(file).to_owned()), | ||
47 | ImportSourcePtr::ExternCrate(ptr) => { | ||
48 | ImportSource::ExternCrate(ptr.to_node(file).to_owned()) | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | pub enum ImportSource { | ||
55 | UseTree(TreeArc<ast::UseTree>), | ||
56 | ExternCrate(TreeArc<ast::ExternCrateItem>), | ||
35 | } | 57 | } |
36 | 58 | ||
37 | impl ImportSourceMap { | 59 | impl ImportSourceMap { |
38 | fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { | 60 | fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) { |
39 | self.map.insert(import, AstPtr::new(segment)) | 61 | self.map.insert(import, ptr) |
40 | } | 62 | } |
41 | 63 | ||
42 | pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { | 64 | pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource { |
43 | let file = match source { | 65 | let file = match source { |
44 | ModuleSource::SourceFile(file) => &*file, | 66 | ModuleSource::SourceFile(file) => &*file, |
45 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | 67 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), |
46 | }; | 68 | }; |
47 | 69 | ||
48 | self.map[import].to_node(file).to_owned() | 70 | self.map[import].to_node(file) |
49 | } | 71 | } |
50 | } | 72 | } |
51 | 73 | ||
@@ -256,18 +278,14 @@ impl RawItemsCollector { | |||
256 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { | 278 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { |
257 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 279 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
258 | 280 | ||
259 | Path::expand_use_item(use_item, |path, segment, alias| { | 281 | Path::expand_use_item(use_item, |path, use_tree, is_glob, alias| { |
260 | let import = self.raw_items.imports.alloc(ImportData { | 282 | let import_data = |
261 | path, | 283 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; |
262 | alias, | 284 | self.push_import( |
263 | is_glob: segment.is_none(), | 285 | current_module, |
264 | is_prelude, | 286 | import_data, |
265 | is_extern_crate: false, | 287 | ImportSourcePtr::UseTree(AstPtr::new(use_tree)), |
266 | }); | 288 | ); |
267 | if let Some(segment) = segment { | ||
268 | self.source_map.insert(import, segment) | ||
269 | } | ||
270 | self.push_item(current_module, RawItem::Import(import)) | ||
271 | }) | 289 | }) |
272 | } | 290 | } |
273 | 291 | ||
@@ -279,14 +297,18 @@ impl RawItemsCollector { | |||
279 | if let Some(name_ref) = extern_crate.name_ref() { | 297 | if let Some(name_ref) = extern_crate.name_ref() { |
280 | let path = Path::from_name_ref(name_ref); | 298 | let path = Path::from_name_ref(name_ref); |
281 | let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name); | 299 | let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name); |
282 | let import = self.raw_items.imports.alloc(ImportData { | 300 | let import_data = ImportData { |
283 | path, | 301 | path, |
284 | alias, | 302 | alias, |
285 | is_glob: false, | 303 | is_glob: false, |
286 | is_prelude: false, | 304 | is_prelude: false, |
287 | is_extern_crate: true, | 305 | is_extern_crate: true, |
288 | }); | 306 | }; |
289 | self.push_item(current_module, RawItem::Import(import)) | 307 | self.push_import( |
308 | current_module, | ||
309 | import_data, | ||
310 | ImportSourcePtr::ExternCrate(AstPtr::new(extern_crate)), | ||
311 | ); | ||
290 | } | 312 | } |
291 | } | 313 | } |
292 | 314 | ||
@@ -303,6 +325,17 @@ impl RawItemsCollector { | |||
303 | self.push_item(current_module, RawItem::Macro(m)); | 325 | self.push_item(current_module, RawItem::Macro(m)); |
304 | } | 326 | } |
305 | 327 | ||
328 | fn push_import( | ||
329 | &mut self, | ||
330 | current_module: Option<Module>, | ||
331 | data: ImportData, | ||
332 | source: ImportSourcePtr, | ||
333 | ) { | ||
334 | let import = self.raw_items.imports.alloc(data); | ||
335 | self.source_map.insert(import, source); | ||
336 | self.push_item(current_module, RawItem::Import(import)) | ||
337 | } | ||
338 | |||
306 | fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { | 339 | fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { |
307 | match current_module { | 340 | match current_module { |
308 | Some(module) => match &mut self.raw_items.modules[module] { | 341 | Some(module) => match &mut self.raw_items.modules[module] { |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 6cc8104f4..5449cddfd 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -46,7 +46,7 @@ impl Path { | |||
46 | /// Calls `cb` with all paths, represented by this use item. | 46 | /// Calls `cb` with all paths, represented by this use item. |
47 | pub fn expand_use_item<'a>( | 47 | pub fn expand_use_item<'a>( |
48 | item: &'a ast::UseItem, | 48 | item: &'a ast::UseItem, |
49 | mut cb: impl FnMut(Path, Option<&'a ast::PathSegment>, Option<Name>), | 49 | mut cb: impl FnMut(Path, &'a ast::UseTree, bool, Option<Name>), |
50 | ) { | 50 | ) { |
51 | if let Some(tree) = item.use_tree() { | 51 | if let Some(tree) = item.use_tree() { |
52 | expand_use_tree(None, tree, &mut cb); | 52 | expand_use_tree(None, tree, &mut cb); |
@@ -156,7 +156,7 @@ impl From<Name> for Path { | |||
156 | fn expand_use_tree<'a>( | 156 | fn expand_use_tree<'a>( |
157 | prefix: Option<Path>, | 157 | prefix: Option<Path>, |
158 | tree: &'a ast::UseTree, | 158 | tree: &'a ast::UseTree, |
159 | cb: &mut impl FnMut(Path, Option<&'a ast::PathSegment>, Option<Name>), | 159 | cb: &mut impl FnMut(Path, &'a ast::UseTree, bool, Option<Name>), |
160 | ) { | 160 | ) { |
161 | if let Some(use_tree_list) = tree.use_tree_list() { | 161 | if let Some(use_tree_list) = tree.use_tree_list() { |
162 | let prefix = match tree.path() { | 162 | let prefix = match tree.path() { |
@@ -181,18 +181,15 @@ fn expand_use_tree<'a>( | |||
181 | if let Some(segment) = ast_path.segment() { | 181 | if let Some(segment) = ast_path.segment() { |
182 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | 182 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { |
183 | if let Some(prefix) = prefix { | 183 | if let Some(prefix) = prefix { |
184 | cb(prefix, Some(segment), alias); | 184 | cb(prefix, tree, false, alias); |
185 | return; | 185 | return; |
186 | } | 186 | } |
187 | } | 187 | } |
188 | } | 188 | } |
189 | } | 189 | } |
190 | if let Some(path) = convert_path(prefix, ast_path) { | 190 | if let Some(path) = convert_path(prefix, ast_path) { |
191 | if tree.has_star() { | 191 | let is_glob = tree.has_star(); |
192 | cb(path, None, alias) | 192 | cb(path, tree, is_glob, alias) |
193 | } else if let Some(segment) = ast_path.segment() { | ||
194 | cb(path, Some(segment), alias) | ||
195 | }; | ||
196 | } | 193 | } |
197 | // FIXME: report errors somewhere | 194 | // FIXME: report errors somewhere |
198 | // We get here if we do | 195 | // We get here if we do |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 9dae4c3d1..182ed4c91 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -9,11 +9,11 @@ use ra_db::{FileId, FilePosition}; | |||
9 | use ra_syntax::{ | 9 | use 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 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum, | 16 | HirDatabase, Function, Struct, Enum,Const,Static, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 17 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
18 | ids::LocationCtx, | 18 | ids::LocationCtx, |
19 | expr, AstId | 19 | expr, AstId |
@@ -87,6 +87,27 @@ fn module_from_source( | |||
87 | ) | 87 | ) |
88 | } | 88 | } |
89 | 89 | ||
90 | pub fn const_from_source( | ||
91 | db: &impl HirDatabase, | ||
92 | file_id: FileId, | ||
93 | const_def: &ast::ConstDef, | ||
94 | ) -> Option<Const> { | ||
95 | let module = module_from_child_node(db, file_id, const_def.syntax())?; | ||
96 | let res = const_from_module(db, module, const_def); | ||
97 | Some(res) | ||
98 | } | ||
99 | |||
100 | pub fn const_from_module( | ||
101 | db: &impl HirDatabase, | ||
102 | module: Module, | ||
103 | const_def: &ast::ConstDef, | ||
104 | ) -> Const { | ||
105 | let (file_id, _) = module.definition_source(db); | ||
106 | let file_id = file_id.into(); | ||
107 | let ctx = LocationCtx::new(db, module, file_id); | ||
108 | Const { id: ctx.to_def(const_def) } | ||
109 | } | ||
110 | |||
90 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { | 111 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { |
91 | let file = db.parse(position.file_id); | 112 | let file = db.parse(position.file_id); |
92 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; | 113 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; |
@@ -134,6 +155,27 @@ pub fn struct_from_module( | |||
134 | Struct { id: ctx.to_def(struct_def) } | 155 | Struct { id: ctx.to_def(struct_def) } |
135 | } | 156 | } |
136 | 157 | ||
158 | pub fn static_from_source( | ||
159 | db: &impl HirDatabase, | ||
160 | file_id: FileId, | ||
161 | static_def: &ast::StaticDef, | ||
162 | ) -> Option<Static> { | ||
163 | let module = module_from_child_node(db, file_id, static_def.syntax())?; | ||
164 | let res = static_from_module(db, module, static_def); | ||
165 | Some(res) | ||
166 | } | ||
167 | |||
168 | pub fn static_from_module( | ||
169 | db: &impl HirDatabase, | ||
170 | module: Module, | ||
171 | static_def: &ast::StaticDef, | ||
172 | ) -> Static { | ||
173 | let (file_id, _) = module.definition_source(db); | ||
174 | let file_id = file_id.into(); | ||
175 | let ctx = LocationCtx::new(db, module, file_id); | ||
176 | Static { id: ctx.to_def(static_def) } | ||
177 | } | ||
178 | |||
137 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { | 179 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { |
138 | let (file_id, _) = module.definition_source(db); | 180 | let (file_id, _) = module.definition_source(db); |
139 | let file_id = file_id.into(); | 181 | let file_id = file_id.into(); |
@@ -155,9 +197,9 @@ pub fn trait_from_module( | |||
155 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { | 197 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { |
156 | let file_id = position.file_id; | 198 | let file_id = position.file_id; |
157 | let file = db.parse(file_id); | 199 | let file = db.parse(file_id); |
158 | find_leaf_at_offset(file.syntax(), position.offset) | 200 | find_token_at_offset(file.syntax(), position.offset) |
159 | .find_map(|node| { | 201 | .find_map(|token| { |
160 | node.ancestors().find_map(|node| { | 202 | token.parent().ancestors().find_map(|node| { |
161 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | 203 | 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) { | 204 | if let Some(func) = function_from_child_node(db, file_id, node) { |
163 | let scopes = func.scopes(db); | 205 | let scopes = func.scopes(db); |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 573115321..887153484 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -27,8 +27,9 @@ use test_utils::tested_by; | |||
27 | 27 | ||
28 | use crate::{ | 28 | use crate::{ |
29 | Function, StructField, Path, Name, | 29 | Function, StructField, Path, Name, |
30 | FnSignature, AdtDef, | 30 | FnSignature, AdtDef,ConstSignature, |
31 | HirDatabase, | 31 | HirDatabase, |
32 | DefWithBody, | ||
32 | ImplItem, | 33 | ImplItem, |
33 | type_ref::{TypeRef, Mutability}, | 34 | type_ref::{TypeRef, Mutability}, |
34 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, | 35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
@@ -43,14 +44,17 @@ use crate::{ | |||
43 | use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; | 44 | use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; |
44 | 45 | ||
45 | /// The entry point of type inference. | 46 | /// The entry point of type inference. |
46 | pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { | 47 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
47 | db.check_canceled(); | 48 | db.check_canceled(); |
48 | let body = func.body(db); | 49 | let body = def.body(db); |
49 | let resolver = func.resolver(db); | 50 | let resolver = def.resolver(db); |
50 | let mut ctx = InferenceContext::new(db, body, resolver); | 51 | let mut ctx = InferenceContext::new(db, body, resolver); |
51 | 52 | ||
52 | let signature = func.signature(db); | 53 | match def { |
53 | ctx.collect_fn_signature(&signature); | 54 | DefWithBody::Const(ref c) => ctx.collect_const_signature(&c.signature(db)), |
55 | DefWithBody::Function(ref f) => ctx.collect_fn_signature(&f.signature(db)), | ||
56 | DefWithBody::Static(ref s) => ctx.collect_const_signature(&s.signature(db)), | ||
57 | } | ||
54 | 58 | ||
55 | ctx.infer_body(); | 59 | ctx.infer_body(); |
56 | 60 | ||
@@ -1142,6 +1146,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1142 | ty | 1146 | ty |
1143 | } | 1147 | } |
1144 | 1148 | ||
1149 | fn collect_const_signature(&mut self, signature: &ConstSignature) { | ||
1150 | self.return_ty = self.make_ty(signature.type_ref()); | ||
1151 | } | ||
1152 | |||
1145 | fn collect_fn_signature(&mut self, signature: &FnSignature) { | 1153 | fn collect_fn_signature(&mut self, signature: &FnSignature) { |
1146 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 1154 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
1147 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1155 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 655f3c522..0b7c841df 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -11,6 +11,8 @@ use crate::{ | |||
11 | source_binder, | 11 | source_binder, |
12 | mock::MockDatabase, | 12 | mock::MockDatabase, |
13 | ty::display::HirDisplay, | 13 | ty::display::HirDisplay, |
14 | ty::InferenceResult, | ||
15 | expr::BodySourceMap | ||
14 | }; | 16 | }; |
15 | 17 | ||
16 | // These tests compare the inference results for all expressions in a file | 18 | // These tests compare the inference results for all expressions in a file |
@@ -1267,6 +1269,9 @@ fn test() { | |||
1267 | } | 1269 | } |
1268 | "#), | 1270 | "#), |
1269 | @r###" | 1271 | @r###" |
1272 | [52; 53) '1': u32 | ||
1273 | [103; 104) '2': u32 | ||
1274 | [211; 212) '5': u32 | ||
1270 | [227; 305) '{ ...:ID; }': () | 1275 | [227; 305) '{ ...:ID; }': () |
1271 | [237; 238) 'x': u32 | 1276 | [237; 238) 'x': u32 |
1272 | [241; 252) 'Struct::FOO': u32 | 1277 | [241; 252) 'Struct::FOO': u32 |
@@ -1855,6 +1860,9 @@ fn test() { | |||
1855 | } | 1860 | } |
1856 | "#), | 1861 | "#), |
1857 | @r###" | 1862 | @r###" |
1863 | [49; 50) '0': u32 | ||
1864 | [80; 83) '101': u32 | ||
1865 | [126; 128) '99': u32 | ||
1858 | [95; 213) '{ ...NST; }': () | 1866 | [95; 213) '{ ...NST; }': () |
1859 | [138; 139) 'x': {unknown} | 1867 | [138; 139) 'x': {unknown} |
1860 | [142; 153) 'LOCAL_CONST': {unknown} | 1868 | [142; 153) 'LOCAL_CONST': {unknown} |
@@ -1881,6 +1889,10 @@ fn test() { | |||
1881 | } | 1889 | } |
1882 | "#), | 1890 | "#), |
1883 | @r###" | 1891 | @r###" |
1892 | [29; 32) '101': u32 | ||
1893 | [70; 73) '101': u32 | ||
1894 | [118; 120) '99': u32 | ||
1895 | [161; 163) '99': u32 | ||
1884 | [85; 280) '{ ...MUT; }': () | 1896 | [85; 280) '{ ...MUT; }': () |
1885 | [173; 174) 'x': {unknown} | 1897 | [173; 174) 'x': {unknown} |
1886 | [177; 189) 'LOCAL_STATIC': {unknown} | 1898 | [177; 189) 'LOCAL_STATIC': {unknown} |
@@ -2212,6 +2224,24 @@ fn test<T: Iterable<Item=u32>>() { | |||
2212 | ); | 2224 | ); |
2213 | } | 2225 | } |
2214 | 2226 | ||
2227 | #[test] | ||
2228 | fn infer_const_body() { | ||
2229 | assert_snapshot_matches!( | ||
2230 | infer(r#" | ||
2231 | const A: u32 = 1 + 1; | ||
2232 | static B: u64 = { let x = 1; x }; | ||
2233 | "#), | ||
2234 | @r###" | ||
2235 | [16; 17) '1': u32 | ||
2236 | [16; 21) '1 + 1': u32 | ||
2237 | [20; 21) '1': u32 | ||
2238 | [39; 55) '{ let ...1; x }': u64 | ||
2239 | [45; 46) 'x': u64 | ||
2240 | [49; 50) '1': u64 | ||
2241 | [52; 53) 'x': u64"### | ||
2242 | ); | ||
2243 | } | ||
2244 | |||
2215 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2245 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2216 | let func = source_binder::function_from_position(db, pos).unwrap(); | 2246 | let func = source_binder::function_from_position(db, pos).unwrap(); |
2217 | let body_source_map = func.body_source_map(db); | 2247 | let body_source_map = func.body_source_map(db); |
@@ -2228,11 +2258,11 @@ fn infer(content: &str) -> String { | |||
2228 | let source_file = db.parse(file_id); | 2258 | let source_file = db.parse(file_id); |
2229 | let mut acc = String::new(); | 2259 | let mut acc = String::new(); |
2230 | acc.push_str("\n"); | 2260 | acc.push_str("\n"); |
2231 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | 2261 | |
2232 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | 2262 | let mut infer_def = |inference_result: Arc<InferenceResult>, |
2233 | let inference_result = func.infer(&db); | 2263 | body_source_map: Arc<BodySourceMap>| { |
2234 | let body_source_map = func.body_source_map(&db); | ||
2235 | let mut types = Vec::new(); | 2264 | let mut types = Vec::new(); |
2265 | |||
2236 | for (pat, ty) in inference_result.type_of_pat.iter() { | 2266 | for (pat, ty) in inference_result.type_of_pat.iter() { |
2237 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 2267 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
2238 | Some(sp) => sp, | 2268 | Some(sp) => sp, |
@@ -2240,6 +2270,7 @@ fn infer(content: &str) -> String { | |||
2240 | }; | 2270 | }; |
2241 | types.push((syntax_ptr, ty)); | 2271 | types.push((syntax_ptr, ty)); |
2242 | } | 2272 | } |
2273 | |||
2243 | for (expr, ty) in inference_result.type_of_expr.iter() { | 2274 | for (expr, ty) in inference_result.type_of_expr.iter() { |
2244 | let syntax_ptr = match body_source_map.expr_syntax(expr) { | 2275 | let syntax_ptr = match body_source_map.expr_syntax(expr) { |
2245 | Some(sp) => sp, | 2276 | Some(sp) => sp, |
@@ -2251,16 +2282,36 @@ fn infer(content: &str) -> String { | |||
2251 | types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); | 2282 | types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); |
2252 | for (syntax_ptr, ty) in &types { | 2283 | for (syntax_ptr, ty) in &types { |
2253 | let node = syntax_ptr.to_node(&source_file); | 2284 | let node = syntax_ptr.to_node(&source_file); |
2254 | write!( | 2285 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node) { |
2255 | acc, | 2286 | (self_param.self_kw_token().range(), "self".to_string()) |
2256 | "{} '{}': {}\n", | 2287 | } else { |
2257 | syntax_ptr.range(), | 2288 | (syntax_ptr.range(), node.text().to_string().replace("\n", " ")) |
2258 | ellipsize(node.text().to_string().replace("\n", " "), 15), | 2289 | }; |
2259 | ty.display(&db) | 2290 | write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); |
2260 | ) | ||
2261 | .unwrap(); | ||
2262 | } | 2291 | } |
2292 | }; | ||
2293 | |||
2294 | for const_def in source_file.syntax().descendants().filter_map(ast::ConstDef::cast) { | ||
2295 | let konst = source_binder::const_from_source(&db, file_id, const_def).unwrap(); | ||
2296 | let inference_result = konst.infer(&db); | ||
2297 | let body_source_map = konst.body_source_map(&db); | ||
2298 | infer_def(inference_result, body_source_map) | ||
2263 | } | 2299 | } |
2300 | |||
2301 | for static_def in source_file.syntax().descendants().filter_map(ast::StaticDef::cast) { | ||
2302 | let static_ = source_binder::static_from_source(&db, file_id, static_def).unwrap(); | ||
2303 | let inference_result = static_.infer(&db); | ||
2304 | let body_source_map = static_.body_source_map(&db); | ||
2305 | infer_def(inference_result, body_source_map) | ||
2306 | } | ||
2307 | |||
2308 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | ||
2309 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | ||
2310 | let inference_result = func.infer(&db); | ||
2311 | let body_source_map = func.body_source_map(&db); | ||
2312 | infer_def(inference_result, body_source_map) | ||
2313 | } | ||
2314 | |||
2264 | acc.truncate(acc.trim_end().len()); | 2315 | acc.truncate(acc.trim_end().len()); |
2265 | acc | 2316 | acc |
2266 | } | 2317 | } |
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index c5e8d5843..29fa7d30b 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs | |||
@@ -28,6 +28,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
28 | let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?; | 28 | let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?; |
29 | 29 | ||
30 | let mut call_info = CallInfo::new(db, function, fn_def)?; | 30 | let mut call_info = CallInfo::new(db, function, fn_def)?; |
31 | |||
31 | // If we have a calling expression let's find which argument we are on | 32 | // If we have a calling expression let's find which argument we are on |
32 | let num_params = call_info.parameters.len(); | 33 | let num_params = call_info.parameters.len(); |
33 | let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); | 34 | let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); |
@@ -38,18 +39,28 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
38 | } | 39 | } |
39 | } else if num_params > 1 { | 40 | } else if num_params > 1 { |
40 | // Count how many parameters into the call we are. | 41 | // Count how many parameters into the call we are. |
41 | if let Some(ref arg_list) = calling_node.arg_list() { | 42 | if let Some(arg_list) = calling_node.arg_list() { |
43 | // Number of arguments specified at the call site | ||
44 | let num_args_at_callsite = arg_list.args().count(); | ||
45 | |||
42 | let arg_list_range = arg_list.syntax().range(); | 46 | let arg_list_range = arg_list.syntax().range(); |
43 | if !arg_list_range.contains_inclusive(position.offset) { | 47 | if !arg_list_range.contains_inclusive(position.offset) { |
44 | tested_by!(call_info_bad_offset); | 48 | tested_by!(call_info_bad_offset); |
45 | return None; | 49 | return None; |
46 | } | 50 | } |
47 | 51 | ||
48 | let param = arg_list | 52 | let mut param = std::cmp::min( |
49 | .args() | 53 | num_args_at_callsite, |
50 | .position(|arg| arg.syntax().range().contains(position.offset)) | 54 | arg_list |
51 | .or(Some(num_params - 1)) | 55 | .args() |
52 | .unwrap(); | 56 | .take_while(|arg| arg.syntax().range().end() < position.offset) |
57 | .count(), | ||
58 | ); | ||
59 | |||
60 | // If we are in a method account for `self` | ||
61 | if has_self { | ||
62 | param = param + 1; | ||
63 | } | ||
53 | 64 | ||
54 | call_info.active_parameter = Some(param); | 65 | call_info.active_parameter = Some(param); |
55 | } | 66 | } |
@@ -156,6 +167,17 @@ fn bar() { foo(3, <|>); }"#, | |||
156 | } | 167 | } |
157 | 168 | ||
158 | #[test] | 169 | #[test] |
170 | fn test_fn_signature_two_args_empty() { | ||
171 | let info = call_info( | ||
172 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | ||
173 | fn bar() { foo(<|>); }"#, | ||
174 | ); | ||
175 | |||
176 | assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); | ||
177 | assert_eq!(info.active_parameter, Some(0)); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
159 | fn test_fn_signature_for_impl() { | 181 | fn test_fn_signature_for_impl() { |
160 | let info = call_info( | 182 | let info = call_info( |
161 | r#"struct F; impl F { pub fn new() { F{}} } | 183 | r#"struct F; impl F { pub fn new() { F{}} } |
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; | |||
13 | mod complete_postfix; | 13 | mod complete_postfix; |
14 | 14 | ||
15 | use ra_db::SourceDatabase; | 15 | use ra_db::SourceDatabase; |
16 | use ra_syntax::ast::{self, AstNode}; | 16 | use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; |
17 | 17 | ||
18 | use crate::{ | 18 | use 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> { | |||
93 | pub fn const_label(node: &ast::ConstDef) -> String { | 92 | pub 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 { | |||
105 | pub fn type_label(node: &ast::TypeAliasDef) -> String { | 103 | pub 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 | ||
8 | use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind}; | 8 | use 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 | ||
77 | fn is_in_loop_body(leaf: &SyntaxNode) -> bool { | 77 | fn 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/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 5ff1b9927..e54fe7b7e 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -19,11 +19,14 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
19 | for (name, res) in module_scope.entries() { | 19 | for (name, res) in module_scope.entries() { |
20 | if Some(module) == ctx.module { | 20 | if Some(module) == ctx.module { |
21 | if let Some(import) = res.import { | 21 | if let Some(import) = res.import { |
22 | let path = module.import_source(ctx.db, import); | 22 | if let hir::ImportSource::UseTree(tree) = |
23 | if path.syntax().range().contains_inclusive(ctx.offset) { | 23 | module.import_source(ctx.db, import) |
24 | // for `use self::foo<|>`, don't suggest `foo` as a completion | 24 | { |
25 | tested_by!(dont_complete_current_use); | 25 | if tree.syntax().range().contains_inclusive(ctx.offset) { |
26 | continue; | 26 | // for `use self::foo<|>`, don't suggest `foo` as a completion |
27 | tested_by!(dont_complete_current_use); | ||
28 | continue; | ||
29 | } | ||
27 | } | 30 | } |
28 | } | 31 | } |
29 | } | 32 | } |
@@ -73,6 +76,18 @@ mod tests { | |||
73 | } | 76 | } |
74 | 77 | ||
75 | #[test] | 78 | #[test] |
79 | fn dont_complete_current_use_in_braces_with_glob() { | ||
80 | let completions = do_completion( | ||
81 | r" | ||
82 | mod foo { pub struct S; } | ||
83 | use self::{foo::*, bar<|>}; | ||
84 | ", | ||
85 | CompletionKind::Reference, | ||
86 | ); | ||
87 | assert_eq!(completions.len(), 2); | ||
88 | } | ||
89 | |||
90 | #[test] | ||
76 | fn completes_mod_with_docs() { | 91 | fn completes_mod_with_docs() { |
77 | check_reference_completion( | 92 | check_reference_completion( |
78 | "mod_with_docs", | 93 | "mod_with_docs", |
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 @@ | |||
1 | use ra_text_edit::AtomTextEdit; | 1 | use ra_text_edit::AtomTextEdit; |
2 | use ra_syntax::{ | 2 | use 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 | }; |
8 | use hir::{source_binder, Resolver}; | 8 | use hir::{source_binder, Resolver}; |
@@ -15,7 +15,7 @@ use crate::{db, FilePosition}; | |||
15 | pub(crate) struct CompletionContext<'a> { | 15 | pub(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 | ||
226 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> { | 227 | fn 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 | ||
231 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | 231 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap index 70ea96e1b..daccd9fba 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap | |||
@@ -1,6 +1,6 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-02-18T09:22:24.062138085Z" | 2 | created: "2019-04-02T07:43:12.954637543Z" |
3 | creator: insta@0.6.2 | 3 | creator: insta@0.7.4 |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: kind_completions |
6 | --- | 6 | --- |
@@ -33,6 +33,9 @@ expression: kind_completions | |||
33 | delete: [180; 180), | 33 | delete: [180; 180), |
34 | insert: "S", | 34 | insert: "S", |
35 | kind: EnumVariant, | 35 | kind: EnumVariant, |
36 | detail: "(S)" | 36 | detail: "(S)", |
37 | documentation: Documentation( | ||
38 | "" | ||
39 | ) | ||
37 | } | 40 | } |
38 | ] | 41 | ] |
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..7293ba359 100644 --- a/crates/ra_ide_api/src/extend_selection.rs +++ b/crates/ra_ide_api/src/extend_selection.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | Direction, SyntaxNode, TextRange, TextUnit, AstNode, | 3 | Direction, SyntaxNode, TextRange, TextUnit, 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::{self, AstNode, AstToken}, | ||
6 | }; | 7 | }; |
7 | 8 | ||
8 | use crate::{FileRange, db::RootDatabase}; | 9 | use 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) = ast::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 | ||
77 | fn extend_single_word_in_comment_or_string( | 83 | fn 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 | ||
104 | fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange { | 110 | fn 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 | ||
127 | fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { | 133 | fn 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 |