aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/generate_function.rs19
-rw-r--r--crates/assists/src/handlers/generate_impl.rs11
-rw-r--r--crates/assists/src/handlers/generate_new.rs8
-rw-r--r--crates/assists/src/handlers/raw_string.rs2
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs19
-rw-r--r--crates/assists/src/utils.rs2
-rw-r--r--crates/hir/src/attrs.rs6
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir/src/db.rs14
-rw-r--r--crates/hir_def/src/attr.rs1
-rw-r--r--crates/hir_def/src/body.rs2
-rw-r--r--crates/hir_def/src/body/tests.rs41
-rw-r--r--crates/hir_def/src/db.rs7
-rw-r--r--crates/hir_def/src/find_path.rs18
-rw-r--r--crates/hir_def/src/import_map.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs31
-rw-r--r--crates/hir_def/src/item_tree/lower.rs45
-rw-r--r--crates/hir_def/src/lang_item.rs2
-rw-r--r--crates/hir_def/src/nameres.rs140
-rw-r--r--crates/hir_def/src/nameres/collector.rs58
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs37
-rw-r--r--crates/hir_def/src/nameres/tests.rs20
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs97
-rw-r--r--crates/hir_def/src/resolver.rs23
-rw-r--r--crates/hir_def/src/test_db.rs6
-rw-r--r--crates/hir_expand/src/ast_id_map.rs20
-rw-r--r--crates/hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/name.rs8
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/diagnostics.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs5
-rw-r--r--crates/hir_ty/src/method_resolution.rs4
-rw-r--r--crates/hir_ty/src/test_db.rs4
-rw-r--r--crates/hir_ty/src/tests/simple.rs24
-rw-r--r--crates/ide/src/display/navigation_target.rs4
-rw-r--r--crates/ide/src/display/short_label.rs10
-rw-r--r--crates/ide/src/doc_links.rs23
-rw-r--r--crates/ide/src/extend_selection.rs4
-rw-r--r--crates/ide/src/goto_definition.rs90
-rw-r--r--crates/ide/src/hover.rs30
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/runnables.rs68
-rw-r--r--crates/ide/src/status.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--crates/ide_db/src/apply_change.rs1
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs2
-rw-r--r--crates/ide_db/src/search.rs10
-rw-r--r--crates/ide_db/src/symbol_index.rs6
-rw-r--r--crates/mbe/src/syntax_bridge.rs6
-rw-r--r--crates/profile/Cargo.toml1
-rw-r--r--crates/profile/src/hprof.rs4
-rw-r--r--crates/profile/src/lib.rs7
-rw-r--r--crates/project_model/src/build_data.rs206
-rw-r--r--crates/project_model/src/cargo_workspace.rs208
-rw-r--r--crates/project_model/src/lib.rs1
-rw-r--r--crates/project_model/src/workspace.rs22
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/bin/args.rs23
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--crates/rust-analyzer/src/handlers.rs17
-rw-r--r--crates/ssr/src/matching.rs13
-rw-r--r--crates/ssr/src/replacing.rs2
-rw-r--r--crates/ssr/src/resolving.rs2
-rw-r--r--crates/syntax/Cargo.toml7
-rw-r--r--crates/syntax/src/algo.rs7
-rw-r--r--crates/syntax/src/ast.rs4
-rw-r--r--crates/syntax/src/ast/make.rs8
-rw-r--r--crates/syntax/src/ast/node_ext.rs10
-rw-r--r--crates/syntax/src/ast/token_ext.rs12
-rw-r--r--crates/syntax/src/lib.rs4
-rw-r--r--crates/syntax/src/parsing/reparsing.rs3
-rw-r--r--crates/syntax/src/parsing/text_tree_sink.rs4
-rw-r--r--crates/syntax/src/syntax_node.rs4
-rw-r--r--crates/syntax/src/validation.rs2
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
180enum GeneratedFunctionTarget { 180enum GeneratedFunctionTarget {
181 BehindItem(SyntaxNode), 181 BehindItem(SyntaxNode),
182 InEmptyItemList(ast::ItemList), 182 InEmptyItemList(SyntaxNode),
183} 183}
184 184
185impl GeneratedFunctionTarget { 185impl 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 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use stdx::format_to; 2use stdx::format_to;
3use syntax::ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}; 3use syntax::{
4 ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
5 SmolStr,
6};
4 7
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 8use 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;
3use stdx::format_to; 3use stdx::format_to;
4use syntax::{ 4use 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
9use crate::{AssistContext, AssistId, AssistKind, Assists}; 9use 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;
3use itertools::Itertools; 3use itertools::Itertools;
4use syntax::{ 4use 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 @@
2use hir_def::{ 2use 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
3pub use hir_def::db::{ 3pub 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};
12pub use hir_expand::db::{ 12pub 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};
6use super::*; 6use super::*;
7 7
8fn lower(ra_fixture: &str) -> Arc<Body> { 8fn 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
23fn check_diagnostics(ra_fixture: &str) { 29fn check_diagnostics(ra_fixture: &str) {
@@ -42,6 +48,25 @@ fn main() { n_nuple!(1,2,3); }
42} 48}
43 49
44#[test] 50#[test]
51fn macro_resolve() {
52 // Regression test for a path resolution bug introduced with inner item handling.
53 lower(
54 r"
55macro_rules! vec {
56 () => { () };
57 ($elem:expr; $n:expr) => { () };
58 ($($x:expr),+ $(,)?) => { () };
59}
60mod m {
61 fn outer() {
62 let _ = vec![FileSet::default(); self.len()];
63 }
64}
65 ",
66 );
67}
68
69#[test]
45fn cfg_diagnostics() { 70fn 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 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use hir_expand::{db::AstDatabase, HirFileId}; 5use hir_expand::{db::AstDatabase, AstId, HirFileId};
6use la_arena::ArenaMap; 6use la_arena::ArenaMap;
7use syntax::SmolStr; 7use syntax::{ast, SmolStr};
8 8
9use crate::{ 9use 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};
23use la_arena::{Arena, Idx, RawIdx}; 23use la_arena::{Arena, Idx, RawIdx};
24use profile::Count;
24use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
25use smallvec::SmallVec; 26use smallvec::SmallVec;
26use syntax::{ast, match_ast}; 27use 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)]
69pub struct ItemTree { 70pub 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
77impl ItemTree { 79impl 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}
6use smallvec::SmallVec; 6use smallvec::SmallVec;
7use syntax::{ 7use syntax::{
8 ast::{self, ModuleItemOwner}, 8 ast::{self, ModuleItemOwner},
9 SyntaxNode, 9 SyntaxNode, WalkEvent,
10}; 10};
11 11
12use crate::{ 12use 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;
59use base_db::{CrateId, Edition, FileId}; 59use base_db::{CrateId, Edition, FileId};
60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; 60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
61use la_arena::Arena; 61use la_arena::Arena;
62use profile::Count;
62use rustc_hash::FxHashMap; 63use rustc_hash::FxHashMap;
63use stdx::format_to; 64use stdx::format_to;
64use syntax::ast; 65use syntax::{ast, AstNode};
65 66
66use crate::{ 67use 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)]
77pub struct DefMap { 78pub 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
114impl Default for ModuleOrigin { 121impl 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) = &current_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
341fn 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)]
280pub enum ModuleSource { 371pub 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
285mod diagnostics { 377mod 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;
45const EXPANSION_DEPTH_LIMIT: usize = 128; 45const EXPANSION_DEPTH_LIMIT: usize = 128;
46const FIXED_POINT_LIMIT: usize = 8192; 46const FIXED_POINT_LIMIT: usize = 8192;
47 47
48pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap { 48pub(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
230impl DefCollector<'_> { 242impl 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<'_, '_> {
1470mod tests { 1506mod 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 &current_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;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics; 5mod diagnostics;
6mod primitives; 6mod primitives;
7mod block;
7 8
8use std::sync::Arc; 9use std::sync::Arc;
9 10
10use base_db::{fixture::WithFixture, SourceDatabase}; 11use base_db::{fixture::WithFixture, SourceDatabase};
11use expect_test::{expect, Expect}; 12use expect_test::{expect, Expect};
13use hir_expand::db::AstDatabase;
12use test_utils::mark; 14use test_utils::mark;
13 15
14use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 16use 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
24fn 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
22fn check(ra_fixture: &str, expect: Expect) { 36fn 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
42fn 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]
29fn crate_def_map_smoke_test() { 49fn 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 @@
1use super::*;
2
3#[test]
4fn inner_item_smoke() {
5 check_at(
6 r#"
7struct inner {}
8fn 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]
24fn use_from_crate() {
25 check_at(
26 r#"
27struct Struct;
28fn 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]
48fn merge_namespaces() {
49 check_at(
50 r#"
51struct name {}
52fn 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]
72fn nested_blocks() {
73 check_at(
74 r#"
75fn 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
15use la_arena::{Arena, Idx}; 15use la_arena::{Arena, Idx};
16use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 16use 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.
19pub struct FileAstId<N: AstNode> { 19pub 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
179fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 179fn 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"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.47", default-features = false } 20chalk-solve = { version = "0.50", default-features = false }
21chalk-ir = "0.47" 21chalk-ir = "0.50"
22chalk-recursive = "0.47" 22chalk-recursive = "0.50"
23la-arena = { version = "0.2.0", path = "../../lib/arena" } 23la-arena = { version = "0.2.0", path = "../../lib/arena" }
24 24
25stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { 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]
32fn infer_box_with_allocator() {
33 check_types(
34 r#"
35//- /main.rs crate:main deps:std
36fn 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::*;
44mod 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]
32fn infer_adt_self() { 56fn 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
56impl ShortLabel for ast::BlockExpr {
57 fn short_label(&self) -> Option<String> {
58 None
59 }
60}
61
56impl ShortLabel for ast::TypeAlias { 62impl 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 {
90impl ShortLabel for ast::ConstParam { 96impl 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;
2use hir::{HasAttrs, ModuleDef, Semantics}; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 defs::{Definition, NameClass, NameRefClass}, 4 defs::{Definition, NameClass, NameRefClass},
5 symbol_index, RootDatabase, 5 RootDatabase,
6}; 6};
7use syntax::{ 7use 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
11use crate::{ 11use 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, &lt) { 48 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
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(&lt)).to_vec() 52 reference_definition(&sema, Either::Left(&lt))
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
65fn def_for_doc_comment( 61fn 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)]
124pub(crate) enum ReferenceResult {
125 Exact(NavigationTarget),
126 Approximate(Vec<NavigationTarget>),
127}
128
129impl 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
138pub(crate) fn reference_definition( 119pub(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; 166extern 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; 179extern 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
301use foo::foo; 271use foo::foo;
302fn bar() { 272fn 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]
308macro_rules! foo { () => { () } } 278macro_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
319use foo::foo$0; 289use foo::foo$0;
320 290
321//- /foo/lib.rs 291//- /foo/lib.rs crate:foo
322#[macro_export] 292#[macro_export]
323macro_rules! foo { () => { () } } 293macro_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
980foo::module$0::mac!(); 950foo::module$0::mac!();
981 951
982//- /foo/lib.rs 952//- /foo/lib.rs crate:foo
983pub mod module { 953pub 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#"
1833pub trait Foo {
1834 fn buzz() -> usize;
1835}
1836/// [Foo][buzz]
1837///
1838/// [buzz]: Foo::buzz
1839pub struct B$0ar
1840"#,
1841 expect![[r#"
1842 *Bar*
1843
1844 ```rust
1845 test
1846 ```
1847
1848 ```rust
1849 pub struct Bar
1850 ```
1851
1852 ---
1853
1854 [Foo](https://docs.rs/test/*/test/trait.Foo.html#tymethod.buzz)
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};
12use test_utils::mark;
12 13
13use crate::{ 14use crate::{
14 display::{ToNav, TryToNav}, 15 display::{ToNav, TryToNav},
@@ -96,28 +97,26 @@ impl Runnable {
96pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 97pub(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
106fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Runnable> { 109fn 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
138pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { 140pub(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)]
327mod tests { 329mod 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
1064mod m;
1065//- /m.rs
1066mod 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
212pub fn index_resolve(db: &RootDatabase, name: &SmolStr) -> Vec<FileSymbol> { 212pub 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"
14cfg-if = "1" 14cfg-if = "1"
15libc = "0.2.73" 15libc = "0.2.73"
16la-arena = { version = "0.2.0", path = "../../lib/arena" } 16la-arena = { version = "0.2.0", path = "../../lib/arena" }
17countme = { version = "2.0.0-pre.2", features = ["enable"] }
17jemalloc-ctl = { version = "0.3.3", optional = true } 18jemalloc-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;
3use std::{ 3use 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
20pub fn init() { 21pub 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
18pub 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.
23pub use countme::Count;
24
18thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false)); 25thread_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
3use std::{
4 ffi::OsStr,
5 io::BufReader,
6 path::{Path, PathBuf},
7 process::{Command, Stdio},
8};
9
10use anyhow::Result;
11use cargo_metadata::{BuildScript, Message, Package, PackageId};
12use itertools::Itertools;
13use paths::{AbsPath, AbsPathBuf};
14use rustc_hash::FxHashMap;
15use stdx::JodChild;
16
17use crate::{cfg_flag::CfgFlag, CargoConfig};
18
19#[derive(Debug, Clone, Default)]
20pub(crate) struct BuildDataMap {
21 data: FxHashMap<PackageId, BuildData>,
22}
23#[derive(Debug, Clone, Default, PartialEq, Eq)]
24pub 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
38impl 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
166fn 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>
176fn 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
3use std::{ 3use 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
12use anyhow::{Context, Result}; 5use anyhow::{Context, Result};
13use base_db::Edition; 6use base_db::Edition;
14use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 7use cargo_metadata::{CargoOpt, MetadataCommand};
15use itertools::Itertools;
16use la_arena::{Arena, Idx}; 8use la_arena::{Arena, Idx};
17use paths::{AbsPath, AbsPathBuf}; 9use paths::{AbsPath, AbsPathBuf};
18use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
19use stdx::JodChild;
20 11
21use crate::cfg_flag::CfgFlag; 12use crate::build_data::{BuildData, BuildDataMap};
22use crate::utf8_stdout; 13use 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)]
367pub(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
374pub(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
470fn 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>
480fn 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;
6mod sysroot; 6mod sysroot;
7mod workspace; 7mod workspace;
8mod rustc_cfg; 8mod rustc_cfg;
9mod build_data;
9 10
10use std::{ 11use 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"
24log = "0.4.8" 24log = "0.4.8"
25lsp-types = { version = "0.86.0", features = ["proposed"] } 25lsp-types = { version = "0.86.0", features = ["proposed"] }
26parking_lot = "0.11.0" 26parking_lot = "0.11.0"
27pico-args = "0.3.1" 27pico-args = "0.4.0"
28oorandom = "11.1.2" 28oorandom = "11.1.2"
29rustc-hash = "1.1.0" 29rustc-hash = "1.1.0"
30serde = { version = "1.0.106", features = ["derive"] } 30serde = { 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
230fn 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
4use std::{ 4use 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;
10use ide_db::base_db::FileRange; 10use ide_db::base_db::FileRange;
11use rustc_hash::FxHashMap; 11use rustc_hash::FxHashMap;
12use std::{cell::Cell, iter::Peekable}; 12use std::{cell::Cell, iter::Peekable};
13use syntax::ast::{AstNode, AstToken};
14use syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken}; 13use syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken};
14use syntax::{
15 ast::{AstNode, AstToken},
16 SmolStr,
17};
15use test_utils::mark; 18use 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]
14itertools = "0.10.0" 14itertools = "0.10.0"
15rowan = "0.10.3" 15rowan = "0.12"
16rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
20indexmap = "1.4.0" 20indexmap = "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
24smol_str = { version = "0.1.15", features = ["serde"] } 21smol_str = { version = "0.1.15", features = ["serde"] }
25serde = { version = "1.0.106", features = ["derive"] } 22serde = { 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
9use indexmap::IndexMap; 10use 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
567fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { 568fn 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
625fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { 626fn 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
13use crate::{ 13use crate::{
14 syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken}, 14 syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken},
15 SmolStr, SyntaxKind, 15 SyntaxKind,
16}; 16};
17 17
18pub use self::{ 18pub 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
480fn unroot(n: SyntaxNode) -> SyntaxNode { 480fn unroot(n: SyntaxNode) -> SyntaxNode {
481 SyntaxNode::new_root(n.green().clone()) 481 SyntaxNode::new_root(n.green().to_owned())
482} 482}
483 483
484pub mod tokens { 484pub 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
15impl ast::Lifetime { 15impl 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
21impl ast::Name { 21impl 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
27impl ast::NameRef { 27impl 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
37fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { 37fn 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};
57pub use parser::{SyntaxKind, T}; 57pub use parser::{SyntaxKind, T};
58pub use rowan::{ 58pub use rowan::{
59 Direction, GreenNode, NodeOrToken, SmolStr, SyntaxText, TextRange, TextSize, TokenAtOffset, 59 Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
60 WalkEvent,
61}; 60};
61pub 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
9use rowan::{GreenNodeBuilder, Language}; 9use rowan::{GreenNodeBuilder, Language};
10 10
11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize}; 11use crate::{Parse, SyntaxError, SyntaxKind, TextSize};
12 12
13pub(crate) use rowan::{GreenNode, GreenToken, NodeOrToken}; 13pub(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)| {