diff options
Diffstat (limited to 'crates')
78 files changed, 1031 insertions, 507 deletions
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs index 06ac85f67..1805c1dfd 100644 --- a/crates/assists/src/handlers/generate_function.rs +++ b/crates/assists/src/handlers/generate_function.rs | |||
@@ -158,11 +158,11 @@ impl FunctionBuilder { | |||
158 | it.text_range().end() | 158 | it.text_range().end() |
159 | } | 159 | } |
160 | GeneratedFunctionTarget::InEmptyItemList(it) => { | 160 | GeneratedFunctionTarget::InEmptyItemList(it) => { |
161 | let indent = IndentLevel::from_node(it.syntax()); | 161 | let indent = IndentLevel::from_node(&it); |
162 | leading_ws = format!("\n{}", indent + 1); | 162 | leading_ws = format!("\n{}", indent + 1); |
163 | fn_def = fn_def.indent(indent + 1); | 163 | fn_def = fn_def.indent(indent + 1); |
164 | trailing_ws = format!("\n{}", indent); | 164 | trailing_ws = format!("\n{}", indent); |
165 | it.syntax().text_range().start() + TextSize::of('{') | 165 | it.text_range().start() + TextSize::of('{') |
166 | } | 166 | } |
167 | }; | 167 | }; |
168 | 168 | ||
@@ -179,14 +179,14 @@ impl FunctionBuilder { | |||
179 | 179 | ||
180 | enum GeneratedFunctionTarget { | 180 | enum GeneratedFunctionTarget { |
181 | BehindItem(SyntaxNode), | 181 | BehindItem(SyntaxNode), |
182 | InEmptyItemList(ast::ItemList), | 182 | InEmptyItemList(SyntaxNode), |
183 | } | 183 | } |
184 | 184 | ||
185 | impl GeneratedFunctionTarget { | 185 | impl GeneratedFunctionTarget { |
186 | fn syntax(&self) -> &SyntaxNode { | 186 | fn syntax(&self) -> &SyntaxNode { |
187 | match self { | 187 | match self { |
188 | GeneratedFunctionTarget::BehindItem(it) => it, | 188 | GeneratedFunctionTarget::BehindItem(it) => it, |
189 | GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(), | 189 | GeneratedFunctionTarget::InEmptyItemList(it) => it, |
190 | } | 190 | } |
191 | } | 191 | } |
192 | } | 192 | } |
@@ -323,7 +323,16 @@ fn next_space_for_fn_in_module( | |||
323 | if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) { | 323 | if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) { |
324 | GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) | 324 | GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) |
325 | } else { | 325 | } else { |
326 | GeneratedFunctionTarget::InEmptyItemList(it.item_list()?) | 326 | GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone()) |
327 | } | ||
328 | } | ||
329 | hir::ModuleSource::BlockExpr(it) => { | ||
330 | if let Some(last_item) = | ||
331 | it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last() | ||
332 | { | ||
333 | GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) | ||
334 | } else { | ||
335 | GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone()) | ||
327 | } | 336 | } |
328 | } | 337 | } |
329 | }; | 338 | }; |
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs index 9af45192b..827477272 100644 --- a/crates/assists/src/handlers/generate_impl.rs +++ b/crates/assists/src/handlers/generate_impl.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | use itertools::Itertools; | 1 | use itertools::Itertools; |
2 | use stdx::format_to; | 2 | use stdx::format_to; |
3 | use syntax::ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}; | 3 | use syntax::{ |
4 | ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}, | ||
5 | SmolStr, | ||
6 | }; | ||
4 | 7 | ||
5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
6 | 9 | ||
@@ -49,16 +52,16 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
49 | format_to!(buf, "{}", type_params.syntax()); | 52 | format_to!(buf, "{}", type_params.syntax()); |
50 | } | 53 | } |
51 | buf.push_str(" "); | 54 | buf.push_str(" "); |
52 | buf.push_str(name.text().as_str()); | 55 | buf.push_str(name.text()); |
53 | if let Some(type_params) = type_params { | 56 | if let Some(type_params) = type_params { |
54 | let lifetime_params = type_params | 57 | let lifetime_params = type_params |
55 | .lifetime_params() | 58 | .lifetime_params() |
56 | .filter_map(|it| it.lifetime()) | 59 | .filter_map(|it| it.lifetime()) |
57 | .map(|it| it.text().clone()); | 60 | .map(|it| SmolStr::from(it.text())); |
58 | let type_params = type_params | 61 | let type_params = type_params |
59 | .type_params() | 62 | .type_params() |
60 | .filter_map(|it| it.name()) | 63 | .filter_map(|it| it.name()) |
61 | .map(|it| it.text().clone()); | 64 | .map(|it| SmolStr::from(it.text())); |
62 | 65 | ||
63 | let generic_params = lifetime_params.chain(type_params).format(", "); | 66 | let generic_params = lifetime_params.chain(type_params).format(", "); |
64 | format_to!(buf, "<{}>", generic_params) | 67 | format_to!(buf, "<{}>", generic_params) |
diff --git a/crates/assists/src/handlers/generate_new.rs b/crates/assists/src/handlers/generate_new.rs index 5c52b2bc8..b7390855a 100644 --- a/crates/assists/src/handlers/generate_new.rs +++ b/crates/assists/src/handlers/generate_new.rs | |||
@@ -3,7 +3,7 @@ use itertools::Itertools; | |||
3 | use stdx::format_to; | 3 | use stdx::format_to; |
4 | use syntax::{ | 4 | use syntax::{ |
5 | ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, | 5 | ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, |
6 | T, | 6 | SmolStr, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -95,14 +95,14 @@ fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String { | |||
95 | format_to!(buf, "{}", type_params.syntax()); | 95 | format_to!(buf, "{}", type_params.syntax()); |
96 | } | 96 | } |
97 | buf.push_str(" "); | 97 | buf.push_str(" "); |
98 | buf.push_str(strukt.name().unwrap().text().as_str()); | 98 | buf.push_str(strukt.name().unwrap().text()); |
99 | if let Some(type_params) = type_params { | 99 | if let Some(type_params) = type_params { |
100 | let lifetime_params = type_params | 100 | let lifetime_params = type_params |
101 | .lifetime_params() | 101 | .lifetime_params() |
102 | .filter_map(|it| it.lifetime()) | 102 | .filter_map(|it| it.lifetime()) |
103 | .map(|it| it.text().clone()); | 103 | .map(|it| SmolStr::from(it.text())); |
104 | let type_params = | 104 | let type_params = |
105 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 105 | type_params.type_params().filter_map(|it| it.name()).map(|it| SmolStr::from(it.text())); |
106 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) | 106 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) |
107 | } | 107 | } |
108 | 108 | ||
diff --git a/crates/assists/src/handlers/raw_string.rs b/crates/assists/src/handlers/raw_string.rs index be963f162..d95267607 100644 --- a/crates/assists/src/handlers/raw_string.rs +++ b/crates/assists/src/handlers/raw_string.rs | |||
@@ -138,7 +138,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
138 | return None; | 138 | return None; |
139 | } | 139 | } |
140 | 140 | ||
141 | let text = token.text().as_str(); | 141 | let text = token.text(); |
142 | if !text.starts_with("r#") && text.ends_with('#') { | 142 | if !text.starts_with("r#") && text.ends_with('#') { |
143 | return None; | 143 | return None; |
144 | } | 144 | } |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index bd4c1c806..6aa9d2f2c 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -3,7 +3,7 @@ use ide_db::imports_locator; | |||
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | use syntax::{ | 4 | use syntax::{ |
5 | ast::{self, make, AstNode}, | 5 | ast::{self, make, AstNode}, |
6 | Direction, SmolStr, | 6 | Direction, |
7 | SyntaxKind::{IDENT, WHITESPACE}, | 7 | SyntaxKind::{IDENT, WHITESPACE}, |
8 | TextSize, | 8 | TextSize, |
9 | }; | 9 | }; |
@@ -43,17 +43,18 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
43 | ) -> Option<()> { | 43 | ) -> Option<()> { |
44 | let attr = ctx.find_node_at_offset::<ast::Attr>()?; | 44 | let attr = ctx.find_node_at_offset::<ast::Attr>()?; |
45 | 45 | ||
46 | let attr_name = attr | 46 | let has_derive = attr |
47 | .syntax() | 47 | .syntax() |
48 | .descendants_with_tokens() | 48 | .descendants_with_tokens() |
49 | .filter(|t| t.kind() == IDENT) | 49 | .filter(|t| t.kind() == IDENT) |
50 | .find_map(syntax::NodeOrToken::into_token) | 50 | .find_map(syntax::NodeOrToken::into_token) |
51 | .filter(|t| t.text() == "derive")? | 51 | .filter(|t| t.text() == "derive") |
52 | .text() | 52 | .is_some(); |
53 | .clone(); | 53 | if !has_derive { |
54 | return None; | ||
55 | } | ||
54 | 56 | ||
55 | let trait_token = | 57 | let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; |
56 | ctx.token_at_offset().find(|t| t.kind() == IDENT && *t.text() != attr_name)?; | ||
57 | let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); | 58 | let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); |
58 | 59 | ||
59 | let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; | 60 | let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; |
@@ -176,9 +177,9 @@ fn update_attribute( | |||
176 | .syntax() | 177 | .syntax() |
177 | .descendants_with_tokens() | 178 | .descendants_with_tokens() |
178 | .filter(|t| t.kind() == IDENT) | 179 | .filter(|t| t.kind() == IDENT) |
179 | .filter_map(|t| t.into_token().map(|t| t.text().clone())) | 180 | .filter_map(|t| t.into_token().map(|t| t.text().to_string())) |
180 | .filter(|t| t != trait_name.text()) | 181 | .filter(|t| t != trait_name.text()) |
181 | .collect::<Vec<SmolStr>>(); | 182 | .collect::<Vec<_>>(); |
182 | let has_more_derives = !new_attr_input.is_empty(); | 183 | let has_more_derives = !new_attr_input.is_empty(); |
183 | 184 | ||
184 | if has_more_derives { | 185 | if has_more_derives { |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index fc9f83bab..44c35bafa 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -223,7 +223,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
223 | let method = mce.name_ref()?; | 223 | let method = mce.name_ref()?; |
224 | let arg_list = mce.arg_list()?; | 224 | let arg_list = mce.arg_list()?; |
225 | 225 | ||
226 | let method = match method.text().as_str() { | 226 | let method = match method.text() { |
227 | "is_some" => "is_none", | 227 | "is_some" => "is_none", |
228 | "is_none" => "is_some", | 228 | "is_none" => "is_some", |
229 | "is_ok" => "is_err", | 229 | "is_ok" => "is_err", |
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 99fb65bac..9e6a3e155 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | use hir_def::{ | 2 | use hir_def::{ |
3 | attr::{Attrs, Documentation}, | 3 | attr::{Attrs, Documentation}, |
4 | path::ModPath, | 4 | path::ModPath, |
5 | per_ns::PerNs, | ||
5 | resolver::HasResolver, | 6 | resolver::HasResolver, |
6 | AttrDefId, GenericParamId, ModuleDefId, | 7 | AttrDefId, GenericParamId, ModuleDefId, |
7 | }; | 8 | }; |
@@ -112,6 +113,11 @@ fn resolve_doc_path( | |||
112 | let path = ast::Path::parse(link).ok()?; | 113 | let path = ast::Path::parse(link).ok()?; |
113 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); | 114 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); |
114 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); | 115 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); |
116 | if resolved == PerNs::none() { | ||
117 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { | ||
118 | return Some(ModuleDefId::TraitId(trait_id)); | ||
119 | }; | ||
120 | } | ||
115 | let def = match ns { | 121 | let def = match ns { |
116 | Some(Namespace::Types) => resolved.take_types()?, | 122 | Some(Namespace::Types) => resolved.take_types()?, |
117 | Some(Namespace::Values) => resolved.take_values()?, | 123 | Some(Namespace::Values) => resolved.take_values()?, |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index a4141e111..aaa7013b6 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -90,7 +90,7 @@ impl Crate { | |||
90 | } | 90 | } |
91 | 91 | ||
92 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { | 92 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { |
93 | let module_id = db.crate_def_map(self.id).root; | 93 | let module_id = db.crate_def_map(self.id).root(); |
94 | Module::new(self, module_id) | 94 | Module::new(self, module_id) |
95 | } | 95 | } |
96 | 96 | ||
@@ -302,7 +302,7 @@ impl Module { | |||
302 | /// in the module tree of any target in `Cargo.toml`. | 302 | /// in the module tree of any target in `Cargo.toml`. |
303 | pub fn crate_root(self, db: &dyn HirDatabase) -> Module { | 303 | pub fn crate_root(self, db: &dyn HirDatabase) -> Module { |
304 | let def_map = db.crate_def_map(self.id.krate); | 304 | let def_map = db.crate_def_map(self.id.krate); |
305 | self.with_module_id(def_map.root) | 305 | self.with_module_id(def_map.root()) |
306 | } | 306 | } |
307 | 307 | ||
308 | /// Iterates over all child modules. | 308 | /// Iterates over all child modules. |
@@ -1000,7 +1000,7 @@ impl MacroDef { | |||
1000 | /// early, in `hir_expand`, where modules simply do not exist yet. | 1000 | /// early, in `hir_expand`, where modules simply do not exist yet. |
1001 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | 1001 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { |
1002 | let krate = self.id.krate; | 1002 | let krate = self.id.krate; |
1003 | let module_id = db.crate_def_map(krate).root; | 1003 | let module_id = db.crate_def_map(krate).root(); |
1004 | Some(Module::new(Crate { id: krate }, module_id)) | 1004 | Some(Module::new(Crate { id: krate }, module_id)) |
1005 | } | 1005 | } |
1006 | 1006 | ||
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index d5d4cf5b6..d444f4bbb 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub use hir_def::db::{ | 3 | pub use hir_def::db::{ |
4 | AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, | 4 | AttrsQuery, BlockDefMapQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, |
5 | CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, ExprScopesQuery, | 5 | CrateDefMapQueryQuery, CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, |
6 | FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, InternConstQuery, | 6 | ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, |
7 | InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, | 7 | InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, |
8 | InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, | 8 | InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, |
9 | ItemTreeQuery, LangItemQuery, StaticDataQuery, StructDataQuery, TraitDataQuery, | 9 | InternUnionQuery, ItemTreeQuery, LangItemQuery, StaticDataQuery, StructDataQuery, |
10 | TypeAliasDataQuery, UnionDataQuery, | 10 | TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, |
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, | 13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 1b09ff816..c72649c41 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -207,6 +207,7 @@ impl Attrs { | |||
207 | mod_data.definition_source(db).as_ref().map(|src| match src { | 207 | mod_data.definition_source(db).as_ref().map(|src| match src { |
208 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, | 208 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, |
209 | ModuleSource::Module(module) => module as &dyn AttrsOwner, | 209 | ModuleSource::Module(module) => module as &dyn AttrsOwner, |
210 | ModuleSource::BlockExpr(block) => block as &dyn AttrsOwner, | ||
210 | }), | 211 | }), |
211 | ), | 212 | ), |
212 | } | 213 | } |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 3b2dd0f6e..2c2c999dd 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -122,7 +122,7 @@ impl Expander { | |||
122 | 122 | ||
123 | let mut err = None; | 123 | let mut err = None; |
124 | let call_id = | 124 | let call_id = |
125 | macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| { | 125 | macro_call.as_call_id_with_errors(db, self.crate_def_map.krate(), resolver, &mut |e| { |
126 | err.get_or_insert(e); | 126 | err.get_or_insert(e); |
127 | }); | 127 | }); |
128 | let call_id = match call_id { | 128 | let call_id = match call_id { |
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index de77d5fc9..2e5d0a01e 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs | |||
@@ -6,18 +6,24 @@ use crate::{test_db::TestDB, ModuleDefId}; | |||
6 | use super::*; | 6 | use super::*; |
7 | 7 | ||
8 | fn lower(ra_fixture: &str) -> Arc<Body> { | 8 | fn lower(ra_fixture: &str) -> Arc<Body> { |
9 | let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); | 9 | let db = crate::test_db::TestDB::with_files(ra_fixture); |
10 | 10 | ||
11 | let krate = db.crate_graph().iter().next().unwrap(); | 11 | let krate = db.crate_graph().iter().next().unwrap(); |
12 | let def_map = db.crate_def_map(krate); | 12 | let def_map = db.crate_def_map(krate); |
13 | let module = def_map.modules_for_file(file_id).next().unwrap(); | 13 | let mut fn_def = None; |
14 | let module = &def_map[module]; | 14 | 'outer: for (_, module) in def_map.modules() { |
15 | let fn_def = match module.scope.declarations().next().unwrap() { | 15 | for decl in module.scope.declarations() { |
16 | ModuleDefId::FunctionId(it) => it, | 16 | match decl { |
17 | _ => panic!(), | 17 | ModuleDefId::FunctionId(it) => { |
18 | }; | 18 | fn_def = Some(it); |
19 | break 'outer; | ||
20 | } | ||
21 | _ => {} | ||
22 | } | ||
23 | } | ||
24 | } | ||
19 | 25 | ||
20 | db.body(fn_def.into()) | 26 | db.body(fn_def.unwrap().into()) |
21 | } | 27 | } |
22 | 28 | ||
23 | fn check_diagnostics(ra_fixture: &str) { | 29 | fn check_diagnostics(ra_fixture: &str) { |
@@ -42,6 +48,25 @@ fn main() { n_nuple!(1,2,3); } | |||
42 | } | 48 | } |
43 | 49 | ||
44 | #[test] | 50 | #[test] |
51 | fn macro_resolve() { | ||
52 | // Regression test for a path resolution bug introduced with inner item handling. | ||
53 | lower( | ||
54 | r" | ||
55 | macro_rules! vec { | ||
56 | () => { () }; | ||
57 | ($elem:expr; $n:expr) => { () }; | ||
58 | ($($x:expr),+ $(,)?) => { () }; | ||
59 | } | ||
60 | mod m { | ||
61 | fn outer() { | ||
62 | let _ = vec![FileSet::default(); self.len()]; | ||
63 | } | ||
64 | } | ||
65 | ", | ||
66 | ); | ||
67 | } | ||
68 | |||
69 | #[test] | ||
45 | fn cfg_diagnostics() { | 70 | fn cfg_diagnostics() { |
46 | check_diagnostics( | 71 | check_diagnostics( |
47 | r" | 72 | r" |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 91c8d45cd..a87c80b8a 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -2,9 +2,9 @@ | |||
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 5 | use hir_expand::{db::AstDatabase, AstId, HirFileId}; |
6 | use la_arena::ArenaMap; | 6 | use la_arena::ArenaMap; |
7 | use syntax::SmolStr; | 7 | use syntax::{ast, SmolStr}; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | adt::{EnumData, StructData}, | 10 | adt::{EnumData, StructData}, |
@@ -55,6 +55,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
55 | #[salsa::invoke(DefMap::crate_def_map_query)] | 55 | #[salsa::invoke(DefMap::crate_def_map_query)] |
56 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>; | 56 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>; |
57 | 57 | ||
58 | #[salsa::invoke(DefMap::block_def_map_query)] | ||
59 | fn block_def_map(&self, krate: CrateId, block: AstId<ast::BlockExpr>) -> Arc<DefMap>; | ||
60 | |||
58 | #[salsa::invoke(StructData::struct_data_query)] | 61 | #[salsa::invoke(StructData::struct_data_query)] |
59 | fn struct_data(&self, id: StructId) -> Arc<StructData>; | 62 | fn struct_data(&self, id: StructId) -> Arc<StructData>; |
60 | #[salsa::invoke(StructData::union_data_query)] | 63 | #[salsa::invoke(StructData::union_data_query)] |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index 422a6eeb4..db2d125ae 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -51,7 +51,7 @@ fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option< | |||
51 | if item == ItemInNs::Types(from.into()) { | 51 | if item == ItemInNs::Types(from.into()) { |
52 | // - if the item is the module we're in, use `self` | 52 | // - if the item is the module we're in, use `self` |
53 | Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) | 53 | Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) |
54 | } else if let Some(parent_id) = def_map.modules[from.local_id].parent { | 54 | } else if let Some(parent_id) = def_map[from.local_id].parent { |
55 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) | 55 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) |
56 | if item | 56 | if item |
57 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | 57 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { |
@@ -111,7 +111,7 @@ fn find_path_inner( | |||
111 | 111 | ||
112 | // - if the item is already in scope, return the name under which it is | 112 | // - if the item is already in scope, return the name under which it is |
113 | let def_map = db.crate_def_map(from.krate); | 113 | let def_map = db.crate_def_map(from.krate); |
114 | let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; | 114 | let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope; |
115 | let scope_name = | 115 | let scope_name = |
116 | if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; | 116 | if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; |
117 | if prefixed.is_none() && scope_name.is_some() { | 117 | if prefixed.is_none() && scope_name.is_some() { |
@@ -123,7 +123,7 @@ fn find_path_inner( | |||
123 | if item | 123 | if item |
124 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | 124 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { |
125 | krate: from.krate, | 125 | krate: from.krate, |
126 | local_id: def_map.root, | 126 | local_id: def_map.root(), |
127 | })) | 127 | })) |
128 | { | 128 | { |
129 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); | 129 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); |
@@ -136,7 +136,7 @@ fn find_path_inner( | |||
136 | } | 136 | } |
137 | 137 | ||
138 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude | 138 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude |
139 | for (name, def_id) in &def_map.extern_prelude { | 139 | for (name, def_id) in def_map.extern_prelude() { |
140 | if item == ItemInNs::Types(*def_id) { | 140 | if item == ItemInNs::Types(*def_id) { |
141 | let name = scope_name.unwrap_or_else(|| name.clone()); | 141 | let name = scope_name.unwrap_or_else(|| name.clone()); |
142 | return Some(ModPath::from_segments(PathKind::Plain, vec![name])); | 142 | return Some(ModPath::from_segments(PathKind::Plain, vec![name])); |
@@ -144,10 +144,10 @@ fn find_path_inner( | |||
144 | } | 144 | } |
145 | 145 | ||
146 | // - if the item is in the prelude, return the name from there | 146 | // - if the item is in the prelude, return the name from there |
147 | if let Some(prelude_module) = def_map.prelude { | 147 | if let Some(prelude_module) = def_map.prelude() { |
148 | let prelude_def_map = db.crate_def_map(prelude_module.krate); | 148 | let prelude_def_map = db.crate_def_map(prelude_module.krate); |
149 | let prelude_scope: &crate::item_scope::ItemScope = | 149 | let prelude_scope: &crate::item_scope::ItemScope = |
150 | &prelude_def_map.modules[prelude_module.local_id].scope; | 150 | &prelude_def_map[prelude_module.local_id].scope; |
151 | if let Some((name, vis)) = prelude_scope.name_of(item) { | 151 | if let Some((name, vis)) = prelude_scope.name_of(item) { |
152 | if vis.is_visible_from(db, from) { | 152 | if vis.is_visible_from(db, from) { |
153 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | 153 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); |
@@ -175,7 +175,7 @@ fn find_path_inner( | |||
175 | 175 | ||
176 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | 176 | // - otherwise, look for modules containing (reexporting) it and import it from one of those |
177 | 177 | ||
178 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; | 178 | let crate_root = ModuleId { local_id: def_map.root(), krate: from.krate }; |
179 | let crate_attrs = db.attrs(crate_root.into()); | 179 | let crate_attrs = db.attrs(crate_root.into()); |
180 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | 180 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); |
181 | let mut best_path = None; | 181 | let mut best_path = None; |
@@ -287,7 +287,7 @@ fn find_local_import_locations( | |||
287 | 287 | ||
288 | // Compute the initial worklist. We start with all direct child modules of `from` as well as all | 288 | // Compute the initial worklist. We start with all direct child modules of `from` as well as all |
289 | // of its (recursive) parent modules. | 289 | // of its (recursive) parent modules. |
290 | let data = &def_map.modules[from.local_id]; | 290 | let data = &def_map[from.local_id]; |
291 | let mut worklist = data | 291 | let mut worklist = data |
292 | .children | 292 | .children |
293 | .values() | 293 | .values() |
@@ -296,7 +296,7 @@ fn find_local_import_locations( | |||
296 | let mut parent = data.parent; | 296 | let mut parent = data.parent; |
297 | while let Some(p) = parent { | 297 | while let Some(p) = parent { |
298 | worklist.push(ModuleId { krate: from.krate, local_id: p }); | 298 | worklist.push(ModuleId { krate: from.krate, local_id: p }); |
299 | parent = def_map.modules[p].parent; | 299 | parent = def_map[p].parent; |
300 | } | 300 | } |
301 | 301 | ||
302 | let mut seen: FxHashSet<_> = FxHashSet::default(); | 302 | let mut seen: FxHashSet<_> = FxHashSet::default(); |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index fac0de90c..0251d016b 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -75,7 +75,7 @@ impl ImportMap { | |||
75 | 75 | ||
76 | // We look only into modules that are public(ly reexported), starting with the crate root. | 76 | // We look only into modules that are public(ly reexported), starting with the crate root. |
77 | let empty = ImportPath { segments: vec![] }; | 77 | let empty = ImportPath { segments: vec![] }; |
78 | let root = ModuleId { krate, local_id: def_map.root }; | 78 | let root = ModuleId { krate, local_id: def_map.root() }; |
79 | let mut worklist = vec![(root, empty)]; | 79 | let mut worklist = vec![(root, empty)]; |
80 | while let Some((module, mod_path)) = worklist.pop() { | 80 | while let Some((module, mod_path)) = worklist.pop() { |
81 | let ext_def_map; | 81 | let ext_def_map; |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index ff62928df..b8d7608e7 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -21,6 +21,7 @@ use hir_expand::{ | |||
21 | HirFileId, InFile, | 21 | HirFileId, InFile, |
22 | }; | 22 | }; |
23 | use la_arena::{Arena, Idx, RawIdx}; | 23 | use la_arena::{Arena, Idx, RawIdx}; |
24 | use profile::Count; | ||
24 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
25 | use smallvec::SmallVec; | 26 | use smallvec::SmallVec; |
26 | use syntax::{ast, match_ast}; | 27 | use syntax::{ast, match_ast}; |
@@ -67,15 +68,16 @@ impl GenericParamsId { | |||
67 | /// The item tree of a source file. | 68 | /// The item tree of a source file. |
68 | #[derive(Debug, Eq, PartialEq)] | 69 | #[derive(Debug, Eq, PartialEq)] |
69 | pub struct ItemTree { | 70 | pub struct ItemTree { |
71 | _c: Count<Self>, | ||
72 | |||
70 | top_level: SmallVec<[ModItem; 1]>, | 73 | top_level: SmallVec<[ModItem; 1]>, |
71 | attrs: FxHashMap<AttrOwner, RawAttrs>, | 74 | attrs: FxHashMap<AttrOwner, RawAttrs>, |
72 | inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>, | ||
73 | 75 | ||
74 | data: Option<Box<ItemTreeData>>, | 76 | data: Option<Box<ItemTreeData>>, |
75 | } | 77 | } |
76 | 78 | ||
77 | impl ItemTree { | 79 | impl ItemTree { |
78 | pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { | 80 | pub(crate) fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { |
79 | let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id)); | 81 | let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id)); |
80 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { | 82 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { |
81 | node | 83 | node |
@@ -118,9 +120,9 @@ impl ItemTree { | |||
118 | 120 | ||
119 | fn empty() -> Self { | 121 | fn empty() -> Self { |
120 | Self { | 122 | Self { |
123 | _c: Count::new(), | ||
121 | top_level: Default::default(), | 124 | top_level: Default::default(), |
122 | attrs: Default::default(), | 125 | attrs: Default::default(), |
123 | inner_items: Default::default(), | ||
124 | data: Default::default(), | 126 | data: Default::default(), |
125 | } | 127 | } |
126 | } | 128 | } |
@@ -147,6 +149,7 @@ impl ItemTree { | |||
147 | macro_defs, | 149 | macro_defs, |
148 | vis, | 150 | vis, |
149 | generics, | 151 | generics, |
152 | inner_items, | ||
150 | } = &mut **data; | 153 | } = &mut **data; |
151 | 154 | ||
152 | imports.shrink_to_fit(); | 155 | imports.shrink_to_fit(); |
@@ -169,6 +172,8 @@ impl ItemTree { | |||
169 | 172 | ||
170 | vis.arena.shrink_to_fit(); | 173 | vis.arena.shrink_to_fit(); |
171 | generics.arena.shrink_to_fit(); | 174 | generics.arena.shrink_to_fit(); |
175 | |||
176 | inner_items.shrink_to_fit(); | ||
172 | } | 177 | } |
173 | } | 178 | } |
174 | 179 | ||
@@ -191,16 +196,18 @@ impl ItemTree { | |||
191 | self.raw_attrs(of).clone().filter(db, krate) | 196 | self.raw_attrs(of).clone().filter(db, krate) |
192 | } | 197 | } |
193 | 198 | ||
194 | /// Returns the lowered inner items that `ast` corresponds to. | 199 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { |
195 | /// | 200 | match &self.data { |
196 | /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered | 201 | Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(), |
197 | /// to multiple items in the `ItemTree`. | 202 | None => None.into_iter().flatten(), |
198 | pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] { | 203 | } |
199 | &self.inner_items[&ast] | ||
200 | } | 204 | } |
201 | 205 | ||
202 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { | 206 | pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] { |
203 | self.inner_items.values().flatten().copied() | 207 | match &self.data { |
208 | Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]), | ||
209 | None => &[], | ||
210 | } | ||
204 | } | 211 | } |
205 | 212 | ||
206 | pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { | 213 | pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { |
@@ -297,6 +304,8 @@ struct ItemTreeData { | |||
297 | 304 | ||
298 | vis: ItemVisibilities, | 305 | vis: ItemVisibilities, |
299 | generics: GenericParamsStorage, | 306 | generics: GenericParamsStorage, |
307 | |||
308 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | ||
300 | } | 309 | } |
301 | 310 | ||
302 | #[derive(Debug, Eq, PartialEq, Hash)] | 311 | #[derive(Debug, Eq, PartialEq, Hash)] |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 5e71ca42c..ce470fc3b 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -6,7 +6,7 @@ use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId} | |||
6 | use smallvec::SmallVec; | 6 | use smallvec::SmallVec; |
7 | use syntax::{ | 7 | use syntax::{ |
8 | ast::{self, ModuleItemOwner}, | 8 | ast::{self, ModuleItemOwner}, |
9 | SyntaxNode, | 9 | SyntaxNode, WalkEvent, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -37,7 +37,6 @@ pub(super) struct Ctx { | |||
37 | file: HirFileId, | 37 | file: HirFileId, |
38 | source_ast_id_map: Arc<AstIdMap>, | 38 | source_ast_id_map: Arc<AstIdMap>, |
39 | body_ctx: crate::body::LowerCtx, | 39 | body_ctx: crate::body::LowerCtx, |
40 | inner_items: Vec<ModItem>, | ||
41 | forced_visibility: Option<RawVisibilityId>, | 40 | forced_visibility: Option<RawVisibilityId>, |
42 | } | 41 | } |
43 | 42 | ||
@@ -49,7 +48,6 @@ impl Ctx { | |||
49 | file, | 48 | file, |
50 | source_ast_id_map: db.ast_id_map(file), | 49 | source_ast_id_map: db.ast_id_map(file), |
51 | body_ctx: crate::body::LowerCtx::new(db, file), | 50 | body_ctx: crate::body::LowerCtx::new(db, file), |
52 | inner_items: Vec::new(), | ||
53 | forced_visibility: None, | 51 | forced_visibility: None, |
54 | } | 52 | } |
55 | } | 53 | } |
@@ -73,8 +71,6 @@ impl Ctx { | |||
73 | } | 71 | } |
74 | 72 | ||
75 | fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { | 73 | fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { |
76 | assert!(inner || self.inner_items.is_empty()); | ||
77 | |||
78 | // Collect inner items for 1-to-1-lowered items. | 74 | // Collect inner items for 1-to-1-lowered items. |
79 | match item { | 75 | match item { |
80 | ast::Item::Struct(_) | 76 | ast::Item::Struct(_) |
@@ -150,14 +146,37 @@ impl Ctx { | |||
150 | 146 | ||
151 | fn collect_inner_items(&mut self, container: &SyntaxNode) { | 147 | fn collect_inner_items(&mut self, container: &SyntaxNode) { |
152 | let forced_vis = self.forced_visibility.take(); | 148 | let forced_vis = self.forced_visibility.take(); |
153 | let mut inner_items = mem::take(&mut self.tree.inner_items); | 149 | |
154 | inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map( | 150 | let mut block_stack = Vec::new(); |
155 | |item| { | 151 | for event in container.preorder().skip(1) { |
156 | let ast_id = self.source_ast_id_map.ast_id(&item); | 152 | match event { |
157 | Some((ast_id, self.lower_mod_item(&item, true)?.0)) | 153 | WalkEvent::Enter(node) => { |
158 | }, | 154 | match_ast! { |
159 | )); | 155 | match node { |
160 | self.tree.inner_items = inner_items; | 156 | ast::BlockExpr(block) => { |
157 | block_stack.push(self.source_ast_id_map.ast_id(&block)); | ||
158 | }, | ||
159 | ast::Item(item) => { | ||
160 | let mod_items = self.lower_mod_item(&item, true); | ||
161 | let current_block = block_stack.last(); | ||
162 | if let (Some(mod_items), Some(block)) = (mod_items, current_block) { | ||
163 | if !mod_items.0.is_empty() { | ||
164 | self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied()); | ||
165 | } | ||
166 | } | ||
167 | }, | ||
168 | _ => {} | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | WalkEvent::Leave(node) => { | ||
173 | if ast::BlockExpr::cast(node).is_some() { | ||
174 | block_stack.pop(); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
161 | self.forced_visibility = forced_vis; | 180 | self.forced_visibility = forced_vis; |
162 | } | 181 | } |
163 | 182 | ||
diff --git a/crates/hir_def/src/lang_item.rs b/crates/hir_def/src/lang_item.rs index 30188b740..9e90f745c 100644 --- a/crates/hir_def/src/lang_item.rs +++ b/crates/hir_def/src/lang_item.rs | |||
@@ -84,7 +84,7 @@ impl LangItems { | |||
84 | 84 | ||
85 | let crate_def_map = db.crate_def_map(krate); | 85 | let crate_def_map = db.crate_def_map(krate); |
86 | 86 | ||
87 | for (_, module_data) in crate_def_map.modules.iter() { | 87 | for (_, module_data) in crate_def_map.modules() { |
88 | for impl_def in module_data.scope.impls() { | 88 | for impl_def in module_data.scope.impls() { |
89 | lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDefId) | 89 | lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDefId) |
90 | } | 90 | } |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 769a557ad..bd3ea9b8b 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -59,9 +59,10 @@ use std::sync::Arc; | |||
59 | use base_db::{CrateId, Edition, FileId}; | 59 | use base_db::{CrateId, Edition, FileId}; |
60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; | 60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; |
61 | use la_arena::Arena; | 61 | use la_arena::Arena; |
62 | use profile::Count; | ||
62 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
63 | use stdx::format_to; | 64 | use stdx::format_to; |
64 | use syntax::ast; | 65 | use syntax::{ast, AstNode}; |
65 | 66 | ||
66 | use crate::{ | 67 | use crate::{ |
67 | db::DefDatabase, | 68 | db::DefDatabase, |
@@ -75,14 +76,16 @@ use crate::{ | |||
75 | /// Contains all top-level defs from a macro-expanded crate | 76 | /// Contains all top-level defs from a macro-expanded crate |
76 | #[derive(Debug, PartialEq, Eq)] | 77 | #[derive(Debug, PartialEq, Eq)] |
77 | pub struct DefMap { | 78 | pub struct DefMap { |
78 | pub root: LocalModuleId, | 79 | _c: Count<Self>, |
79 | pub modules: Arena<ModuleData>, | 80 | parent: Option<Arc<DefMap>>, |
80 | pub(crate) krate: CrateId, | 81 | root: LocalModuleId, |
82 | modules: Arena<ModuleData>, | ||
83 | krate: CrateId, | ||
81 | /// The prelude module for this crate. This either comes from an import | 84 | /// The prelude module for this crate. This either comes from an import |
82 | /// marked with the `prelude_import` attribute, or (in the normal case) from | 85 | /// marked with the `prelude_import` attribute, or (in the normal case) from |
83 | /// a dependency (`std` or `core`). | 86 | /// a dependency (`std` or `core`). |
84 | pub(crate) prelude: Option<ModuleId>, | 87 | prelude: Option<ModuleId>, |
85 | pub(crate) extern_prelude: FxHashMap<Name, ModuleDefId>, | 88 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
86 | 89 | ||
87 | edition: Edition, | 90 | edition: Edition, |
88 | diagnostics: Vec<DefDiagnostic>, | 91 | diagnostics: Vec<DefDiagnostic>, |
@@ -109,6 +112,10 @@ pub enum ModuleOrigin { | |||
109 | Inline { | 112 | Inline { |
110 | definition: AstId<ast::Module>, | 113 | definition: AstId<ast::Module>, |
111 | }, | 114 | }, |
115 | /// Pseudo-module introduced by a block scope (contains only inner items). | ||
116 | BlockExpr { | ||
117 | block: AstId<ast::BlockExpr>, | ||
118 | }, | ||
112 | } | 119 | } |
113 | 120 | ||
114 | impl Default for ModuleOrigin { | 121 | impl Default for ModuleOrigin { |
@@ -122,7 +129,7 @@ impl ModuleOrigin { | |||
122 | match self { | 129 | match self { |
123 | ModuleOrigin::File { declaration: module, .. } | 130 | ModuleOrigin::File { declaration: module, .. } |
124 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), | 131 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), |
125 | ModuleOrigin::CrateRoot { .. } => None, | 132 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, |
126 | } | 133 | } |
127 | } | 134 | } |
128 | 135 | ||
@@ -137,7 +144,7 @@ impl ModuleOrigin { | |||
137 | 144 | ||
138 | pub fn is_inline(&self) -> bool { | 145 | pub fn is_inline(&self) -> bool { |
139 | match self { | 146 | match self { |
140 | ModuleOrigin::Inline { .. } => true, | 147 | ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true, |
141 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, | 148 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, |
142 | } | 149 | } |
143 | } | 150 | } |
@@ -155,6 +162,9 @@ impl ModuleOrigin { | |||
155 | definition.file_id, | 162 | definition.file_id, |
156 | ModuleSource::Module(definition.to_node(db.upcast())), | 163 | ModuleSource::Module(definition.to_node(db.upcast())), |
157 | ), | 164 | ), |
165 | ModuleOrigin::BlockExpr { block } => { | ||
166 | InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast()))) | ||
167 | } | ||
158 | } | 168 | } |
159 | } | 169 | } |
160 | } | 170 | } |
@@ -174,24 +184,51 @@ impl DefMap { | |||
174 | let _p = profile::span("crate_def_map_query").detail(|| { | 184 | let _p = profile::span("crate_def_map_query").detail(|| { |
175 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() | 185 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() |
176 | }); | 186 | }); |
177 | let def_map = { | 187 | let edition = db.crate_graph()[krate].edition; |
178 | let edition = db.crate_graph()[krate].edition; | 188 | let def_map = DefMap::empty(krate, edition); |
179 | let mut modules: Arena<ModuleData> = Arena::default(); | 189 | let def_map = collector::collect_defs(db, def_map, None); |
180 | let root = modules.alloc(ModuleData::default()); | ||
181 | DefMap { | ||
182 | krate, | ||
183 | edition, | ||
184 | extern_prelude: FxHashMap::default(), | ||
185 | prelude: None, | ||
186 | root, | ||
187 | modules, | ||
188 | diagnostics: Vec::new(), | ||
189 | } | ||
190 | }; | ||
191 | let def_map = collector::collect_defs(db, def_map); | ||
192 | Arc::new(def_map) | 190 | Arc::new(def_map) |
193 | } | 191 | } |
194 | 192 | ||
193 | pub(crate) fn block_def_map_query( | ||
194 | db: &dyn DefDatabase, | ||
195 | krate: CrateId, | ||
196 | block: AstId<ast::BlockExpr>, | ||
197 | ) -> Arc<DefMap> { | ||
198 | let item_tree = db.item_tree(block.file_id); | ||
199 | let block_items = item_tree.inner_items_of_block(block.value); | ||
200 | |||
201 | let parent = parent_def_map(db, krate, block); | ||
202 | |||
203 | if block_items.is_empty() { | ||
204 | // If there are no inner items, nothing new is brought into scope, so we can just return | ||
205 | // the parent DefMap. This keeps DefMap parent chains short. | ||
206 | return parent; | ||
207 | } | ||
208 | |||
209 | let mut def_map = DefMap::empty(krate, parent.edition); | ||
210 | def_map.parent = Some(parent); | ||
211 | |||
212 | let def_map = collector::collect_defs(db, def_map, Some(block.value)); | ||
213 | Arc::new(def_map) | ||
214 | } | ||
215 | |||
216 | fn empty(krate: CrateId, edition: Edition) -> DefMap { | ||
217 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
218 | let root = modules.alloc(ModuleData::default()); | ||
219 | DefMap { | ||
220 | _c: Count::new(), | ||
221 | parent: None, | ||
222 | krate, | ||
223 | edition, | ||
224 | extern_prelude: FxHashMap::default(), | ||
225 | prelude: None, | ||
226 | root, | ||
227 | modules, | ||
228 | diagnostics: Vec::new(), | ||
229 | } | ||
230 | } | ||
231 | |||
195 | pub fn add_diagnostics( | 232 | pub fn add_diagnostics( |
196 | &self, | 233 | &self, |
197 | db: &dyn DefDatabase, | 234 | db: &dyn DefDatabase, |
@@ -208,6 +245,26 @@ impl DefMap { | |||
208 | .map(|(id, _data)| id) | 245 | .map(|(id, _data)| id) |
209 | } | 246 | } |
210 | 247 | ||
248 | pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ { | ||
249 | self.modules.iter() | ||
250 | } | ||
251 | |||
252 | pub fn root(&self) -> LocalModuleId { | ||
253 | self.root | ||
254 | } | ||
255 | |||
256 | pub(crate) fn krate(&self) -> CrateId { | ||
257 | self.krate | ||
258 | } | ||
259 | |||
260 | pub(crate) fn prelude(&self) -> Option<ModuleId> { | ||
261 | self.prelude | ||
262 | } | ||
263 | |||
264 | pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleDefId)> + '_ { | ||
265 | self.extern_prelude.iter() | ||
266 | } | ||
267 | |||
211 | pub(crate) fn resolve_path( | 268 | pub(crate) fn resolve_path( |
212 | &self, | 269 | &self, |
213 | db: &dyn DefDatabase, | 270 | db: &dyn DefDatabase, |
@@ -224,7 +281,12 @@ impl DefMap { | |||
224 | // even), as this should be a great debugging aid. | 281 | // even), as this should be a great debugging aid. |
225 | pub fn dump(&self) -> String { | 282 | pub fn dump(&self) -> String { |
226 | let mut buf = String::new(); | 283 | let mut buf = String::new(); |
227 | go(&mut buf, self, "crate", self.root); | 284 | let mut current_map = self; |
285 | while let Some(parent) = ¤t_map.parent { | ||
286 | go(&mut buf, current_map, "block scope", current_map.root); | ||
287 | current_map = &**parent; | ||
288 | } | ||
289 | go(&mut buf, current_map, "crate", current_map.root); | ||
228 | return buf; | 290 | return buf; |
229 | 291 | ||
230 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { | 292 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { |
@@ -276,10 +338,40 @@ impl ModuleData { | |||
276 | } | 338 | } |
277 | } | 339 | } |
278 | 340 | ||
341 | fn parent_def_map( | ||
342 | db: &dyn DefDatabase, | ||
343 | krate: CrateId, | ||
344 | block: AstId<ast::BlockExpr>, | ||
345 | ) -> Arc<DefMap> { | ||
346 | // FIXME: store this info in the item tree instead of reparsing here | ||
347 | let ast_id_map = db.ast_id_map(block.file_id); | ||
348 | let block_ptr = ast_id_map.get(block.value); | ||
349 | let root = match db.parse_or_expand(block.file_id) { | ||
350 | Some(it) => it, | ||
351 | None => { | ||
352 | return Arc::new(DefMap::empty(krate, Edition::Edition2018)); | ||
353 | } | ||
354 | }; | ||
355 | let ast = block_ptr.to_node(&root); | ||
356 | |||
357 | for ancestor in ast.syntax().ancestors().skip(1) { | ||
358 | if let Some(block_expr) = ast::BlockExpr::cast(ancestor) { | ||
359 | let ancestor_id = ast_id_map.ast_id(&block_expr); | ||
360 | let ast_id = InFile::new(block.file_id, ancestor_id); | ||
361 | let parent_map = db.block_def_map(krate, ast_id); | ||
362 | return parent_map; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | // No enclosing block scope, so the parent is the crate-level DefMap. | ||
367 | db.crate_def_map(krate) | ||
368 | } | ||
369 | |||
279 | #[derive(Debug, Clone, PartialEq, Eq)] | 370 | #[derive(Debug, Clone, PartialEq, Eq)] |
280 | pub enum ModuleSource { | 371 | pub enum ModuleSource { |
281 | SourceFile(ast::SourceFile), | 372 | SourceFile(ast::SourceFile), |
282 | Module(ast::Module), | 373 | Module(ast::Module), |
374 | BlockExpr(ast::BlockExpr), | ||
283 | } | 375 | } |
284 | 376 | ||
285 | mod diagnostics { | 377 | mod diagnostics { |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 61da56340..cd68efbe6 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -45,7 +45,11 @@ const GLOB_RECURSION_LIMIT: usize = 100; | |||
45 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 45 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
46 | const FIXED_POINT_LIMIT: usize = 8192; | 46 | const FIXED_POINT_LIMIT: usize = 8192; |
47 | 47 | ||
48 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap { | 48 | pub(super) fn collect_defs( |
49 | db: &dyn DefDatabase, | ||
50 | mut def_map: DefMap, | ||
51 | block: Option<FileAstId<ast::BlockExpr>>, | ||
52 | ) -> DefMap { | ||
49 | let crate_graph = db.crate_graph(); | 53 | let crate_graph = db.crate_graph(); |
50 | 54 | ||
51 | // populate external prelude | 55 | // populate external prelude |
@@ -93,6 +97,14 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap | |||
93 | exports_proc_macros: false, | 97 | exports_proc_macros: false, |
94 | from_glob_import: Default::default(), | 98 | from_glob_import: Default::default(), |
95 | }; | 99 | }; |
100 | match block { | ||
101 | Some(block) => { | ||
102 | collector.seed_with_inner(block); | ||
103 | } | ||
104 | None => { | ||
105 | collector.seed_with_top_level(); | ||
106 | } | ||
107 | } | ||
96 | collector.collect(); | 108 | collector.collect(); |
97 | collector.finish() | 109 | collector.finish() |
98 | } | 110 | } |
@@ -228,7 +240,7 @@ struct DefCollector<'a> { | |||
228 | } | 240 | } |
229 | 241 | ||
230 | impl DefCollector<'_> { | 242 | impl DefCollector<'_> { |
231 | fn collect(&mut self) { | 243 | fn seed_with_top_level(&mut self) { |
232 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | 244 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; |
233 | let item_tree = self.db.item_tree(file_id.into()); | 245 | let item_tree = self.db.item_tree(file_id.into()); |
234 | let module_id = self.def_map.root; | 246 | let module_id = self.def_map.root; |
@@ -248,7 +260,31 @@ impl DefCollector<'_> { | |||
248 | } | 260 | } |
249 | .collect(item_tree.top_level_items()); | 261 | .collect(item_tree.top_level_items()); |
250 | } | 262 | } |
263 | } | ||
264 | |||
265 | fn seed_with_inner(&mut self, block: FileAstId<ast::BlockExpr>) { | ||
266 | let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; | ||
267 | let item_tree = self.db.item_tree(file_id.into()); | ||
268 | let module_id = self.def_map.root; | ||
269 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | ||
270 | if item_tree | ||
271 | .top_level_attrs(self.db, self.def_map.krate) | ||
272 | .cfg() | ||
273 | .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) | ||
274 | { | ||
275 | ModCollector { | ||
276 | def_collector: &mut *self, | ||
277 | macro_depth: 0, | ||
278 | module_id, | ||
279 | file_id: file_id.into(), | ||
280 | item_tree: &item_tree, | ||
281 | mod_dir: ModDir::root(), | ||
282 | } | ||
283 | .collect(item_tree.inner_items_of_block(block)); | ||
284 | } | ||
285 | } | ||
251 | 286 | ||
287 | fn collect(&mut self) { | ||
252 | // main name resolution fixed-point loop. | 288 | // main name resolution fixed-point loop. |
253 | let mut i = 0; | 289 | let mut i = 0; |
254 | loop { | 290 | loop { |
@@ -1470,7 +1506,6 @@ impl ModCollector<'_, '_> { | |||
1470 | mod tests { | 1506 | mod tests { |
1471 | use crate::{db::DefDatabase, test_db::TestDB}; | 1507 | use crate::{db::DefDatabase, test_db::TestDB}; |
1472 | use base_db::{fixture::WithFixture, SourceDatabase}; | 1508 | use base_db::{fixture::WithFixture, SourceDatabase}; |
1473 | use la_arena::Arena; | ||
1474 | 1509 | ||
1475 | use super::*; | 1510 | use super::*; |
1476 | 1511 | ||
@@ -1489,6 +1524,7 @@ mod tests { | |||
1489 | exports_proc_macros: false, | 1524 | exports_proc_macros: false, |
1490 | from_glob_import: Default::default(), | 1525 | from_glob_import: Default::default(), |
1491 | }; | 1526 | }; |
1527 | collector.seed_with_top_level(); | ||
1492 | collector.collect(); | 1528 | collector.collect(); |
1493 | collector.def_map | 1529 | collector.def_map |
1494 | } | 1530 | } |
@@ -1497,20 +1533,8 @@ mod tests { | |||
1497 | let (db, _file_id) = TestDB::with_single_file(&code); | 1533 | let (db, _file_id) = TestDB::with_single_file(&code); |
1498 | let krate = db.test_crate(); | 1534 | let krate = db.test_crate(); |
1499 | 1535 | ||
1500 | let def_map = { | 1536 | let edition = db.crate_graph()[krate].edition; |
1501 | let edition = db.crate_graph()[krate].edition; | 1537 | let def_map = DefMap::empty(krate, edition); |
1502 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
1503 | let root = modules.alloc(ModuleData::default()); | ||
1504 | DefMap { | ||
1505 | krate, | ||
1506 | edition, | ||
1507 | extern_prelude: FxHashMap::default(), | ||
1508 | prelude: None, | ||
1509 | root, | ||
1510 | modules, | ||
1511 | diagnostics: Vec::new(), | ||
1512 | } | ||
1513 | }; | ||
1514 | do_collect_defs(&db, def_map) | 1538 | do_collect_defs(&db, def_map) |
1515 | } | 1539 | } |
1516 | 1540 | ||
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index 096a7d0ac..ec90f4e65 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -104,6 +104,43 @@ impl DefMap { | |||
104 | path: &ModPath, | 104 | path: &ModPath, |
105 | shadow: BuiltinShadowMode, | 105 | shadow: BuiltinShadowMode, |
106 | ) -> ResolvePathResult { | 106 | ) -> ResolvePathResult { |
107 | let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); | ||
108 | result.segment_index = Some(usize::max_value()); | ||
109 | |||
110 | let mut current_map = self; | ||
111 | loop { | ||
112 | let new = current_map.resolve_path_fp_with_macro_single( | ||
113 | db, | ||
114 | mode, | ||
115 | original_module, | ||
116 | path, | ||
117 | shadow, | ||
118 | ); | ||
119 | |||
120 | // Merge `new` into `result`. | ||
121 | result.resolved_def = result.resolved_def.or(new.resolved_def); | ||
122 | if result.reached_fixedpoint == ReachedFixedPoint::No { | ||
123 | result.reached_fixedpoint = new.reached_fixedpoint; | ||
124 | } | ||
125 | // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? | ||
126 | result.krate = result.krate.or(new.krate); | ||
127 | result.segment_index = result.segment_index.min(new.segment_index); | ||
128 | |||
129 | match ¤t_map.parent { | ||
130 | Some(map) => current_map = map, | ||
131 | None => return result, | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | pub(super) fn resolve_path_fp_with_macro_single( | ||
137 | &self, | ||
138 | db: &dyn DefDatabase, | ||
139 | mode: ResolveMode, | ||
140 | original_module: LocalModuleId, | ||
141 | path: &ModPath, | ||
142 | shadow: BuiltinShadowMode, | ||
143 | ) -> ResolvePathResult { | ||
107 | let mut segments = path.segments.iter().enumerate(); | 144 | let mut segments = path.segments.iter().enumerate(); |
108 | let mut curr_per_ns: PerNs = match path.kind { | 145 | let mut curr_per_ns: PerNs = match path.kind { |
109 | PathKind::DollarCrate(krate) => { | 146 | PathKind::DollarCrate(krate) => { |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 723481c36..73e3a4702 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -4,11 +4,13 @@ mod macros; | |||
4 | mod mod_resolution; | 4 | mod mod_resolution; |
5 | mod diagnostics; | 5 | mod diagnostics; |
6 | mod primitives; | 6 | mod primitives; |
7 | mod block; | ||
7 | 8 | ||
8 | use std::sync::Arc; | 9 | use std::sync::Arc; |
9 | 10 | ||
10 | use base_db::{fixture::WithFixture, SourceDatabase}; | 11 | use base_db::{fixture::WithFixture, SourceDatabase}; |
11 | use expect_test::{expect, Expect}; | 12 | use expect_test::{expect, Expect}; |
13 | use hir_expand::db::AstDatabase; | ||
12 | use test_utils::mark; | 14 | use test_utils::mark; |
13 | 15 | ||
14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 16 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; |
@@ -19,12 +21,30 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { | |||
19 | db.crate_def_map(krate) | 21 | db.crate_def_map(krate) |
20 | } | 22 | } |
21 | 23 | ||
24 | fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { | ||
25 | let (db, position) = TestDB::with_position(ra_fixture); | ||
26 | let module = db.module_for_file(position.file_id); | ||
27 | let ast_map = db.ast_id_map(position.file_id.into()); | ||
28 | let ast = db.parse(position.file_id); | ||
29 | let block: ast::BlockExpr = | ||
30 | syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); | ||
31 | let block_id = ast_map.ast_id(&block); | ||
32 | |||
33 | db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) | ||
34 | } | ||
35 | |||
22 | fn check(ra_fixture: &str, expect: Expect) { | 36 | fn check(ra_fixture: &str, expect: Expect) { |
23 | let def_map = compute_crate_def_map(ra_fixture); | 37 | let def_map = compute_crate_def_map(ra_fixture); |
24 | let actual = def_map.dump(); | 38 | let actual = def_map.dump(); |
25 | expect.assert_eq(&actual); | 39 | expect.assert_eq(&actual); |
26 | } | 40 | } |
27 | 41 | ||
42 | fn check_at(ra_fixture: &str, expect: Expect) { | ||
43 | let def_map = compute_block_def_map(ra_fixture); | ||
44 | let actual = def_map.dump(); | ||
45 | expect.assert_eq(&actual); | ||
46 | } | ||
47 | |||
28 | #[test] | 48 | #[test] |
29 | fn crate_def_map_smoke_test() { | 49 | fn crate_def_map_smoke_test() { |
30 | check( | 50 | check( |
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs new file mode 100644 index 000000000..01d6326a7 --- /dev/null +++ b/crates/hir_def/src/nameres/tests/block.rs | |||
@@ -0,0 +1,97 @@ | |||
1 | use super::*; | ||
2 | |||
3 | #[test] | ||
4 | fn inner_item_smoke() { | ||
5 | check_at( | ||
6 | r#" | ||
7 | struct inner {} | ||
8 | fn outer() { | ||
9 | $0 | ||
10 | fn inner() {} | ||
11 | } | ||
12 | "#, | ||
13 | expect![[r#" | ||
14 | block scope | ||
15 | inner: v | ||
16 | crate | ||
17 | inner: t | ||
18 | outer: v | ||
19 | "#]], | ||
20 | ); | ||
21 | } | ||
22 | |||
23 | #[test] | ||
24 | fn use_from_crate() { | ||
25 | check_at( | ||
26 | r#" | ||
27 | struct Struct; | ||
28 | fn outer() { | ||
29 | use Struct; | ||
30 | use crate::Struct as CrateStruct; | ||
31 | use self::Struct as SelfStruct; | ||
32 | $0 | ||
33 | } | ||
34 | "#, | ||
35 | expect![[r#" | ||
36 | block scope | ||
37 | CrateStruct: t v | ||
38 | SelfStruct: t v | ||
39 | Struct: t v | ||
40 | crate | ||
41 | Struct: t v | ||
42 | outer: v | ||
43 | "#]], | ||
44 | ); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn merge_namespaces() { | ||
49 | check_at( | ||
50 | r#" | ||
51 | struct name {} | ||
52 | fn outer() { | ||
53 | fn name() {} | ||
54 | |||
55 | use name as imported; // should import both `name`s | ||
56 | |||
57 | $0 | ||
58 | } | ||
59 | "#, | ||
60 | expect![[r#" | ||
61 | block scope | ||
62 | imported: t v | ||
63 | name: v | ||
64 | crate | ||
65 | name: t | ||
66 | outer: v | ||
67 | "#]], | ||
68 | ); | ||
69 | } | ||
70 | |||
71 | #[test] | ||
72 | fn nested_blocks() { | ||
73 | check_at( | ||
74 | r#" | ||
75 | fn outer() { | ||
76 | struct inner1 {} | ||
77 | fn inner() { | ||
78 | use inner1; | ||
79 | use outer; | ||
80 | fn inner2() {} | ||
81 | $0 | ||
82 | } | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | block scope | ||
87 | inner1: t | ||
88 | inner2: v | ||
89 | outer: v | ||
90 | block scope | ||
91 | inner: v | ||
92 | inner1: t | ||
93 | crate | ||
94 | outer: v | ||
95 | "#]], | ||
96 | ); | ||
97 | } | ||
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index a505bf2be..b2f577649 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -146,6 +146,19 @@ impl Resolver { | |||
146 | self.resolve_module_path(db, path, BuiltinShadowMode::Module) | 146 | self.resolve_module_path(db, path, BuiltinShadowMode::Module) |
147 | } | 147 | } |
148 | 148 | ||
149 | pub fn resolve_module_path_in_trait_items( | ||
150 | &self, | ||
151 | db: &dyn DefDatabase, | ||
152 | path: &ModPath, | ||
153 | ) -> Option<TraitId> { | ||
154 | let (item_map, module) = self.module_scope()?; | ||
155 | let (module_res, ..) = item_map.resolve_path(db, module, &path, BuiltinShadowMode::Module); | ||
156 | match module_res.take_types()? { | ||
157 | ModuleDefId::TraitId(it) => Some(it), | ||
158 | _ => None, | ||
159 | } | ||
160 | } | ||
161 | |||
149 | pub fn resolve_path_in_type_ns( | 162 | pub fn resolve_path_in_type_ns( |
150 | &self, | 163 | &self, |
151 | db: &dyn DefDatabase, | 164 | db: &dyn DefDatabase, |
@@ -416,7 +429,7 @@ impl Resolver { | |||
416 | let mut traits = FxHashSet::default(); | 429 | let mut traits = FxHashSet::default(); |
417 | for scope in &self.scopes { | 430 | for scope in &self.scopes { |
418 | if let Scope::ModuleScope(m) = scope { | 431 | if let Scope::ModuleScope(m) = scope { |
419 | if let Some(prelude) = m.crate_def_map.prelude { | 432 | if let Some(prelude) = m.crate_def_map.prelude() { |
420 | let prelude_def_map = db.crate_def_map(prelude.krate); | 433 | let prelude_def_map = db.crate_def_map(prelude.krate); |
421 | traits.extend(prelude_def_map[prelude.local_id].scope.traits()); | 434 | traits.extend(prelude_def_map[prelude.local_id].scope.traits()); |
422 | } | 435 | } |
@@ -446,11 +459,11 @@ impl Resolver { | |||
446 | 459 | ||
447 | pub fn module(&self) -> Option<ModuleId> { | 460 | pub fn module(&self) -> Option<ModuleId> { |
448 | let (def_map, local_id) = self.module_scope()?; | 461 | let (def_map, local_id) = self.module_scope()?; |
449 | Some(ModuleId { krate: def_map.krate, local_id }) | 462 | Some(ModuleId { krate: def_map.krate(), local_id }) |
450 | } | 463 | } |
451 | 464 | ||
452 | pub fn krate(&self) -> Option<CrateId> { | 465 | pub fn krate(&self) -> Option<CrateId> { |
453 | self.module_scope().map(|t| t.0.krate) | 466 | self.module_scope().map(|t| t.0.krate()) |
454 | } | 467 | } |
455 | 468 | ||
456 | pub fn where_predicates_in_scope<'a>( | 469 | pub fn where_predicates_in_scope<'a>( |
@@ -509,13 +522,13 @@ impl Scope { | |||
509 | seen.insert((name.clone(), scope)); | 522 | seen.insert((name.clone(), scope)); |
510 | f(name.clone(), ScopeDef::PerNs(scope)); | 523 | f(name.clone(), ScopeDef::PerNs(scope)); |
511 | }); | 524 | }); |
512 | m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { | 525 | m.crate_def_map.extern_prelude().for_each(|(name, &def)| { |
513 | f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); | 526 | f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); |
514 | }); | 527 | }); |
515 | BUILTIN_SCOPE.iter().for_each(|(name, &def)| { | 528 | BUILTIN_SCOPE.iter().for_each(|(name, &def)| { |
516 | f(name.clone(), ScopeDef::PerNs(def)); | 529 | f(name.clone(), ScopeDef::PerNs(def)); |
517 | }); | 530 | }); |
518 | if let Some(prelude) = m.crate_def_map.prelude { | 531 | if let Some(prelude) = m.crate_def_map.prelude() { |
519 | let prelude_def_map = db.crate_def_map(prelude.krate); | 532 | let prelude_def_map = db.crate_def_map(prelude.krate); |
520 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { | 533 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { |
521 | let seen_tuple = (name.clone(), def); | 534 | let seen_tuple = (name.clone(), def); |
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 574c0201a..4ff219fb7 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -75,7 +75,7 @@ impl TestDB { | |||
75 | pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId { | 75 | pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId { |
76 | for &krate in self.relevant_crates(file_id).iter() { | 76 | for &krate in self.relevant_crates(file_id).iter() { |
77 | let crate_def_map = self.crate_def_map(krate); | 77 | let crate_def_map = self.crate_def_map(krate); |
78 | for (local_id, data) in crate_def_map.modules.iter() { | 78 | for (local_id, data) in crate_def_map.modules() { |
79 | if data.origin.file_id() == Some(file_id) { | 79 | if data.origin.file_id() == Some(file_id) { |
80 | return crate::ModuleId { krate, local_id }; | 80 | return crate::ModuleId { krate, local_id }; |
81 | } | 81 | } |
@@ -110,7 +110,7 @@ impl TestDB { | |||
110 | let crate_graph = self.crate_graph(); | 110 | let crate_graph = self.crate_graph(); |
111 | for krate in crate_graph.iter() { | 111 | for krate in crate_graph.iter() { |
112 | let crate_def_map = self.crate_def_map(krate); | 112 | let crate_def_map = self.crate_def_map(krate); |
113 | for (module_id, _) in crate_def_map.modules.iter() { | 113 | for (module_id, _) in crate_def_map.modules() { |
114 | let file_id = crate_def_map[module_id].origin.file_id(); | 114 | let file_id = crate_def_map[module_id].origin.file_id(); |
115 | files.extend(file_id) | 115 | files.extend(file_id) |
116 | } | 116 | } |
@@ -135,7 +135,7 @@ impl TestDB { | |||
135 | let crate_def_map = self.crate_def_map(krate); | 135 | let crate_def_map = self.crate_def_map(krate); |
136 | 136 | ||
137 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | 137 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); |
138 | for (module_id, module) in crate_def_map.modules.iter() { | 138 | for (module_id, module) in crate_def_map.modules() { |
139 | crate_def_map.add_diagnostics(self, module_id, &mut sink); | 139 | crate_def_map.add_diagnostics(self, module_id, &mut sink); |
140 | 140 | ||
141 | for decl in module.scope.declarations() { | 141 | for decl in module.scope.declarations() { |
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs index 2401b0cc5..0991fffd8 100644 --- a/crates/hir_expand/src/ast_id_map.rs +++ b/crates/hir_expand/src/ast_id_map.rs | |||
@@ -13,7 +13,7 @@ use std::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use la_arena::{Arena, Idx}; | 15 | use la_arena::{Arena, Idx}; |
16 | use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | 16 | use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; |
17 | 17 | ||
18 | /// `AstId` points to an AST node in a specific file. | 18 | /// `AstId` points to an AST node in a specific file. |
19 | pub struct FileAstId<N: AstNode> { | 19 | pub struct FileAstId<N: AstNode> { |
@@ -72,12 +72,20 @@ impl AstIdMap { | |||
72 | // get lower ids then children. That is, adding a new child does not | 72 | // get lower ids then children. That is, adding a new child does not |
73 | // change parent's id. This means that, say, adding a new function to a | 73 | // change parent's id. This means that, say, adding a new function to a |
74 | // trait does not change ids of top-level items, which helps caching. | 74 | // trait does not change ids of top-level items, which helps caching. |
75 | bdfs(node, |it| match ast::Item::cast(it) { | 75 | bdfs(node, |it| { |
76 | Some(module_item) => { | 76 | match_ast! { |
77 | res.alloc(module_item.syntax()); | 77 | match it { |
78 | true | 78 | ast::Item(module_item) => { |
79 | res.alloc(module_item.syntax()); | ||
80 | true | ||
81 | }, | ||
82 | ast::BlockExpr(block) => { | ||
83 | res.alloc(block.syntax()); | ||
84 | true | ||
85 | }, | ||
86 | _ => false, | ||
87 | } | ||
79 | } | 88 | } |
80 | None => false, | ||
81 | }); | 89 | }); |
82 | res | 90 | res |
83 | } | 91 | } |
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index eb257579f..b7f1aae8f 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -102,7 +102,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> { | |||
102 | debug!("name token not found"); | 102 | debug!("name token not found"); |
103 | mbe::ExpandError::ConversionError | 103 | mbe::ExpandError::ConversionError |
104 | })?; | 104 | })?; |
105 | let name_token = tt::Ident { id: name_token_id, text: name.text().clone() }; | 105 | let name_token = tt::Ident { id: name_token_id, text: name.text().into() }; |
106 | let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count()); | 106 | let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count()); |
107 | Ok(BasicAdtInfo { name: name_token, type_params }) | 107 | Ok(BasicAdtInfo { name: name_token, type_params }) |
108 | } | 108 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 467516eb7..cb6e23320 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -173,7 +173,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | |||
173 | }; | 173 | }; |
174 | let loc = db.lookup_intern_macro(id); | 174 | let loc = db.lookup_intern_macro(id); |
175 | let arg = loc.kind.arg(db)?; | 175 | let arg = loc.kind.arg(db)?; |
176 | Some(arg.green().clone()) | 176 | Some(arg.green().to_owned()) |
177 | } | 177 | } |
178 | 178 | ||
179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | 179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 95d853b6d..d692cec14 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -38,7 +38,7 @@ impl Name { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | pub fn new_lifetime(lt: &ast::Lifetime) -> Name { | 40 | pub fn new_lifetime(lt: &ast::Lifetime) -> Name { |
41 | Self::new_text(lt.text().clone()) | 41 | Self::new_text(lt.text().into()) |
42 | } | 42 | } |
43 | 43 | ||
44 | /// Shortcut to create inline plain text name | 44 | /// Shortcut to create inline plain text name |
@@ -47,12 +47,12 @@ impl Name { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | /// Resolve a name from the text of token. | 49 | /// Resolve a name from the text of token. |
50 | fn resolve(raw_text: &SmolStr) -> Name { | 50 | fn resolve(raw_text: &str) -> Name { |
51 | let raw_start = "r#"; | 51 | let raw_start = "r#"; |
52 | if raw_text.as_str().starts_with(raw_start) { | 52 | if raw_text.starts_with(raw_start) { |
53 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) | 53 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) |
54 | } else { | 54 | } else { |
55 | Name::new_text(raw_text.clone()) | 55 | Name::new_text(raw_text.into()) |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 98434b741..db42a00dc 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -17,9 +17,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.47", default-features = false } | 20 | chalk-solve = { version = "0.50", default-features = false } |
21 | chalk-ir = "0.47" | 21 | chalk-ir = "0.50" |
22 | chalk-recursive = "0.47" | 22 | chalk-recursive = "0.50" |
23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index c67a289f2..247da43f2 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -409,7 +409,7 @@ mod tests { | |||
409 | let crate_def_map = self.crate_def_map(krate); | 409 | let crate_def_map = self.crate_def_map(krate); |
410 | 410 | ||
411 | let mut fns = Vec::new(); | 411 | let mut fns = Vec::new(); |
412 | for (module_id, _) in crate_def_map.modules.iter() { | 412 | for (module_id, _) in crate_def_map.modules() { |
413 | for decl in crate_def_map[module_id].scope.declarations() { | 413 | for decl in crate_def_map[module_id].scope.declarations() { |
414 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | 414 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); |
415 | validate_module_item(self, krate, decl, &mut sink); | 415 | validate_module_item(self, krate, decl, &mut sink); |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 9bf3b51b0..d7351d212 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -491,7 +491,10 @@ impl<'a> InferenceContext<'a> { | |||
491 | Expr::Box { expr } => { | 491 | Expr::Box { expr } => { |
492 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | 492 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
493 | if let Some(box_) = self.resolve_boxed_box() { | 493 | if let Some(box_) = self.resolve_boxed_box() { |
494 | Ty::apply_one(TypeCtor::Adt(box_), inner_ty) | 494 | let mut sb = Substs::build_for_type_ctor(self.db, TypeCtor::Adt(box_)); |
495 | sb = sb.push(inner_ty); | ||
496 | sb = sb.fill(repeat_with(|| self.table.new_type_var())); | ||
497 | Ty::apply(TypeCtor::Adt(box_), sb.build()) | ||
495 | } else { | 498 | } else { |
496 | Ty::Unknown | 499 | Ty::Unknown |
497 | } | 500 | } |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 8a289f52a..f06aeeb42 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -112,7 +112,7 @@ impl TraitImpls { | |||
112 | let mut impls = Self { map: FxHashMap::default() }; | 112 | let mut impls = Self { map: FxHashMap::default() }; |
113 | 113 | ||
114 | let crate_def_map = db.crate_def_map(krate); | 114 | let crate_def_map = db.crate_def_map(krate); |
115 | for (_module_id, module_data) in crate_def_map.modules.iter() { | 115 | for (_module_id, module_data) in crate_def_map.modules() { |
116 | for impl_id in module_data.scope.impls() { | 116 | for impl_id in module_data.scope.impls() { |
117 | let target_trait = match db.impl_trait(impl_id) { | 117 | let target_trait = match db.impl_trait(impl_id) { |
118 | Some(tr) => tr.value.trait_, | 118 | Some(tr) => tr.value.trait_, |
@@ -198,7 +198,7 @@ impl InherentImpls { | |||
198 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); | 198 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); |
199 | 199 | ||
200 | let crate_def_map = db.crate_def_map(krate); | 200 | let crate_def_map = db.crate_def_map(krate); |
201 | for (_module_id, module_data) in crate_def_map.modules.iter() { | 201 | for (_module_id, module_data) in crate_def_map.modules() { |
202 | for impl_id in module_data.scope.impls() { | 202 | for impl_id in module_data.scope.impls() { |
203 | let data = db.impl_data(impl_id); | 203 | let data = db.impl_data(impl_id); |
204 | if data.target_trait.is_some() { | 204 | if data.target_trait.is_some() { |
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs index 646e16bbe..3bbcbc242 100644 --- a/crates/hir_ty/src/test_db.rs +++ b/crates/hir_ty/src/test_db.rs | |||
@@ -81,7 +81,7 @@ impl TestDB { | |||
81 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { | 81 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { |
82 | for &krate in self.relevant_crates(file_id).iter() { | 82 | for &krate in self.relevant_crates(file_id).iter() { |
83 | let crate_def_map = self.crate_def_map(krate); | 83 | let crate_def_map = self.crate_def_map(krate); |
84 | for (local_id, data) in crate_def_map.modules.iter() { | 84 | for (local_id, data) in crate_def_map.modules() { |
85 | if data.origin.file_id() == Some(file_id) { | 85 | if data.origin.file_id() == Some(file_id) { |
86 | return ModuleId { krate, local_id }; | 86 | return ModuleId { krate, local_id }; |
87 | } | 87 | } |
@@ -95,7 +95,7 @@ impl TestDB { | |||
95 | let crate_graph = self.crate_graph(); | 95 | let crate_graph = self.crate_graph(); |
96 | for krate in crate_graph.iter() { | 96 | for krate in crate_graph.iter() { |
97 | let crate_def_map = self.crate_def_map(krate); | 97 | let crate_def_map = self.crate_def_map(krate); |
98 | for (module_id, _) in crate_def_map.modules.iter() { | 98 | for (module_id, _) in crate_def_map.modules() { |
99 | let file_id = crate_def_map[module_id].origin.file_id(); | 99 | let file_id = crate_def_map[module_id].origin.file_id(); |
100 | files.extend(file_id) | 100 | files.extend(file_id) |
101 | } | 101 | } |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 8d431b920..16682f76f 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -29,6 +29,30 @@ mod boxed { | |||
29 | } | 29 | } |
30 | 30 | ||
31 | #[test] | 31 | #[test] |
32 | fn infer_box_with_allocator() { | ||
33 | check_types( | ||
34 | r#" | ||
35 | //- /main.rs crate:main deps:std | ||
36 | fn test() { | ||
37 | let x = box 1; | ||
38 | let t = (x, box x, box &1, box [1]); | ||
39 | t; | ||
40 | } //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; _], {unknown}>) | ||
41 | |||
42 | //- /std.rs crate:std | ||
43 | #[prelude_import] use prelude::*; | ||
44 | mod boxed { | ||
45 | #[lang = "owned_box"] | ||
46 | pub struct Box<T: ?Sized, A: Allocator> { | ||
47 | inner: *mut T, | ||
48 | allocator: A, | ||
49 | } | ||
50 | } | ||
51 | "#, | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
32 | fn infer_adt_self() { | 56 | fn infer_adt_self() { |
33 | check_types( | 57 | check_types( |
34 | r#" | 58 | r#" |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 8d08e4763..16fa828ad 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -130,8 +130,7 @@ impl NavigationTarget { | |||
130 | node: InFile<&dyn ast::NameOwner>, | 130 | node: InFile<&dyn ast::NameOwner>, |
131 | kind: SymbolKind, | 131 | kind: SymbolKind, |
132 | ) -> NavigationTarget { | 132 | ) -> NavigationTarget { |
133 | let name = | 133 | let name = node.value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into()); |
134 | node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); | ||
135 | let focus_range = | 134 | let focus_range = |
136 | node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range); | 135 | node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range); |
137 | let frange = node.map(|it| it.syntax()).original_file_range(db); | 136 | let frange = node.map(|it| it.syntax()).original_file_range(db); |
@@ -272,6 +271,7 @@ impl ToNav for hir::Module { | |||
272 | ModuleSource::Module(node) => { | 271 | ModuleSource::Module(node) => { |
273 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) | 272 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) |
274 | } | 273 | } |
274 | ModuleSource::BlockExpr(node) => (node.syntax(), None), | ||
275 | }; | 275 | }; |
276 | let frange = src.with_value(syntax).original_file_range(db); | 276 | let frange = src.with_value(syntax).original_file_range(db); |
277 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module) | 277 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module) |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index 990f740b8..7ac050473 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -53,6 +53,12 @@ impl ShortLabel for ast::SourceFile { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | impl ShortLabel for ast::BlockExpr { | ||
57 | fn short_label(&self) -> Option<String> { | ||
58 | None | ||
59 | } | ||
60 | } | ||
61 | |||
56 | impl ShortLabel for ast::TypeAlias { | 62 | impl ShortLabel for ast::TypeAlias { |
57 | fn short_label(&self) -> Option<String> { | 63 | fn short_label(&self) -> Option<String> { |
58 | short_label_from_node(self, "type ") | 64 | short_label_from_node(self, "type ") |
@@ -90,7 +96,7 @@ impl ShortLabel for ast::Variant { | |||
90 | impl ShortLabel for ast::ConstParam { | 96 | impl ShortLabel for ast::ConstParam { |
91 | fn short_label(&self) -> Option<String> { | 97 | fn short_label(&self) -> Option<String> { |
92 | let mut buf = "const ".to_owned(); | 98 | let mut buf = "const ".to_owned(); |
93 | buf.push_str(self.name()?.text().as_str()); | 99 | buf.push_str(self.name()?.text()); |
94 | if let Some(type_ref) = self.ty() { | 100 | if let Some(type_ref) = self.ty() { |
95 | format_to!(buf, ": {}", type_ref.syntax()); | 101 | format_to!(buf, ": {}", type_ref.syntax()); |
96 | } | 102 | } |
@@ -117,6 +123,6 @@ where | |||
117 | { | 123 | { |
118 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default(); | 124 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default(); |
119 | buf.push_str(label); | 125 | buf.push_str(label); |
120 | buf.push_str(node.name()?.text().as_str()); | 126 | buf.push_str(node.name()?.text()); |
121 | Some(buf) | 127 | Some(buf) |
122 | } | 128 | } |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 1f08d7810..730e0dd0a 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -221,14 +221,31 @@ fn rewrite_intra_doc_link( | |||
221 | }?; | 221 | }?; |
222 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
223 | let canonical_path = resolved.canonical_path(db)?; | 223 | let canonical_path = resolved.canonical_path(db)?; |
224 | let new_target = get_doc_url(db, &krate)? | 224 | let mut new_url = get_doc_url(db, &krate)? |
225 | .join(&format!("{}/", krate.display_name(db)?)) | 225 | .join(&format!("{}/", krate.display_name(db)?)) |
226 | .ok()? | 226 | .ok()? |
227 | .join(&canonical_path.replace("::", "/")) | 227 | .join(&canonical_path.replace("::", "/")) |
228 | .ok()? | 228 | .ok()? |
229 | .join(&get_symbol_filename(db, &resolved)?) | 229 | .join(&get_symbol_filename(db, &resolved)?) |
230 | .ok()? | 230 | .ok()?; |
231 | .into_string(); | 231 | |
232 | if let ModuleDef::Trait(t) = resolved { | ||
233 | let items = t.items(db); | ||
234 | if let Some(field_or_assoc_item) = items.iter().find_map(|assoc_item| { | ||
235 | if let Some(name) = assoc_item.name(db) { | ||
236 | if link.to_string() == format!("{}::{}", canonical_path, name) { | ||
237 | return Some(FieldOrAssocItem::AssocItem(*assoc_item)); | ||
238 | } | ||
239 | } | ||
240 | None | ||
241 | }) { | ||
242 | if let Some(fragment) = get_symbol_fragment(db, &field_or_assoc_item) { | ||
243 | new_url = new_url.join(&fragment).ok()?; | ||
244 | } | ||
245 | }; | ||
246 | } | ||
247 | |||
248 | let new_target = new_url.into_string(); | ||
232 | let new_title = strip_prefixes_suffixes(title); | 249 | let new_title = strip_prefixes_suffixes(title); |
233 | Some((new_target, new_title.to_string())) | 250 | Some((new_target, new_title.to_string())) |
234 | } | 251 | } |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 17a540972..2d722dee0 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -213,8 +213,8 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange | |||
213 | let ws_text = ws.text(); | 213 | let ws_text = ws.text(); |
214 | let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start(); | 214 | let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start(); |
215 | let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); | 215 | let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); |
216 | let ws_suffix = &ws_text.as_str()[suffix]; | 216 | let ws_suffix = &ws_text[suffix]; |
217 | let ws_prefix = &ws_text.as_str()[prefix]; | 217 | let ws_prefix = &ws_text[prefix]; |
218 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { | 218 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { |
219 | if let Some(node) = ws.next_sibling_or_token() { | 219 | if let Some(node) = ws.next_sibling_or_token() { |
220 | let start = match ws_prefix.rfind('\n') { | 220 | let start = match ws_prefix.rfind('\n') { |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index a1d2bce1d..1a997fa40 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -2,16 +2,14 @@ use either::Either; | |||
2 | use hir::{HasAttrs, ModuleDef, Semantics}; | 2 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | defs::{Definition, NameClass, NameRefClass}, | 4 | defs::{Definition, NameClass, NameRefClass}, |
5 | symbol_index, RootDatabase, | 5 | RootDatabase, |
6 | }; | 6 | }; |
7 | use syntax::{ | 7 | use syntax::{ |
8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, | 8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | display::{ToNav, TryToNav}, | 12 | display::TryToNav, doc_links::extract_definitions_from_markdown, runnables::doc_owner_to_def, |
13 | doc_links::extract_definitions_from_markdown, | ||
14 | runnables::doc_owner_to_def, | ||
15 | FilePosition, NavigationTarget, RangeInfo, | 13 | FilePosition, NavigationTarget, RangeInfo, |
16 | }; | 14 | }; |
17 | 15 | ||
@@ -38,28 +36,26 @@ pub(crate) fn goto_definition( | |||
38 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | 36 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); |
39 | } | 37 | } |
40 | 38 | ||
41 | let nav_targets = match_ast! { | 39 | let nav = match_ast! { |
42 | match parent { | 40 | match parent { |
43 | ast::NameRef(name_ref) => { | 41 | ast::NameRef(name_ref) => { |
44 | reference_definition(&sema, Either::Right(&name_ref)).to_vec() | 42 | reference_definition(&sema, Either::Right(&name_ref)) |
45 | }, | 43 | }, |
46 | ast::Name(name) => { | 44 | ast::Name(name) => { |
47 | let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); | 45 | let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); |
48 | let nav = def.try_to_nav(sema.db)?; | 46 | def.try_to_nav(sema.db) |
49 | vec![nav] | ||
50 | }, | 47 | }, |
51 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { | 48 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { |
52 | let def = name_class.referenced_or_defined(sema.db); | 49 | let def = name_class.referenced_or_defined(sema.db); |
53 | let nav = def.try_to_nav(sema.db)?; | 50 | def.try_to_nav(sema.db) |
54 | vec![nav] | ||
55 | } else { | 51 | } else { |
56 | reference_definition(&sema, Either::Left(<)).to_vec() | 52 | reference_definition(&sema, Either::Left(<)) |
57 | }, | 53 | }, |
58 | _ => return None, | 54 | _ => return None, |
59 | } | 55 | } |
60 | }; | 56 | }; |
61 | 57 | ||
62 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) | 58 | Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect())) |
63 | } | 59 | } |
64 | 60 | ||
65 | fn def_for_doc_comment( | 61 | fn def_for_doc_comment( |
@@ -120,42 +116,16 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
120 | } | 116 | } |
121 | } | 117 | } |
122 | 118 | ||
123 | #[derive(Debug)] | ||
124 | pub(crate) enum ReferenceResult { | ||
125 | Exact(NavigationTarget), | ||
126 | Approximate(Vec<NavigationTarget>), | ||
127 | } | ||
128 | |||
129 | impl ReferenceResult { | ||
130 | fn to_vec(self) -> Vec<NavigationTarget> { | ||
131 | match self { | ||
132 | ReferenceResult::Exact(target) => vec![target], | ||
133 | ReferenceResult::Approximate(vec) => vec, | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | pub(crate) fn reference_definition( | 119 | pub(crate) fn reference_definition( |
139 | sema: &Semantics<RootDatabase>, | 120 | sema: &Semantics<RootDatabase>, |
140 | name_ref: Either<&ast::Lifetime, &ast::NameRef>, | 121 | name_ref: Either<&ast::Lifetime, &ast::NameRef>, |
141 | ) -> ReferenceResult { | 122 | ) -> Option<NavigationTarget> { |
142 | let name_kind = name_ref.either( | 123 | let name_kind = name_ref.either( |
143 | |lifetime| NameRefClass::classify_lifetime(sema, lifetime), | 124 | |lifetime| NameRefClass::classify_lifetime(sema, lifetime), |
144 | |name_ref| NameRefClass::classify(sema, name_ref), | 125 | |name_ref| NameRefClass::classify(sema, name_ref), |
145 | ); | 126 | )?; |
146 | if let Some(def) = name_kind { | 127 | let def = name_kind.referenced(sema.db); |
147 | let def = def.referenced(sema.db); | 128 | def.try_to_nav(sema.db) |
148 | return match def.try_to_nav(sema.db) { | ||
149 | Some(nav) => ReferenceResult::Exact(nav), | ||
150 | None => ReferenceResult::Approximate(Vec::new()), | ||
151 | }; | ||
152 | } | ||
153 | |||
154 | // Fallback index based approach: | ||
155 | let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text); | ||
156 | let navs = | ||
157 | symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect(); | ||
158 | ReferenceResult::Approximate(navs) | ||
159 | } | 129 | } |
160 | 130 | ||
161 | #[cfg(test)] | 131 | #[cfg(test)] |
@@ -192,12 +162,12 @@ mod tests { | |||
192 | fn goto_def_for_extern_crate() { | 162 | fn goto_def_for_extern_crate() { |
193 | check( | 163 | check( |
194 | r#" | 164 | r#" |
195 | //- /main.rs crate:main deps:std | 165 | //- /main.rs crate:main deps:std |
196 | extern crate std$0; | 166 | extern crate std$0; |
197 | //- /std/lib.rs crate:std | 167 | //- /std/lib.rs crate:std |
198 | // empty | 168 | // empty |
199 | //^ file | 169 | //^ file |
200 | "#, | 170 | "#, |
201 | ) | 171 | ) |
202 | } | 172 | } |
203 | 173 | ||
@@ -205,12 +175,12 @@ mod tests { | |||
205 | fn goto_def_for_renamed_extern_crate() { | 175 | fn goto_def_for_renamed_extern_crate() { |
206 | check( | 176 | check( |
207 | r#" | 177 | r#" |
208 | //- /main.rs crate:main deps:std | 178 | //- /main.rs crate:main deps:std |
209 | extern crate std as abc$0; | 179 | extern crate std as abc$0; |
210 | //- /std/lib.rs crate:std | 180 | //- /std/lib.rs crate:std |
211 | // empty | 181 | // empty |
212 | //^ file | 182 | //^ file |
213 | "#, | 183 | "#, |
214 | ) | 184 | ) |
215 | } | 185 | } |
216 | 186 | ||
@@ -297,13 +267,13 @@ fn bar() { | |||
297 | fn goto_def_for_macros_from_other_crates() { | 267 | fn goto_def_for_macros_from_other_crates() { |
298 | check( | 268 | check( |
299 | r#" | 269 | r#" |
300 | //- /lib.rs | 270 | //- /lib.rs crate:main deps:foo |
301 | use foo::foo; | 271 | use foo::foo; |
302 | fn bar() { | 272 | fn bar() { |
303 | $0foo!(); | 273 | $0foo!(); |
304 | } | 274 | } |
305 | 275 | ||
306 | //- /foo/lib.rs | 276 | //- /foo/lib.rs crate:foo |
307 | #[macro_export] | 277 | #[macro_export] |
308 | macro_rules! foo { () => { () } } | 278 | macro_rules! foo { () => { () } } |
309 | //^^^ | 279 | //^^^ |
@@ -315,10 +285,10 @@ macro_rules! foo { () => { () } } | |||
315 | fn goto_def_for_macros_in_use_tree() { | 285 | fn goto_def_for_macros_in_use_tree() { |
316 | check( | 286 | check( |
317 | r#" | 287 | r#" |
318 | //- /lib.rs | 288 | //- /lib.rs crate:main deps:foo |
319 | use foo::foo$0; | 289 | use foo::foo$0; |
320 | 290 | ||
321 | //- /foo/lib.rs | 291 | //- /foo/lib.rs crate:foo |
322 | #[macro_export] | 292 | #[macro_export] |
323 | macro_rules! foo { () => { () } } | 293 | macro_rules! foo { () => { () } } |
324 | //^^^ | 294 | //^^^ |
@@ -976,10 +946,10 @@ type Alias<T> = T$0; | |||
976 | fn goto_def_for_macro_container() { | 946 | fn goto_def_for_macro_container() { |
977 | check( | 947 | check( |
978 | r#" | 948 | r#" |
979 | //- /lib.rs | 949 | //- /lib.rs crate:main deps:foo |
980 | foo::module$0::mac!(); | 950 | foo::module$0::mac!(); |
981 | 951 | ||
982 | //- /foo/lib.rs | 952 | //- /foo/lib.rs crate:foo |
983 | pub mod module { | 953 | pub mod module { |
984 | //^^^^^^ | 954 | //^^^^^^ |
985 | #[macro_export] | 955 | #[macro_export] |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 44ebdbd35..d47a4cb0f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -321,6 +321,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
321 | match it.definition_source(db).value { | 321 | match it.definition_source(db).value { |
322 | ModuleSource::Module(it) => it.short_label(), | 322 | ModuleSource::Module(it) => it.short_label(), |
323 | ModuleSource::SourceFile(it) => it.short_label(), | 323 | ModuleSource::SourceFile(it) => it.short_label(), |
324 | ModuleSource::BlockExpr(it) => it.short_label(), | ||
324 | }, | 325 | }, |
325 | mod_path, | 326 | mod_path, |
326 | ), | 327 | ), |
@@ -1825,6 +1826,35 @@ pub struct B$0ar | |||
1825 | "#]], | 1826 | "#]], |
1826 | ); | 1827 | ); |
1827 | } | 1828 | } |
1829 | #[test] | ||
1830 | fn test_hover_intra_link_reference_to_trait_method() { | ||
1831 | check( | ||
1832 | r#" | ||
1833 | pub trait Foo { | ||
1834 | fn buzz() -> usize; | ||
1835 | } | ||
1836 | /// [Foo][buzz] | ||
1837 | /// | ||
1838 | /// [buzz]: Foo::buzz | ||
1839 | pub struct B$0ar | ||
1840 | "#, | ||
1841 | expect | ||
1855 | "#]], | ||
1856 | ); | ||
1857 | } | ||
1828 | 1858 | ||
1829 | #[test] | 1859 | #[test] |
1830 | fn test_hover_external_url() { | 1860 | fn test_hover_external_url() { |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index a2039fcc7..54485fd30 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -411,7 +411,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
411 | match expr { | 411 | match expr { |
412 | ast::Expr::MethodCallExpr(method_call_expr) => { | 412 | ast::Expr::MethodCallExpr(method_call_expr) => { |
413 | let name_ref = method_call_expr.name_ref()?; | 413 | let name_ref = method_call_expr.name_ref()?; |
414 | match name_ref.text().as_str() { | 414 | match name_ref.text() { |
415 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), | 415 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), |
416 | name_ref => Some(name_ref.to_owned()), | 416 | name_ref => Some(name_ref.to_owned()), |
417 | } | 417 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 981467c8d..631bde0f1 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -59,7 +59,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
59 | // The node is either the first or the last in the file | 59 | // The node is either the first or the last in the file |
60 | let suff = &token.text()[TextRange::new( | 60 | let suff = &token.text()[TextRange::new( |
61 | offset - token.text_range().start() + TextSize::of('\n'), | 61 | offset - token.text_range().start() + TextSize::of('\n'), |
62 | TextSize::of(token.text().as_str()), | 62 | TextSize::of(token.text()), |
63 | )]; | 63 | )]; |
64 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); | 64 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); |
65 | 65 | ||
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index e282b31af..33170906d 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -9,6 +9,7 @@ use syntax::{ | |||
9 | ast::{self, AstNode, AttrsOwner}, | 9 | ast::{self, AstNode, AttrsOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | use test_utils::mark; | ||
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | display::{ToNav, TryToNav}, | 15 | display::{ToNav, TryToNav}, |
@@ -96,28 +97,26 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 97 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 98 | let sema = Semantics::new(db); |
98 | let module = match sema.to_module_def(file_id) { | 99 | let module = match sema.to_module_def(file_id) { |
99 | None => return vec![], | 100 | None => return Vec::new(), |
100 | Some(it) => it, | 101 | Some(it) => it, |
101 | }; | 102 | }; |
102 | 103 | ||
103 | runnables_mod(&sema, module) | 104 | let mut res = Vec::new(); |
105 | runnables_mod(&sema, &mut res, module); | ||
106 | res | ||
104 | } | 107 | } |
105 | 108 | ||
106 | fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Runnable> { | 109 | fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module: hir::Module) { |
107 | let mut res: Vec<Runnable> = module | 110 | acc.extend(module.declarations(sema.db).into_iter().filter_map(|def| { |
108 | .declarations(sema.db) | 111 | let runnable = match def { |
109 | .into_iter() | 112 | hir::ModuleDef::Module(it) => runnable_mod(&sema, it), |
110 | .filter_map(|def| { | 113 | hir::ModuleDef::Function(it) => runnable_fn(&sema, it), |
111 | let runnable = match def { | 114 | _ => None, |
112 | hir::ModuleDef::Module(it) => runnable_mod(&sema, it), | 115 | }; |
113 | hir::ModuleDef::Function(it) => runnable_fn(&sema, it), | 116 | runnable.or_else(|| module_def_doctest(&sema, def)) |
114 | _ => None, | 117 | })); |
115 | }; | ||
116 | runnable.or_else(|| module_def_doctest(&sema, def)) | ||
117 | }) | ||
118 | .collect(); | ||
119 | 118 | ||
120 | res.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( | 119 | acc.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( |
121 | |def| match def { | 120 | |def| match def { |
122 | hir::AssocItem::Function(it) => { | 121 | hir::AssocItem::Function(it) => { |
123 | runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) | 122 | runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) |
@@ -127,12 +126,15 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Run | |||
127 | }, | 126 | }, |
128 | )); | 127 | )); |
129 | 128 | ||
130 | res.extend(module.declarations(sema.db).into_iter().flat_map(|def| match def { | 129 | for def in module.declarations(sema.db) { |
131 | hir::ModuleDef::Module(it) => runnables_mod(sema, it), | 130 | if let hir::ModuleDef::Module(submodule) = def { |
132 | _ => vec![], | 131 | match submodule.definition_source(sema.db).value { |
133 | })); | 132 | hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule), |
134 | 133 | hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules), | |
135 | res | 134 | hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable |
135 | } | ||
136 | } | ||
137 | } | ||
136 | } | 138 | } |
137 | 139 | ||
138 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { | 140 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
@@ -326,6 +328,7 @@ fn has_test_function_or_multiple_test_submodules( | |||
326 | #[cfg(test)] | 328 | #[cfg(test)] |
327 | mod tests { | 329 | mod tests { |
328 | use expect_test::{expect, Expect}; | 330 | use expect_test::{expect, Expect}; |
331 | use test_utils::mark; | ||
329 | 332 | ||
330 | use crate::fixture; | 333 | use crate::fixture; |
331 | 334 | ||
@@ -1050,4 +1053,25 @@ mod tests { | |||
1050 | "#]], | 1053 | "#]], |
1051 | ); | 1054 | ); |
1052 | } | 1055 | } |
1056 | |||
1057 | #[test] | ||
1058 | fn dont_recurse_in_outline_submodules() { | ||
1059 | mark::check!(dont_recurse_in_outline_submodules); | ||
1060 | check( | ||
1061 | r#" | ||
1062 | //- /lib.rs | ||
1063 | $0 | ||
1064 | mod m; | ||
1065 | //- /m.rs | ||
1066 | mod tests { | ||
1067 | #[test] | ||
1068 | fn t() {} | ||
1069 | } | ||
1070 | "#, | ||
1071 | &[], | ||
1072 | expect![[r#" | ||
1073 | [] | ||
1074 | "#]], | ||
1075 | ); | ||
1076 | } | ||
1053 | } | 1077 | } |
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index e10d7c3a4..137c38c0d 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs | |||
@@ -38,6 +38,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | |||
38 | format_to!(buf, "{}\n", syntax_tree_stats(db)); | 38 | format_to!(buf, "{}\n", syntax_tree_stats(db)); |
39 | format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); | 39 | format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); |
40 | format_to!(buf, "{} total\n", memory_usage()); | 40 | format_to!(buf, "{} total\n", memory_usage()); |
41 | format_to!(buf, "\ncounts:\n{}", profile::countme::get_all()); | ||
41 | 42 | ||
42 | if let Some(file_id) = file_id { | 43 | if let Some(file_id) = file_id { |
43 | format_to!(buf, "\nfile info:\n"); | 44 | format_to!(buf, "\nfile info:\n"); |
@@ -60,6 +61,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | |||
60 | None => format_to!(buf, "does not belong to any crate"), | 61 | None => format_to!(buf, "does not belong to any crate"), |
61 | } | 62 | } |
62 | } | 63 | } |
64 | |||
63 | buf | 65 | buf |
64 | } | 66 | } |
65 | 67 | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 63bff6376..8c67a0863 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> { | |||
31 | let parent = string.syntax().parent(); | 31 | let parent = string.syntax().parent(); |
32 | 32 | ||
33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | 33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; |
34 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { | 34 | if !matches!(name.text(), "format_args" | "format_args_nl") { |
35 | return None; | 35 | return None; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 281461493..8cdc3688f 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -116,7 +116,7 @@ pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | |||
116 | None => (), | 116 | None => (), |
117 | } | 117 | } |
118 | 118 | ||
119 | let line: &str = comment.text().as_str(); | 119 | let line: &str = comment.text(); |
120 | let range = comment.syntax().text_range(); | 120 | let range = comment.syntax().text_range(); |
121 | 121 | ||
122 | let mut pos = TextSize::of(comment.prefix()); | 122 | let mut pos = TextSize::of(comment.prefix()); |
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs index c770a236b..9d9b6de7a 100644 --- a/crates/ide_db/src/apply_change.rs +++ b/crates/ide_db/src/apply_change.rs | |||
@@ -149,6 +149,7 @@ impl RootDatabase { | |||
149 | 149 | ||
150 | // DefDatabase | 150 | // DefDatabase |
151 | hir::db::ItemTreeQuery | 151 | hir::db::ItemTreeQuery |
152 | hir::db::BlockDefMapQuery | ||
152 | hir::db::CrateDefMapQueryQuery | 153 | hir::db::CrateDefMapQueryQuery |
153 | hir::db::StructDataQuery | 154 | hir::db::StructDataQuery |
154 | hir::db::UnionDataQuery | 155 | hir::db::UnionDataQuery |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index d9875ffef..a8091dbee 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -343,7 +343,7 @@ impl NameRefClass { | |||
343 | hir::AssocItem::TypeAlias(it) => Some(*it), | 343 | hir::AssocItem::TypeAlias(it) => Some(*it), |
344 | _ => None, | 344 | _ => None, |
345 | }) | 345 | }) |
346 | .find(|alias| alias.name(sema.db).to_string() == **name_ref.text()) | 346 | .find(|alias| &alias.name(sema.db).to_string() == name_ref.text()) |
347 | { | 347 | { |
348 | return Some(NameRefClass::Definition(Definition::ModuleDef( | 348 | return Some(NameRefClass::Definition(Definition::ModuleDef( |
349 | ModuleDef::TypeAlias(ty), | 349 | ModuleDef::TypeAlias(ty), |
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 877d4f1c7..fd4035198 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -507,7 +507,7 @@ impl ImportGroup { | |||
507 | PathSegmentKind::SelfKw => ImportGroup::ThisModule, | 507 | PathSegmentKind::SelfKw => ImportGroup::ThisModule, |
508 | PathSegmentKind::SuperKw => ImportGroup::SuperModule, | 508 | PathSegmentKind::SuperKw => ImportGroup::SuperModule, |
509 | PathSegmentKind::CrateKw => ImportGroup::ThisCrate, | 509 | PathSegmentKind::CrateKw => ImportGroup::ThisCrate, |
510 | PathSegmentKind::Name(name) => match name.text().as_str() { | 510 | PathSegmentKind::Name(name) => match name.text() { |
511 | "std" => ImportGroup::Std, | 511 | "std" => ImportGroup::Std, |
512 | "core" => ImportGroup::Std, | 512 | "core" => ImportGroup::Std, |
513 | _ => ImportGroup::ExternCrate, | 513 | _ => ImportGroup::ExternCrate, |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 0ecb13a64..b9ba0aed5 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -228,6 +228,15 @@ impl Definition { | |||
228 | // so do nothing. | 228 | // so do nothing. |
229 | } | 229 | } |
230 | } | 230 | } |
231 | ModuleSource::BlockExpr(b) => { | ||
232 | if is_first { | ||
233 | let range = Some(b.syntax().text_range()); | ||
234 | res.insert(file_id, range); | ||
235 | } else { | ||
236 | // We have already added the enclosing file to the search scope, | ||
237 | // so do nothing. | ||
238 | } | ||
239 | } | ||
231 | ModuleSource::SourceFile(_) => { | 240 | ModuleSource::SourceFile(_) => { |
232 | res.insert(file_id, None); | 241 | res.insert(file_id, None); |
233 | } | 242 | } |
@@ -257,6 +266,7 @@ impl Definition { | |||
257 | let mut res = FxHashMap::default(); | 266 | let mut res = FxHashMap::default(); |
258 | let range = match module_src.value { | 267 | let range = match module_src.value { |
259 | ModuleSource::Module(m) => Some(m.syntax().text_range()), | 268 | ModuleSource::Module(m) => Some(m.syntax().text_range()), |
269 | ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), | ||
260 | ModuleSource::SourceFile(_) => None, | 270 | ModuleSource::SourceFile(_) => None, |
261 | }; | 271 | }; |
262 | res.insert(file_id, range); | 272 | res.insert(file_id, range); |
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 0aa6a0765..e954bd72e 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs | |||
@@ -191,7 +191,7 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil | |||
191 | 191 | ||
192 | let def_map = db.crate_def_map(krate); | 192 | let def_map = db.crate_def_map(krate); |
193 | let mut files = Vec::new(); | 193 | let mut files = Vec::new(); |
194 | let mut modules = vec![def_map.root]; | 194 | let mut modules = vec![def_map.root()]; |
195 | while let Some(module) = modules.pop() { | 195 | while let Some(module) = modules.pop() { |
196 | let data = &def_map[module]; | 196 | let data = &def_map[module]; |
197 | files.extend(data.origin.file_id()); | 197 | files.extend(data.origin.file_id()); |
@@ -209,7 +209,7 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<Fil | |||
209 | query.search(&buf) | 209 | query.search(&buf) |
210 | } | 210 | } |
211 | 211 | ||
212 | pub fn index_resolve(db: &RootDatabase, name: &SmolStr) -> Vec<FileSymbol> { | 212 | pub fn index_resolve(db: &RootDatabase, name: &str) -> Vec<FileSymbol> { |
213 | let mut query = Query::new(name.to_string()); | 213 | let mut query = Query::new(name.to_string()); |
214 | query.exact(); | 214 | query.exact(); |
215 | query.limit(4); | 215 | query.limit(4); |
@@ -409,7 +409,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { | |||
409 | fn decl<N: NameOwner>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { | 409 | fn decl<N: NameOwner>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { |
410 | let name = node.name()?; | 410 | let name = node.name()?; |
411 | let name_range = name.syntax().text_range(); | 411 | let name_range = name.syntax().text_range(); |
412 | let name = name.text().clone(); | 412 | let name = name.text().into(); |
413 | let ptr = SyntaxNodePtr::new(node.syntax()); | 413 | let ptr = SyntaxNodePtr::new(node.syntax()); |
414 | 414 | ||
415 | Some((name, ptr, name_range)) | 415 | Some((name, ptr, name_range)) |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 51002e7b8..0cdc175be 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -507,7 +507,7 @@ impl SrcToken for SynToken { | |||
507 | } | 507 | } |
508 | } | 508 | } |
509 | fn to_text(&self) -> SmolStr { | 509 | fn to_text(&self) -> SmolStr { |
510 | self.token().text().clone() | 510 | self.token().text().into() |
511 | } | 511 | } |
512 | } | 512 | } |
513 | 513 | ||
@@ -682,10 +682,8 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
682 | self.text_pos += TextSize::of(text); | 682 | self.text_pos += TextSize::of(text); |
683 | } | 683 | } |
684 | 684 | ||
685 | let text = SmolStr::new(self.buf.as_str()); | 685 | self.inner.token(kind, self.buf.as_str()); |
686 | self.buf.clear(); | 686 | self.buf.clear(); |
687 | self.inner.token(kind, text); | ||
688 | |||
689 | // Add whitespace between adjoint puncts | 687 | // Add whitespace between adjoint puncts |
690 | let next = last.bump(); | 688 | let next = last.bump(); |
691 | if let ( | 689 | if let ( |
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index f7231c2b8..cc7da27f7 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml | |||
@@ -14,6 +14,7 @@ once_cell = "1.3.1" | |||
14 | cfg-if = "1" | 14 | cfg-if = "1" |
15 | libc = "0.2.73" | 15 | libc = "0.2.73" |
16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | countme = { version = "2.0.0-pre.2", features = ["enable"] } | ||
17 | jemalloc-ctl = { version = "0.3.3", optional = true } | 18 | jemalloc-ctl = { version = "0.3.3", optional = true } |
18 | 19 | ||
19 | [target.'cfg(target_os = "linux")'.dependencies] | 20 | [target.'cfg(target_os = "linux")'.dependencies] |
diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs index 8957ea016..29d2ed518 100644 --- a/crates/profile/src/hprof.rs +++ b/crates/profile/src/hprof.rs | |||
@@ -3,6 +3,7 @@ use once_cell::sync::Lazy; | |||
3 | use std::{ | 3 | use std::{ |
4 | cell::RefCell, | 4 | cell::RefCell, |
5 | collections::{BTreeMap, HashSet}, | 5 | collections::{BTreeMap, HashSet}, |
6 | env, | ||
6 | io::{stderr, Write}, | 7 | io::{stderr, Write}, |
7 | sync::{ | 8 | sync::{ |
8 | atomic::{AtomicBool, Ordering}, | 9 | atomic::{AtomicBool, Ordering}, |
@@ -18,7 +19,8 @@ use crate::tree::{Idx, Tree}; | |||
18 | /// env RA_PROFILE=foo|bar|baz // enabled only selected entries | 19 | /// env RA_PROFILE=foo|bar|baz // enabled only selected entries |
19 | /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms | 20 | /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms |
20 | pub fn init() { | 21 | pub fn init() { |
21 | let spec = std::env::var("RA_PROFILE").unwrap_or_default(); | 22 | countme::enable(env::var("RA_COUNT").is_ok()); |
23 | let spec = env::var("RA_PROFILE").unwrap_or_default(); | ||
22 | init_from(&spec); | 24 | init_from(&spec); |
23 | } | 25 | } |
24 | 26 | ||
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs index aa6ccc36c..79dba47d5 100644 --- a/crates/profile/src/lib.rs +++ b/crates/profile/src/lib.rs | |||
@@ -15,6 +15,13 @@ pub use crate::{ | |||
15 | stop_watch::{StopWatch, StopWatchSpan}, | 15 | stop_watch::{StopWatch, StopWatchSpan}, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub use countme; | ||
19 | /// Include `_c: Count<Self>` field in important structs to count them. | ||
20 | /// | ||
21 | /// To view the counts, run with `RA_COUNT=1`. The overhead of disabled count is | ||
22 | /// almost zero. | ||
23 | pub use countme::Count; | ||
24 | |||
18 | thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false)); | 25 | thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false)); |
19 | 26 | ||
20 | /// Allows to check if the current code is withing some dynamic scope, can be | 27 | /// Allows to check if the current code is withing some dynamic scope, can be |
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs new file mode 100644 index 000000000..cf32995e0 --- /dev/null +++ b/crates/project_model/src/build_data.rs | |||
@@ -0,0 +1,206 @@ | |||
1 | //! Handles build script specific information | ||
2 | |||
3 | use std::{ | ||
4 | ffi::OsStr, | ||
5 | io::BufReader, | ||
6 | path::{Path, PathBuf}, | ||
7 | process::{Command, Stdio}, | ||
8 | }; | ||
9 | |||
10 | use anyhow::Result; | ||
11 | use cargo_metadata::{BuildScript, Message, Package, PackageId}; | ||
12 | use itertools::Itertools; | ||
13 | use paths::{AbsPath, AbsPathBuf}; | ||
14 | use rustc_hash::FxHashMap; | ||
15 | use stdx::JodChild; | ||
16 | |||
17 | use crate::{cfg_flag::CfgFlag, CargoConfig}; | ||
18 | |||
19 | #[derive(Debug, Clone, Default)] | ||
20 | pub(crate) struct BuildDataMap { | ||
21 | data: FxHashMap<PackageId, BuildData>, | ||
22 | } | ||
23 | #[derive(Debug, Clone, Default, PartialEq, Eq)] | ||
24 | pub struct BuildData { | ||
25 | /// List of config flags defined by this package's build script | ||
26 | pub cfgs: Vec<CfgFlag>, | ||
27 | /// List of cargo-related environment variables with their value | ||
28 | /// | ||
29 | /// If the package has a build script which defines environment variables, | ||
30 | /// they can also be found here. | ||
31 | pub envs: Vec<(String, String)>, | ||
32 | /// Directory where a build script might place its output | ||
33 | pub out_dir: Option<AbsPathBuf>, | ||
34 | /// Path to the proc-macro library file if this package exposes proc-macros | ||
35 | pub proc_macro_dylib_path: Option<AbsPathBuf>, | ||
36 | } | ||
37 | |||
38 | impl BuildDataMap { | ||
39 | pub(crate) fn new( | ||
40 | cargo_toml: &AbsPath, | ||
41 | cargo_features: &CargoConfig, | ||
42 | packages: &Vec<Package>, | ||
43 | progress: &dyn Fn(String), | ||
44 | ) -> Result<BuildDataMap> { | ||
45 | let mut cmd = Command::new(toolchain::cargo()); | ||
46 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) | ||
47 | .arg(cargo_toml.as_ref()); | ||
48 | |||
49 | // --all-targets includes tests, benches and examples in addition to the | ||
50 | // default lib and bins. This is an independent concept from the --targets | ||
51 | // flag below. | ||
52 | cmd.arg("--all-targets"); | ||
53 | |||
54 | if let Some(target) = &cargo_features.target { | ||
55 | cmd.args(&["--target", target]); | ||
56 | } | ||
57 | |||
58 | if cargo_features.all_features { | ||
59 | cmd.arg("--all-features"); | ||
60 | } else { | ||
61 | if cargo_features.no_default_features { | ||
62 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
63 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
64 | cmd.arg("--no-default-features"); | ||
65 | } | ||
66 | if !cargo_features.features.is_empty() { | ||
67 | cmd.arg("--features"); | ||
68 | cmd.arg(cargo_features.features.join(" ")); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); | ||
73 | |||
74 | let mut child = cmd.spawn().map(JodChild)?; | ||
75 | let child_stdout = child.stdout.take().unwrap(); | ||
76 | let stdout = BufReader::new(child_stdout); | ||
77 | |||
78 | let mut res = BuildDataMap::default(); | ||
79 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
80 | if let Ok(message) = message { | ||
81 | match message { | ||
82 | Message::BuildScriptExecuted(BuildScript { | ||
83 | package_id, | ||
84 | out_dir, | ||
85 | cfgs, | ||
86 | env, | ||
87 | .. | ||
88 | }) => { | ||
89 | let cfgs = { | ||
90 | let mut acc = Vec::new(); | ||
91 | for cfg in cfgs { | ||
92 | match cfg.parse::<CfgFlag>() { | ||
93 | Ok(it) => acc.push(it), | ||
94 | Err(err) => { | ||
95 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
96 | } | ||
97 | }; | ||
98 | } | ||
99 | acc | ||
100 | }; | ||
101 | let res = res.data.entry(package_id.clone()).or_default(); | ||
102 | // cargo_metadata crate returns default (empty) path for | ||
103 | // older cargos, which is not absolute, so work around that. | ||
104 | if out_dir != PathBuf::default() { | ||
105 | let out_dir = AbsPathBuf::assert(out_dir); | ||
106 | res.out_dir = Some(out_dir); | ||
107 | res.cfgs = cfgs; | ||
108 | } | ||
109 | |||
110 | res.envs = env; | ||
111 | } | ||
112 | Message::CompilerArtifact(message) => { | ||
113 | progress(format!("metadata {}", message.target.name)); | ||
114 | |||
115 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
116 | let package_id = message.package_id; | ||
117 | // Skip rmeta file | ||
118 | if let Some(filename) = | ||
119 | message.filenames.iter().find(|name| is_dylib(name)) | ||
120 | { | ||
121 | let filename = AbsPathBuf::assert(filename.clone()); | ||
122 | let res = res.data.entry(package_id.clone()).or_default(); | ||
123 | res.proc_macro_dylib_path = Some(filename); | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | Message::CompilerMessage(message) => { | ||
128 | progress(message.target.name.clone()); | ||
129 | } | ||
130 | Message::Unknown => (), | ||
131 | Message::BuildFinished(_) => {} | ||
132 | Message::TextLine(_) => {} | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | res.inject_cargo_env(packages); | ||
137 | Ok(res) | ||
138 | } | ||
139 | |||
140 | pub(crate) fn with_cargo_env(packages: &Vec<Package>) -> Self { | ||
141 | let mut res = Self::default(); | ||
142 | res.inject_cargo_env(packages); | ||
143 | res | ||
144 | } | ||
145 | |||
146 | pub(crate) fn get(&self, id: &PackageId) -> Option<&BuildData> { | ||
147 | self.data.get(id) | ||
148 | } | ||
149 | |||
150 | fn inject_cargo_env(&mut self, packages: &Vec<Package>) { | ||
151 | for meta_pkg in packages { | ||
152 | let resource = self.data.entry(meta_pkg.id.clone()).or_default(); | ||
153 | inject_cargo_env(meta_pkg, &mut resource.envs); | ||
154 | |||
155 | if let Some(out_dir) = &resource.out_dir { | ||
156 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
157 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
158 | resource.envs.push(("OUT_DIR".to_string(), out_dir)); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // FIXME: File a better way to know if it is a dylib | ||
166 | fn is_dylib(path: &Path) -> bool { | ||
167 | match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) { | ||
168 | None => false, | ||
169 | Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), | ||
170 | } | ||
171 | } | ||
172 | |||
173 | /// Recreates the compile-time environment variables that Cargo sets. | ||
174 | /// | ||
175 | /// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> | ||
176 | fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { | ||
177 | // FIXME: Missing variables: | ||
178 | // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name> | ||
179 | |||
180 | let mut manifest_dir = package.manifest_path.clone(); | ||
181 | manifest_dir.pop(); | ||
182 | if let Some(cargo_manifest_dir) = manifest_dir.to_str() { | ||
183 | env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into())); | ||
184 | } | ||
185 | |||
186 | env.push(("CARGO_PKG_VERSION".into(), package.version.to_string())); | ||
187 | env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string())); | ||
188 | env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string())); | ||
189 | env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string())); | ||
190 | |||
191 | let pre = package.version.pre.iter().map(|id| id.to_string()).format("."); | ||
192 | env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string())); | ||
193 | |||
194 | let authors = package.authors.join(";"); | ||
195 | env.push(("CARGO_PKG_AUTHORS".into(), authors)); | ||
196 | |||
197 | env.push(("CARGO_PKG_NAME".into(), package.name.clone())); | ||
198 | env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default())); | ||
199 | //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default())); | ||
200 | env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default())); | ||
201 | env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default())); | ||
202 | |||
203 | let license_file = | ||
204 | package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default(); | ||
205 | env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file)); | ||
206 | } | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index c0ed37fc1..c8a5333c4 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,24 +1,15 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{convert::TryInto, ops, process::Command}; |
4 | convert::TryInto, | ||
5 | ffi::OsStr, | ||
6 | io::BufReader, | ||
7 | ops, | ||
8 | path::{Path, PathBuf}, | ||
9 | process::{Command, Stdio}, | ||
10 | }; | ||
11 | 4 | ||
12 | use anyhow::{Context, Result}; | 5 | use anyhow::{Context, Result}; |
13 | use base_db::Edition; | 6 | use base_db::Edition; |
14 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; | 7 | use cargo_metadata::{CargoOpt, MetadataCommand}; |
15 | use itertools::Itertools; | ||
16 | use la_arena::{Arena, Idx}; | 8 | use la_arena::{Arena, Idx}; |
17 | use paths::{AbsPath, AbsPathBuf}; | 9 | use paths::{AbsPath, AbsPathBuf}; |
18 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
19 | use stdx::JodChild; | ||
20 | 11 | ||
21 | use crate::cfg_flag::CfgFlag; | 12 | use crate::build_data::{BuildData, BuildDataMap}; |
22 | use crate::utf8_stdout; | 13 | use crate::utf8_stdout; |
23 | 14 | ||
24 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo | 15 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo |
@@ -99,19 +90,12 @@ pub struct PackageData { | |||
99 | pub dependencies: Vec<PackageDependency>, | 90 | pub dependencies: Vec<PackageDependency>, |
100 | /// Rust edition for this package | 91 | /// Rust edition for this package |
101 | pub edition: Edition, | 92 | pub edition: Edition, |
102 | /// List of features to activate | 93 | /// Features provided by the crate, mapped to the features required by that feature. |
103 | pub features: Vec<String>, | 94 | pub features: FxHashMap<String, Vec<String>>, |
104 | /// List of config flags defined by this package's build script | 95 | /// List of features enabled on this package |
105 | pub cfgs: Vec<CfgFlag>, | 96 | pub active_features: Vec<String>, |
106 | /// List of cargo-related environment variables with their value | 97 | /// Build script related data for this package |
107 | /// | 98 | pub build_data: BuildData, |
108 | /// If the package has a build script which defines environment variables, | ||
109 | /// they can also be found here. | ||
110 | pub envs: Vec<(String, String)>, | ||
111 | /// Directory where a build script might place its output | ||
112 | pub out_dir: Option<AbsPathBuf>, | ||
113 | /// Path to the proc-macro library file if this package exposes proc-macros | ||
114 | pub proc_macro_dylib_path: Option<AbsPathBuf>, | ||
115 | } | 99 | } |
116 | 100 | ||
117 | #[derive(Debug, Clone, Eq, PartialEq)] | 101 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -244,17 +228,11 @@ impl CargoWorkspace { | |||
244 | ) | 228 | ) |
245 | })?; | 229 | })?; |
246 | 230 | ||
247 | let mut out_dir_by_id = FxHashMap::default(); | 231 | let resources = if config.load_out_dirs_from_check { |
248 | let mut cfgs = FxHashMap::default(); | 232 | BuildDataMap::new(cargo_toml, config, &meta.packages, progress)? |
249 | let mut envs = FxHashMap::default(); | 233 | } else { |
250 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 234 | BuildDataMap::with_cargo_env(&meta.packages) |
251 | if config.load_out_dirs_from_check { | 235 | }; |
252 | let resources = load_extern_resources(cargo_toml, config, progress)?; | ||
253 | out_dir_by_id = resources.out_dirs; | ||
254 | cfgs = resources.cfgs; | ||
255 | envs = resources.env; | ||
256 | proc_macro_dylib_paths = resources.proc_dylib_paths; | ||
257 | } | ||
258 | 236 | ||
259 | let mut pkg_by_id = FxHashMap::default(); | 237 | let mut pkg_by_id = FxHashMap::default(); |
260 | let mut packages = Arena::default(); | 238 | let mut packages = Arena::default(); |
@@ -265,7 +243,7 @@ impl CargoWorkspace { | |||
265 | meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); | 243 | meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); |
266 | for meta_pkg in meta.packages { | 244 | for meta_pkg in meta.packages { |
267 | let id = meta_pkg.id.clone(); | 245 | let id = meta_pkg.id.clone(); |
268 | inject_cargo_env(&meta_pkg, envs.entry(id).or_default()); | 246 | let build_data = resources.get(&id).cloned().unwrap_or_default(); |
269 | 247 | ||
270 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = | 248 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = |
271 | meta_pkg; | 249 | meta_pkg; |
@@ -281,11 +259,9 @@ impl CargoWorkspace { | |||
281 | is_member, | 259 | is_member, |
282 | edition, | 260 | edition, |
283 | dependencies: Vec::new(), | 261 | dependencies: Vec::new(), |
284 | features: Vec::new(), | 262 | features: meta_pkg.features.into_iter().collect(), |
285 | cfgs: cfgs.get(&id).cloned().unwrap_or_default(), | 263 | active_features: Vec::new(), |
286 | envs: envs.get(&id).cloned().unwrap_or_default(), | 264 | build_data, |
287 | out_dir: out_dir_by_id.get(&id).cloned(), | ||
288 | proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(), | ||
289 | }); | 265 | }); |
290 | let pkg_data = &mut packages[pkg]; | 266 | let pkg_data = &mut packages[pkg]; |
291 | pkg_by_id.insert(id, pkg); | 267 | pkg_by_id.insert(id, pkg); |
@@ -328,7 +304,7 @@ impl CargoWorkspace { | |||
328 | let dep = PackageDependency { name: dep_node.name, pkg }; | 304 | let dep = PackageDependency { name: dep_node.name, pkg }; |
329 | packages[source].dependencies.push(dep); | 305 | packages[source].dependencies.push(dep); |
330 | } | 306 | } |
331 | packages[source].features.extend(node.features); | 307 | packages[source].active_features.extend(node.features); |
332 | } | 308 | } |
333 | 309 | ||
334 | let workspace_root = AbsPathBuf::assert(meta.workspace_root); | 310 | let workspace_root = AbsPathBuf::assert(meta.workspace_root); |
@@ -362,149 +338,3 @@ impl CargoWorkspace { | |||
362 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 | 338 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 |
363 | } | 339 | } |
364 | } | 340 | } |
365 | |||
366 | #[derive(Debug, Clone, Default)] | ||
367 | pub(crate) struct ExternResources { | ||
368 | out_dirs: FxHashMap<PackageId, AbsPathBuf>, | ||
369 | proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>, | ||
370 | cfgs: FxHashMap<PackageId, Vec<CfgFlag>>, | ||
371 | env: FxHashMap<PackageId, Vec<(String, String)>>, | ||
372 | } | ||
373 | |||
374 | pub(crate) fn load_extern_resources( | ||
375 | cargo_toml: &Path, | ||
376 | cargo_features: &CargoConfig, | ||
377 | progress: &dyn Fn(String), | ||
378 | ) -> Result<ExternResources> { | ||
379 | let mut cmd = Command::new(toolchain::cargo()); | ||
380 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | ||
381 | |||
382 | // --all-targets includes tests, benches and examples in addition to the | ||
383 | // default lib and bins. This is an independent concept from the --targets | ||
384 | // flag below. | ||
385 | cmd.arg("--all-targets"); | ||
386 | |||
387 | if let Some(target) = &cargo_features.target { | ||
388 | cmd.args(&["--target", target]); | ||
389 | } | ||
390 | |||
391 | if cargo_features.all_features { | ||
392 | cmd.arg("--all-features"); | ||
393 | } else { | ||
394 | if cargo_features.no_default_features { | ||
395 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
396 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
397 | cmd.arg("--no-default-features"); | ||
398 | } | ||
399 | if !cargo_features.features.is_empty() { | ||
400 | cmd.arg("--features"); | ||
401 | cmd.arg(cargo_features.features.join(" ")); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); | ||
406 | |||
407 | let mut child = cmd.spawn().map(JodChild)?; | ||
408 | let child_stdout = child.stdout.take().unwrap(); | ||
409 | let stdout = BufReader::new(child_stdout); | ||
410 | |||
411 | let mut res = ExternResources::default(); | ||
412 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
413 | if let Ok(message) = message { | ||
414 | match message { | ||
415 | Message::BuildScriptExecuted(BuildScript { | ||
416 | package_id, | ||
417 | out_dir, | ||
418 | cfgs, | ||
419 | env, | ||
420 | .. | ||
421 | }) => { | ||
422 | let cfgs = { | ||
423 | let mut acc = Vec::new(); | ||
424 | for cfg in cfgs { | ||
425 | match cfg.parse::<CfgFlag>() { | ||
426 | Ok(it) => acc.push(it), | ||
427 | Err(err) => { | ||
428 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
429 | } | ||
430 | }; | ||
431 | } | ||
432 | acc | ||
433 | }; | ||
434 | // cargo_metadata crate returns default (empty) path for | ||
435 | // older cargos, which is not absolute, so work around that. | ||
436 | if out_dir != PathBuf::default() { | ||
437 | let out_dir = AbsPathBuf::assert(out_dir); | ||
438 | res.out_dirs.insert(package_id.clone(), out_dir); | ||
439 | res.cfgs.insert(package_id.clone(), cfgs); | ||
440 | } | ||
441 | |||
442 | res.env.insert(package_id, env); | ||
443 | } | ||
444 | Message::CompilerArtifact(message) => { | ||
445 | progress(format!("metadata {}", message.target.name)); | ||
446 | |||
447 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
448 | let package_id = message.package_id; | ||
449 | // Skip rmeta file | ||
450 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) | ||
451 | { | ||
452 | let filename = AbsPathBuf::assert(filename.clone()); | ||
453 | res.proc_dylib_paths.insert(package_id, filename); | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | Message::CompilerMessage(message) => { | ||
458 | progress(message.target.name.clone()); | ||
459 | } | ||
460 | Message::Unknown => (), | ||
461 | Message::BuildFinished(_) => {} | ||
462 | Message::TextLine(_) => {} | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | Ok(res) | ||
467 | } | ||
468 | |||
469 | // FIXME: File a better way to know if it is a dylib | ||
470 | fn is_dylib(path: &Path) -> bool { | ||
471 | match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) { | ||
472 | None => false, | ||
473 | Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /// Recreates the compile-time environment variables that Cargo sets. | ||
478 | /// | ||
479 | /// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> | ||
480 | fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { | ||
481 | // FIXME: Missing variables: | ||
482 | // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name> | ||
483 | |||
484 | let mut manifest_dir = package.manifest_path.clone(); | ||
485 | manifest_dir.pop(); | ||
486 | if let Some(cargo_manifest_dir) = manifest_dir.to_str() { | ||
487 | env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into())); | ||
488 | } | ||
489 | |||
490 | env.push(("CARGO_PKG_VERSION".into(), package.version.to_string())); | ||
491 | env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string())); | ||
492 | env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string())); | ||
493 | env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string())); | ||
494 | |||
495 | let pre = package.version.pre.iter().map(|id| id.to_string()).format("."); | ||
496 | env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string())); | ||
497 | |||
498 | let authors = package.authors.join(";"); | ||
499 | env.push(("CARGO_PKG_AUTHORS".into(), authors)); | ||
500 | |||
501 | env.push(("CARGO_PKG_NAME".into(), package.name.clone())); | ||
502 | env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default())); | ||
503 | //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default())); | ||
504 | env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default())); | ||
505 | env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default())); | ||
506 | |||
507 | let license_file = | ||
508 | package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default(); | ||
509 | env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file)); | ||
510 | } | ||
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 970a7e140..525c336e6 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -6,6 +6,7 @@ mod project_json; | |||
6 | mod sysroot; | 6 | mod sysroot; |
7 | mod workspace; | 7 | mod workspace; |
8 | mod rustc_cfg; | 8 | mod rustc_cfg; |
9 | mod build_data; | ||
9 | 10 | ||
10 | use std::{ | 11 | use std::{ |
11 | fs::{read_dir, ReadDir}, | 12 | fs::{read_dir, ReadDir}, |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 8e0481ae9..bc5041e5a 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -178,7 +178,7 @@ impl ProjectWorkspace { | |||
178 | let pkg_root = cargo[pkg].root().to_path_buf(); | 178 | let pkg_root = cargo[pkg].root().to_path_buf(); |
179 | 179 | ||
180 | let mut include = vec![pkg_root.clone()]; | 180 | let mut include = vec![pkg_root.clone()]; |
181 | include.extend(cargo[pkg].out_dir.clone()); | 181 | include.extend(cargo[pkg].build_data.out_dir.clone()); |
182 | 182 | ||
183 | let mut exclude = vec![pkg_root.join(".git")]; | 183 | let mut exclude = vec![pkg_root.join(".git")]; |
184 | if is_member { | 184 | if is_member { |
@@ -481,26 +481,24 @@ fn add_target_crate_root( | |||
481 | let edition = pkg.edition; | 481 | let edition = pkg.edition; |
482 | let cfg_options = { | 482 | let cfg_options = { |
483 | let mut opts = cfg_options.clone(); | 483 | let mut opts = cfg_options.clone(); |
484 | for feature in pkg.features.iter() { | 484 | for feature in pkg.active_features.iter() { |
485 | opts.insert_key_value("feature".into(), feature.into()); | 485 | opts.insert_key_value("feature".into(), feature.into()); |
486 | } | 486 | } |
487 | opts.extend(pkg.cfgs.iter().cloned()); | 487 | opts.extend(pkg.build_data.cfgs.iter().cloned()); |
488 | opts | 488 | opts |
489 | }; | 489 | }; |
490 | 490 | ||
491 | let mut env = Env::default(); | 491 | let mut env = Env::default(); |
492 | for (k, v) in &pkg.envs { | 492 | for (k, v) in &pkg.build_data.envs { |
493 | env.set(k, v.clone()); | 493 | env.set(k, v.clone()); |
494 | } | 494 | } |
495 | if let Some(out_dir) = &pkg.out_dir { | ||
496 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
497 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
498 | env.set("OUT_DIR", out_dir); | ||
499 | } | ||
500 | } | ||
501 | 495 | ||
502 | let proc_macro = | 496 | let proc_macro = pkg |
503 | pkg.proc_macro_dylib_path.as_ref().map(|it| proc_macro_loader(&it)).unwrap_or_default(); | 497 | .build_data |
498 | .proc_macro_dylib_path | ||
499 | .as_ref() | ||
500 | .map(|it| proc_macro_loader(&it)) | ||
501 | .unwrap_or_default(); | ||
504 | 502 | ||
505 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); | 503 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); |
506 | let crate_id = crate_graph.add_crate_root( | 504 | let crate_id = crate_graph.add_crate_root( |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 3cb45b030..268c00942 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -24,7 +24,7 @@ jod-thread = "0.1.0" | |||
24 | log = "0.4.8" | 24 | log = "0.4.8" |
25 | lsp-types = { version = "0.86.0", features = ["proposed"] } | 25 | lsp-types = { version = "0.86.0", features = ["proposed"] } |
26 | parking_lot = "0.11.0" | 26 | parking_lot = "0.11.0" |
27 | pico-args = "0.3.1" | 27 | pico-args = "0.4.0" |
28 | oorandom = "11.1.2" | 28 | oorandom = "11.1.2" |
29 | rustc-hash = "1.1.0" | 29 | rustc-hash = "1.1.0" |
30 | serde = { version = "1.0.106", features = ["derive"] } | 30 | serde = { version = "1.0.106", features = ["derive"] } |
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 0a471154e..7d917946e 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs | |||
@@ -109,7 +109,7 @@ impl Args { | |||
109 | let mut matches = Arguments::from_env(); | 109 | let mut matches = Arguments::from_env(); |
110 | 110 | ||
111 | if matches.contains("--version") { | 111 | if matches.contains("--version") { |
112 | matches.finish()?; | 112 | finish_args(matches)?; |
113 | return Ok(Args { | 113 | return Ok(Args { |
114 | verbosity: Verbosity::Normal, | 114 | verbosity: Verbosity::Normal, |
115 | log_file: None, | 115 | log_file: None, |
@@ -143,7 +143,7 @@ impl Args { | |||
143 | let subcommand = match matches.subcommand()? { | 143 | let subcommand = match matches.subcommand()? { |
144 | Some(it) => it, | 144 | Some(it) => it, |
145 | None => { | 145 | None => { |
146 | matches.finish()?; | 146 | finish_args(matches)?; |
147 | return Ok(Args { verbosity, log_file, command: Command::RunServer }); | 147 | return Ok(Args { verbosity, log_file, command: Command::RunServer }); |
148 | } | 148 | } |
149 | }; | 149 | }; |
@@ -160,7 +160,7 @@ impl Args { | |||
160 | load_output_dirs: matches.contains("--load-output-dirs"), | 160 | load_output_dirs: matches.contains("--load-output-dirs"), |
161 | with_proc_macro: matches.contains("--with-proc-macro"), | 161 | with_proc_macro: matches.contains("--with-proc-macro"), |
162 | path: matches | 162 | path: matches |
163 | .free_from_str()? | 163 | .opt_free_from_str()? |
164 | .ok_or_else(|| format_err!("expected positional argument"))?, | 164 | .ok_or_else(|| format_err!("expected positional argument"))?, |
165 | }), | 165 | }), |
166 | "analysis-bench" => Command::Bench(BenchCmd { | 166 | "analysis-bench" => Command::Bench(BenchCmd { |
@@ -187,21 +187,21 @@ impl Args { | |||
187 | load_output_dirs: matches.contains("--load-output-dirs"), | 187 | load_output_dirs: matches.contains("--load-output-dirs"), |
188 | with_proc_macro: matches.contains("--with-proc-macro"), | 188 | with_proc_macro: matches.contains("--with-proc-macro"), |
189 | path: matches | 189 | path: matches |
190 | .free_from_str()? | 190 | .opt_free_from_str()? |
191 | .ok_or_else(|| format_err!("expected positional argument"))?, | 191 | .ok_or_else(|| format_err!("expected positional argument"))?, |
192 | }), | 192 | }), |
193 | "diagnostics" => Command::Diagnostics { | 193 | "diagnostics" => Command::Diagnostics { |
194 | load_output_dirs: matches.contains("--load-output-dirs"), | 194 | load_output_dirs: matches.contains("--load-output-dirs"), |
195 | with_proc_macro: matches.contains("--with-proc-macro"), | 195 | with_proc_macro: matches.contains("--with-proc-macro"), |
196 | path: matches | 196 | path: matches |
197 | .free_from_str()? | 197 | .opt_free_from_str()? |
198 | .ok_or_else(|| format_err!("expected positional argument"))?, | 198 | .ok_or_else(|| format_err!("expected positional argument"))?, |
199 | }, | 199 | }, |
200 | "proc-macro" => Command::ProcMacro, | 200 | "proc-macro" => Command::ProcMacro, |
201 | "ssr" => Command::Ssr { | 201 | "ssr" => Command::Ssr { |
202 | rules: { | 202 | rules: { |
203 | let mut acc = Vec::new(); | 203 | let mut acc = Vec::new(); |
204 | while let Some(rule) = matches.free_from_str()? { | 204 | while let Some(rule) = matches.opt_free_from_str()? { |
205 | acc.push(rule); | 205 | acc.push(rule); |
206 | } | 206 | } |
207 | acc | 207 | acc |
@@ -211,7 +211,7 @@ impl Args { | |||
211 | debug_snippet: matches.opt_value_from_str("--debug")?, | 211 | debug_snippet: matches.opt_value_from_str("--debug")?, |
212 | patterns: { | 212 | patterns: { |
213 | let mut acc = Vec::new(); | 213 | let mut acc = Vec::new(); |
214 | while let Some(rule) = matches.free_from_str()? { | 214 | while let Some(rule) = matches.opt_free_from_str()? { |
215 | acc.push(rule); | 215 | acc.push(rule); |
216 | } | 216 | } |
217 | acc | 217 | acc |
@@ -222,7 +222,14 @@ impl Args { | |||
222 | return Ok(Args { verbosity, log_file: None, command: Command::Help }); | 222 | return Ok(Args { verbosity, log_file: None, command: Command::Help }); |
223 | } | 223 | } |
224 | }; | 224 | }; |
225 | matches.finish()?; | 225 | finish_args(matches)?; |
226 | Ok(Args { verbosity, log_file, command }) | 226 | Ok(Args { verbosity, log_file, command }) |
227 | } | 227 | } |
228 | } | 228 | } |
229 | |||
230 | fn finish_args(args: Arguments) -> Result<()> { | ||
231 | if !args.finish().is_empty() { | ||
232 | bail!("Unused arguments."); | ||
233 | } | ||
234 | Ok(()) | ||
235 | } | ||
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index fd1407e60..66416f709 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | //! errors. | 2 | //! errors. |
3 | 3 | ||
4 | use std::{ | 4 | use std::{ |
5 | env, | ||
5 | path::PathBuf, | 6 | path::PathBuf, |
6 | time::{SystemTime, UNIX_EPOCH}, | 7 | time::{SystemTime, UNIX_EPOCH}, |
7 | }; | 8 | }; |
@@ -295,6 +296,10 @@ impl AnalysisStatsCmd { | |||
295 | report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); | 296 | report_metric("total memory", memory.allocated.megabytes() as u64, "MB"); |
296 | } | 297 | } |
297 | 298 | ||
299 | if env::var("RA_COUNT").is_ok() { | ||
300 | eprintln!("{}", profile::countme::get_all()); | ||
301 | } | ||
302 | |||
298 | if self.memory_usage && verbosity.is_verbose() { | 303 | if self.memory_usage && verbosity.is_verbose() { |
299 | print_memory_usage(host, vfs); | 304 | print_memory_usage(host, vfs); |
300 | } | 305 | } |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 10cbd7eeb..809452e6d 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -859,6 +859,23 @@ pub(crate) fn handle_formatting( | |||
859 | RustfmtConfig::Rustfmt { extra_args } => { | 859 | RustfmtConfig::Rustfmt { extra_args } => { |
860 | let mut cmd = process::Command::new(toolchain::rustfmt()); | 860 | let mut cmd = process::Command::new(toolchain::rustfmt()); |
861 | cmd.args(extra_args); | 861 | cmd.args(extra_args); |
862 | // try to chdir to the file so we can respect `rustfmt.toml` | ||
863 | // FIXME: use `rustfmt --config-path` once | ||
864 | // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed | ||
865 | match params.text_document.uri.to_file_path() { | ||
866 | Ok(mut path) => { | ||
867 | // pop off file name | ||
868 | if path.pop() && path.is_dir() { | ||
869 | cmd.current_dir(path); | ||
870 | } | ||
871 | } | ||
872 | Err(_) => { | ||
873 | log::error!( | ||
874 | "Unable to get file path for {}, rustfmt.toml might be ignored", | ||
875 | params.text_document.uri | ||
876 | ); | ||
877 | } | ||
878 | } | ||
862 | if let Some(&crate_id) = crate_ids.first() { | 879 | if let Some(&crate_id) = crate_ids.first() { |
863 | // Assume all crates are in the same edition | 880 | // Assume all crates are in the same edition |
864 | let edition = snap.analysis.crate_edition(crate_id)?; | 881 | let edition = snap.analysis.crate_edition(crate_id)?; |
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index 42d313f91..df013bae9 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs | |||
@@ -10,8 +10,11 @@ use hir::Semantics; | |||
10 | use ide_db::base_db::FileRange; | 10 | use ide_db::base_db::FileRange; |
11 | use rustc_hash::FxHashMap; | 11 | use rustc_hash::FxHashMap; |
12 | use std::{cell::Cell, iter::Peekable}; | 12 | use std::{cell::Cell, iter::Peekable}; |
13 | use syntax::ast::{AstNode, AstToken}; | ||
14 | use syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken}; | 13 | use syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken}; |
14 | use syntax::{ | ||
15 | ast::{AstNode, AstToken}, | ||
16 | SmolStr, | ||
17 | }; | ||
15 | use test_utils::mark; | 18 | use test_utils::mark; |
16 | 19 | ||
17 | // Creates a match error. If we're currently attempting to match some code that we thought we were | 20 | // Creates a match error. If we're currently attempting to match some code that we thought we were |
@@ -398,11 +401,11 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
398 | code: &SyntaxNode, | 401 | code: &SyntaxNode, |
399 | ) -> Result<(), MatchFailed> { | 402 | ) -> Result<(), MatchFailed> { |
400 | // Build a map keyed by field name. | 403 | // Build a map keyed by field name. |
401 | let mut fields_by_name = FxHashMap::default(); | 404 | let mut fields_by_name: FxHashMap<SmolStr, SyntaxNode> = FxHashMap::default(); |
402 | for child in code.children() { | 405 | for child in code.children() { |
403 | if let Some(record) = ast::RecordExprField::cast(child.clone()) { | 406 | if let Some(record) = ast::RecordExprField::cast(child.clone()) { |
404 | if let Some(name) = record.field_name() { | 407 | if let Some(name) = record.field_name() { |
405 | fields_by_name.insert(name.text().clone(), child.clone()); | 408 | fields_by_name.insert(name.text().into(), child.clone()); |
406 | } | 409 | } |
407 | } | 410 | } |
408 | } | 411 | } |
@@ -473,9 +476,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { | |||
473 | } | 476 | } |
474 | SyntaxElement::Node(n) => { | 477 | SyntaxElement::Node(n) => { |
475 | if let Some(first_token) = n.first_token() { | 478 | if let Some(first_token) = n.first_token() { |
476 | if Some(first_token.text().as_str()) | 479 | if Some(first_token.text()) == next_pattern_token.as_deref() { |
477 | == next_pattern_token.as_deref() | ||
478 | { | ||
479 | if let Some(SyntaxElement::Node(p)) = pattern.next() { | 480 | if let Some(SyntaxElement::Node(p)) = pattern.next() { |
480 | // We have a subtree that starts with the next token in our pattern. | 481 | // We have a subtree that starts with the next token in our pattern. |
481 | self.attempt_match_token_tree(phase, &p, &n)?; | 482 | self.attempt_match_token_tree(phase, &p, &n)?; |
diff --git a/crates/ssr/src/replacing.rs b/crates/ssr/src/replacing.rs index 7e7ce37bd..06a94a46c 100644 --- a/crates/ssr/src/replacing.rs +++ b/crates/ssr/src/replacing.rs | |||
@@ -173,7 +173,7 @@ impl ReplacementRenderer<'_> { | |||
173 | ); | 173 | ); |
174 | } | 174 | } |
175 | } else { | 175 | } else { |
176 | self.out.push_str(token.text().as_str()); | 176 | self.out.push_str(token.text()); |
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
diff --git a/crates/ssr/src/resolving.rs b/crates/ssr/src/resolving.rs index f5ceb5729..14e5a3b69 100644 --- a/crates/ssr/src/resolving.rs +++ b/crates/ssr/src/resolving.rs | |||
@@ -228,7 +228,7 @@ impl<'db> ResolutionScope<'db> { | |||
228 | None, | 228 | None, |
229 | |_ty, assoc_item| { | 229 | |_ty, assoc_item| { |
230 | let item_name = assoc_item.name(self.scope.db)?; | 230 | let item_name = assoc_item.name(self.scope.db)?; |
231 | if item_name.to_string().as_str() == name.text().as_str() { | 231 | if item_name.to_string().as_str() == name.text() { |
232 | Some(hir::PathResolution::AssocItem(assoc_item)) | 232 | Some(hir::PathResolution::AssocItem(assoc_item)) |
233 | } else { | 233 | } else { |
234 | None | 234 | None |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 52394b337..24298fbfa 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -12,15 +12,12 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.3" | 15 | rowan = "0.12" |
16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
20 | indexmap = "1.4.0" | 20 | indexmap = "1.4.0" |
21 | # This crate transitively depends on `smol_str` via `rowan`. | ||
22 | # ideally, `serde` should be enabled by `rust-analyzer`, but we enable it here | ||
23 | # to reduce number of compilations | ||
24 | smol_str = { version = "0.1.15", features = ["serde"] } | 21 | smol_str = { version = "0.1.15", features = ["serde"] } |
25 | serde = { version = "1.0.106", features = ["derive"] } | 22 | serde = { version = "1.0.106", features = ["derive"] } |
26 | 23 | ||
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 827ae78f9..2ff92f9f6 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -4,6 +4,7 @@ use std::{ | |||
4 | fmt, | 4 | fmt, |
5 | hash::BuildHasherDefault, | 5 | hash::BuildHasherDefault, |
6 | ops::{self, RangeInclusive}, | 6 | ops::{self, RangeInclusive}, |
7 | ptr, | ||
7 | }; | 8 | }; |
8 | 9 | ||
9 | use indexmap::IndexMap; | 10 | use indexmap::IndexMap; |
@@ -171,7 +172,7 @@ pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { | |||
171 | && lhs.text_range().len() == rhs.text_range().len() | 172 | && lhs.text_range().len() == rhs.text_range().len() |
172 | && match (&lhs, &rhs) { | 173 | && match (&lhs, &rhs) { |
173 | (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { | 174 | (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { |
174 | lhs.green() == rhs.green() || lhs.text() == rhs.text() | 175 | ptr::eq(lhs.green(), rhs.green()) || lhs.text() == rhs.text() |
175 | } | 176 | } |
176 | (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), | 177 | (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(), |
177 | _ => false, | 178 | _ => false, |
@@ -566,7 +567,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
566 | 567 | ||
567 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 568 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
568 | match element { | 569 | match element { |
569 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), | 570 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().to_owned()), |
570 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | 571 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), |
571 | } | 572 | } |
572 | } | 573 | } |
@@ -624,7 +625,7 @@ fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize { | |||
624 | 625 | ||
625 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 626 | fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
626 | match element { | 627 | match element { |
627 | NodeOrToken::Node(it) => it.green().clone().into(), | 628 | NodeOrToken::Node(it) => it.green().to_owned().into(), |
628 | NodeOrToken::Token(it) => it.green().clone().into(), | 629 | NodeOrToken::Token(it) => it.green().clone().into(), |
629 | } | 630 | } |
630 | } | 631 | } |
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 83de067d9..a25ff655e 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs | |||
@@ -12,7 +12,7 @@ use std::marker::PhantomData; | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken}, | 14 | syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken}, |
15 | SmolStr, SyntaxKind, | 15 | SyntaxKind, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub use self::{ | 18 | pub use self::{ |
@@ -54,7 +54,7 @@ pub trait AstToken { | |||
54 | 54 | ||
55 | fn syntax(&self) -> &SyntaxToken; | 55 | fn syntax(&self) -> &SyntaxToken; |
56 | 56 | ||
57 | fn text(&self) -> &SmolStr { | 57 | fn text(&self) -> &str { |
58 | self.syntax().text() | 58 | self.syntax().text() |
59 | } | 59 | } |
60 | } | 60 | } |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 9ffc3ae11..b755c9692 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -478,7 +478,7 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
478 | } | 478 | } |
479 | 479 | ||
480 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 480 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
481 | SyntaxNode::new_root(n.green().clone()) | 481 | SyntaxNode::new_root(n.green().to_owned()) |
482 | } | 482 | } |
483 | 483 | ||
484 | pub mod tokens { | 484 | pub mod tokens { |
@@ -495,7 +495,7 @@ pub mod tokens { | |||
495 | .syntax() | 495 | .syntax() |
496 | .descendants_with_tokens() | 496 | .descendants_with_tokens() |
497 | .filter_map(|it| it.into_token()) | 497 | .filter_map(|it| it.into_token()) |
498 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ") | 498 | .find(|it| it.kind() == WHITESPACE && it.text() == " ") |
499 | .unwrap() | 499 | .unwrap() |
500 | } | 500 | } |
501 | 501 | ||
@@ -523,7 +523,7 @@ pub mod tokens { | |||
523 | .syntax() | 523 | .syntax() |
524 | .descendants_with_tokens() | 524 | .descendants_with_tokens() |
525 | .filter_map(|it| it.into_token()) | 525 | .filter_map(|it| it.into_token()) |
526 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n") | 526 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n") |
527 | .unwrap() | 527 | .unwrap() |
528 | } | 528 | } |
529 | 529 | ||
@@ -533,7 +533,7 @@ pub mod tokens { | |||
533 | .syntax() | 533 | .syntax() |
534 | .descendants_with_tokens() | 534 | .descendants_with_tokens() |
535 | .filter_map(|it| it.into_token()) | 535 | .filter_map(|it| it.into_token()) |
536 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n\n") | 536 | .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n") |
537 | .unwrap() | 537 | .unwrap() |
538 | } | 538 | } |
539 | 539 | ||
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 738c92a5b..5c8cf900f 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -13,19 +13,19 @@ use crate::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | impl ast::Lifetime { | 15 | impl ast::Lifetime { |
16 | pub fn text(&self) -> &SmolStr { | 16 | pub fn text(&self) -> &str { |
17 | text_of_first_token(self.syntax()) | 17 | text_of_first_token(self.syntax()) |
18 | } | 18 | } |
19 | } | 19 | } |
20 | 20 | ||
21 | impl ast::Name { | 21 | impl ast::Name { |
22 | pub fn text(&self) -> &SmolStr { | 22 | pub fn text(&self) -> &str { |
23 | text_of_first_token(self.syntax()) | 23 | text_of_first_token(self.syntax()) |
24 | } | 24 | } |
25 | } | 25 | } |
26 | 26 | ||
27 | impl ast::NameRef { | 27 | impl ast::NameRef { |
28 | pub fn text(&self) -> &SmolStr { | 28 | pub fn text(&self) -> &str { |
29 | text_of_first_token(self.syntax()) | 29 | text_of_first_token(self.syntax()) |
30 | } | 30 | } |
31 | 31 | ||
@@ -34,7 +34,7 @@ impl ast::NameRef { | |||
34 | } | 34 | } |
35 | } | 35 | } |
36 | 36 | ||
37 | fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { | 37 | fn text_of_first_token(node: &SyntaxNode) -> &str { |
38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().text() | 38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().text() |
39 | } | 39 | } |
40 | 40 | ||
@@ -121,7 +121,7 @@ impl ast::Attr { | |||
121 | pub fn simple_name(&self) -> Option<SmolStr> { | 121 | pub fn simple_name(&self) -> Option<SmolStr> { |
122 | let path = self.path()?; | 122 | let path = self.path()?; |
123 | match (path.segment(), path.qualifier()) { | 123 | match (path.segment(), path.qualifier()) { |
124 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().clone()), | 124 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()), |
125 | _ => None, | 125 | _ => None, |
126 | } | 126 | } |
127 | } | 127 | } |
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 5e9620a40..5e07ec7d1 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -41,7 +41,7 @@ impl ast::Comment { | |||
41 | match kind { | 41 | match kind { |
42 | CommentKind { shape, doc: Some(_) } => { | 42 | CommentKind { shape, doc: Some(_) } => { |
43 | let prefix = kind.prefix(); | 43 | let prefix = kind.prefix(); |
44 | let text = &self.text().as_str()[prefix.len()..]; | 44 | let text = &self.text()[prefix.len()..]; |
45 | let ws = text.chars().next().filter(|c| c.is_whitespace()); | 45 | let ws = text.chars().next().filter(|c| c.is_whitespace()); |
46 | let text = ws.map_or(text, |ws| &text[ws.len_utf8()..]); | 46 | let text = ws.map_or(text, |ws| &text[ws.len_utf8()..]); |
47 | match shape { | 47 | match shape { |
@@ -156,13 +156,13 @@ impl ast::String { | |||
156 | 156 | ||
157 | pub fn value(&self) -> Option<Cow<'_, str>> { | 157 | pub fn value(&self) -> Option<Cow<'_, str>> { |
158 | if self.is_raw() { | 158 | if self.is_raw() { |
159 | let text = self.text().as_str(); | 159 | let text = self.text(); |
160 | let text = | 160 | let text = |
161 | &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 161 | &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
162 | return Some(Cow::Borrowed(text)); | 162 | return Some(Cow::Borrowed(text)); |
163 | } | 163 | } |
164 | 164 | ||
165 | let text = self.text().as_str(); | 165 | let text = self.text(); |
166 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 166 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
167 | 167 | ||
168 | let mut buf = String::new(); | 168 | let mut buf = String::new(); |
@@ -190,7 +190,7 @@ impl ast::String { | |||
190 | } | 190 | } |
191 | 191 | ||
192 | pub fn quote_offsets(&self) -> Option<QuoteOffsets> { | 192 | pub fn quote_offsets(&self) -> Option<QuoteOffsets> { |
193 | let text = self.text().as_str(); | 193 | let text = self.text(); |
194 | let offsets = QuoteOffsets::new(text)?; | 194 | let offsets = QuoteOffsets::new(text)?; |
195 | let o = self.syntax().text_range().start(); | 195 | let o = self.syntax().text_range().start(); |
196 | let offsets = QuoteOffsets { | 196 | let offsets = QuoteOffsets { |
@@ -560,7 +560,7 @@ impl HasFormatSpecifier for ast::String { | |||
560 | fn char_ranges( | 560 | fn char_ranges( |
561 | &self, | 561 | &self, |
562 | ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> { | 562 | ) -> Option<Vec<(TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>> { |
563 | let text = self.text().as_str(); | 563 | let text = self.text(); |
564 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 564 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
565 | let offset = self.text_range_between_quotes()?.start() - self.syntax().text_range().start(); | 565 | let offset = self.text_range_between_quotes()?.start() - self.syntax().text_range().start(); |
566 | 566 | ||
@@ -590,7 +590,7 @@ impl ast::IntNumber { | |||
590 | pub fn value(&self) -> Option<u128> { | 590 | pub fn value(&self) -> Option<u128> { |
591 | let token = self.syntax(); | 591 | let token = self.syntax(); |
592 | 592 | ||
593 | let mut text = token.text().as_str(); | 593 | let mut text = token.text(); |
594 | if let Some(suffix) = self.suffix() { | 594 | if let Some(suffix) = self.suffix() { |
595 | text = &text[..text.len() - suffix.len()] | 595 | text = &text[..text.len() - suffix.len()] |
596 | } | 596 | } |
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index ea7482bb1..11294c5b2 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs | |||
@@ -56,9 +56,9 @@ pub use crate::{ | |||
56 | }; | 56 | }; |
57 | pub use parser::{SyntaxKind, T}; | 57 | pub use parser::{SyntaxKind, T}; |
58 | pub use rowan::{ | 58 | pub use rowan::{ |
59 | Direction, GreenNode, NodeOrToken, SmolStr, SyntaxText, TextRange, TextSize, TokenAtOffset, | 59 | Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent, |
60 | WalkEvent, | ||
61 | }; | 60 | }; |
61 | pub use smol_str::SmolStr; | ||
62 | 62 | ||
63 | /// `Parse` is the result of the parsing: a syntax tree and a collection of | 63 | /// `Parse` is the result of the parsing: a syntax tree and a collection of |
64 | /// errors. | 64 | /// errors. |
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index 76f01084c..3d637bf91 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs | |||
@@ -73,8 +73,7 @@ fn reparse_token<'node>( | |||
73 | new_text.pop(); | 73 | new_text.pop(); |
74 | } | 74 | } |
75 | 75 | ||
76 | let new_token = | 76 | let new_token = GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), &new_text); |
77 | GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into()); | ||
78 | Some(( | 77 | Some(( |
79 | prev_token.replace_with(new_token), | 78 | prev_token.replace_with(new_token), |
80 | new_err.into_iter().collect(), | 79 | new_err.into_iter().collect(), |
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs index ce27c3dd9..d5ddc076f 100644 --- a/crates/syntax/src/parsing/text_tree_sink.rs +++ b/crates/syntax/src/parsing/text_tree_sink.rs | |||
@@ -8,7 +8,7 @@ use crate::{ | |||
8 | ast, | 8 | ast, |
9 | parsing::Token, | 9 | parsing::Token, |
10 | syntax_node::GreenNode, | 10 | syntax_node::GreenNode, |
11 | SmolStr, SyntaxError, | 11 | SyntaxError, |
12 | SyntaxKind::{self, *}, | 12 | SyntaxKind::{self, *}, |
13 | SyntaxTreeBuilder, TextRange, TextSize, | 13 | SyntaxTreeBuilder, TextRange, TextSize, |
14 | }; | 14 | }; |
@@ -135,7 +135,7 @@ impl<'a> TextTreeSink<'a> { | |||
135 | 135 | ||
136 | fn do_token(&mut self, kind: SyntaxKind, len: TextSize, n_tokens: usize) { | 136 | fn do_token(&mut self, kind: SyntaxKind, len: TextSize, n_tokens: usize) { |
137 | let range = TextRange::at(self.text_pos, len); | 137 | let range = TextRange::at(self.text_pos, len); |
138 | let text: SmolStr = self.text[range].into(); | 138 | let text = &self.text[range]; |
139 | self.text_pos += len; | 139 | self.text_pos += len; |
140 | self.token_pos += n_tokens; | 140 | self.token_pos += n_tokens; |
141 | self.inner.token(kind, text); | 141 | self.inner.token(kind, text); |
diff --git a/crates/syntax/src/syntax_node.rs b/crates/syntax/src/syntax_node.rs index cc30138fa..8f643b228 100644 --- a/crates/syntax/src/syntax_node.rs +++ b/crates/syntax/src/syntax_node.rs | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | use rowan::{GreenNodeBuilder, Language}; | 9 | use rowan::{GreenNodeBuilder, Language}; |
10 | 10 | ||
11 | use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize}; | 11 | use crate::{Parse, SyntaxError, SyntaxKind, TextSize}; |
12 | 12 | ||
13 | pub(crate) use rowan::{GreenNode, GreenToken, NodeOrToken}; | 13 | pub(crate) use rowan::{GreenNode, GreenToken, NodeOrToken}; |
14 | 14 | ||
@@ -53,7 +53,7 @@ impl SyntaxTreeBuilder { | |||
53 | Parse::new(green, errors) | 53 | Parse::new(green, errors) |
54 | } | 54 | } |
55 | 55 | ||
56 | pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { | 56 | pub fn token(&mut self, kind: SyntaxKind, text: &str) { |
57 | let kind = RustLanguage::kind_to_raw(kind); | 57 | let kind = RustLanguage::kind_to_raw(kind); |
58 | self.inner.token(kind, text) | 58 | self.inner.token(kind, text) |
59 | } | 59 | } |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 7901580ee..7694e8834 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -116,7 +116,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | |||
116 | } | 116 | } |
117 | 117 | ||
118 | let token = literal.token(); | 118 | let token = literal.token(); |
119 | let text = token.text().as_str(); | 119 | let text = token.text(); |
120 | 120 | ||
121 | // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205) | 121 | // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205) |
122 | let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { | 122 | let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { |