aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-07-31 03:12:44 +0100
committerZac Pullar-Strecker <[email protected]>2020-07-31 03:12:44 +0100
commitf05d7b41a719d848844b054a16477b29d0f063c6 (patch)
tree0a8a0946e8aef2ce64d4c13d0035ba41cce2daf3 /crates/ra_hir_def/src
parent73ff610e41959e3e7c78a2b4b25b086883132956 (diff)
parent6b7cb8b5ab539fc4333ce34bc29bf77c976f232a (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Hasn't fixed tests yet.
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r--crates/ra_hir_def/src/adt.rs18
-rw-r--r--crates/ra_hir_def/src/attr.rs28
-rw-r--r--crates/ra_hir_def/src/body.rs69
-rw-r--r--crates/ra_hir_def/src/body/lower.rs48
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs2
-rw-r--r--crates/ra_hir_def/src/data.rs4
-rw-r--r--crates/ra_hir_def/src/generics.rs12
-rw-r--r--crates/ra_hir_def/src/import_map.rs370
-rw-r--r--crates/ra_hir_def/src/item_scope.rs132
-rw-r--r--crates/ra_hir_def/src/item_tree.rs53
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs187
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs218
-rw-r--r--crates/ra_hir_def/src/keys.rs26
-rw-r--r--crates/ra_hir_def/src/lib.rs55
-rw-r--r--crates/ra_hir_def/src/nameres.rs22
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs116
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs10
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs972
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs578
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs1061
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs1289
-rw-r--r--crates/ra_hir_def/src/nameres/tests/primitives.rs33
-rw-r--r--crates/ra_hir_def/src/path.rs2
-rw-r--r--crates/ra_hir_def/src/path/lower.rs6
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs8
-rw-r--r--crates/ra_hir_def/src/test_db.rs28
-rw-r--r--crates/ra_hir_def/src/type_ref.rs34
-rw-r--r--crates/ra_hir_def/src/visibility.rs41
30 files changed, 2938 insertions, 2591 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 4994a2125..6cb56a1cd 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,7 +8,7 @@ use hir_expand::{
8 InFile, 8 InFile,
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12 12
13use crate::{ 13use crate::{
14 body::{CfgExpander, LowerCtx}, 14 body::{CfgExpander, LowerCtx},
@@ -112,7 +112,7 @@ impl EnumData {
112 112
113impl HasChildSource for EnumId { 113impl HasChildSource for EnumId {
114 type ChildId = LocalEnumVariantId; 114 type ChildId = LocalEnumVariantId;
115 type Value = ast::EnumVariant; 115 type Value = ast::Variant;
116 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 116 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
117 let src = self.lookup(db).source(db); 117 let src = self.lookup(db).source(db);
118 let mut trace = Trace::new_for_map(); 118 let mut trace = Trace::new_for_map();
@@ -123,8 +123,8 @@ impl HasChildSource for EnumId {
123 123
124fn lower_enum( 124fn lower_enum(
125 db: &dyn DefDatabase, 125 db: &dyn DefDatabase,
126 trace: &mut Trace<EnumVariantData, ast::EnumVariant>, 126 trace: &mut Trace<EnumVariantData, ast::Variant>,
127 ast: &InFile<ast::EnumDef>, 127 ast: &InFile<ast::Enum>,
128 module_id: ModuleId, 128 module_id: ModuleId,
129) { 129) {
130 let expander = CfgExpander::new(db, ast.file_id, module_id.krate); 130 let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
@@ -179,7 +179,7 @@ impl VariantData {
179 179
180impl HasChildSource for VariantId { 180impl HasChildSource for VariantId {
181 type ChildId = LocalFieldId; 181 type ChildId = LocalFieldId;
182 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; 182 type Value = Either<ast::TupleField, ast::RecordField>;
183 183
184 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 184 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
185 let (src, module_id) = match self { 185 let (src, module_id) = match self {
@@ -194,7 +194,7 @@ impl HasChildSource for VariantId {
194 } 194 }
195 VariantId::UnionId(it) => ( 195 VariantId::UnionId(it) => (
196 it.lookup(db).source(db).map(|it| { 196 it.lookup(db).source(db).map(|it| {
197 it.record_field_def_list() 197 it.record_field_list()
198 .map(ast::StructKind::Record) 198 .map(ast::StructKind::Record)
199 .unwrap_or(ast::StructKind::Unit) 199 .unwrap_or(ast::StructKind::Unit)
200 }), 200 }),
@@ -218,7 +218,7 @@ pub enum StructKind {
218fn lower_struct( 218fn lower_struct(
219 db: &dyn DefDatabase, 219 db: &dyn DefDatabase,
220 expander: &mut CfgExpander, 220 expander: &mut CfgExpander,
221 trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, 221 trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>,
222 ast: &InFile<ast::StructKind>, 222 ast: &InFile<ast::StructKind>,
223) -> StructKind { 223) -> StructKind {
224 let ctx = LowerCtx::new(db, ast.file_id); 224 let ctx = LowerCtx::new(db, ast.file_id);
@@ -234,7 +234,7 @@ fn lower_struct(
234 || Either::Left(fd.clone()), 234 || Either::Left(fd.clone()),
235 || FieldData { 235 || FieldData {
236 name: Name::new_tuple_field(i), 236 name: Name::new_tuple_field(i),
237 type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()), 237 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
238 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 238 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
239 }, 239 },
240 ); 240 );
@@ -251,7 +251,7 @@ fn lower_struct(
251 || Either::Right(fd.clone()), 251 || Either::Right(fd.clone()),
252 || FieldData { 252 || FieldData {
253 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 253 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
254 type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()), 254 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
255 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 255 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
256 }, 256 },
257 ); 257 );
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index e228e2145..050832ce0 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -5,7 +5,7 @@ use std::{ops, sync::Arc};
5use either::Either; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile}; 6use hir_expand::{hygiene::Hygiene, AstId, InFile};
7use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
8use ra_cfg::CfgOptions; 8use ra_cfg::{CfgExpr, CfgOptions};
9use ra_syntax::{ 9use ra_syntax::{
10 ast::{self, AstNode, AttrsOwner}, 10 ast::{self, AstNode, AttrsOwner},
11 SmolStr, 11 SmolStr,
@@ -125,9 +125,12 @@ impl Attrs {
125 AttrQuery { attrs: self, key } 125 AttrQuery { attrs: self, key }
126 } 126 }
127 127
128 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { 128 pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ {
129 // FIXME: handle cfg_attr :-) 129 // FIXME: handle cfg_attr :-)
130 self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) 130 self.by_key("cfg").tt_values().map(CfgExpr::parse)
131 }
132 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
133 self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false))
131 } 134 }
132} 135}
133 136
@@ -148,18 +151,15 @@ pub enum AttrInput {
148impl Attr { 151impl Attr {
149 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 152 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
150 let path = ModPath::from_src(ast.path()?, hygiene)?; 153 let path = ModPath::from_src(ast.path()?, hygiene)?;
151 let input = match ast.input() { 154 let input = if let Some(lit) = ast.literal() {
152 None => None, 155 // FIXME: escape? raw string?
153 Some(ast::AttrInput::Literal(lit)) => { 156 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
154 // FIXME: escape? raw string? 157 Some(AttrInput::Literal(value))
155 let value = lit.syntax().first_token()?.text().trim_matches('"').into(); 158 } else if let Some(tt) = ast.token_tree() {
156 Some(AttrInput::Literal(value)) 159 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
157 } 160 } else {
158 Some(ast::AttrInput::TokenTree(tt)) => { 161 None
159 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
160 }
161 }; 162 };
162
163 Some(Attr { path, input }) 163 Some(Attr { path, input })
164 } 164 }
165} 165}
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 4f2350915..d5f18b920 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -14,6 +14,7 @@ use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
16use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
17use test_utils::mark;
17 18
18pub(crate) use lower::LowerCtx; 19pub(crate) use lower::LowerCtx;
19 20
@@ -42,9 +43,15 @@ pub(crate) struct Expander {
42 current_file_id: HirFileId, 43 current_file_id: HirFileId,
43 ast_id_map: Arc<AstIdMap>, 44 ast_id_map: Arc<AstIdMap>,
44 module: ModuleId, 45 module: ModuleId,
45 recursive_limit: usize, 46 recursion_limit: usize,
46} 47}
47 48
49#[cfg(test)]
50const EXPANSION_RECURSION_LIMIT: usize = 32;
51
52#[cfg(not(test))]
53const EXPANSION_RECURSION_LIMIT: usize = 128;
54
48impl CfgExpander { 55impl CfgExpander {
49 pub(crate) fn new( 56 pub(crate) fn new(
50 db: &dyn DefDatabase, 57 db: &dyn DefDatabase,
@@ -81,7 +88,7 @@ impl Expander {
81 current_file_id, 88 current_file_id,
82 ast_id_map, 89 ast_id_map,
83 module, 90 module,
84 recursive_limit: 0, 91 recursion_limit: 0,
85 } 92 }
86 } 93 }
87 94
@@ -91,7 +98,9 @@ impl Expander {
91 local_scope: Option<&ItemScope>, 98 local_scope: Option<&ItemScope>,
92 macro_call: ast::MacroCall, 99 macro_call: ast::MacroCall,
93 ) -> Option<(Mark, T)> { 100 ) -> Option<(Mark, T)> {
94 if self.recursive_limit > 1024 { 101 self.recursion_limit += 1;
102 if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
103 mark::hit!(your_stack_belongs_to_me);
95 return None; 104 return None;
96 } 105 }
97 106
@@ -118,8 +127,6 @@ impl Expander {
118 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); 127 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
119 self.current_file_id = file_id; 128 self.current_file_id = file_id;
120 self.ast_id_map = db.ast_id_map(file_id); 129 self.ast_id_map = db.ast_id_map(file_id);
121 self.recursive_limit += 1;
122
123 return Some((mark, expr)); 130 return Some((mark, expr));
124 } 131 }
125 } 132 }
@@ -134,7 +141,7 @@ impl Expander {
134 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 141 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
135 self.current_file_id = mark.file_id; 142 self.current_file_id = mark.file_id;
136 self.ast_id_map = mem::take(&mut mark.ast_id_map); 143 self.ast_id_map = mem::take(&mut mark.ast_id_map);
137 self.recursive_limit -= 1; 144 self.recursion_limit -= 1;
138 mark.bomb.defuse(); 145 mark.bomb.defuse();
139 } 146 }
140 147
@@ -209,7 +216,7 @@ pub struct BodySourceMap {
209 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, 216 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
210 pat_map: FxHashMap<PatSource, PatId>, 217 pat_map: FxHashMap<PatSource, PatId>,
211 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, 218 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
212 field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>, 219 field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>,
213 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, 220 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
214} 221}
215 222
@@ -302,7 +309,53 @@ impl BodySourceMap {
302 self.pat_map.get(&src).cloned() 309 self.pat_map.get(&src).cloned()
303 } 310 }
304 311
305 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { 312 pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
313 let src = node.map(|it| Either::Right(AstPtr::new(it)));
314 self.pat_map.get(&src).cloned()
315 }
316
317 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> {
306 self.field_map[&(expr, field)].clone() 318 self.field_map[&(expr, field)].clone()
307 } 319 }
308} 320}
321
322#[cfg(test)]
323mod tests {
324 use ra_db::{fixture::WithFixture, SourceDatabase};
325 use test_utils::mark;
326
327 use crate::ModuleDefId;
328
329 use super::*;
330
331 fn lower(ra_fixture: &str) -> Arc<Body> {
332 let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);
333
334 let krate = db.crate_graph().iter().next().unwrap();
335 let def_map = db.crate_def_map(krate);
336 let module = def_map.modules_for_file(file_id).next().unwrap();
337 let module = &def_map[module];
338 let fn_def = match module.scope.declarations().next().unwrap() {
339 ModuleDefId::FunctionId(it) => it,
340 _ => panic!(),
341 };
342
343 db.body(fn_def.into())
344 }
345
346 #[test]
347 fn your_stack_belongs_to_me() {
348 mark::check!(your_stack_belongs_to_me);
349 lower(
350 "
351macro_rules! n_nuple {
352 ($e:tt) => ();
353 ($($rest:tt)*) => {{
354 (n_nuple!($($rest)*)None,)
355 }};
356}
357fn main() { n_nuple!(1,2,3); }
358",
359 );
360 }
361}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index c6bc85e2f..827ced4ad 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -11,7 +11,7 @@ use ra_arena::Arena;
11use ra_syntax::{ 11use ra_syntax::{
12 ast::{ 12 ast::{
13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, 13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
14 SlicePatComponents, TypeAscriptionOwner, 14 SlicePatComponents,
15 }, 15 },
16 AstNode, AstPtr, 16 AstNode, AstPtr,
17}; 17};
@@ -379,10 +379,10 @@ impl ExprCollector<'_> {
379 let expr = e.expr().map(|e| self.collect_expr(e)); 379 let expr = e.expr().map(|e| self.collect_expr(e));
380 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 380 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
381 } 381 }
382 ast::Expr::RecordLit(e) => { 382 ast::Expr::RecordExpr(e) => {
383 let path = e.path().and_then(|path| self.expander.parse_path(path)); 383 let path = e.path().and_then(|path| self.expander.parse_path(path));
384 let mut field_ptrs = Vec::new(); 384 let mut field_ptrs = Vec::new();
385 let record_lit = if let Some(nfl) = e.record_field_list() { 385 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
386 let fields = nfl 386 let fields = nfl
387 .fields() 387 .fields()
388 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 388 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
@@ -432,7 +432,7 @@ impl ExprCollector<'_> {
432 } 432 }
433 ast::Expr::CastExpr(e) => { 433 ast::Expr::CastExpr(e) => {
434 let expr = self.collect_expr_opt(e.expr()); 434 let expr = self.collect_expr_opt(e.expr());
435 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref()); 435 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
436 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 436 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
437 } 437 }
438 ast::Expr::RefExpr(e) => { 438 ast::Expr::RefExpr(e) => {
@@ -466,16 +466,13 @@ impl ExprCollector<'_> {
466 if let Some(pl) = e.param_list() { 466 if let Some(pl) = e.param_list() {
467 for param in pl.params() { 467 for param in pl.params() {
468 let pat = self.collect_pat_opt(param.pat()); 468 let pat = self.collect_pat_opt(param.pat());
469 let type_ref = 469 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
470 param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
471 args.push(pat); 470 args.push(pat);
472 arg_types.push(type_ref); 471 arg_types.push(type_ref);
473 } 472 }
474 } 473 }
475 let ret_type = e 474 let ret_type =
476 .ret_type() 475 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it));
477 .and_then(|r| r.type_ref())
478 .map(|it| TypeRef::from_ast(&self.ctx(), it));
479 let body = self.collect_expr_opt(e.body()); 476 let body = self.collect_expr_opt(e.body());
480 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 477 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
481 } 478 }
@@ -607,8 +604,7 @@ impl ExprCollector<'_> {
607 .map(|s| match s { 604 .map(|s| match s {
608 ast::Stmt::LetStmt(stmt) => { 605 ast::Stmt::LetStmt(stmt) => {
609 let pat = self.collect_pat_opt(stmt.pat()); 606 let pat = self.collect_pat_opt(stmt.pat());
610 let type_ref = 607 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
611 stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
612 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 608 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
613 Statement::Let { pat, type_ref, initializer } 609 Statement::Let { pat, type_ref, initializer }
614 } 610 }
@@ -627,53 +623,53 @@ impl ExprCollector<'_> {
627 .items() 623 .items()
628 .filter_map(|item| { 624 .filter_map(|item| {
629 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 625 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
630 ast::ModuleItem::FnDef(def) => { 626 ast::Item::Fn(def) => {
631 let id = self.find_inner_item(&def)?; 627 let id = self.find_inner_item(&def)?;
632 ( 628 (
633 FunctionLoc { container: container.into(), id }.intern(self.db).into(), 629 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
634 def.name(), 630 def.name(),
635 ) 631 )
636 } 632 }
637 ast::ModuleItem::TypeAliasDef(def) => { 633 ast::Item::TypeAlias(def) => {
638 let id = self.find_inner_item(&def)?; 634 let id = self.find_inner_item(&def)?;
639 ( 635 (
640 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), 636 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
641 def.name(), 637 def.name(),
642 ) 638 )
643 } 639 }
644 ast::ModuleItem::ConstDef(def) => { 640 ast::Item::Const(def) => {
645 let id = self.find_inner_item(&def)?; 641 let id = self.find_inner_item(&def)?;
646 ( 642 (
647 ConstLoc { container: container.into(), id }.intern(self.db).into(), 643 ConstLoc { container: container.into(), id }.intern(self.db).into(),
648 def.name(), 644 def.name(),
649 ) 645 )
650 } 646 }
651 ast::ModuleItem::StaticDef(def) => { 647 ast::Item::Static(def) => {
652 let id = self.find_inner_item(&def)?; 648 let id = self.find_inner_item(&def)?;
653 (StaticLoc { container, id }.intern(self.db).into(), def.name()) 649 (StaticLoc { container, id }.intern(self.db).into(), def.name())
654 } 650 }
655 ast::ModuleItem::StructDef(def) => { 651 ast::Item::Struct(def) => {
656 let id = self.find_inner_item(&def)?; 652 let id = self.find_inner_item(&def)?;
657 (StructLoc { container, id }.intern(self.db).into(), def.name()) 653 (StructLoc { container, id }.intern(self.db).into(), def.name())
658 } 654 }
659 ast::ModuleItem::EnumDef(def) => { 655 ast::Item::Enum(def) => {
660 let id = self.find_inner_item(&def)?; 656 let id = self.find_inner_item(&def)?;
661 (EnumLoc { container, id }.intern(self.db).into(), def.name()) 657 (EnumLoc { container, id }.intern(self.db).into(), def.name())
662 } 658 }
663 ast::ModuleItem::UnionDef(def) => { 659 ast::Item::Union(def) => {
664 let id = self.find_inner_item(&def)?; 660 let id = self.find_inner_item(&def)?;
665 (UnionLoc { container, id }.intern(self.db).into(), def.name()) 661 (UnionLoc { container, id }.intern(self.db).into(), def.name())
666 } 662 }
667 ast::ModuleItem::TraitDef(def) => { 663 ast::Item::Trait(def) => {
668 let id = self.find_inner_item(&def)?; 664 let id = self.find_inner_item(&def)?;
669 (TraitLoc { container, id }.intern(self.db).into(), def.name()) 665 (TraitLoc { container, id }.intern(self.db).into(), def.name())
670 } 666 }
671 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks 667 ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
672 ast::ModuleItem::ImplDef(_) 668 ast::Item::Impl(_)
673 | ast::ModuleItem::UseItem(_) 669 | ast::Item::Use(_)
674 | ast::ModuleItem::ExternCrateItem(_) 670 | ast::Item::ExternCrate(_)
675 | ast::ModuleItem::Module(_) 671 | ast::Item::Module(_)
676 | ast::ModuleItem::MacroCall(_) => return None, 672 | ast::Item::MacroCall(_) => return None,
677 }; 673 };
678 674
679 Some((def, name)) 675 Some((def, name))
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
index a885ec96d..dcb00a1d9 100644
--- a/crates/ra_hir_def/src/child_by_source.rs
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -162,7 +162,7 @@ impl ChildBySource for EnumId {
162 let arena_map = arena_map.as_ref(); 162 let arena_map = arena_map.as_ref();
163 for (local_id, source) in arena_map.value.iter() { 163 for (local_id, source) in arena_map.value.iter() {
164 let id = EnumVariantId { parent: *self, local_id }; 164 let id = EnumVariantId { parent: *self, local_id };
165 res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id) 165 res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
166 } 166 }
167 167
168 res 168 res
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 282ade2a3..88a8ef9bf 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -27,11 +27,12 @@ pub struct FunctionData {
27 /// can be called as a method. 27 /// can be called as a method.
28 pub has_self_param: bool, 28 pub has_self_param: bool,
29 pub is_unsafe: bool, 29 pub is_unsafe: bool,
30 pub is_varargs: bool,
30 pub visibility: RawVisibility, 31 pub visibility: RawVisibility,
31} 32}
32 33
33impl FunctionData { 34impl FunctionData {
34 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { 35 pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
35 let loc = func.lookup(db); 36 let loc = func.lookup(db);
36 let item_tree = db.item_tree(loc.id.file_id); 37 let item_tree = db.item_tree(loc.id.file_id);
37 let func = &item_tree[loc.id.value]; 38 let func = &item_tree[loc.id.value];
@@ -43,6 +44,7 @@ impl FunctionData {
43 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), 44 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
44 has_self_param: func.has_self_param, 45 has_self_param: func.has_self_param,
45 is_unsafe: func.is_unsafe, 46 is_unsafe: func.is_unsafe,
47 is_varargs: func.is_varargs,
46 visibility: item_tree[func.visibility].clone(), 48 visibility: item_tree[func.visibility].clone(),
47 }) 49 })
48 } 50 }
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 6a0f493a7..8ea61fcf2 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -12,7 +12,7 @@ use hir_expand::{
12use ra_arena::{map::ArenaMap, Arena}; 12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId; 13use ra_db::FileId;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 15use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
16 16
17use crate::{ 17use crate::{
18 body::LowerCtx, 18 body::LowerCtx,
@@ -66,7 +66,7 @@ pub enum WherePredicateTarget {
66 TypeParam(LocalTypeParamId), 66 TypeParam(LocalTypeParamId),
67} 67}
68 68
69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; 69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
70 70
71impl GenericParams { 71impl GenericParams {
72 pub(crate) fn generic_params_query( 72 pub(crate) fn generic_params_query(
@@ -205,9 +205,9 @@ impl GenericParams {
205 &mut self, 205 &mut self,
206 lower_ctx: &LowerCtx, 206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap, 207 sm: &mut SourceMap,
208 node: &dyn TypeParamsOwner, 208 node: &dyn GenericParamsOwner,
209 ) { 209 ) {
210 if let Some(params) = node.type_param_list() { 210 if let Some(params) = node.generic_param_list() {
211 self.fill_params(lower_ctx, sm, params) 211 self.fill_params(lower_ctx, sm, params)
212 } 212 }
213 if let Some(where_clause) = node.where_clause() { 213 if let Some(where_clause) = node.where_clause() {
@@ -232,7 +232,7 @@ impl GenericParams {
232 &mut self, 232 &mut self,
233 lower_ctx: &LowerCtx, 233 lower_ctx: &LowerCtx,
234 sm: &mut SourceMap, 234 sm: &mut SourceMap,
235 params: ast::TypeParamList, 235 params: ast::GenericParamList,
236 ) { 236 ) {
237 for type_param in params.type_params() { 237 for type_param in params.type_params() {
238 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 238 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
@@ -317,7 +317,7 @@ impl GenericParams {
317 317
318impl HasChildSource for GenericDefId { 318impl HasChildSource for GenericDefId {
319 type ChildId = LocalTypeParamId; 319 type ChildId = LocalTypeParamId;
320 type Value = Either<ast::TraitDef, ast::TypeParam>; 320 type Value = Either<ast::Trait, ast::TypeParam>;
321 fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> { 321 fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> {
322 let (_, sm) = GenericParams::new(db, *self); 322 let (_, sm) = GenericParams::new(db, *self);
323 sm 323 sm
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
index 68e20d06b..9e4c30b1a 100644
--- a/crates/ra_hir_def/src/import_map.rs
+++ b/crates/ra_hir_def/src/import_map.rs
@@ -5,14 +5,16 @@ use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
5use fst::{self, Streamer}; 5use fst::{self, Streamer};
6use indexmap::{map::Entry, IndexMap}; 6use indexmap::{map::Entry, IndexMap};
7use ra_db::CrateId; 7use ra_db::CrateId;
8use rustc_hash::FxHasher; 8use ra_syntax::SmolStr;
9use rustc_hash::{FxHashMap, FxHasher};
10use smallvec::SmallVec;
9 11
10use crate::{ 12use crate::{
11 db::DefDatabase, 13 db::DefDatabase,
12 item_scope::ItemInNs, 14 item_scope::ItemInNs,
13 path::{ModPath, PathKind}, 15 path::{ModPath, PathKind},
14 visibility::Visibility, 16 visibility::Visibility,
15 ModuleDefId, ModuleId, 17 AssocItemId, ModuleDefId, ModuleId, TraitId,
16}; 18};
17 19
18type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; 20type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
@@ -34,6 +36,7 @@ pub struct ImportInfo {
34/// 36///
35/// Note that all paths are relative to the containing crate's root, so the crate name still needs 37/// Note that all paths are relative to the containing crate's root, so the crate name still needs
36/// to be prepended to the `ModPath` before the path is valid. 38/// to be prepended to the `ModPath` before the path is valid.
39#[derive(Default)]
37pub struct ImportMap { 40pub struct ImportMap {
38 map: FxIndexMap<ItemInNs, ImportInfo>, 41 map: FxIndexMap<ItemInNs, ImportInfo>,
39 42
@@ -45,13 +48,17 @@ pub struct ImportMap {
45 /// the index of the first one. 48 /// the index of the first one.
46 importables: Vec<ItemInNs>, 49 importables: Vec<ItemInNs>,
47 fst: fst::Map<Vec<u8>>, 50 fst: fst::Map<Vec<u8>>,
51
52 /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
53 /// exported.
54 assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>,
48} 55}
49 56
50impl ImportMap { 57impl ImportMap {
51 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 58 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
52 let _p = ra_prof::profile("import_map_query"); 59 let _p = ra_prof::profile("import_map_query");
53 let def_map = db.crate_def_map(krate); 60 let def_map = db.crate_def_map(krate);
54 let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); 61 let mut import_map = Self::default();
55 62
56 // We look only into modules that are public(ly reexported), starting with the crate root. 63 // We look only into modules that are public(ly reexported), starting with the crate root.
57 let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; 64 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
@@ -85,7 +92,7 @@ impl ImportMap {
85 92
86 for item in per_ns.iter_items() { 93 for item in per_ns.iter_items() {
87 let path = mk_path(); 94 let path = mk_path();
88 match import_map.entry(item) { 95 match import_map.map.entry(item) {
89 Entry::Vacant(entry) => { 96 Entry::Vacant(entry) => {
90 entry.insert(ImportInfo { path, container: module }); 97 entry.insert(ImportInfo { path, container: module });
91 } 98 }
@@ -105,11 +112,16 @@ impl ImportMap {
105 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { 112 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
106 worklist.push((mod_id, mk_path())); 113 worklist.push((mod_id, mk_path()));
107 } 114 }
115
116 // If we've added a path to a trait, add the trait's methods to the method map.
117 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
118 import_map.collect_trait_methods(db, tr);
119 }
108 } 120 }
109 } 121 }
110 } 122 }
111 123
112 let mut importables = import_map.iter().collect::<Vec<_>>(); 124 let mut importables = import_map.map.iter().collect::<Vec<_>>();
113 125
114 importables.sort_by(cmp); 126 importables.sort_by(cmp);
115 127
@@ -133,10 +145,10 @@ impl ImportMap {
133 builder.insert(key, start as u64).unwrap(); 145 builder.insert(key, start as u64).unwrap();
134 } 146 }
135 147
136 let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); 148 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
137 let importables = importables.iter().map(|(item, _)| **item).collect(); 149 import_map.importables = importables.iter().map(|(item, _)| **item).collect();
138 150
139 Arc::new(Self { map: import_map, fst, importables }) 151 Arc::new(import_map)
140 } 152 }
141 153
142 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. 154 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
@@ -147,6 +159,13 @@ impl ImportMap {
147 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { 159 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
148 self.map.get(&item) 160 self.map.get(&item)
149 } 161 }
162
163 fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) {
164 let data = db.trait_data(tr);
165 for (name, item) in data.items.iter() {
166 self.assoc_map.entry(name.to_string().into()).or_default().push(*item);
167 }
168 }
150} 169}
151 170
152impl PartialEq for ImportMap { 171impl PartialEq for ImportMap {
@@ -290,37 +309,32 @@ pub fn search_dependencies<'a>(
290 } 309 }
291 } 310 }
292 311
312 // Add all exported associated items whose names match the query (exactly).
313 for map in &import_maps {
314 if let Some(v) = map.assoc_map.get(&*query.query) {
315 res.extend(v.iter().map(|&assoc| {
316 ItemInNs::Types(match assoc {
317 AssocItemId::FunctionId(it) => it.into(),
318 AssocItemId::ConstId(it) => it.into(),
319 AssocItemId::TypeAliasId(it) => it.into(),
320 })
321 }));
322 }
323 }
324
293 res 325 res
294} 326}
295 327
296#[cfg(test)] 328#[cfg(test)]
297mod tests { 329mod tests {
298 use super::*; 330 use expect::{expect, Expect};
299 use crate::test_db::TestDB; 331 use ra_db::{fixture::WithFixture, SourceDatabase, Upcast};
300 use insta::assert_snapshot;
301 use itertools::Itertools;
302 use ra_db::fixture::WithFixture;
303 use ra_db::{SourceDatabase, Upcast};
304 332
305 fn import_map(ra_fixture: &str) -> String { 333 use crate::{test_db::TestDB, AssocContainerId, Lookup};
306 let db = TestDB::with_files(ra_fixture);
307 let crate_graph = db.crate_graph();
308 334
309 let s = crate_graph 335 use super::*;
310 .iter()
311 .filter_map(|krate| {
312 let cdata = &crate_graph[krate];
313 let name = cdata.display_name.as_ref()?;
314
315 let map = db.import_map(krate);
316
317 Some(format!("{}:\n{:?}", name, map))
318 })
319 .join("\n");
320 s
321 }
322 336
323 fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { 337 fn check_search(ra_fixture: &str, krate_name: &str, query: Query, expect: Expect) {
324 let db = TestDB::with_files(ra_fixture); 338 let db = TestDB::with_files(ra_fixture);
325 let crate_graph = db.crate_graph(); 339 let crate_graph = db.crate_graph();
326 let krate = crate_graph 340 let krate = crate_graph
@@ -331,7 +345,7 @@ mod tests {
331 }) 345 })
332 .unwrap(); 346 .unwrap();
333 347
334 search_dependencies(db.upcast(), krate, query) 348 let actual = search_dependencies(db.upcast(), krate, query)
335 .into_iter() 349 .into_iter()
336 .filter_map(|item| { 350 .filter_map(|item| {
337 let mark = match item { 351 let mark = match item {
@@ -339,23 +353,67 @@ mod tests {
339 ItemInNs::Values(_) => "v", 353 ItemInNs::Values(_) => "v",
340 ItemInNs::Macros(_) => "m", 354 ItemInNs::Macros(_) => "m",
341 }; 355 };
356 let item = assoc_to_trait(&db, item);
342 item.krate(db.upcast()).map(|krate| { 357 item.krate(db.upcast()).map(|krate| {
343 let map = db.import_map(krate); 358 let map = db.import_map(krate);
344 let path = map.path_of(item).unwrap(); 359 let path = map.path_of(item).unwrap();
345 format!( 360 format!(
346 "{}::{} ({})", 361 "{}::{} ({})\n",
347 crate_graph[krate].display_name.as_ref().unwrap(), 362 crate_graph[krate].display_name.as_ref().unwrap(),
348 path, 363 path,
349 mark 364 mark
350 ) 365 )
351 }) 366 })
352 }) 367 })
353 .join("\n") 368 .collect::<String>();
369 expect.assert_eq(&actual)
370 }
371
372 fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs {
373 let assoc: AssocItemId = match item {
374 ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
375 ModuleDefId::TypeAliasId(it) => it.into(),
376 ModuleDefId::FunctionId(it) => it.into(),
377 ModuleDefId::ConstId(it) => it.into(),
378 _ => return item,
379 },
380 _ => return item,
381 };
382
383 let container = match assoc {
384 AssocItemId::FunctionId(it) => it.lookup(db).container,
385 AssocItemId::ConstId(it) => it.lookup(db).container,
386 AssocItemId::TypeAliasId(it) => it.lookup(db).container,
387 };
388
389 match container {
390 AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()),
391 _ => item,
392 }
393 }
394
395 fn check(ra_fixture: &str, expect: Expect) {
396 let db = TestDB::with_files(ra_fixture);
397 let crate_graph = db.crate_graph();
398
399 let actual = crate_graph
400 .iter()
401 .filter_map(|krate| {
402 let cdata = &crate_graph[krate];
403 let name = cdata.display_name.as_ref()?;
404
405 let map = db.import_map(krate);
406
407 Some(format!("{}:\n{:?}\n", name, map))
408 })
409 .collect::<String>();
410
411 expect.assert_eq(&actual)
354 } 412 }
355 413
356 #[test] 414 #[test]
357 fn smoke() { 415 fn smoke() {
358 let map = import_map( 416 check(
359 r" 417 r"
360 //- /main.rs crate:main deps:lib 418 //- /main.rs crate:main deps:lib
361 419
@@ -380,24 +438,23 @@ mod tests {
380 pub struct Pub2; // t + v 438 pub struct Pub2; // t + v
381 struct Priv; 439 struct Priv;
382 ", 440 ",
441 expect![[r#"
442 main:
443 - publ1 (t)
444 - real_pu2 (t)
445 - real_pub (t)
446 - real_pub::Pub (t)
447 lib:
448 - Pub (t)
449 - Pub2 (t)
450 - Pub2 (v)
451 "#]],
383 ); 452 );
384
385 assert_snapshot!(map, @r###"
386 main:
387 - publ1 (t)
388 - real_pu2 (t)
389 - real_pub (t)
390 - real_pub::Pub (t)
391 lib:
392 - Pub (t)
393 - Pub2 (t)
394 - Pub2 (v)
395 "###);
396 } 453 }
397 454
398 #[test] 455 #[test]
399 fn prefers_shortest_path() { 456 fn prefers_shortest_path() {
400 let map = import_map( 457 check(
401 r" 458 r"
402 //- /main.rs crate:main 459 //- /main.rs crate:main
403 460
@@ -409,21 +466,20 @@ mod tests {
409 pub use super::sub::subsub::Def; 466 pub use super::sub::subsub::Def;
410 } 467 }
411 ", 468 ",
469 expect![[r#"
470 main:
471 - sub (t)
472 - sub::Def (t)
473 - sub::subsub (t)
474 "#]],
412 ); 475 );
413
414 assert_snapshot!(map, @r###"
415 main:
416 - sub (t)
417 - sub::Def (t)
418 - sub::subsub (t)
419 "###);
420 } 476 }
421 477
422 #[test] 478 #[test]
423 fn type_reexport_cross_crate() { 479 fn type_reexport_cross_crate() {
424 // Reexports need to be visible from a crate, even if the original crate exports the item 480 // Reexports need to be visible from a crate, even if the original crate exports the item
425 // at a shorter path. 481 // at a shorter path.
426 let map = import_map( 482 check(
427 r" 483 r"
428 //- /main.rs crate:main deps:lib 484 //- /main.rs crate:main deps:lib
429 pub mod m { 485 pub mod m {
@@ -432,22 +488,21 @@ mod tests {
432 //- /lib.rs crate:lib 488 //- /lib.rs crate:lib
433 pub struct S; 489 pub struct S;
434 ", 490 ",
491 expect![[r#"
492 main:
493 - m (t)
494 - m::S (t)
495 - m::S (v)
496 lib:
497 - S (t)
498 - S (v)
499 "#]],
435 ); 500 );
436
437 assert_snapshot!(map, @r###"
438 main:
439 - m (t)
440 - m::S (t)
441 - m::S (v)
442 lib:
443 - S (t)
444 - S (v)
445 "###);
446 } 501 }
447 502
448 #[test] 503 #[test]
449 fn macro_reexport() { 504 fn macro_reexport() {
450 let map = import_map( 505 check(
451 r" 506 r"
452 //- /main.rs crate:main deps:lib 507 //- /main.rs crate:main deps:lib
453 pub mod m { 508 pub mod m {
@@ -459,21 +514,20 @@ mod tests {
459 () => {}; 514 () => {};
460 } 515 }
461 ", 516 ",
517 expect![[r#"
518 main:
519 - m (t)
520 - m::pub_macro (m)
521 lib:
522 - pub_macro (m)
523 "#]],
462 ); 524 );
463
464 assert_snapshot!(map, @r###"
465 main:
466 - m (t)
467 - m::pub_macro (m)
468 lib:
469 - pub_macro (m)
470 "###);
471 } 525 }
472 526
473 #[test] 527 #[test]
474 fn module_reexport() { 528 fn module_reexport() {
475 // Reexporting modules from a dependency adds all contents to the import map. 529 // Reexporting modules from a dependency adds all contents to the import map.
476 let map = import_map( 530 check(
477 r" 531 r"
478 //- /main.rs crate:main deps:lib 532 //- /main.rs crate:main deps:lib
479 pub use lib::module as reexported_module; 533 pub use lib::module as reexported_module;
@@ -482,24 +536,23 @@ mod tests {
482 pub struct S; 536 pub struct S;
483 } 537 }
484 ", 538 ",
539 expect![[r#"
540 main:
541 - reexported_module (t)
542 - reexported_module::S (t)
543 - reexported_module::S (v)
544 lib:
545 - module (t)
546 - module::S (t)
547 - module::S (v)
548 "#]],
485 ); 549 );
486
487 assert_snapshot!(map, @r###"
488 main:
489 - reexported_module (t)
490 - reexported_module::S (t)
491 - reexported_module::S (v)
492 lib:
493 - module (t)
494 - module::S (t)
495 - module::S (v)
496 "###);
497 } 550 }
498 551
499 #[test] 552 #[test]
500 fn cyclic_module_reexport() { 553 fn cyclic_module_reexport() {
501 // A cyclic reexport does not hang. 554 // A cyclic reexport does not hang.
502 let map = import_map( 555 check(
503 r" 556 r"
504 //- /lib.rs crate:lib 557 //- /lib.rs crate:lib
505 pub mod module { 558 pub mod module {
@@ -511,36 +564,35 @@ mod tests {
511 pub use super::module; 564 pub use super::module;
512 } 565 }
513 ", 566 ",
567 expect![[r#"
568 lib:
569 - module (t)
570 - module::S (t)
571 - module::S (v)
572 - sub (t)
573 "#]],
514 ); 574 );
515
516 assert_snapshot!(map, @r###"
517 lib:
518 - module (t)
519 - module::S (t)
520 - module::S (v)
521 - sub (t)
522 "###);
523 } 575 }
524 576
525 #[test] 577 #[test]
526 fn private_macro() { 578 fn private_macro() {
527 let map = import_map( 579 check(
528 r" 580 r"
529 //- /lib.rs crate:lib 581 //- /lib.rs crate:lib
530 macro_rules! private_macro { 582 macro_rules! private_macro {
531 () => {}; 583 () => {};
532 } 584 }
533 ", 585 ",
534 ); 586 expect![[r#"
587 lib:
535 588
536 assert_snapshot!(map, @r###" 589 "#]],
537 lib: 590 );
538 "###);
539 } 591 }
540 592
541 #[test] 593 #[test]
542 fn namespacing() { 594 fn namespacing() {
543 let map = import_map( 595 check(
544 r" 596 r"
545 //- /lib.rs crate:lib 597 //- /lib.rs crate:lib
546 pub struct Thing; // t + v 598 pub struct Thing; // t + v
@@ -549,16 +601,15 @@ mod tests {
549 () => {}; 601 () => {};
550 } 602 }
551 ", 603 ",
604 expect![[r#"
605 lib:
606 - Thing (m)
607 - Thing (t)
608 - Thing (v)
609 "#]],
552 ); 610 );
553 611
554 assert_snapshot!(map, @r###" 612 check(
555 lib:
556 - Thing (m)
557 - Thing (t)
558 - Thing (v)
559 "###);
560
561 let map = import_map(
562 r" 613 r"
563 //- /lib.rs crate:lib 614 //- /lib.rs crate:lib
564 pub mod Thing {} // t 615 pub mod Thing {} // t
@@ -567,13 +618,12 @@ mod tests {
567 () => {}; 618 () => {};
568 } 619 }
569 ", 620 ",
621 expect![[r#"
622 lib:
623 - Thing (m)
624 - Thing (t)
625 "#]],
570 ); 626 );
571
572 assert_snapshot!(map, @r###"
573 lib:
574 - Thing (m)
575 - Thing (t)
576 "###);
577 } 627 }
578 628
579 #[test] 629 #[test]
@@ -602,23 +652,33 @@ mod tests {
602 } 652 }
603 "#; 653 "#;
604 654
605 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); 655 check_search(
606 assert_snapshot!(res, @r###" 656 ra_fixture,
607 dep::fmt (t) 657 "main",
608 dep::Fmt (t) 658 Query::new("fmt"),
609 dep::Fmt (v) 659 expect![[r#"
610 dep::Fmt (m) 660 dep::fmt (t)
611 dep::fmt::Display (t) 661 dep::Fmt (t)
612 dep::format (v) 662 dep::Fmt (v)
613 "###); 663 dep::Fmt (m)
614 664 dep::fmt::Display (t)
615 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); 665 dep::format (v)
616 assert_snapshot!(res, @r###" 666 dep::fmt::Display (t)
617 dep::fmt (t) 667 "#]],
618 dep::Fmt (t) 668 );
619 dep::Fmt (v) 669
620 dep::Fmt (m) 670 check_search(
621 "###); 671 ra_fixture,
672 "main",
673 Query::new("fmt").anchor_end(),
674 expect![[r#"
675 dep::fmt (t)
676 dep::Fmt (t)
677 dep::Fmt (v)
678 dep::Fmt (m)
679 dep::fmt::Display (t)
680 "#]],
681 );
622 } 682 }
623 683
624 #[test] 684 #[test]
@@ -631,26 +691,32 @@ mod tests {
631 pub struct FMT; 691 pub struct FMT;
632 "#; 692 "#;
633 693
634 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); 694 check_search(
635 695 ra_fixture,
636 assert_snapshot!(res, @r###" 696 "main",
637 dep::fmt (t) 697 Query::new("FMT"),
638 dep::fmt (v) 698 expect![[r#"
639 dep::FMT (t) 699 dep::fmt (t)
640 dep::FMT (v) 700 dep::fmt (v)
641 "###); 701 dep::FMT (t)
642 702 dep::FMT (v)
643 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); 703 "#]],
704 );
644 705
645 assert_snapshot!(res, @r###" 706 check_search(
646 dep::FMT (t) 707 ra_fixture,
647 dep::FMT (v) 708 "main",
648 "###); 709 Query::new("FMT").case_sensitive(),
710 expect![[r#"
711 dep::FMT (t)
712 dep::FMT (v)
713 "#]],
714 );
649 } 715 }
650 716
651 #[test] 717 #[test]
652 fn search_limit() { 718 fn search_limit() {
653 let res = search_dependencies_of( 719 check_search(
654 r#" 720 r#"
655 //- /main.rs crate:main deps:dep 721 //- /main.rs crate:main deps:dep
656 //- /dep.rs crate:dep 722 //- /dep.rs crate:dep
@@ -670,10 +736,10 @@ mod tests {
670 "#, 736 "#,
671 "main", 737 "main",
672 Query::new("").limit(2), 738 Query::new("").limit(2),
739 expect![[r#"
740 dep::fmt (t)
741 dep::Fmt (t)
742 "#]],
673 ); 743 );
674 assert_snapshot!(res, @r###"
675 dep::fmt (t)
676 dep::Fmt (t)
677 "###);
678 } 744 }
679} 745}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 4d446c707..8fee4b15e 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -1,6 +1,8 @@
1//! Describes items defined or visible (ie, imported) in a certain scope. 1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks. 2//! This is shared between modules and blocks.
3 3
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use ra_db::CrateId; 8use ra_db::CrateId;
@@ -27,9 +29,15 @@ pub struct PerNsGlobImports {
27 29
28#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
29pub struct ItemScope { 31pub struct ItemScope {
30 visible: FxHashMap<Name, PerNs>, 32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
31 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
32 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
33 /// Macros visible in current module in legacy textual scope 41 /// Macros visible in current module in legacy textual scope
34 /// 42 ///
35 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. 43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -65,14 +73,16 @@ pub(crate) enum BuiltinShadowMode {
65/// Other methods will only resolve values, types and module scoped macros only. 73/// Other methods will only resolve values, types and module scoped macros only.
66impl ItemScope { 74impl ItemScope {
67 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 75 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
68 //FIXME: shadowing 76 // FIXME: shadowing
69 self.visible.iter().map(|(n, def)| (n, *def)) 77 let keys: FxHashSet<_> = self
70 } 78 .types
71 79 .keys()
72 pub fn entries_without_primitives<'a>( 80 .chain(self.values.keys())
73 &'a self, 81 .chain(self.macros.keys())
74 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 82 .chain(self.unresolved.iter())
75 self.visible.iter().map(|(n, def)| (n, *def)) 83 .collect();
84
85 keys.into_iter().map(move |name| (name, self.get(name)))
76 } 86 }
77 87
78 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 88 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -91,7 +101,7 @@ impl ItemScope {
91 101
92 /// Iterate over all module scoped macros 102 /// Iterate over all module scoped macros
93 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 103 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
94 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 104 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
95 } 105 }
96 106
97 /// Iterate over all legacy textual scoped macros visible at the end of the module 107 /// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -101,12 +111,16 @@ impl ItemScope {
101 111
102 /// Get a name from current module scope, legacy macros are not included 112 /// Get a name from current module scope, legacy macros are not included
103 pub(crate) fn get(&self, name: &Name) -> PerNs { 113 pub(crate) fn get(&self, name: &Name) -> PerNs {
104 self.visible.get(name).copied().unwrap_or_else(PerNs::none) 114 PerNs {
115 types: self.types.get(name).copied(),
116 values: self.values.get(name).copied(),
117 macros: self.macros.get(name).copied(),
118 }
105 } 119 }
106 120
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 121 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108 for (name, per_ns) in &self.visible { 122 for (name, per_ns) in self.entries() {
109 if let Some(vis) = item.match_with(*per_ns) { 123 if let Some(vis) = item.match_with(per_ns) {
110 return Some((name, vis)); 124 return Some((name, vis));
111 } 125 }
112 } 126 }
@@ -114,10 +128,13 @@ impl ItemScope {
114 } 128 }
115 129
116 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
117 self.visible.values().filter_map(|def| match def.take_types() { 131 self.types
118 Some(ModuleDefId::TraitId(t)) => Some(t), 132 .values()
119 _ => None, 133 .filter_map(|(def, _)| match def {
120 }) 134 ModuleDefId::TraitId(t) => Some(*t),
135 _ => None,
136 })
137 .chain(self.unnamed_trait_imports.keys().copied())
121 } 138 }
122 139
123 pub(crate) fn define_def(&mut self, def: ModuleDefId) { 140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
@@ -136,23 +153,40 @@ impl ItemScope {
136 self.legacy_macros.insert(name, mac); 153 self.legacy_macros.insert(name, mac);
137 } 154 }
138 155
156 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157 self.unnamed_trait_imports.get(&tr).copied()
158 }
159
160 pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161 self.unnamed_trait_imports.insert(tr, vis);
162 }
163
139 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
140 let mut changed = false; 165 let mut changed = false;
141 let existing = self.visible.entry(name).or_default();
142 166
143 if existing.types.is_none() && def.types.is_some() { 167 if let Some(types) = def.types {
144 existing.types = def.types; 168 self.types.entry(name.clone()).or_insert_with(|| {
145 changed = true; 169 changed = true;
170 types
171 });
146 } 172 }
147 173 if let Some(values) = def.values {
148 if existing.values.is_none() && def.values.is_some() { 174 self.values.entry(name.clone()).or_insert_with(|| {
149 existing.values = def.values; 175 changed = true;
150 changed = true; 176 values
177 });
178 }
179 if let Some(macros) = def.macros {
180 self.macros.entry(name.clone()).or_insert_with(|| {
181 changed = true;
182 macros
183 });
151 } 184 }
152 185
153 if existing.macros.is_none() && def.macros.is_some() { 186 if def.is_none() {
154 existing.macros = def.macros; 187 if self.unresolved.insert(name) {
155 changed = true; 188 changed = true;
189 }
156 } 190 }
157 191
158 changed 192 changed
@@ -166,17 +200,17 @@ impl ItemScope {
166 def_import_type: ImportType, 200 def_import_type: ImportType,
167 ) -> bool { 201 ) -> bool {
168 let mut changed = false; 202 let mut changed = false;
169 let existing = self.visible.entry(lookup.1.clone()).or_default();
170 203
171 macro_rules! check_changed { 204 macro_rules! check_changed {
172 ( 205 (
173 $changed:ident, 206 $changed:ident,
174 ( $existing:ident / $def:ident ) . $field:ident, 207 ( $this:ident / $def:ident ) . $field:ident,
175 $glob_imports:ident [ $lookup:ident ], 208 $glob_imports:ident [ $lookup:ident ],
176 $def_import_type:ident 209 $def_import_type:ident
177 ) => { 210 ) => {{
178 match ($existing.$field, $def.$field) { 211 let existing = $this.$field.entry($lookup.1.clone());
179 (None, Some(_)) => { 212 match (existing, $def.$field) {
213 (Entry::Vacant(entry), Some(_)) => {
180 match $def_import_type { 214 match $def_import_type {
181 ImportType::Glob => { 215 ImportType::Glob => {
182 $glob_imports.$field.insert($lookup.clone()); 216 $glob_imports.$field.insert($lookup.clone());
@@ -186,32 +220,46 @@ impl ItemScope {
186 } 220 }
187 } 221 }
188 222
189 $existing.$field = $def.$field; 223 if let Some(fld) = $def.$field {
224 entry.insert(fld);
225 }
190 $changed = true; 226 $changed = true;
191 } 227 }
192 (Some(_), Some(_)) 228 (Entry::Occupied(mut entry), Some(_))
193 if $glob_imports.$field.contains(&$lookup) 229 if $glob_imports.$field.contains(&$lookup)
194 && matches!($def_import_type, ImportType::Named) => 230 && matches!($def_import_type, ImportType::Named) =>
195 { 231 {
196 mark::hit!(import_shadowed); 232 mark::hit!(import_shadowed);
197 $glob_imports.$field.remove(&$lookup); 233 $glob_imports.$field.remove(&$lookup);
198 $existing.$field = $def.$field; 234 if let Some(fld) = $def.$field {
235 entry.insert(fld);
236 }
199 $changed = true; 237 $changed = true;
200 } 238 }
201 _ => {} 239 _ => {}
202 } 240 }
203 }; 241 }};
204 } 242 }
205 243
206 check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); 244 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
207 check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); 245 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
208 check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); 246 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
247
248 if def.is_none() {
249 if self.unresolved.insert(lookup.1) {
250 changed = true;
251 }
252 }
209 253
210 changed 254 changed
211 } 255 }
212 256
213 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
214 self.visible.iter().map(|(name, res)| (name.clone(), *res)) 258 self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259 self.unnamed_trait_imports
260 .iter()
261 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
262 )
215 } 263 }
216 264
217 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index 3e603bd55..a67e75dac 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -13,7 +13,7 @@ use std::{
13 sync::Arc, 13 sync::Arc,
14}; 14};
15 15
16use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; 16use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
17use either::Either; 17use either::Either;
18use hir_expand::{ 18use hir_expand::{
19 ast_id_map::FileAstId, 19 ast_id_map::FileAstId,
@@ -70,7 +70,7 @@ impl GenericParamsId {
70pub struct ItemTree { 70pub struct ItemTree {
71 top_level: SmallVec<[ModItem; 1]>, 71 top_level: SmallVec<[ModItem; 1]>,
72 attrs: FxHashMap<AttrOwner, Attrs>, 72 attrs: FxHashMap<AttrOwner, Attrs>,
73 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>, 73 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
74 74
75 data: Option<Box<ItemTreeData>>, 75 data: Option<Box<ItemTreeData>>,
76} 76}
@@ -187,7 +187,7 @@ impl ItemTree {
187 /// 187 ///
188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered 188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
189 /// to multiple items in the `ItemTree`. 189 /// to multiple items in the `ItemTree`.
190 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] { 190 pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
191 &self.inner_items[&ast] 191 &self.inner_items[&ast]
192 } 192 }
193 193
@@ -310,7 +310,7 @@ from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
310 310
311/// Trait implemented by all item nodes in the item tree. 311/// Trait implemented by all item nodes in the item tree.
312pub trait ItemTreeNode: Clone { 312pub trait ItemTreeNode: Clone {
313 type Source: AstNode + Into<ast::ModuleItem>; 313 type Source: AstNode + Into<ast::Item>;
314 314
315 fn ast_id(&self) -> FileAstId<Self::Source>; 315 fn ast_id(&self) -> FileAstId<Self::Source>;
316 316
@@ -411,17 +411,17 @@ macro_rules! mod_items {
411} 411}
412 412
413mod_items! { 413mod_items! {
414 Import in imports -> ast::UseItem, 414 Import in imports -> ast::Use,
415 ExternCrate in extern_crates -> ast::ExternCrateItem, 415 ExternCrate in extern_crates -> ast::ExternCrate,
416 Function in functions -> ast::FnDef, 416 Function in functions -> ast::Fn,
417 Struct in structs -> ast::StructDef, 417 Struct in structs -> ast::Struct,
418 Union in unions -> ast::UnionDef, 418 Union in unions -> ast::Union,
419 Enum in enums -> ast::EnumDef, 419 Enum in enums -> ast::Enum,
420 Const in consts -> ast::ConstDef, 420 Const in consts -> ast::Const,
421 Static in statics -> ast::StaticDef, 421 Static in statics -> ast::Static,
422 Trait in traits -> ast::TraitDef, 422 Trait in traits -> ast::Trait,
423 Impl in impls -> ast::ImplDef, 423 Impl in impls -> ast::Impl,
424 TypeAlias in type_aliases -> ast::TypeAliasDef, 424 TypeAlias in type_aliases -> ast::TypeAlias,
425 Mod in mods -> ast::Module, 425 Mod in mods -> ast::Module,
426 MacroCall in macro_calls -> ast::MacroCall, 426 MacroCall in macro_calls -> ast::MacroCall,
427} 427}
@@ -482,7 +482,7 @@ pub struct Import {
482 pub is_prelude: bool, 482 pub is_prelude: bool,
483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many 483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
484 /// `Import`s can map to the same `use` item. 484 /// `Import`s can map to the same `use` item.
485 pub ast_id: FileAstId<ast::UseItem>, 485 pub ast_id: FileAstId<ast::Use>,
486} 486}
487 487
488#[derive(Debug, Clone, Eq, PartialEq)] 488#[derive(Debug, Clone, Eq, PartialEq)]
@@ -492,7 +492,7 @@ pub struct ExternCrate {
492 pub visibility: RawVisibilityId, 492 pub visibility: RawVisibilityId,
493 /// Whether this is a `#[macro_use] extern crate ...`. 493 /// Whether this is a `#[macro_use] extern crate ...`.
494 pub is_macro_use: bool, 494 pub is_macro_use: bool,
495 pub ast_id: FileAstId<ast::ExternCrateItem>, 495 pub ast_id: FileAstId<ast::ExternCrate>,
496} 496}
497 497
498#[derive(Debug, Clone, Eq, PartialEq)] 498#[derive(Debug, Clone, Eq, PartialEq)]
@@ -503,8 +503,9 @@ pub struct Function {
503 pub has_self_param: bool, 503 pub has_self_param: bool,
504 pub is_unsafe: bool, 504 pub is_unsafe: bool,
505 pub params: Box<[TypeRef]>, 505 pub params: Box<[TypeRef]>,
506 pub is_varargs: bool,
506 pub ret_type: TypeRef, 507 pub ret_type: TypeRef,
507 pub ast_id: FileAstId<ast::FnDef>, 508 pub ast_id: FileAstId<ast::Fn>,
508} 509}
509 510
510#[derive(Debug, Clone, Eq, PartialEq)] 511#[derive(Debug, Clone, Eq, PartialEq)]
@@ -513,7 +514,7 @@ pub struct Struct {
513 pub visibility: RawVisibilityId, 514 pub visibility: RawVisibilityId,
514 pub generic_params: GenericParamsId, 515 pub generic_params: GenericParamsId,
515 pub fields: Fields, 516 pub fields: Fields,
516 pub ast_id: FileAstId<ast::StructDef>, 517 pub ast_id: FileAstId<ast::Struct>,
517 pub kind: StructDefKind, 518 pub kind: StructDefKind,
518} 519}
519 520
@@ -533,7 +534,7 @@ pub struct Union {
533 pub visibility: RawVisibilityId, 534 pub visibility: RawVisibilityId,
534 pub generic_params: GenericParamsId, 535 pub generic_params: GenericParamsId,
535 pub fields: Fields, 536 pub fields: Fields,
536 pub ast_id: FileAstId<ast::UnionDef>, 537 pub ast_id: FileAstId<ast::Union>,
537} 538}
538 539
539#[derive(Debug, Clone, Eq, PartialEq)] 540#[derive(Debug, Clone, Eq, PartialEq)]
@@ -542,7 +543,7 @@ pub struct Enum {
542 pub visibility: RawVisibilityId, 543 pub visibility: RawVisibilityId,
543 pub generic_params: GenericParamsId, 544 pub generic_params: GenericParamsId,
544 pub variants: IdRange<Variant>, 545 pub variants: IdRange<Variant>,
545 pub ast_id: FileAstId<ast::EnumDef>, 546 pub ast_id: FileAstId<ast::Enum>,
546} 547}
547 548
548#[derive(Debug, Clone, Eq, PartialEq)] 549#[derive(Debug, Clone, Eq, PartialEq)]
@@ -551,7 +552,7 @@ pub struct Const {
551 pub name: Option<Name>, 552 pub name: Option<Name>,
552 pub visibility: RawVisibilityId, 553 pub visibility: RawVisibilityId,
553 pub type_ref: TypeRef, 554 pub type_ref: TypeRef,
554 pub ast_id: FileAstId<ast::ConstDef>, 555 pub ast_id: FileAstId<ast::Const>,
555} 556}
556 557
557#[derive(Debug, Clone, Eq, PartialEq)] 558#[derive(Debug, Clone, Eq, PartialEq)]
@@ -560,7 +561,7 @@ pub struct Static {
560 pub visibility: RawVisibilityId, 561 pub visibility: RawVisibilityId,
561 pub mutable: bool, 562 pub mutable: bool,
562 pub type_ref: TypeRef, 563 pub type_ref: TypeRef,
563 pub ast_id: FileAstId<ast::StaticDef>, 564 pub ast_id: FileAstId<ast::Static>,
564} 565}
565 566
566#[derive(Debug, Clone, Eq, PartialEq)] 567#[derive(Debug, Clone, Eq, PartialEq)]
@@ -570,7 +571,7 @@ pub struct Trait {
570 pub generic_params: GenericParamsId, 571 pub generic_params: GenericParamsId,
571 pub auto: bool, 572 pub auto: bool,
572 pub items: Box<[AssocItem]>, 573 pub items: Box<[AssocItem]>,
573 pub ast_id: FileAstId<ast::TraitDef>, 574 pub ast_id: FileAstId<ast::Trait>,
574} 575}
575 576
576#[derive(Debug, Clone, Eq, PartialEq)] 577#[derive(Debug, Clone, Eq, PartialEq)]
@@ -580,7 +581,7 @@ pub struct Impl {
580 pub target_type: TypeRef, 581 pub target_type: TypeRef,
581 pub is_negative: bool, 582 pub is_negative: bool,
582 pub items: Box<[AssocItem]>, 583 pub items: Box<[AssocItem]>,
583 pub ast_id: FileAstId<ast::ImplDef>, 584 pub ast_id: FileAstId<ast::Impl>,
584} 585}
585 586
586#[derive(Debug, Clone, PartialEq, Eq)] 587#[derive(Debug, Clone, PartialEq, Eq)]
@@ -591,7 +592,7 @@ pub struct TypeAlias {
591 pub bounds: Box<[TypeBound]>, 592 pub bounds: Box<[TypeBound]>,
592 pub generic_params: GenericParamsId, 593 pub generic_params: GenericParamsId,
593 pub type_ref: Option<TypeRef>, 594 pub type_ref: Option<TypeRef>,
594 pub ast_id: FileAstId<ast::TypeAliasDef>, 595 pub ast_id: FileAstId<ast::TypeAlias>,
595} 596}
596 597
597#[derive(Debug, Clone, Eq, PartialEq)] 598#[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 5149dd141..feb31579e 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -1,10 +1,7 @@
1//! AST -> `ItemTree` lowering code. 1//! AST -> `ItemTree` lowering code.
2 2
3use super::*; 3use std::{collections::hash_map::Entry, mem, sync::Arc};
4use crate::{ 4
5 attr::Attrs,
6 generics::{GenericParams, TypeParamData, TypeParamProvenance},
7};
8use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; 5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
9use ra_arena::map::ArenaMap; 6use ra_arena::map::ArenaMap;
10use ra_syntax::{ 7use ra_syntax::{
@@ -12,7 +9,13 @@ use ra_syntax::{
12 SyntaxNode, 9 SyntaxNode,
13}; 10};
14use smallvec::SmallVec; 11use smallvec::SmallVec;
15use std::{collections::hash_map::Entry, mem, sync::Arc}; 12
13use crate::{
14 attr::Attrs,
15 generics::{GenericParams, TypeParamData, TypeParamProvenance},
16};
17
18use super::*;
16 19
17fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { 20fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
18 FileItemTreeId { index, _p: PhantomData } 21 FileItemTreeId { index, _p: PhantomData }
@@ -70,19 +73,19 @@ impl Ctx {
70 self.tree.data_mut() 73 self.tree.data_mut()
71 } 74 }
72 75
73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { 76 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> {
74 assert!(inner || self.inner_items.is_empty()); 77 assert!(inner || self.inner_items.is_empty());
75 78
76 // Collect inner items for 1-to-1-lowered items. 79 // Collect inner items for 1-to-1-lowered items.
77 match item { 80 match item {
78 ast::ModuleItem::StructDef(_) 81 ast::Item::Struct(_)
79 | ast::ModuleItem::UnionDef(_) 82 | ast::Item::Union(_)
80 | ast::ModuleItem::EnumDef(_) 83 | ast::Item::Enum(_)
81 | ast::ModuleItem::FnDef(_) 84 | ast::Item::Fn(_)
82 | ast::ModuleItem::TypeAliasDef(_) 85 | ast::Item::TypeAlias(_)
83 | ast::ModuleItem::ConstDef(_) 86 | ast::Item::Const(_)
84 | ast::ModuleItem::StaticDef(_) 87 | ast::Item::Static(_)
85 | ast::ModuleItem::MacroCall(_) => { 88 | ast::Item::MacroCall(_) => {
86 // Skip this if we're already collecting inner items. We'll descend into all nodes 89 // Skip this if we're already collecting inner items. We'll descend into all nodes
87 // already. 90 // already.
88 if !inner { 91 if !inner {
@@ -92,34 +95,30 @@ impl Ctx {
92 95
93 // These are handled in their respective `lower_X` method (since we can't just blindly 96 // These are handled in their respective `lower_X` method (since we can't just blindly
94 // walk them). 97 // walk them).
95 ast::ModuleItem::TraitDef(_) 98 ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
96 | ast::ModuleItem::ImplDef(_)
97 | ast::ModuleItem::ExternBlock(_) => {}
98 99
99 // These don't have inner items. 100 // These don't have inner items.
100 ast::ModuleItem::Module(_) 101 ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
101 | ast::ModuleItem::ExternCrateItem(_)
102 | ast::ModuleItem::UseItem(_) => {}
103 }; 102 };
104 103
105 let attrs = Attrs::new(item, &self.hygiene); 104 let attrs = Attrs::new(item, &self.hygiene);
106 let items = match item { 105 let items = match item {
107 ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), 106 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
108 ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), 107 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
109 ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), 108 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into),
110 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), 109 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into),
111 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), 110 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
112 ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), 111 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into),
113 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), 112 ast::Item::Const(ast) => Some(self.lower_const(ast).into()),
114 ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), 113 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
115 ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), 114 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into),
116 ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), 115 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into),
117 ast::ModuleItem::UseItem(ast) => Some(ModItems( 116 ast::Item::Use(ast) => Some(ModItems(
118 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), 117 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
119 )), 118 )),
120 ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), 119 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
121 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 120 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
122 ast::ModuleItem::ExternBlock(ast) => { 121 ast::Item::ExternBlock(ast) => {
123 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) 122 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
124 } 123 }
125 }; 124 };
@@ -147,27 +146,26 @@ impl Ctx {
147 fn collect_inner_items(&mut self, container: &SyntaxNode) { 146 fn collect_inner_items(&mut self, container: &SyntaxNode) {
148 let forced_vis = self.forced_visibility.take(); 147 let forced_vis = self.forced_visibility.take();
149 let mut inner_items = mem::take(&mut self.tree.inner_items); 148 let mut inner_items = mem::take(&mut self.tree.inner_items);
150 inner_items.extend( 149 inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map(
151 container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { 150 |item| {
152 let ast_id = self.source_ast_id_map.ast_id(&item); 151 let ast_id = self.source_ast_id_map.ast_id(&item);
153 Some((ast_id, self.lower_mod_item(&item, true)?.0)) 152 Some((ast_id, self.lower_mod_item(&item, true)?.0))
154 }), 153 },
155 ); 154 ));
156 self.tree.inner_items = inner_items; 155 self.tree.inner_items = inner_items;
157 self.forced_visibility = forced_vis; 156 self.forced_visibility = forced_vis;
158 } 157 }
159 158
160 fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> { 159 fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> {
161 match item { 160 match item {
162 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), 161 ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
163 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), 162 ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
164 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), 163 ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
165 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 164 ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
166 _ => None,
167 } 165 }
168 } 166 }
169 167
170 fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> { 168 fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
171 let visibility = self.lower_visibility(strukt); 169 let visibility = self.lower_visibility(strukt);
172 let name = strukt.name()?.as_name(); 170 let name = strukt.name()?.as_name();
173 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); 171 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
@@ -196,7 +194,7 @@ impl Ctx {
196 } 194 }
197 } 195 }
198 196
199 fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> IdRange<Field> { 197 fn lower_record_fields(&mut self, fields: &ast::RecordFieldList) -> IdRange<Field> {
200 let start = self.next_field_idx(); 198 let start = self.next_field_idx();
201 for field in fields.fields() { 199 for field in fields.fields() {
202 if let Some(data) = self.lower_record_field(&field) { 200 if let Some(data) = self.lower_record_field(&field) {
@@ -208,42 +206,39 @@ impl Ctx {
208 IdRange::new(start..end) 206 IdRange::new(start..end)
209 } 207 }
210 208
211 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> { 209 fn lower_record_field(&mut self, field: &ast::RecordField) -> Option<Field> {
212 let name = field.name()?.as_name(); 210 let name = field.name()?.as_name();
213 let visibility = self.lower_visibility(field); 211 let visibility = self.lower_visibility(field);
214 let type_ref = self.lower_type_ref(&field.ascribed_type()?); 212 let type_ref = self.lower_type_ref_opt(field.ty());
215 let res = Field { name, type_ref, visibility }; 213 let res = Field { name, type_ref, visibility };
216 Some(res) 214 Some(res)
217 } 215 }
218 216
219 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> IdRange<Field> { 217 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldList) -> IdRange<Field> {
220 let start = self.next_field_idx(); 218 let start = self.next_field_idx();
221 for (i, field) in fields.fields().enumerate() { 219 for (i, field) in fields.fields().enumerate() {
222 if let Some(data) = self.lower_tuple_field(i, &field) { 220 let data = self.lower_tuple_field(i, &field);
223 let idx = self.data().fields.alloc(data); 221 let idx = self.data().fields.alloc(data);
224 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); 222 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
225 }
226 } 223 }
227 let end = self.next_field_idx(); 224 let end = self.next_field_idx();
228 IdRange::new(start..end) 225 IdRange::new(start..end)
229 } 226 }
230 227
231 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> { 228 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
232 let name = Name::new_tuple_field(idx); 229 let name = Name::new_tuple_field(idx);
233 let visibility = self.lower_visibility(field); 230 let visibility = self.lower_visibility(field);
234 let type_ref = self.lower_type_ref(&field.type_ref()?); 231 let type_ref = self.lower_type_ref_opt(field.ty());
235 let res = Field { name, type_ref, visibility }; 232 let res = Field { name, type_ref, visibility };
236 Some(res) 233 res
237 } 234 }
238 235
239 fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> { 236 fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
240 let visibility = self.lower_visibility(union); 237 let visibility = self.lower_visibility(union);
241 let name = union.name()?.as_name(); 238 let name = union.name()?.as_name();
242 let generic_params = self.lower_generic_params(GenericsOwner::Union, union); 239 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
243 let fields = match union.record_field_def_list() { 240 let fields = match union.record_field_list() {
244 Some(record_field_def_list) => { 241 Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
245 self.lower_fields(&StructKind::Record(record_field_def_list))
246 }
247 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())), 242 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())),
248 }; 243 };
249 let ast_id = self.source_ast_id_map.ast_id(union); 244 let ast_id = self.source_ast_id_map.ast_id(union);
@@ -251,7 +246,7 @@ impl Ctx {
251 Some(id(self.data().unions.alloc(res))) 246 Some(id(self.data().unions.alloc(res)))
252 } 247 }
253 248
254 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { 249 fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
255 let visibility = self.lower_visibility(enum_); 250 let visibility = self.lower_visibility(enum_);
256 let name = enum_.name()?.as_name(); 251 let name = enum_.name()?.as_name();
257 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); 252 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
@@ -264,7 +259,7 @@ impl Ctx {
264 Some(id(self.data().enums.alloc(res))) 259 Some(id(self.data().enums.alloc(res)))
265 } 260 }
266 261
267 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> IdRange<Variant> { 262 fn lower_variants(&mut self, variants: &ast::VariantList) -> IdRange<Variant> {
268 let start = self.next_variant_idx(); 263 let start = self.next_variant_idx();
269 for variant in variants.variants() { 264 for variant in variants.variants() {
270 if let Some(data) = self.lower_variant(&variant) { 265 if let Some(data) = self.lower_variant(&variant) {
@@ -276,14 +271,14 @@ impl Ctx {
276 IdRange::new(start..end) 271 IdRange::new(start..end)
277 } 272 }
278 273
279 fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> { 274 fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
280 let name = variant.name()?.as_name(); 275 let name = variant.name()?.as_name();
281 let fields = self.lower_fields(&variant.kind()); 276 let fields = self.lower_fields(&variant.kind());
282 let res = Variant { name, fields }; 277 let res = Variant { name, fields };
283 Some(res) 278 Some(res)
284 } 279 }
285 280
286 fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> { 281 fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
287 let visibility = self.lower_visibility(func); 282 let visibility = self.lower_visibility(func);
288 let name = func.name()?.as_name(); 283 let name = func.name()?.as_name();
289 284
@@ -291,7 +286,7 @@ impl Ctx {
291 let mut has_self_param = false; 286 let mut has_self_param = false;
292 if let Some(param_list) = func.param_list() { 287 if let Some(param_list) = func.param_list() {
293 if let Some(self_param) = param_list.self_param() { 288 if let Some(self_param) = param_list.self_param() {
294 let self_type = match self_param.ascribed_type() { 289 let self_type = match self_param.ty() {
295 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), 290 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
296 None => { 291 None => {
297 let self_type = TypeRef::Path(name![Self].into()); 292 let self_type = TypeRef::Path(name![Self].into());
@@ -310,11 +305,19 @@ impl Ctx {
310 has_self_param = true; 305 has_self_param = true;
311 } 306 }
312 for param in param_list.params() { 307 for param in param_list.params() {
313 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); 308 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
314 params.push(type_ref); 309 params.push(type_ref);
315 } 310 }
316 } 311 }
317 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { 312
313 let mut is_varargs = false;
314 if let Some(params) = func.param_list() {
315 if let Some(last) = params.params().last() {
316 is_varargs = last.dotdotdot_token().is_some();
317 }
318 }
319
320 let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
318 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), 321 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
319 _ => TypeRef::unit(), 322 _ => TypeRef::unit(),
320 }; 323 };
@@ -335,6 +338,7 @@ impl Ctx {
335 has_self_param, 338 has_self_param,
336 is_unsafe: func.unsafe_token().is_some(), 339 is_unsafe: func.unsafe_token().is_some(),
337 params: params.into_boxed_slice(), 340 params: params.into_boxed_slice(),
341 is_varargs,
338 ret_type, 342 ret_type,
339 ast_id, 343 ast_id,
340 }; 344 };
@@ -345,10 +349,10 @@ impl Ctx {
345 349
346 fn lower_type_alias( 350 fn lower_type_alias(
347 &mut self, 351 &mut self,
348 type_alias: &ast::TypeAliasDef, 352 type_alias: &ast::TypeAlias,
349 ) -> Option<FileItemTreeId<TypeAlias>> { 353 ) -> Option<FileItemTreeId<TypeAlias>> {
350 let name = type_alias.name()?.as_name(); 354 let name = type_alias.name()?.as_name();
351 let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); 355 let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
352 let visibility = self.lower_visibility(type_alias); 356 let visibility = self.lower_visibility(type_alias);
353 let bounds = self.lower_type_bounds(type_alias); 357 let bounds = self.lower_type_bounds(type_alias);
354 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); 358 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
@@ -364,9 +368,9 @@ impl Ctx {
364 Some(id(self.data().type_aliases.alloc(res))) 368 Some(id(self.data().type_aliases.alloc(res)))
365 } 369 }
366 370
367 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { 371 fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
368 let name = static_.name()?.as_name(); 372 let name = static_.name()?.as_name();
369 let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); 373 let type_ref = self.lower_type_ref_opt(static_.ty());
370 let visibility = self.lower_visibility(static_); 374 let visibility = self.lower_visibility(static_);
371 let mutable = static_.mut_token().is_some(); 375 let mutable = static_.mut_token().is_some();
372 let ast_id = self.source_ast_id_map.ast_id(static_); 376 let ast_id = self.source_ast_id_map.ast_id(static_);
@@ -374,9 +378,9 @@ impl Ctx {
374 Some(id(self.data().statics.alloc(res))) 378 Some(id(self.data().statics.alloc(res)))
375 } 379 }
376 380
377 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { 381 fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
378 let name = konst.name().map(|it| it.as_name()); 382 let name = konst.name().map(|it| it.as_name());
379 let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); 383 let type_ref = self.lower_type_ref_opt(konst.ty());
380 let visibility = self.lower_visibility(konst); 384 let visibility = self.lower_visibility(konst);
381 let ast_id = self.source_ast_id_map.ast_id(konst); 385 let ast_id = self.source_ast_id_map.ast_id(konst);
382 let res = Const { name, visibility, type_ref, ast_id }; 386 let res = Const { name, visibility, type_ref, ast_id };
@@ -409,15 +413,15 @@ impl Ctx {
409 Some(id(self.data().mods.alloc(res))) 413 Some(id(self.data().mods.alloc(res)))
410 } 414 }
411 415
412 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { 416 fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
413 let name = trait_def.name()?.as_name(); 417 let name = trait_def.name()?.as_name();
414 let visibility = self.lower_visibility(trait_def); 418 let visibility = self.lower_visibility(trait_def);
415 let generic_params = 419 let generic_params =
416 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 420 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
417 let auto = trait_def.auto_token().is_some(); 421 let auto = trait_def.auto_token().is_some();
418 let items = trait_def.item_list().map(|list| { 422 let items = trait_def.assoc_item_list().map(|list| {
419 self.with_inherited_visibility(visibility, |this| { 423 self.with_inherited_visibility(visibility, |this| {
420 list.items() 424 list.assoc_items()
421 .filter_map(|item| { 425 .filter_map(|item| {
422 let attrs = Attrs::new(&item, &this.hygiene); 426 let attrs = Attrs::new(&item, &this.hygiene);
423 this.collect_inner_items(item.syntax()); 427 this.collect_inner_items(item.syntax());
@@ -441,7 +445,7 @@ impl Ctx {
441 Some(id(self.data().traits.alloc(res))) 445 Some(id(self.data().traits.alloc(res)))
442 } 446 }
443 447
444 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { 448 fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
445 let generic_params = 449 let generic_params =
446 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); 450 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
447 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); 451 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr));
@@ -450,8 +454,9 @@ impl Ctx {
450 454
451 // We cannot use `assoc_items()` here as that does not include macro calls. 455 // We cannot use `assoc_items()` here as that does not include macro calls.
452 let items = impl_def 456 let items = impl_def
453 .item_list()? 457 .assoc_item_list()
454 .items() 458 .into_iter()
459 .flat_map(|it| it.assoc_items())
455 .filter_map(|item| { 460 .filter_map(|item| {
456 self.collect_inner_items(item.syntax()); 461 self.collect_inner_items(item.syntax());
457 let assoc = self.lower_assoc_item(&item)?; 462 let assoc = self.lower_assoc_item(&item)?;
@@ -465,7 +470,7 @@ impl Ctx {
465 Some(id(self.data().impls.alloc(res))) 470 Some(id(self.data().impls.alloc(res)))
466 } 471 }
467 472
468 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { 473 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
469 // FIXME: cfg_attr 474 // FIXME: cfg_attr
470 let is_prelude = use_item.has_atom_attr("prelude_import"); 475 let is_prelude = use_item.has_atom_attr("prelude_import");
471 let visibility = self.lower_visibility(use_item); 476 let visibility = self.lower_visibility(use_item);
@@ -494,10 +499,10 @@ impl Ctx {
494 499
495 fn lower_extern_crate( 500 fn lower_extern_crate(
496 &mut self, 501 &mut self,
497 extern_crate: &ast::ExternCrateItem, 502 extern_crate: &ast::ExternCrate,
498 ) -> Option<FileItemTreeId<ExternCrate>> { 503 ) -> Option<FileItemTreeId<ExternCrate>> {
499 let path = ModPath::from_name_ref(&extern_crate.name_ref()?); 504 let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
500 let alias = extern_crate.alias().map(|a| { 505 let alias = extern_crate.rename().map(|a| {
501 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) 506 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
502 }); 507 });
503 let visibility = self.lower_visibility(extern_crate); 508 let visibility = self.lower_visibility(extern_crate);
@@ -543,14 +548,16 @@ impl Ctx {
543 self.collect_inner_items(item.syntax()); 548 self.collect_inner_items(item.syntax());
544 let attrs = Attrs::new(&item, &self.hygiene); 549 let attrs = Attrs::new(&item, &self.hygiene);
545 let id: ModItem = match item { 550 let id: ModItem = match item {
546 ast::ExternItem::FnDef(ast) => { 551 ast::ExternItem::Fn(ast) => {
547 let func = self.lower_function(&ast)?; 552 let func = self.lower_function(&ast)?;
553 self.data().functions[func.index].is_unsafe = true;
548 func.into() 554 func.into()
549 } 555 }
550 ast::ExternItem::StaticDef(ast) => { 556 ast::ExternItem::Static(ast) => {
551 let statik = self.lower_static(&ast)?; 557 let statik = self.lower_static(&ast)?;
552 statik.into() 558 statik.into()
553 } 559 }
560 ast::ExternItem::MacroCall(_) => return None,
554 }; 561 };
555 self.add_attrs(id.into(), attrs); 562 self.add_attrs(id.into(), attrs);
556 Some(id) 563 Some(id)
@@ -563,10 +570,10 @@ impl Ctx {
563 fn lower_generic_params_and_inner_items( 570 fn lower_generic_params_and_inner_items(
564 &mut self, 571 &mut self,
565 owner: GenericsOwner<'_>, 572 owner: GenericsOwner<'_>,
566 node: &impl ast::TypeParamsOwner, 573 node: &impl ast::GenericParamsOwner,
567 ) -> GenericParamsId { 574 ) -> GenericParamsId {
568 // Generics are part of item headers and may contain inner items we need to collect. 575 // Generics are part of item headers and may contain inner items we need to collect.
569 if let Some(params) = node.type_param_list() { 576 if let Some(params) = node.generic_param_list() {
570 self.collect_inner_items(params.syntax()); 577 self.collect_inner_items(params.syntax());
571 } 578 }
572 if let Some(clause) = node.where_clause() { 579 if let Some(clause) = node.where_clause() {
@@ -579,7 +586,7 @@ impl Ctx {
579 fn lower_generic_params( 586 fn lower_generic_params(
580 &mut self, 587 &mut self,
581 owner: GenericsOwner<'_>, 588 owner: GenericsOwner<'_>,
582 node: &impl ast::TypeParamsOwner, 589 node: &impl ast::GenericParamsOwner,
583 ) -> GenericParamsId { 590 ) -> GenericParamsId {
584 let mut sm = &mut ArenaMap::default(); 591 let mut sm = &mut ArenaMap::default();
585 let mut generics = GenericParams::default(); 592 let mut generics = GenericParams::default();
@@ -692,7 +699,7 @@ enum GenericsOwner<'a> {
692 Enum, 699 Enum,
693 Union, 700 Union,
694 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. 701 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
695 Trait(&'a ast::TraitDef), 702 Trait(&'a ast::Trait),
696 TypeAlias, 703 TypeAlias,
697 Impl, 704 Impl,
698} 705}
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs
index 08559fb92..a81497fa8 100644
--- a/crates/ra_hir_def/src/item_tree/tests.rs
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -1,13 +1,15 @@
1use super::{ItemTree, ModItem, ModKind}; 1use expect::{expect, Expect};
2use crate::{db::DefDatabase, test_db::TestDB};
3use hir_expand::{db::AstDatabase, HirFileId, InFile}; 2use hir_expand::{db::AstDatabase, HirFileId, InFile};
4use insta::assert_snapshot;
5use ra_db::fixture::WithFixture; 3use ra_db::fixture::WithFixture;
6use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode};
7use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
8use std::sync::Arc; 6use std::sync::Arc;
9use stdx::format_to; 7use stdx::format_to;
10 8
9use crate::{db::DefDatabase, test_db::TestDB};
10
11use super::{ItemTree, ModItem, ModKind};
12
11fn test_inner_items(ra_fixture: &str) { 13fn test_inner_items(ra_fixture: &str) {
12 let (db, file_id) = TestDB::with_single_file(ra_fixture); 14 let (db, file_id) = TestDB::with_single_file(ra_fixture);
13 let file_id = HirFileId::from(file_id); 15 let file_id = HirFileId::from(file_id);
@@ -19,7 +21,7 @@ fn test_inner_items(ra_fixture: &str) {
19 let mut outer_items = FxHashSet::default(); 21 let mut outer_items = FxHashSet::default();
20 let mut worklist = tree.top_level_items().to_vec(); 22 let mut worklist = tree.top_level_items().to_vec();
21 while let Some(item) = worklist.pop() { 23 while let Some(item) = worklist.pop() {
22 let node: ast::ModuleItem = match item { 24 let node: ast::Item = match item {
23 ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), 25 ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(),
24 ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), 26 ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(),
25 ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), 27 ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(),
@@ -51,7 +53,7 @@ fn test_inner_items(ra_fixture: &str) {
51 53
52 // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or 54 // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or
53 // registered as inner items. 55 // registered as inner items.
54 for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { 56 for item in root.descendants().skip(1).filter_map(ast::Item::cast) {
55 if outer_items.contains(&item) { 57 if outer_items.contains(&item) {
56 continue; 58 continue;
57 } 59 }
@@ -162,9 +164,15 @@ fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) {
162 } 164 }
163} 165}
164 166
167fn check(ra_fixture: &str, expect: Expect) {
168 let actual = print_item_tree(ra_fixture);
169 expect.assert_eq(&actual);
170}
171
165#[test] 172#[test]
166fn smoke() { 173fn smoke() {
167 assert_snapshot!(print_item_tree(r" 174 check(
175 r"
168 #![attr] 176 #![attr]
169 177
170 #[attr_on_use] 178 #[attr_on_use]
@@ -214,42 +222,44 @@ fn smoke() {
214 #[union_fld] 222 #[union_fld]
215 fld: u16, 223 fld: u16,
216 } 224 }
217 "), @r###" 225 ",
218inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } 226 expect![[r##"
219 227 inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) }
220top-level items: 228
221#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] 229 top-level items:
222Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } 230 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
223#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] 231 Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
224Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } 232 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
225#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] 233 Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
226ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) } 234 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
227#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] 235 ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrate>(1) }
228Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) } 236 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
229> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] 237 Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Trait>(2) }
230> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) } 238 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }]
231> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] 239 > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAlias>(8) }
232> Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) } 240 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }]
233> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] 241 > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Const>(9) }
234> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) } 242 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }]
235> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] 243 > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(10) }
236> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) } 244 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }]
237#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] 245 > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(11) }
238Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit } 246 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }]
239#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] 247 Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(3), kind: Unit }
240Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::<ra_hir_def::item_tree::Field>(0..1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple } 248 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }]
241#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] 249 Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::<ra_hir_def::item_tree::Field>(0..1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(4), kind: Tuple }
242Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(1..2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record } 250 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }]
243#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] 251 Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(1..2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(5), kind: Record }
244Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::<ra_hir_def::item_tree::Variant>(0..1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) } 252 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }]
245#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] 253 Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::<ra_hir_def::item_tree::Variant>(0..1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Enum>(6) }
246Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(3..4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) } 254 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }]
247 "###); 255 Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(3..4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Union>(7) }
256 "##]],
257 );
248} 258}
249 259
250#[test] 260#[test]
251fn simple_inner_items() { 261fn simple_inner_items() {
252 let tree = print_item_tree( 262 check(
253 r" 263 r"
254 impl<T:A> D for Response<T> { 264 impl<T:A> D for Response<T> {
255 fn foo() { 265 fn foo() {
@@ -260,26 +270,25 @@ fn simple_inner_items() {
260 } 270 }
261 } 271 }
262 ", 272 ",
263 ); 273 expect![[r#"
274 inner attrs: Attrs { entries: None }
264 275
265 assert_snapshot!(tree, @r###" 276 top-level items:
266inner attrs: Attrs { entries: None } 277 Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
278 > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
267 279
268top-level items: 280 inner items:
269Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
270> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
271 281
272inner items: 282 for AST FileAstId::<ra_syntax::ast::generated::nodes::Item>(2):
283 Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
273 284
274for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2): 285 "#]],
275Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } 286 );
276
277 "###);
278} 287}
279 288
280#[test] 289#[test]
281fn extern_attrs() { 290fn extern_attrs() {
282 let tree = print_item_tree( 291 check(
283 r#" 292 r#"
284 #[block_attr] 293 #[block_attr]
285 extern "C" { 294 extern "C" {
@@ -289,22 +298,21 @@ fn extern_attrs() {
289 fn b() {} 298 fn b() {}
290 } 299 }
291 "#, 300 "#,
301 expect![[r##"
302 inner attrs: Attrs { entries: None }
303
304 top-level items:
305 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
306 Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
307 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
308 Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
309 "##]],
292 ); 310 );
293
294 assert_snapshot!(tree, @r###"
295inner attrs: Attrs { entries: None }
296
297top-level items:
298#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
299Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
300#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
301Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
302 "###);
303} 311}
304 312
305#[test] 313#[test]
306fn trait_attrs() { 314fn trait_attrs() {
307 let tree = print_item_tree( 315 check(
308 r#" 316 r#"
309 #[trait_attr] 317 #[trait_attr]
310 trait Tr { 318 trait Tr {
@@ -314,24 +322,23 @@ fn trait_attrs() {
314 fn b() {} 322 fn b() {}
315 } 323 }
316 "#, 324 "#,
325 expect![[r##"
326 inner attrs: Attrs { entries: None }
327
328 top-level items:
329 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
330 Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Trait>(0) }
331 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
332 > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
333 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
334 > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
335 "##]],
317 ); 336 );
318
319 assert_snapshot!(tree, @r###"
320inner attrs: Attrs { entries: None }
321
322top-level items:
323#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
324Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) }
325> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
326> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
327> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
328> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
329 "###);
330} 337}
331 338
332#[test] 339#[test]
333fn impl_attrs() { 340fn impl_attrs() {
334 let tree = print_item_tree( 341 check(
335 r#" 342 r#"
336 #[impl_attr] 343 #[impl_attr]
337 impl Ty { 344 impl Ty {
@@ -341,19 +348,18 @@ fn impl_attrs() {
341 fn b() {} 348 fn b() {}
342 } 349 }
343 "#, 350 "#,
351 expect![[r##"
352 inner attrs: Attrs { entries: None }
353
354 top-level items:
355 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
356 Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
357 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
358 > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
359 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
360 > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
361 "##]],
344 ); 362 );
345
346 assert_snapshot!(tree, @r###"
347inner attrs: Attrs { entries: None }
348
349top-level items:
350#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
351Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
352> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
353> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
354> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
355> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
356 "###);
357} 363}
358 364
359#[test] 365#[test]
@@ -391,45 +397,43 @@ fn cursed_inner_items() {
391 397
392#[test] 398#[test]
393fn inner_item_attrs() { 399fn inner_item_attrs() {
394 let tree = print_item_tree( 400 check(
395 r" 401 r"
396 fn foo() { 402 fn foo() {
397 #[on_inner] 403 #[on_inner]
398 fn inner() {} 404 fn inner() {}
399 } 405 }
400 ", 406 ",
401 ); 407 expect![[r##"
402 408 inner attrs: Attrs { entries: None }
403 assert_snapshot!(tree, @r###"
404inner attrs: Attrs { entries: None }
405 409
406top-level items: 410 top-level items:
407Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) } 411 Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(0) }
408 412
409inner items: 413 inner items:
410 414
411for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1): 415 for AST FileAstId::<ra_syntax::ast::generated::nodes::Item>(1):
412#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] 416 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }]
413Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } 417 Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
414 418
415 "###); 419 "##]],
420 );
416} 421}
417 422
418#[test] 423#[test]
419fn assoc_item_macros() { 424fn assoc_item_macros() {
420 let tree = print_item_tree( 425 check(
421 r" 426 r"
422 impl S { 427 impl S {
423 items!(); 428 items!();
424 } 429 }
425 ", 430 ",
426 ); 431 expect![[r#"
427 432 inner attrs: Attrs { entries: None }
428 assert_snapshot!(tree, @r###"
429inner attrs: Attrs { entries: None }
430 433
431top-level items: 434 top-level items:
432Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } 435 Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
433> MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) } 436 > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) }
434 "###); 437 "#]],
438 );
435} 439}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
index a7349a21d..441bdbead 100644
--- a/crates/ra_hir_def/src/keys.rs
+++ b/crates/ra_hir_def/src/keys.rs
@@ -14,19 +14,19 @@ use crate::{
14 14
15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; 15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
16 16
17pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new(); 17pub const FUNCTION: Key<ast::Fn, FunctionId> = Key::new();
18pub const CONST: Key<ast::ConstDef, ConstId> = Key::new(); 18pub const CONST: Key<ast::Const, ConstId> = Key::new();
19pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new(); 19pub const STATIC: Key<ast::Static, StaticId> = Key::new();
20pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new(); 20pub const TYPE_ALIAS: Key<ast::TypeAlias, TypeAliasId> = Key::new();
21pub const IMPL: Key<ast::ImplDef, ImplId> = Key::new(); 21pub const IMPL: Key<ast::Impl, ImplId> = Key::new();
22pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new(); 22pub const TRAIT: Key<ast::Trait, TraitId> = Key::new();
23pub const STRUCT: Key<ast::StructDef, StructId> = Key::new(); 23pub const STRUCT: Key<ast::Struct, StructId> = Key::new();
24pub const UNION: Key<ast::UnionDef, UnionId> = Key::new(); 24pub const UNION: Key<ast::Union, UnionId> = Key::new();
25pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new(); 25pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
26 26
27pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new(); 27pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
28pub const TUPLE_FIELD: Key<ast::TupleFieldDef, FieldId> = Key::new(); 28pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
29pub const RECORD_FIELD: Key<ast::RecordFieldDef, FieldId> = Key::new(); 29pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); 30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
31 31
32pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); 32pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 564434ccc..237b1038a 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -65,6 +65,7 @@ use item_tree::{
65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, 65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
66 TypeAlias, Union, 66 TypeAlias, Union,
67}; 67};
68use stdx::impl_from;
68 69
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70pub struct ModuleId { 71pub struct ModuleId {
@@ -158,17 +159,17 @@ pub struct FunctionId(salsa::InternId);
158type FunctionLoc = AssocItemLoc<Function>; 159type FunctionLoc = AssocItemLoc<Function>;
159impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); 160impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
160 161
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
162pub struct StructId(salsa::InternId); 163pub struct StructId(salsa::InternId);
163type StructLoc = ItemLoc<Struct>; 164type StructLoc = ItemLoc<Struct>;
164impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); 165impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
165 166
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
167pub struct UnionId(salsa::InternId); 168pub struct UnionId(salsa::InternId);
168pub type UnionLoc = ItemLoc<Union>; 169pub type UnionLoc = ItemLoc<Union>;
169impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); 170impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
170 171
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 172#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
172pub struct EnumId(salsa::InternId); 173pub struct EnumId(salsa::InternId);
173pub type EnumLoc = ItemLoc<Enum>; 174pub type EnumLoc = ItemLoc<Enum>;
174impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); 175impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
@@ -223,25 +224,6 @@ pub struct TypeParamId {
223 224
224pub type LocalTypeParamId = Idx<generics::TypeParamData>; 225pub type LocalTypeParamId = Idx<generics::TypeParamData>;
225 226
226macro_rules! impl_froms {
227 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
228 $(
229 impl From<$v> for $e {
230 fn from(it: $v) -> $e {
231 $e::$v(it)
232 }
233 }
234 $($(
235 impl From<$sv> for $e {
236 fn from(it: $sv) -> $e {
237 $e::$v($v::$sv(it))
238 }
239 }
240 )*)?
241 )*
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
246pub enum ContainerId { 228pub enum ContainerId {
247 ModuleId(ModuleId), 229 ModuleId(ModuleId),
@@ -254,16 +236,16 @@ pub enum AssocContainerId {
254 ImplId(ImplId), 236 ImplId(ImplId),
255 TraitId(TraitId), 237 TraitId(TraitId),
256} 238}
257impl_froms!(AssocContainerId: ContainerId); 239impl_from!(ContainerId for AssocContainerId);
258 240
259/// A Data Type 241/// A Data Type
260#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
261pub enum AdtId { 243pub enum AdtId {
262 StructId(StructId), 244 StructId(StructId),
263 UnionId(UnionId), 245 UnionId(UnionId),
264 EnumId(EnumId), 246 EnumId(EnumId),
265} 247}
266impl_froms!(AdtId: StructId, UnionId, EnumId); 248impl_from!(StructId, UnionId, EnumId for AdtId);
267 249
268/// The defs which can be visible in the module. 250/// The defs which can be visible in the module.
269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -279,8 +261,8 @@ pub enum ModuleDefId {
279 TypeAliasId(TypeAliasId), 261 TypeAliasId(TypeAliasId),
280 BuiltinType(BuiltinType), 262 BuiltinType(BuiltinType),
281} 263}
282impl_froms!( 264impl_from!(
283 ModuleDefId: ModuleId, 265 ModuleId,
284 FunctionId, 266 FunctionId,
285 AdtId(StructId, EnumId, UnionId), 267 AdtId(StructId, EnumId, UnionId),
286 EnumVariantId, 268 EnumVariantId,
@@ -289,6 +271,7 @@ impl_froms!(
289 TraitId, 271 TraitId,
290 TypeAliasId, 272 TypeAliasId,
291 BuiltinType 273 BuiltinType
274 for ModuleDefId
292); 275);
293 276
294/// The defs which have a body. 277/// The defs which have a body.
@@ -299,7 +282,7 @@ pub enum DefWithBodyId {
299 ConstId(ConstId), 282 ConstId(ConstId),
300} 283}
301 284
302impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); 285impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
303 286
304#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 287#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
305pub enum AssocItemId { 288pub enum AssocItemId {
@@ -311,7 +294,7 @@ pub enum AssocItemId {
311// sure that you can only turn actual assoc items into AssocItemIds. This would 294// sure that you can only turn actual assoc items into AssocItemIds. This would
312// require not implementing From, and instead having some checked way of 295// require not implementing From, and instead having some checked way of
313// casting them, and somehow making the constructors private, which would be annoying. 296// casting them, and somehow making the constructors private, which would be annoying.
314impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); 297impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
315 298
316#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 299#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
317pub enum GenericDefId { 300pub enum GenericDefId {
@@ -326,14 +309,15 @@ pub enum GenericDefId {
326 // consts can have type parameters from their parents (i.e. associated consts of traits) 309 // consts can have type parameters from their parents (i.e. associated consts of traits)
327 ConstId(ConstId), 310 ConstId(ConstId),
328} 311}
329impl_froms!( 312impl_from!(
330 GenericDefId: FunctionId, 313 FunctionId,
331 AdtId(StructId, EnumId, UnionId), 314 AdtId(StructId, EnumId, UnionId),
332 TraitId, 315 TraitId,
333 TypeAliasId, 316 TypeAliasId,
334 ImplId, 317 ImplId,
335 EnumVariantId, 318 EnumVariantId,
336 ConstId 319 ConstId
320 for GenericDefId
337); 321);
338 322
339impl From<AssocItemId> for GenericDefId { 323impl From<AssocItemId> for GenericDefId {
@@ -361,8 +345,8 @@ pub enum AttrDefId {
361 ImplId(ImplId), 345 ImplId(ImplId),
362} 346}
363 347
364impl_froms!( 348impl_from!(
365 AttrDefId: ModuleId, 349 ModuleId,
366 FieldId, 350 FieldId,
367 AdtId(StructId, EnumId, UnionId), 351 AdtId(StructId, EnumId, UnionId),
368 EnumVariantId, 352 EnumVariantId,
@@ -373,6 +357,7 @@ impl_froms!(
373 TypeAliasId, 357 TypeAliasId,
374 MacroDefId, 358 MacroDefId,
375 ImplId 359 ImplId
360 for AttrDefId
376); 361);
377 362
378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -381,7 +366,7 @@ pub enum VariantId {
381 StructId(StructId), 366 StructId(StructId),
382 UnionId(UnionId), 367 UnionId(UnionId),
383} 368}
384impl_froms!(VariantId: EnumVariantId, StructId, UnionId); 369impl_from!(EnumVariantId, StructId, UnionId for VariantId);
385 370
386trait Intern { 371trait Intern {
387 type ID; 372 type ID;
@@ -536,7 +521,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
536 } 521 }
537} 522}
538 523
539impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { 524impl AsMacroCall for AstIdWithPath<ast::Item> {
540 fn as_call_id( 525 fn as_call_id(
541 &self, 526 &self,
542 db: &dyn db::DefDatabase, 527 db: &dyn db::DefDatabase,
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index b279bdeef..3d9b55a73 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -229,37 +229,37 @@ impl CrateDefMap {
229 // even), as this should be a great debugging aid. 229 // even), as this should be a great debugging aid.
230 pub fn dump(&self) -> String { 230 pub fn dump(&self) -> String {
231 let mut buf = String::new(); 231 let mut buf = String::new();
232 go(&mut buf, self, "\ncrate", self.root); 232 go(&mut buf, self, "crate", self.root);
233 return buf.trim().to_string(); 233 return buf;
234 234
235 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { 235 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
236 *buf += path; 236 format_to!(buf, "{}\n", path);
237 *buf += "\n";
238 237
239 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); 238 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
240 entries.sort_by_key(|(name, _)| name.clone()); 239 entries.sort_by_key(|(name, _)| name.clone());
241 240
242 for (name, def) in entries { 241 for (name, def) in entries {
243 format_to!(buf, "{}:", name); 242 format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
244 243
245 if def.types.is_some() { 244 if def.types.is_some() {
246 *buf += " t"; 245 buf.push_str(" t");
247 } 246 }
248 if def.values.is_some() { 247 if def.values.is_some() {
249 *buf += " v"; 248 buf.push_str(" v");
250 } 249 }
251 if def.macros.is_some() { 250 if def.macros.is_some() {
252 *buf += " m"; 251 buf.push_str(" m");
253 } 252 }
254 if def.is_none() { 253 if def.is_none() {
255 *buf += " _"; 254 buf.push_str(" _");
256 } 255 }
257 256
258 *buf += "\n"; 257 buf.push_str("\n");
259 } 258 }
260 259
261 for (name, child) in map.modules[module].children.iter() { 260 for (name, child) in map.modules[module].children.iter() {
262 let path = &format!("{}::{}", path, name); 261 let path = format!("{}::{}", path, name);
262 buf.push('\n');
263 go(buf, map, &path, *child); 263 go(buf, map, &path, *child);
264 } 264 }
265 } 265 }
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index a35ac1024..28b7a20c5 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -36,6 +36,10 @@ use crate::{
36 TraitLoc, TypeAliasLoc, UnionLoc, 36 TraitLoc, TypeAliasLoc, UnionLoc,
37}; 37};
38 38
39const GLOB_RECURSION_LIMIT: usize = 100;
40const EXPANSION_DEPTH_LIMIT: usize = 128;
41const FIXED_POINT_LIMIT: usize = 8192;
42
39pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 43pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
40 let crate_graph = db.crate_graph(); 44 let crate_graph = db.crate_graph();
41 45
@@ -166,7 +170,7 @@ struct MacroDirective {
166#[derive(Clone, Debug, Eq, PartialEq)] 170#[derive(Clone, Debug, Eq, PartialEq)]
167struct DeriveDirective { 171struct DeriveDirective {
168 module_id: LocalModuleId, 172 module_id: LocalModuleId,
169 ast_id: AstIdWithPath<ast::ModuleItem>, 173 ast_id: AstIdWithPath<ast::Item>,
170} 174}
171 175
172struct DefData<'a> { 176struct DefData<'a> {
@@ -217,7 +221,7 @@ impl DefCollector<'_> {
217 ReachedFixedPoint::Yes => break, 221 ReachedFixedPoint::Yes => break,
218 ReachedFixedPoint::No => i += 1, 222 ReachedFixedPoint::No => i += 1,
219 } 223 }
220 if i == 10000 { 224 if i == FIXED_POINT_LIMIT {
221 log::error!("name resolution is stuck"); 225 log::error!("name resolution is stuck");
222 break; 226 break;
223 } 227 }
@@ -306,7 +310,7 @@ impl DefCollector<'_> {
306 if export { 310 if export {
307 self.update( 311 self.update(
308 self.def_map.root, 312 self.def_map.root,
309 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
310 Visibility::Public, 314 Visibility::Public,
311 ImportType::Named, 315 ImportType::Named,
312 ); 316 );
@@ -332,7 +336,7 @@ impl DefCollector<'_> {
332 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { 336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
333 self.update( 337 self.update(
334 self.def_map.root, 338 self.def_map.root,
335 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
336 Visibility::Public, 340 Visibility::Public,
337 ImportType::Named, 341 ImportType::Named,
338 ); 342 );
@@ -530,7 +534,7 @@ impl DefCollector<'_> {
530 let name = variant_data.name.clone(); 534 let name = variant_data.name.clone();
531 let variant = EnumVariantId { parent: e, local_id }; 535 let variant = EnumVariantId { parent: e, local_id };
532 let res = PerNs::both(variant.into(), variant.into(), vis); 536 let res = PerNs::both(variant.into(), variant.into(), vis);
533 (name, res) 537 (Some(name), res)
534 }) 538 })
535 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
536 self.update(module_id, &resolutions, vis, ImportType::Glob); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -546,15 +550,15 @@ impl DefCollector<'_> {
546 match import.path.segments.last() { 550 match import.path.segments.last() {
547 Some(last_segment) => { 551 Some(last_segment) => {
548 let name = match &import.alias { 552 let name = match &import.alias {
549 Some(ImportAlias::Alias(name)) => name.clone(), 553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
550 Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 554 Some(ImportAlias::Underscore) => None,
551 None => last_segment.clone(), 555 None => Some(last_segment.clone()),
552 }; 556 };
553 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
554 558
555 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
556 if import.is_extern_crate && module_id == self.def_map.root { 560 if import.is_extern_crate && module_id == self.def_map.root {
557 if let Some(def) = def.take_types() { 561 if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
558 self.def_map.extern_prelude.insert(name.clone(), def); 562 self.def_map.extern_prelude.insert(name.clone(), def);
559 } 563 }
560 } 564 }
@@ -569,36 +573,73 @@ impl DefCollector<'_> {
569 fn update( 573 fn update(
570 &mut self, 574 &mut self,
571 module_id: LocalModuleId, 575 module_id: LocalModuleId,
572 resolutions: &[(Name, PerNs)], 576 resolutions: &[(Option<Name>, PerNs)],
573 vis: Visibility, 577 vis: Visibility,
574 import_type: ImportType, 578 import_type: ImportType,
575 ) { 579 ) {
580 self.db.check_canceled();
576 self.update_recursive(module_id, resolutions, vis, import_type, 0) 581 self.update_recursive(module_id, resolutions, vis, import_type, 0)
577 } 582 }
578 583
579 fn update_recursive( 584 fn update_recursive(
580 &mut self, 585 &mut self,
581 module_id: LocalModuleId, 586 module_id: LocalModuleId,
582 resolutions: &[(Name, PerNs)], 587 resolutions: &[(Option<Name>, PerNs)],
583 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
584 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
585 vis: Visibility, 590 vis: Visibility,
586 import_type: ImportType, 591 import_type: ImportType,
587 depth: usize, 592 depth: usize,
588 ) { 593 ) {
589 if depth > 100 { 594 if depth > GLOB_RECURSION_LIMIT {
590 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
591 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
592 } 597 }
593 let scope = &mut self.def_map.modules[module_id].scope;
594 let mut changed = false; 598 let mut changed = false;
599
595 for (name, res) in resolutions { 600 for (name, res) in resolutions {
596 changed |= scope.push_res_with_import( 601 match name {
597 &mut self.from_glob_import, 602 Some(name) => {
598 (module_id, name.clone()), 603 let scope = &mut self.def_map.modules[module_id].scope;
599 res.with_visibility(vis), 604 changed |= scope.push_res_with_import(
600 import_type, 605 &mut self.from_glob_import,
601 ); 606 (module_id, name.clone()),
607 res.with_visibility(vis),
608 import_type,
609 );
610 }
611 None => {
612 let tr = match res.take_types() {
613 Some(ModuleDefId::TraitId(tr)) => tr,
614 Some(other) => {
615 log::debug!("non-trait `_` import of {:?}", other);
616 continue;
617 }
618 None => continue,
619 };
620 let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621 let should_update = match old_vis {
622 None => true,
623 Some(old_vis) => {
624 let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625 panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626 });
627
628 if max_vis == old_vis {
629 false
630 } else {
631 mark::hit!(upgrade_underscore_visibility);
632 true
633 }
634 }
635 };
636
637 if should_update {
638 changed = true;
639 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640 }
641 }
642 }
602 } 643 }
603 644
604 if !changed { 645 if !changed {
@@ -609,14 +650,15 @@ impl DefCollector<'_> {
609 .get(&module_id) 650 .get(&module_id)
610 .into_iter() 651 .into_iter()
611 .flat_map(|v| v.iter()) 652 .flat_map(|v| v.iter())
653 .filter(|(glob_importing_module, _)| {
654 // we know all resolutions have the same visibility (`vis`), so we
655 // just need to check that once
656 vis.is_visible_from_def_map(&self.def_map, *glob_importing_module)
657 })
612 .cloned() 658 .cloned()
613 .collect::<Vec<_>>(); 659 .collect::<Vec<_>>();
660
614 for (glob_importing_module, glob_import_vis) in glob_imports { 661 for (glob_importing_module, glob_import_vis) in glob_imports {
615 // we know all resolutions have the same visibility (`vis`), so we
616 // just need to check that once
617 if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) {
618 continue;
619 }
620 self.update_recursive( 662 self.update_recursive(
621 glob_importing_module, 663 glob_importing_module,
622 resolutions, 664 resolutions,
@@ -677,10 +719,6 @@ impl DefCollector<'_> {
677 self.unexpanded_attribute_macros = attribute_macros; 719 self.unexpanded_attribute_macros = attribute_macros;
678 720
679 for (module_id, macro_call_id, depth) in resolved { 721 for (module_id, macro_call_id, depth) in resolved {
680 if depth > 1024 {
681 log::debug!("Max macro expansion depth reached");
682 continue;
683 }
684 self.collect_macro_expansion(module_id, macro_call_id, depth); 722 self.collect_macro_expansion(module_id, macro_call_id, depth);
685 } 723 }
686 724
@@ -717,6 +755,11 @@ impl DefCollector<'_> {
717 macro_call_id: MacroCallId, 755 macro_call_id: MacroCallId,
718 depth: usize, 756 depth: usize,
719 ) { 757 ) {
758 if depth > EXPANSION_DEPTH_LIMIT {
759 mark::hit!(macro_expansion_overflow);
760 log::warn!("macro expansion is too deep");
761 return;
762 }
720 let file_id: HirFileId = macro_call_id.as_file(); 763 let file_id: HirFileId = macro_call_id.as_file();
721 let item_tree = self.db.item_tree(file_id); 764 let item_tree = self.db.item_tree(file_id);
722 let mod_dir = self.mod_dirs[&module_id].clone(); 765 let mod_dir = self.mod_dirs[&module_id].clone();
@@ -943,7 +986,7 @@ impl ModCollector<'_, '_> {
943 .unwrap_or(Visibility::Public); 986 .unwrap_or(Visibility::Public);
944 self.def_collector.update( 987 self.def_collector.update(
945 self.module_id, 988 self.module_id,
946 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], 989 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
947 vis, 990 vis,
948 ImportType::Named, 991 ImportType::Named,
949 ) 992 )
@@ -1050,14 +1093,14 @@ impl ModCollector<'_, '_> {
1050 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1093 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1051 self.def_collector.update( 1094 self.def_collector.update(
1052 self.module_id, 1095 self.module_id,
1053 &[(name, PerNs::from_def(def, vis, false))], 1096 &[(Some(name), PerNs::from_def(def, vis, false))],
1054 vis, 1097 vis,
1055 ImportType::Named, 1098 ImportType::Named,
1056 ); 1099 );
1057 res 1100 res
1058 } 1101 }
1059 1102
1060 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) { 1103 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1061 for derive_subtree in attrs.by_key("derive").tt_values() { 1104 for derive_subtree in attrs.by_key("derive").tt_values() {
1062 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1105 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
1063 for tt in &derive_subtree.token_trees { 1106 for tt in &derive_subtree.token_trees {
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index 39e9a6d97..953961632 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -1,23 +1,24 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use hir_expand::name::Name; 2use hir_expand::name::Name;
3use ra_db::{FileId, RelativePathBuf}; 3use ra_db::FileId;
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5 5
6use crate::{db::DefDatabase, HirFileId}; 6use crate::{db::DefDatabase, HirFileId};
7 7
8#[derive(Clone, Debug)] 8#[derive(Clone, Debug)]
9pub(super) struct ModDir { 9pub(super) struct ModDir {
10 /// `.` for `mod.rs`, `lib.rs` 10 /// `` for `mod.rs`, `lib.rs`
11 /// `./foo` for `foo.rs` 11 /// `foo/` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` 12 /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs`
13 path: RelativePathBuf, 13 /// Invariant: path.is_empty() || path.ends_with('/')
14 dir_path: DirPath,
14 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` 15 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
15 root_non_dir_owner: bool, 16 root_non_dir_owner: bool,
16} 17}
17 18
18impl ModDir { 19impl ModDir {
19 pub(super) fn root() -> ModDir { 20 pub(super) fn root() -> ModDir {
20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } 21 ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false }
21 } 22 }
22 23
23 pub(super) fn descend_into_definition( 24 pub(super) fn descend_into_definition(
@@ -25,17 +26,21 @@ impl ModDir {
25 name: &Name, 26 name: &Name,
26 attr_path: Option<&SmolStr>, 27 attr_path: Option<&SmolStr>,
27 ) -> ModDir { 28 ) -> ModDir {
28 let mut path = self.path.clone(); 29 let path = match attr_path.map(|it| it.as_str()) {
29 match attr_to_path(attr_path) { 30 None => {
30 None => path.push(&name.to_string()), 31 let mut path = self.dir_path.clone();
32 path.push(&name.to_string());
33 path
34 }
31 Some(attr_path) => { 35 Some(attr_path) => {
32 if self.root_non_dir_owner { 36 let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner);
33 assert!(path.pop()); 37 if !(path.is_empty() || path.ends_with('/')) {
38 path.push('/')
34 } 39 }
35 path.push(attr_path); 40 DirPath::new(path)
36 } 41 }
37 } 42 };
38 ModDir { path, root_non_dir_owner: false } 43 ModDir { dir_path: path, root_non_dir_owner: false }
39 } 44 }
40 45
41 pub(super) fn resolve_declaration( 46 pub(super) fn resolve_declaration(
@@ -48,34 +53,87 @@ impl ModDir {
48 let file_id = file_id.original_file(db.upcast()); 53 let file_id = file_id.original_file(db.upcast());
49 54
50 let mut candidate_files = Vec::new(); 55 let mut candidate_files = Vec::new();
51 match attr_to_path(attr_path) { 56 match attr_path {
52 Some(attr_path) => { 57 Some(attr_path) => {
53 let base = 58 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
54 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path };
55 candidate_files.push(base.join(attr_path).to_string())
56 } 59 }
57 None => { 60 None => {
58 candidate_files.push(self.path.join(&format!("{}.rs", name)).to_string()); 61 candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
59 candidate_files.push(self.path.join(&format!("{}/mod.rs", name)).to_string()); 62 candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
60 } 63 }
61 }; 64 };
62 65
63 for candidate in candidate_files.iter() { 66 for candidate in candidate_files.it