aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs26
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs4
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs13
-rw-r--r--crates/ra_assists/src/utils.rs10
-rw-r--r--crates/ra_hir/src/code_model.rs2
-rw-r--r--crates/ra_hir_def/src/adt.rs17
-rw-r--r--crates/ra_hir_def/src/body.rs11
-rw-r--r--crates/ra_hir_def/src/body/lower.rs19
-rw-r--r--crates/ra_hir_def/src/data.rs21
-rw-r--r--crates/ra_hir_def/src/item_scope.rs11
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs13
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs18
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs32
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs4
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs29
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs46
-rw-r--r--crates/ra_ide/src/runnables.rs43
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs2
-rw-r--r--crates/ra_syntax/src/ast/edit.rs6
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs36
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs26
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs2
-rw-r--r--docs/user/readme.adoc12
-rw-r--r--xtask/src/ast_src.rs4
26 files changed, 271 insertions, 140 deletions
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index e466c9a86..e47feda71 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10 10
11use crate::{ 11use crate::{
12 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 12 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
13 utils::{get_missing_impl_items, resolve_target_trait}, 13 utils::{get_missing_assoc_items, resolve_target_trait},
14 Assist, AssistCtx, AssistId, 14 Assist, AssistCtx, AssistId,
15}; 15};
16 16
@@ -112,25 +112,25 @@ fn add_missing_impl_members_inner(
112 112
113 let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?; 113 let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?;
114 114
115 let def_name = |item: &ast::ImplItem| -> Option<SmolStr> { 115 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
116 match item { 116 match item {
117 ast::ImplItem::FnDef(def) => def.name(), 117 ast::AssocItem::FnDef(def) => def.name(),
118 ast::ImplItem::TypeAliasDef(def) => def.name(), 118 ast::AssocItem::TypeAliasDef(def) => def.name(),
119 ast::ImplItem::ConstDef(def) => def.name(), 119 ast::AssocItem::ConstDef(def) => def.name(),
120 } 120 }
121 .map(|it| it.text().clone()) 121 .map(|it| it.text().clone())
122 }; 122 };
123 123
124 let missing_items = get_missing_impl_items(&ctx.sema, &impl_node) 124 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_node)
125 .iter() 125 .iter()
126 .map(|i| match i { 126 .map(|i| match i {
127 hir::AssocItem::Function(i) => ast::ImplItem::FnDef(i.source(ctx.db).value), 127 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value),
128 hir::AssocItem::TypeAlias(i) => ast::ImplItem::TypeAliasDef(i.source(ctx.db).value), 128 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db).value),
129 hir::AssocItem::Const(i) => ast::ImplItem::ConstDef(i.source(ctx.db).value), 129 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db).value),
130 }) 130 })
131 .filter(|t| def_name(&t).is_some()) 131 .filter(|t| def_name(&t).is_some())
132 .filter(|t| match t { 132 .filter(|t| match t {
133 ast::ImplItem::FnDef(def) => match mode { 133 ast::AssocItem::FnDef(def) => match mode {
134 AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), 134 AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(),
135 AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(), 135 AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(),
136 }, 136 },
@@ -145,7 +145,7 @@ fn add_missing_impl_members_inner(
145 let sema = ctx.sema; 145 let sema = ctx.sema;
146 146
147 ctx.add_assist(AssistId(assist_id), label, |edit| { 147 ctx.add_assist(AssistId(assist_id), label, |edit| {
148 let n_existing_items = impl_item_list.impl_items().count(); 148 let n_existing_items = impl_item_list.assoc_items().count();
149 let source_scope = sema.scope_for_def(trait_); 149 let source_scope = sema.scope_for_def(trait_);
150 let target_scope = sema.scope(impl_item_list.syntax()); 150 let target_scope = sema.scope(impl_item_list.syntax());
151 let ast_transform = QualifyPaths::new(&target_scope, &source_scope) 151 let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
@@ -154,13 +154,13 @@ fn add_missing_impl_members_inner(
154 .into_iter() 154 .into_iter()
155 .map(|it| ast_transform::apply(&*ast_transform, it)) 155 .map(|it| ast_transform::apply(&*ast_transform, it))
156 .map(|it| match it { 156 .map(|it| match it {
157 ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), 157 ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)),
158 _ => it, 158 _ => it,
159 }) 159 })
160 .map(|it| edit::remove_attrs_and_docs(&it)); 160 .map(|it| edit::remove_attrs_and_docs(&it));
161 let new_impl_item_list = impl_item_list.append_items(items); 161 let new_impl_item_list = impl_item_list.append_items(items);
162 let cursor_position = { 162 let cursor_position = {
163 let first_new_item = new_impl_item_list.impl_items().nth(n_existing_items).unwrap(); 163 let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap();
164 first_new_item.syntax().text_range().start() 164 first_new_item.syntax().text_range().start()
165 }; 165 };
166 166
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 0f9174a29..e8a36c7de 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -162,8 +162,8 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<a
162 162
163fn has_new_fn(imp: &ast::ImplDef) -> bool { 163fn has_new_fn(imp: &ast::ImplDef) -> bool {
164 if let Some(il) = imp.item_list() { 164 if let Some(il) = imp.item_list() {
165 for item in il.impl_items() { 165 for item in il.assoc_items() {
166 if let ast::ImplItem::FnDef(f) = item { 166 if let ast::AssocItem::FnDef(f) = item {
167 if let Some(name) = f.name() { 167 if let Some(name) = f.name() {
168 if name.text().eq_ignore_ascii_case("new") { 168 if name.text().eq_ignore_ascii_case("new") {
169 return true; 169 return true;
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 44f6a1dae..1cd532e80 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -47,8 +47,7 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> {
47 return None; 47 return None;
48 } 48 }
49 (vis_offset(&parent), keyword.text_range()) 49 (vis_offset(&parent), keyword.text_range())
50 } else { 50 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
51 let field_name: ast::Name = ctx.find_node_at_offset()?;
52 let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; 51 let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
53 if field.name()? != field_name { 52 if field.name()? != field_name {
54 tested_by!(change_visibility_field_false_positive); 53 tested_by!(change_visibility_field_false_positive);
@@ -58,6 +57,13 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> {
58 return None; 57 return None;
59 } 58 }
60 (vis_offset(field.syntax()), field_name.syntax().text_range()) 59 (vis_offset(field.syntax()), field_name.syntax().text_range())
60 } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() {
61 if field.visibility().is_some() {
62 return None;
63 }
64 (vis_offset(field.syntax()), field.syntax().text_range())
65 } else {
66 return None;
61 }; 67 };
62 68
63 ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { 69 ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| {
@@ -129,7 +135,8 @@ mod tests {
129 change_visibility, 135 change_visibility,
130 r"struct S { <|>field: u32 }", 136 r"struct S { <|>field: u32 }",
131 r"struct S { <|>pub(crate) field: u32 }", 137 r"struct S { <|>pub(crate) field: u32 }",
132 ) 138 );
139 check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )");
133 } 140 }
134 141
135 #[test] 142 #[test]
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 6be704ce3..2f15a3f15 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -13,7 +13,7 @@ use rustc_hash::FxHashSet;
13 13
14pub(crate) use insert_use::insert_use_statement; 14pub(crate) use insert_use::insert_use_statement;
15 15
16pub fn get_missing_impl_items( 16pub fn get_missing_assoc_items(
17 sema: &Semantics<RootDatabase>, 17 sema: &Semantics<RootDatabase>,
18 impl_def: &ast::ImplDef, 18 impl_def: &ast::ImplDef,
19) -> Vec<hir::AssocItem> { 19) -> Vec<hir::AssocItem> {
@@ -23,21 +23,21 @@ pub fn get_missing_impl_items(
23 let mut impl_type = FxHashSet::default(); 23 let mut impl_type = FxHashSet::default();
24 24
25 if let Some(item_list) = impl_def.item_list() { 25 if let Some(item_list) = impl_def.item_list() {
26 for item in item_list.impl_items() { 26 for item in item_list.assoc_items() {
27 match item { 27 match item {
28 ast::ImplItem::FnDef(f) => { 28 ast::AssocItem::FnDef(f) => {
29 if let Some(n) = f.name() { 29 if let Some(n) = f.name() {
30 impl_fns_consts.insert(n.syntax().to_string()); 30 impl_fns_consts.insert(n.syntax().to_string());
31 } 31 }
32 } 32 }
33 33
34 ast::ImplItem::TypeAliasDef(t) => { 34 ast::AssocItem::TypeAliasDef(t) => {
35 if let Some(n) = t.name() { 35 if let Some(n) = t.name() {
36 impl_type.insert(n.syntax().to_string()); 36 impl_type.insert(n.syntax().to_string());
37 } 37 }
38 } 38 }
39 39
40 ast::ImplItem::ConstDef(c) => { 40 ast::AssocItem::ConstDef(c) => {
41 if let Some(n) = c.name() { 41 if let Some(n) = c.name() {
42 impl_fns_consts.insert(n.syntax().to_string()); 42 impl_fns_consts.insert(n.syntax().to_string());
43 } 43 }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index a004363ee..5f480c304 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1211,7 +1211,7 @@ impl Type {
1211 1211
1212 // This would be nicer if it just returned an iterator, but that runs into 1212 // This would be nicer if it just returned an iterator, but that runs into
1213 // lifetime problems, because we need to borrow temp `CrateImplDefs`. 1213 // lifetime problems, because we need to borrow temp `CrateImplDefs`.
1214 pub fn iterate_impl_items<T>( 1214 pub fn iterate_assoc_items<T>(
1215 self, 1215 self,
1216 db: &dyn HirDatabase, 1216 db: &dyn HirDatabase,
1217 krate: Crate, 1217 krate: Crate,
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index d0912ddaa..2bc34d449 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -118,11 +118,12 @@ fn lower_enum(
118 module_id: ModuleId, 118 module_id: ModuleId,
119) { 119) {
120 let expander = CfgExpander::new(db, ast.file_id, module_id.krate); 120 let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
121 let variants = 121 let variants = ast
122 ast.value.variant_list().into_iter().flat_map(|it| it.variants()).filter(|var| { 122 .value
123 let attrs = expander.parse_attrs(var); 123 .variant_list()
124 expander.is_cfg_enabled(&attrs) 124 .into_iter()
125 }); 125 .flat_map(|it| it.variants())
126 .filter(|var| expander.is_cfg_enabled(var));
126 for var in variants { 127 for var in variants {
127 trace.alloc( 128 trace.alloc(
128 || var.clone(), 129 || var.clone(),
@@ -215,8 +216,7 @@ fn lower_struct(
215 match &ast.value { 216 match &ast.value {
216 ast::StructKind::Tuple(fl) => { 217 ast::StructKind::Tuple(fl) => {
217 for (i, fd) in fl.fields().enumerate() { 218 for (i, fd) in fl.fields().enumerate() {
218 let attrs = expander.parse_attrs(&fd); 219 if !expander.is_cfg_enabled(&fd) {
219 if !expander.is_cfg_enabled(&attrs) {
220 continue; 220 continue;
221 } 221 }
222 222
@@ -233,8 +233,7 @@ fn lower_struct(
233 } 233 }
234 ast::StructKind::Record(fl) => { 234 ast::StructKind::Record(fl) => {
235 for fd in fl.fields() { 235 for fd in fl.fields() {
236 let attrs = expander.parse_attrs(&fd); 236 if !expander.is_cfg_enabled(&fd) {
237 if !expander.is_cfg_enabled(&attrs) {
238 continue; 237 continue;
239 } 238 }
240 239
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 4edaad960..f5a7305dc 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -60,7 +60,8 @@ impl CfgExpander {
60 Attrs::new(owner, &self.hygiene) 60 Attrs::new(owner, &self.hygiene)
61 } 61 }
62 62
63 pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { 63 pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
64 let attrs = self.parse_attrs(owner);
64 attrs.is_cfg_enabled(&self.cfg_options) 65 attrs.is_cfg_enabled(&self.cfg_options)
65 } 66 }
66} 67}
@@ -141,12 +142,8 @@ impl Expander {
141 InFile { file_id: self.current_file_id, value } 142 InFile { file_id: self.current_file_id, value }
142 } 143 }
143 144
144 pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { 145 pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
145 self.cfg_expander.parse_attrs(owner) 146 self.cfg_expander.is_cfg_enabled(owner)
146 }
147
148 pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
149 self.cfg_expander.is_cfg_enabled(attrs)
150 } 147 }
151 148
152 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 149 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 687216dc3..443b057ab 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -162,8 +162,7 @@ impl ExprCollector<'_> {
162 162
163 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { 163 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
164 let syntax_ptr = AstPtr::new(&expr); 164 let syntax_ptr = AstPtr::new(&expr);
165 let attrs = self.expander.parse_attrs(&expr); 165 if !self.expander.is_cfg_enabled(&expr) {
166 if !self.expander.is_cfg_enabled(&attrs) {
167 return self.missing_expr(); 166 return self.missing_expr();
168 } 167 }
169 match expr { 168 match expr {
@@ -329,8 +328,7 @@ impl ExprCollector<'_> {
329 .fields() 328 .fields()
330 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 329 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
331 .filter_map(|field| { 330 .filter_map(|field| {
332 let attrs = self.expander.parse_attrs(&field); 331 if !self.expander.is_cfg_enabled(&field) {
333 if !self.expander.is_cfg_enabled(&attrs) {
334 return None; 332 return None;
335 } 333 }
336 let name = field.field_name()?.as_name(); 334 let name = field.field_name()?.as_name();
@@ -575,9 +573,16 @@ impl ExprCollector<'_> {
575 self.body.item_scope.define_def(def); 573 self.body.item_scope.define_def(def);
576 if let Some(name) = name { 574 if let Some(name) = name {
577 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 575 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
578 self.body 576 let has_constructor = match def {
579 .item_scope 577 ModuleDefId::AdtId(AdtId::StructId(s)) => {
580 .push_res(name.as_name(), crate::per_ns::PerNs::from_def(def, vis)); 578 self.db.struct_data(s).variant_data.kind() != StructKind::Record
579 }
580 _ => true,
581 };
582 self.body.item_scope.push_res(
583 name.as_name(),
584 crate::per_ns::PerNs::from_def(def, vis, has_constructor),
585 );
581 } 586 }
582 } 587 }
583 } 588 }
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index d4cba4d05..e7eb2bb11 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -9,7 +9,7 @@ use hir_expand::{
9}; 9};
10use ra_prof::profile; 10use ra_prof::profile;
11use ra_syntax::ast::{ 11use ra_syntax::ast::{
12 self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, 12 self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner,
13 VisibilityOwner, 13 VisibilityOwner,
14}; 14};
15 15
@@ -164,7 +164,7 @@ impl TraitData {
164 items.extend(collect_items( 164 items.extend(collect_items(
165 db, 165 db,
166 &mut expander, 166 &mut expander,
167 item_list.impl_items(), 167 item_list.assoc_items(),
168 src.file_id, 168 src.file_id,
169 container, 169 container,
170 )); 170 ));
@@ -219,7 +219,7 @@ impl ImplData {
219 if let Some(item_list) = src.value.item_list() { 219 if let Some(item_list) = src.value.item_list() {
220 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); 220 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id);
221 items.extend( 221 items.extend(
222 collect_items(db, &mut expander, item_list.impl_items(), src.file_id, container) 222 collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container)
223 .into_iter() 223 .into_iter()
224 .map(|(_, item)| item), 224 .map(|(_, item)| item),
225 ); 225 );
@@ -304,7 +304,7 @@ fn collect_items_in_macro(
304 let mut res = collect_items( 304 let mut res = collect_items(
305 db, 305 db,
306 expander, 306 expander,
307 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), 307 items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())),
308 items.file_id, 308 items.file_id,
309 container, 309 container,
310 ); 310 );
@@ -325,31 +325,30 @@ fn collect_items_in_macro(
325fn collect_items( 325fn collect_items(
326 db: &dyn DefDatabase, 326 db: &dyn DefDatabase,
327 expander: &mut Expander, 327 expander: &mut Expander,
328 impl_items: impl Iterator<Item = ImplItem>, 328 assoc_items: impl Iterator<Item = AssocItem>,
329 file_id: crate::HirFileId, 329 file_id: crate::HirFileId,
330 container: AssocContainerId, 330 container: AssocContainerId,
331) -> Vec<(Name, AssocItemId)> { 331) -> Vec<(Name, AssocItemId)> {
332 let items = db.ast_id_map(file_id); 332 let items = db.ast_id_map(file_id);
333 333
334 impl_items 334 assoc_items
335 .filter_map(|item_node| match item_node { 335 .filter_map(|item_node| match item_node {
336 ast::ImplItem::FnDef(it) => { 336 ast::AssocItem::FnDef(it) => {
337 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 337 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
338 let attrs = expander.parse_attrs(&it); 338 if !expander.is_cfg_enabled(&it) {
339 if !expander.is_cfg_enabled(&attrs) {
340 return None; 339 return None;
341 } 340 }
342 let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 341 let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) }
343 .intern(db); 342 .intern(db);
344 Some((name, def.into())) 343 Some((name, def.into()))
345 } 344 }
346 ast::ImplItem::ConstDef(it) => { 345 ast::AssocItem::ConstDef(it) => {
347 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 346 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
348 let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 347 let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) }
349 .intern(db); 348 .intern(db);
350 Some((name, def.into())) 349 Some((name, def.into()))
351 } 350 }
352 ast::ImplItem::TypeAliasDef(it) => { 351 ast::AssocItem::TypeAliasDef(it) => {
353 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 352 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
354 let def = 353 let def =
355 TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 354 TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) }
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 259b9ff03..fc15948ad 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -151,13 +151,20 @@ impl ItemScope {
151} 151}
152 152
153impl PerNs { 153impl PerNs {
154 pub(crate) fn from_def(def: ModuleDefId, v: Visibility) -> PerNs { 154 pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
155 match def { 155 match def {
156 ModuleDefId::ModuleId(_) => PerNs::types(def, v), 156 ModuleDefId::ModuleId(_) => PerNs::types(def, v),
157 ModuleDefId::FunctionId(_) => PerNs::values(def, v), 157 ModuleDefId::FunctionId(_) => PerNs::values(def, v),
158 ModuleDefId::AdtId(adt) => match adt { 158 ModuleDefId::AdtId(adt) => match adt {
159 AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def, v), 159 AdtId::UnionId(_) => PerNs::types(def, v),
160 AdtId::EnumId(_) => PerNs::types(def, v), 160 AdtId::EnumId(_) => PerNs::types(def, v),
161 AdtId::StructId(_) => {
162 if has_constructor {
163 PerNs::both(def, def, v)
164 } else {
165 PerNs::types(def, v)
166 }
167 }
161 }, 168 },
162 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v), 169 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
163 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v), 170 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index bf3968bd6..db994122a 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -830,7 +830,7 @@ impl ModCollector<'_, '_> {
830 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; 830 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
831 let def: ModuleDefId = module.into(); 831 let def: ModuleDefId = module.into();
832 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 832 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
833 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis); 833 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis, false))], vis);
834 res 834 res
835 } 835 }
836 836
@@ -844,6 +844,8 @@ impl ModCollector<'_, '_> {
844 let name = def.name.clone(); 844 let name = def.name.clone();
845 let container = ContainerId::ModuleId(module); 845 let container = ContainerId::ModuleId(module);
846 let vis = &def.visibility; 846 let vis = &def.visibility;
847 let mut has_constructor = false;
848
847 let def: ModuleDefId = match def.kind { 849 let def: ModuleDefId = match def.kind {
848 raw::DefKind::Function(ast_id) => FunctionLoc { 850 raw::DefKind::Function(ast_id) => FunctionLoc {
849 container: container.into(), 851 container: container.into(),
@@ -851,7 +853,8 @@ impl ModCollector<'_, '_> {
851 } 853 }
852 .intern(self.def_collector.db) 854 .intern(self.def_collector.db)
853 .into(), 855 .into(),
854 raw::DefKind::Struct(ast_id) => { 856 raw::DefKind::Struct(ast_id, mode) => {
857 has_constructor = mode != raw::StructDefKind::Record;
855 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) } 858 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
856 .intern(self.def_collector.db) 859 .intern(self.def_collector.db)
857 .into() 860 .into()
@@ -894,7 +897,11 @@ impl ModCollector<'_, '_> {
894 .def_map 897 .def_map
895 .resolve_visibility(self.def_collector.db, self.module_id, vis) 898 .resolve_visibility(self.def_collector.db, self.module_id, vis)
896 .unwrap_or(Visibility::Public); 899 .unwrap_or(Visibility::Public);
897 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis) 900 self.def_collector.update(
901 self.module_id,
902 &[(name, PerNs::from_def(def, vis, has_constructor))],
903 vis,
904 )
898 } 905 }
899 906
900 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { 907 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index a71503c76..f2716a295 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -156,9 +156,16 @@ pub(super) struct DefData {
156} 156}
157 157
158#[derive(Debug, PartialEq, Eq, Clone, Copy)] 158#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159pub(super) enum StructDefKind {
160 Record,
161 Tuple,
162 Unit,
163}
164
165#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159pub(super) enum DefKind { 166pub(super) enum DefKind {
160 Function(FileAstId<ast::FnDef>), 167 Function(FileAstId<ast::FnDef>),
161 Struct(FileAstId<ast::StructDef>), 168 Struct(FileAstId<ast::StructDef>, StructDefKind),
162 Union(FileAstId<ast::UnionDef>), 169 Union(FileAstId<ast::UnionDef>),
163 Enum(FileAstId<ast::EnumDef>), 170 Enum(FileAstId<ast::EnumDef>),
164 Const(FileAstId<ast::ConstDef>), 171 Const(FileAstId<ast::ConstDef>),
@@ -171,7 +178,7 @@ impl DefKind {
171 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { 178 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> {
172 match self { 179 match self {
173 DefKind::Function(it) => it.upcast(), 180 DefKind::Function(it) => it.upcast(),
174 DefKind::Struct(it) => it.upcast(), 181 DefKind::Struct(it, _) => it.upcast(),
175 DefKind::Union(it) => it.upcast(), 182 DefKind::Union(it) => it.upcast(),
176 DefKind::Enum(it) => it.upcast(), 183 DefKind::Enum(it) => it.upcast(),
177 DefKind::Const(it) => it.upcast(), 184 DefKind::Const(it) => it.upcast(),
@@ -236,9 +243,14 @@ impl RawItemsCollector {
236 return; 243 return;
237 } 244 }
238 ast::ModuleItem::StructDef(it) => { 245 ast::ModuleItem::StructDef(it) => {
246 let kind = match it.kind() {
247 ast::StructKind::Record(_) => StructDefKind::Record,
248 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
249 ast::StructKind::Unit => StructDefKind::Unit,
250 };
239 let id = self.source_ast_id_map.ast_id(&it); 251 let id = self.source_ast_id_map.ast_id(&it);
240 let name = it.name(); 252 let name = it.name();
241 (DefKind::Struct(id), name) 253 (DefKind::Struct(id, kind), name)
242 } 254 }
243 ast::ModuleItem::UnionDef(it) => { 255 ast::ModuleItem::UnionDef(it) => {
244 let id = self.source_ast_id_map.ast_id(&it); 256 let id = self.source_ast_id_map.ast_id(&it);
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 83120fa36..1b66c1aac 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -67,7 +67,7 @@ fn crate_def_map_smoke_test() {
67 ⋮Baz: t v 67 ⋮Baz: t v
68 ⋮E: t 68 ⋮E: t
69 ⋮EXT: v 69 ⋮EXT: v
70 ⋮U: t v 70 ⋮U: t
71 ⋮ext: v 71 ⋮ext: v
72 "###) 72 "###)
73} 73}
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 9bc0e6287..40289e3ca 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -19,12 +19,12 @@ fn macro_rules_are_globally_visible() {
19 ); 19 );
20 assert_snapshot!(map, @r###" 20 assert_snapshot!(map, @r###"
21 ⋮crate 21 ⋮crate
22 ⋮Foo: t v 22 ⋮Foo: t
23 ⋮nested: t 23 ⋮nested: t
24 24
25 ⋮crate::nested 25 ⋮crate::nested
26 ⋮Bar: t v 26 ⋮Bar: t
27 ⋮Baz: t v 27 ⋮Baz: t
28 "###); 28 "###);
29} 29}
30 30
@@ -91,13 +91,13 @@ fn macro_rules_from_other_crates_are_visible() {
91 ); 91 );
92 assert_snapshot!(map, @r###" 92 assert_snapshot!(map, @r###"
93 ⋮crate 93 ⋮crate
94 ⋮Bar: t v 94 ⋮Bar: t
95 ⋮Foo: t v 95 ⋮Foo: t
96 ⋮bar: t 96 ⋮bar: t
97 97
98 ⋮crate::bar 98 ⋮crate::bar
99 ⋮Bar: t v 99 ⋮Bar: t
100 ⋮Foo: t v 100 ⋮Foo: t
101 ⋮bar: t 101 ⋮bar: t
102 "###); 102 "###);
103} 103}
@@ -124,13 +124,13 @@ fn macro_rules_export_with_local_inner_macros_are_visible() {
124 ); 124 );
125 assert_snapshot!(map, @r###" 125 assert_snapshot!(map, @r###"
126 ⋮crate 126 ⋮crate
127 ⋮Bar: t v 127 ⋮Bar: t
128 ⋮Foo: t v 128 ⋮Foo: t
129 ⋮bar: t 129 ⋮bar: t
130 130
131 ⋮crate::bar 131 ⋮crate::bar
132 ⋮Bar: t v 132 ⋮Bar: t
133 ⋮Foo: t v 133 ⋮Foo: t
134 ⋮bar: t 134 ⋮bar: t
135 "###); 135 "###);
136} 136}
@@ -161,13 +161,13 @@ fn local_inner_macros_makes_local_macros_usable() {
161 ); 161 );
162 assert_snapshot!(map, @r###" 162 assert_snapshot!(map, @r###"
163 ⋮crate 163 ⋮crate
164 ⋮Bar: t v 164 ⋮Bar: t
165 ⋮Foo: t v 165 ⋮Foo: t
166 ⋮bar: t 166 ⋮bar: t
167 167
168 ⋮crate::bar 168 ⋮crate::bar
169 ⋮Bar: t v 169 ⋮Bar: t
170 ⋮Foo: t v 170 ⋮Foo: t
171 ⋮bar: t 171 ⋮bar: t
172 "###); 172 "###);
173} 173}
@@ -204,7 +204,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
204 ); 204 );
205 assert_snapshot!(map, @r###" 205 assert_snapshot!(map, @r###"
206 ⋮crate 206 ⋮crate
207 ⋮Foo: t v 207 ⋮Foo: t
208 ⋮bar: m 208 ⋮bar: m
209 ⋮foo: m 209 ⋮foo: m
210 "###); 210 "###);
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 29e38a06c..07398ddcc 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -269,7 +269,7 @@ fn test() { S.foo()<|>; }
269} 269}
270 270
271#[test] 271#[test]
272fn infer_impl_items_generated_by_macros() { 272fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 273 let t = type_at(
274 r#" 274 r#"
275//- /main.rs 275//- /main.rs
@@ -288,7 +288,7 @@ fn test() { S.foo()<|>; }
288} 288}
289 289
290#[test] 290#[test]
291fn infer_impl_items_generated_by_macros_chain() { 291fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 292 let t = type_at(
293 r#" 293 r#"
294//- /main.rs 294//- /main.rs
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 8a1292c7a..115ad8328 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -535,6 +535,35 @@ fn foo(b: Bar) {
535} 535}
536 536
537#[test] 537#[test]
538fn issue_4235_name_conflicts() {
539 assert_snapshot!(
540 infer(r#"
541struct FOO {}
542static FOO:FOO = FOO {};
543
544impl FOO {
545 fn foo(&self) {}
546}
547
548fn main() {
549 let a = &FOO;
550 a.foo();
551}
552"#), @r###"
553 32..38 'FOO {}': FOO
554 64..68 'self': &FOO
555 70..72 '{}': ()
556 86..120 '{ ...o(); }': ()
557 96..97 'a': &FOO
558 100..104 '&FOO': &FOO
559 101..104 'FOO': FOO
560 110..111 'a': &FOO
561 110..117 'a.foo()': ()
562"###
563 );
564}
565
566#[test]
538fn issue_4053_diesel_where_clauses() { 567fn issue_4053_diesel_where_clauses() {
539 assert_snapshot!( 568 assert_snapshot!(
540 infer(r#" 569 infer(r#"
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index d9ea92ef8..7fcd22525 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -84,7 +84,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
84 }); 84 });
85 85
86 // Iterate assoc types separately 86 // Iterate assoc types separately
87 ty.iterate_impl_items(ctx.db, krate, |item| { 87 ty.iterate_assoc_items(ctx.db, krate, |item| {
88 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 88 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
89 return None; 89 return None;
90 } 90 }
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index ee32d1ff6..039df03e0 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -32,7 +32,7 @@
32//! ``` 32//! ```
33 33
34use hir::{self, Docs, HasSource}; 34use hir::{self, Docs, HasSource};
35use ra_assists::utils::get_missing_impl_items; 35use ra_assists::utils::get_missing_assoc_items;
36use ra_syntax::{ 36use ra_syntax::{
37 ast::{self, edit, ImplDef}, 37 ast::{self, edit, ImplDef},
38 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 38 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
@@ -50,7 +50,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
50 if let Some((trigger, impl_def)) = completion_match(ctx) { 50 if let Some((trigger, impl_def)) = completion_match(ctx) {
51 match trigger.kind() { 51 match trigger.kind() {
52 SyntaxKind::NAME_REF => { 52 SyntaxKind::NAME_REF => {
53 get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { 53 get_missing_assoc_items(&ctx.sema, &impl_def).iter().for_each(|item| match item {
54 hir::AssocItem::Function(fn_item) => { 54 hir::AssocItem::Function(fn_item) => {
55 add_function_impl(&trigger, acc, ctx, &fn_item) 55 add_function_impl(&trigger, acc, ctx, &fn_item)
56 } 56 }
@@ -64,34 +64,40 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
64 } 64 }
65 65
66 SyntaxKind::FN_DEF => { 66 SyntaxKind::FN_DEF => {
67 for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( 67 for missing_fn in
68 |item| match item { 68 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| {
69 hir::AssocItem::Function(fn_item) => Some(fn_item), 69 match item {
70 _ => None, 70 hir::AssocItem::Function(fn_item) => Some(fn_item),
71 }, 71 _ => None,
72 ) { 72 }
73 })
74 {
73 add_function_impl(&trigger, acc, ctx, &missing_fn); 75 add_function_impl(&trigger, acc, ctx, &missing_fn);
74 } 76 }
75 } 77 }
76 78
77 SyntaxKind::TYPE_ALIAS_DEF => { 79 SyntaxKind::TYPE_ALIAS_DEF => {
78 for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( 80 for missing_fn in
79 |item| match item { 81 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| {
80 hir::AssocItem::TypeAlias(type_item) => Some(type_item), 82 match item {
81 _ => None, 83 hir::AssocItem::TypeAlias(type_item) => Some(type_item),
82 }, 84 _ => None,
83 ) { 85 }
86 })
87 {
84 add_type_alias_impl(&trigger, acc, ctx, &missing_fn); 88 add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
85 } 89 }
86 } 90 }
87 91
88 SyntaxKind::CONST_DEF => { 92 SyntaxKind::CONST_DEF => {
89 for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( 93 for missing_fn in
90 |item| match item { 94 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| {
91 hir::AssocItem::Const(const_item) => Some(const_item), 95 match item {
92 _ => None, 96 hir::AssocItem::Const(const_item) => Some(const_item),
93 }, 97 _ => None,
94 ) { 98 }
99 })
100 {
95 add_const_impl(&trigger, acc, ctx, &missing_fn); 101 add_const_impl(&trigger, acc, ctx, &missing_fn);
96 } 102 }
97 } 103 }
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 38637c19c..fa8a9d92c 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -9,6 +9,7 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::FileId; 11use crate::FileId;
12use ast::DocCommentsOwner;
12use std::fmt::Display; 13use std::fmt::Display;
13 14
14#[derive(Debug)] 15#[derive(Debug)]
@@ -37,6 +38,7 @@ pub enum RunnableKind {
37 Test { test_id: TestId, attr: TestAttr }, 38 Test { test_id: TestId, attr: TestAttr },
38 TestMod { path: String }, 39 TestMod { path: String },
39 Bench { test_id: TestId }, 40 Bench { test_id: TestId },
41 DocTest { test_id: TestId },
40 Bin, 42 Bin,
41} 43}
42 44
@@ -81,6 +83,8 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
81 RunnableKind::Test { test_id, attr } 83 RunnableKind::Test { test_id, attr }
82 } else if fn_def.has_atom_attr("bench") { 84 } else if fn_def.has_atom_attr("bench") {
83 RunnableKind::Bench { test_id } 85 RunnableKind::Bench { test_id }
86 } else if has_doc_test(&fn_def) {
87 RunnableKind::DocTest { test_id }
84 } else { 88 } else {
85 return None; 89 return None;
86 } 90 }
@@ -117,6 +121,10 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
117 .any(|attribute_text| attribute_text.contains("test")) 121 .any(|attribute_text| attribute_text.contains("test"))
118} 122}
119 123
124fn has_doc_test(fn_def: &ast::FnDef) -> bool {
125 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
126}
127
120fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { 128fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
121 let has_test_function = module 129 let has_test_function = module
122 .item_list()? 130 .item_list()?
@@ -195,6 +203,41 @@ mod tests {
195 } 203 }
196 204
197 #[test] 205 #[test]
206 fn test_runnables_doc_test() {
207 let (analysis, pos) = analysis_and_position(
208 r#"
209 //- /lib.rs
210 <|> //empty
211 fn main() {}
212
213 /// ```
214 /// let x = 5;
215 /// ```
216 fn foo() {}
217 "#,
218 );
219 let runnables = analysis.runnables(pos.file_id).unwrap();
220 assert_debug_snapshot!(&runnables,
221 @r###"
222 [
223 Runnable {
224 range: 1..21,
225 kind: Bin,
226 },
227 Runnable {
228 range: 22..64,
229 kind: DocTest {
230 test_id: Path(
231 "foo",
232 ),
233 },
234 },
235 ]
236 "###
237 );
238 }
239
240 #[test]
198 fn test_runnables_module() { 241 fn test_runnables_module() {
199 let (analysis, pos) = analysis_and_position( 242 let (analysis, pos) = analysis_and_position(
200 r#" 243 r#"
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index bb28acfd9..fc4133a67 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -63,7 +63,7 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke
63// * Items(SmallVec<[P<ast::Item>; 1]>) -> token_tree_to_items 63// * Items(SmallVec<[P<ast::Item>; 1]>) -> token_tree_to_items
64// 64//
65// * TraitItems(SmallVec<[ast::TraitItem; 1]>) 65// * TraitItems(SmallVec<[ast::TraitItem; 1]>)
66// * ImplItems(SmallVec<[ast::ImplItem; 1]>) 66// * AssocItems(SmallVec<[ast::AssocItem; 1]>)
67// * ForeignItems(SmallVec<[ast::ForeignItem; 1]> 67// * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
68 68
69pub fn token_tree_to_syntax_node( 69pub fn token_tree_to_syntax_node(
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index c507dc683..3e6dd6061 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -79,7 +79,7 @@ where
79 79
80impl ast::ItemList { 80impl ast::ItemList {
81 #[must_use] 81 #[must_use]
82 pub fn append_items(&self, items: impl IntoIterator<Item = ast::ImplItem>) -> ast::ItemList { 82 pub fn append_items(&self, items: impl IntoIterator<Item = ast::AssocItem>) -> ast::ItemList {
83 let mut res = self.clone(); 83 let mut res = self.clone();
84 if !self.syntax().text().contains_char('\n') { 84 if !self.syntax().text().contains_char('\n') {
85 res = make_multiline(res); 85 res = make_multiline(res);
@@ -89,8 +89,8 @@ impl ast::ItemList {
89 } 89 }
90 90
91 #[must_use] 91 #[must_use]
92 pub fn append_item(&self, item: ast::ImplItem) -> ast::ItemList { 92 pub fn append_item(&self, item: ast::AssocItem) -> ast::ItemList {
93 let (indent, position) = match self.impl_items().last() { 93 let (indent, position) = match self.assoc_items().last() {
94 Some(it) => ( 94 Some(it) => (
95 leading_indent(it.syntax()).unwrap_or_default().to_string(), 95 leading_indent(it.syntax()).unwrap_or_default().to_string(),
96 InsertPosition::After(it.syntax().clone().into()), 96 InsertPosition::After(it.syntax().clone().into()),
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index c2cc25958..b00c15608 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -196,7 +196,7 @@ pub struct ItemList {
196impl ast::ModuleItemOwner for ItemList {} 196impl ast::ModuleItemOwner for ItemList {}
197impl ItemList { 197impl ItemList {
198 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 198 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
199 pub fn impl_items(&self) -> AstChildren<ImplItem> { support::children(&self.syntax) } 199 pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
200 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 200 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
201} 201}
202 202
@@ -1429,13 +1429,13 @@ impl ast::AttrsOwner for ModuleItem {}
1429impl ast::VisibilityOwner for ModuleItem {} 1429impl ast::VisibilityOwner for ModuleItem {}
1430 1430
1431#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1431#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1432pub enum ImplItem { 1432pub enum AssocItem {
1433 FnDef(FnDef), 1433 FnDef(FnDef),
1434 TypeAliasDef(TypeAliasDef), 1434 TypeAliasDef(TypeAliasDef),
1435 ConstDef(ConstDef), 1435 ConstDef(ConstDef),
1436} 1436}
1437impl ast::NameOwner for ImplItem {} 1437impl ast::NameOwner for AssocItem {}
1438impl ast::AttrsOwner for ImplItem {} 1438impl ast::AttrsOwner for AssocItem {}
1439 1439
1440#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1440#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1441pub enum ExternItem { 1441pub enum ExternItem {
@@ -3167,16 +3167,16 @@ impl AstNode for ModuleItem {
3167 } 3167 }
3168 } 3168 }
3169} 3169}
3170impl From<FnDef> for ImplItem { 3170impl From<FnDef> for AssocItem {
3171 fn from(node: FnDef) -> ImplItem { ImplItem::FnDef(node) } 3171 fn from(node: FnDef) -> AssocItem { AssocItem::FnDef(node) }
3172} 3172}
3173impl From<TypeAliasDef> for ImplItem { 3173impl From<TypeAliasDef> for AssocItem {
3174 fn from(node: TypeAliasDef) -> ImplItem { ImplItem::TypeAliasDef(node) } 3174 fn from(node: TypeAliasDef) -> AssocItem { AssocItem::TypeAliasDef(node) }
3175} 3175}
3176impl From<ConstDef> for ImplItem { 3176impl From<ConstDef> for AssocItem {
3177 fn from(node: ConstDef) -> ImplItem { ImplItem::ConstDef(node) } 3177 fn from(node: ConstDef) -> AssocItem { AssocItem::ConstDef(node) }
3178} 3178}
3179impl AstNode for ImplItem { 3179impl AstNode for AssocItem {
3180 fn can_cast(kind: SyntaxKind) -> bool { 3180 fn can_cast(kind: SyntaxKind) -> bool {
3181 match kind { 3181 match kind {
3182 FN_DEF | TYPE_ALIAS_DEF | CONST_DEF => true, 3182 FN_DEF | TYPE_ALIAS_DEF | CONST_DEF => true,
@@ -3185,18 +3185,18 @@ impl AstNode for ImplItem {
3185 } 3185 }
3186 fn cast(syntax: SyntaxNode) -> Option<Self> { 3186 fn cast(syntax: SyntaxNode) -> Option<Self> {
3187 let res = match syntax.kind() { 3187 let res = match syntax.kind() {
3188 FN_DEF => ImplItem::FnDef(FnDef { syntax }), 3188 FN_DEF => AssocItem::FnDef(FnDef { syntax }),
3189 TYPE_ALIAS_DEF => ImplItem::TypeAliasDef(TypeAliasDef { syntax }), 3189 TYPE_ALIAS_DEF => AssocItem::TypeAliasDef(TypeAliasDef { syntax }),
3190 CONST_DEF => ImplItem::ConstDef(ConstDef { syntax }), 3190 CONST_DEF => AssocItem::ConstDef(ConstDef { syntax }),
3191 _ => return None, 3191 _ => return None,
3192 }; 3192 };
3193 Some(res) 3193 Some(res)
3194 } 3194 }
3195 fn syntax(&self) -> &SyntaxNode { 3195 fn syntax(&self) -> &SyntaxNode {
3196 match self { 3196 match self {
3197 ImplItem::FnDef(it) => &it.syntax, 3197 AssocItem::FnDef(it) => &it.syntax,
3198 ImplItem::TypeAliasDef(it) => &it.syntax, 3198 AssocItem::TypeAliasDef(it) => &it.syntax,
3199 ImplItem::ConstDef(it) => &it.syntax, 3199 AssocItem::ConstDef(it) => &it.syntax,
3200 } 3200 }
3201 } 3201 }
3202} 3202}
@@ -3641,7 +3641,7 @@ impl std::fmt::Display for ModuleItem {
3641 std::fmt::Display::fmt(self.syntax(), f) 3641 std::fmt::Display::fmt(self.syntax(), f)
3642 } 3642 }
3643} 3643}
3644impl std::fmt::Display for ImplItem { 3644impl std::fmt::Display for AssocItem {
3645 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 3645 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3646 std::fmt::Display::fmt(self.syntax(), f) 3646 std::fmt::Display::fmt(self.syntax(), f)
3647 } 3647 }
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 10c25666a..5e5a17943 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -27,7 +27,7 @@ impl CargoTargetSpec {
27 RunnableKind::Test { test_id, attr } => { 27 RunnableKind::Test { test_id, attr } => {
28 args.push("test".to_string()); 28 args.push("test".to_string());
29 if let Some(spec) = spec { 29 if let Some(spec) = spec {
30 spec.push_to(&mut args); 30 spec.push_to(&mut args, kind);
31 } 31 }
32 extra_args.push(test_id.to_string()); 32 extra_args.push(test_id.to_string());
33 if let TestId::Path(_) = test_id { 33 if let TestId::Path(_) = test_id {
@@ -35,13 +35,13 @@ impl CargoTargetSpec {
35 } 35 }
36 extra_args.push("--nocapture".to_string()); 36 extra_args.push("--nocapture".to_string());
37 if attr.ignore { 37 if attr.ignore {
38 extra_args.push("--ignored".to_string()) 38 extra_args.push("--ignored".to_string());
39 } 39 }
40 } 40 }
41 RunnableKind::TestMod { path } => { 41 RunnableKind::TestMod { path } => {
42 args.push("test".to_string()); 42 args.push("test".to_string());
43 if let Some(spec) = spec { 43 if let Some(spec) = spec {
44 spec.push_to(&mut args); 44 spec.push_to(&mut args, kind);
45 } 45 }
46 extra_args.push(path.to_string()); 46 extra_args.push(path.to_string());
47 extra_args.push("--nocapture".to_string()); 47 extra_args.push("--nocapture".to_string());
@@ -49,7 +49,7 @@ impl CargoTargetSpec {
49 RunnableKind::Bench { test_id } => { 49 RunnableKind::Bench { test_id } => {
50 args.push("bench".to_string()); 50 args.push("bench".to_string());
51 if let Some(spec) = spec { 51 if let Some(spec) = spec {
52 spec.push_to(&mut args); 52 spec.push_to(&mut args, kind);
53 } 53 }
54 extra_args.push(test_id.to_string()); 54 extra_args.push(test_id.to_string());
55 if let TestId::Path(_) = test_id { 55 if let TestId::Path(_) = test_id {
@@ -57,10 +57,19 @@ impl CargoTargetSpec {
57 } 57 }
58 extra_args.push("--nocapture".to_string()); 58 extra_args.push("--nocapture".to_string());
59 } 59 }
60 RunnableKind::DocTest { test_id } => {
61 args.push("test".to_string());
62 args.push("--doc".to_string());
63 if let Some(spec) = spec {
64 spec.push_to(&mut args, kind);
65 }
66 extra_args.push(test_id.to_string());
67 extra_args.push("--nocapture".to_string());
68 }
60 RunnableKind::Bin => { 69 RunnableKind::Bin => {
61 args.push("run".to_string()); 70 args.push("run".to_string());
62 if let Some(spec) = spec { 71 if let Some(spec) = spec {
63 spec.push_to(&mut args); 72 spec.push_to(&mut args, kind);
64 } 73 }
65 } 74 }
66 } 75 }
@@ -91,9 +100,14 @@ impl CargoTargetSpec {
91 Ok(res) 100 Ok(res)
92 } 101 }
93 102
94 pub(crate) fn push_to(self, buf: &mut Vec<String>) { 103 pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
95 buf.push("--package".to_string()); 104 buf.push("--package".to_string());
96 buf.push(self.package); 105 buf.push(self.package);
106
107 // Can't mix --doc with other target flags
108 if let RunnableKind::DocTest { .. } = kind {
109 return;
110 }
97 match self.target_kind { 111 match self.target_kind {
98 TargetKind::Bin => { 112 TargetKind::Bin => {
99 buf.push("--bin".to_string()); 113 buf.push("--bin".to_string());
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index c7a96ba93..15e8305f8 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -835,6 +835,7 @@ pub fn handle_code_lens(
835 for runnable in world.analysis().runnables(file_id)? { 835 for runnable in world.analysis().runnables(file_id)? {
836 let title = match &runnable.kind { 836 let title = match &runnable.kind {
837 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test", 837 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test",
838 RunnableKind::DocTest { .. } => "▶️\u{fe0e}Run Doctest",
838 RunnableKind::Bench { .. } => "Run Bench", 839 RunnableKind::Bench { .. } => "Run Bench",
839 RunnableKind::Bin => "Run", 840 RunnableKind::Bin => "Run",
840 } 841 }
@@ -1018,6 +1019,7 @@ fn to_lsp_runnable(
1018 RunnableKind::Test { test_id, .. } => format!("test {}", test_id), 1019 RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
1019 RunnableKind::TestMod { path } => format!("test-mod {}", path), 1020 RunnableKind::TestMod { path } => format!("test-mod {}", path),
1020 RunnableKind::Bench { test_id } => format!("bench {}", test_id), 1021 RunnableKind::Bench { test_id } => format!("bench {}", test_id),
1022 RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id),
1021 RunnableKind::Bin => "run binary".to_string(), 1023 RunnableKind::Bin => "run binary".to_string(),
1022 }; 1024 };
1023 Ok(req::Runnable { 1025 Ok(req::Runnable {
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index b1af72ce6..69f5b13d6 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -57,7 +57,11 @@ To disable this notification put the following to `settings.json`
57---- 57----
58==== 58====
59 59
60The server binary is stored in `~/.config/Code/User/globalStorage/matklad.rust-analyzer` (Linux) or in `~/.Library/Application Support/Code/User/globalStorage/matklad.rust-analyzer` (macOS) or in `%APPDATA%\Code\User\globalStorage` (Windows). 60The server binary is stored in:
61
62* Linux: `~/.config/Code/User/globalStorage/matklad.rust-analyzer`
63* macOS: `~/Library/Application Support/Code/User/globalStorage/matklad.rust-analyzer`
64* Windows: `%APPDATA%\Code\User\globalStorage`
61 65
62Note that we only support the latest version of VS Code. 66Note that we only support the latest version of VS Code.
63 67
@@ -159,11 +163,11 @@ Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode
1593. Run `lsp` in a Rust buffer. 1633. Run `lsp` in a Rust buffer.
1604. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. 1644. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys.
161 165
162=== Vim 166=== Vim/NeoVim
163 167
164Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. 168Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example.
165 169
166The are several LSP client implementations for vim: 170The are several LSP client implementations for vim or neovim:
167 171
168==== coc-rust-analyzer 172==== coc-rust-analyzer
169 173
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 2f8065b73..fe3eb85de 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -373,7 +373,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
373 373
374 struct ItemList: ModuleItemOwner { 374 struct ItemList: ModuleItemOwner {
375 T!['{'], 375 T!['{'],
376 impl_items: [ImplItem], 376 assoc_items: [AssocItem],
377 T!['}'] 377 T!['}']
378 } 378 }
379 379
@@ -685,7 +685,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
685 } 685 }
686 686
687 /* impl blocks can also contain MacroCall */ 687 /* impl blocks can also contain MacroCall */
688 enum ImplItem: NameOwner, AttrsOwner { 688 enum AssocItem: NameOwner, AttrsOwner {
689 FnDef, TypeAliasDef, ConstDef 689 FnDef, TypeAliasDef, ConstDef
690 } 690 }
691 691