aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/attr.rs175
-rw-r--r--crates/hir_def/src/body.rs6
-rw-r--r--crates/hir_def/src/body/lower.rs28
-rw-r--r--crates/hir_def/src/find_path.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs5
-rw-r--r--crates/hir_def/src/item_tree/lower.rs37
-rw-r--r--crates/hir_def/src/lib.rs18
-rw-r--r--crates/hir_def/src/nameres.rs3
-rw-r--r--crates/hir_def/src/nameres/collector.rs22
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs58
-rw-r--r--crates/hir_def/src/path.rs9
-rw-r--r--crates/hir_def/src/path/lower.rs4
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs23
-rw-r--r--crates/hir_def/src/visibility.rs8
14 files changed, 269 insertions, 129 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index d9294d93a..aadd4e44a 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -9,7 +9,7 @@ use std::{
9use base_db::CrateId; 9use base_db::CrateId;
10use cfg::{CfgExpr, CfgOptions}; 10use cfg::{CfgExpr, CfgOptions};
11use either::Either; 11use either::Either;
12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile}; 12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
13use itertools::Itertools; 13use itertools::Itertools;
14use la_arena::ArenaMap; 14use la_arena::ArenaMap;
15use mbe::ast_to_token_tree; 15use mbe::ast_to_token_tree;
@@ -95,19 +95,19 @@ impl ops::Deref for AttrsWithOwner {
95impl RawAttrs { 95impl RawAttrs {
96 pub(crate) const EMPTY: Self = Self { entries: None }; 96 pub(crate) const EMPTY: Self = Self { entries: None };
97 97
98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { 98 pub(crate) fn new(
99 db: &dyn DefDatabase,
100 owner: &dyn ast::AttrsOwner,
101 hygiene: &Hygiene,
102 ) -> Self {
99 let entries = collect_attrs(owner) 103 let entries = collect_attrs(owner)
100 .enumerate() 104 .flat_map(|(id, attr)| match attr {
101 .flat_map(|(i, attr)| { 105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id),
102 let index = AttrId(i as u32); 106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
103 match attr { 107 id,
104 Either::Left(attr) => Attr::from_src(attr, hygiene, index), 108 input: Some(AttrInput::Literal(SmolStr::new(doc))),
105 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 109 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
106 id: index, 110 }),
107 input: Some(AttrInput::Literal(SmolStr::new(doc))),
108 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109 }),
110 }
111 }) 111 })
112 .collect::<Arc<_>>(); 112 .collect::<Arc<_>>();
113 113
@@ -116,10 +116,11 @@ impl RawAttrs {
116 116
117 fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { 117 fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self {
118 let hygiene = Hygiene::new(db.upcast(), owner.file_id); 118 let hygiene = Hygiene::new(db.upcast(), owner.file_id);
119 Self::new(owner.value, &hygiene) 119 Self::new(db, owner.value, &hygiene)
120 } 120 }
121 121
122 pub(crate) fn merge(&self, other: Self) -> Self { 122 pub(crate) fn merge(&self, other: Self) -> Self {
123 // FIXME: This needs to fixup `AttrId`s
123 match (&self.entries, &other.entries) { 124 match (&self.entries, &other.entries) {
124 (None, None) => Self::EMPTY, 125 (None, None) => Self::EMPTY,
125 (Some(entries), None) | (None, Some(entries)) => { 126 (Some(entries), None) | (None, Some(entries)) => {
@@ -170,7 +171,7 @@ impl RawAttrs {
170 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; 171 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
171 // FIXME hygiene 172 // FIXME hygiene
172 let hygiene = Hygiene::new_unhygienic(); 173 let hygiene = Hygiene::new_unhygienic();
173 Attr::from_src(attr, &hygiene, index) 174 Attr::from_src(db, attr, &hygiene, index)
174 }); 175 });
175 176
176 let cfg_options = &crate_graph[krate].cfg_options; 177 let cfg_options = &crate_graph[krate].cfg_options;
@@ -371,39 +372,26 @@ impl AttrsWithOwner {
371 372
372 let def_map = module.def_map(db); 373 let def_map = module.def_map(db);
373 let mod_data = &def_map[module.local_id]; 374 let mod_data = &def_map[module.local_id];
374 let attrs = match mod_data.declaration_source(db) { 375 match mod_data.declaration_source(db) {
375 Some(it) => { 376 Some(it) => {
376 let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner) 377 let mut map = AttrSourceMap::new(InFile::new(it.file_id, &it.value));
377 .map(|attr| InFile::new(it.file_id, attr))
378 .collect();
379 if let InFile { file_id, value: ModuleSource::SourceFile(file) } = 378 if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
380 mod_data.definition_source(db) 379 mod_data.definition_source(db)
381 { 380 {
382 attrs.extend( 381 map.merge(AttrSourceMap::new(InFile::new(file_id, &file)));
383 collect_attrs(&file as &dyn ast::AttrsOwner)
384 .map(|attr| InFile::new(file_id, attr)),
385 )
386 } 382 }
387 attrs 383 return map;
388 } 384 }
389 None => { 385 None => {
390 let InFile { file_id, value } = mod_data.definition_source(db); 386 let InFile { file_id, value } = mod_data.definition_source(db);
391 match &value { 387 let attrs_owner = match &value {
392 ModuleSource::SourceFile(file) => { 388 ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
393 collect_attrs(file as &dyn ast::AttrsOwner) 389 ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
394 } 390 ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
395 ModuleSource::Module(module) => { 391 };
396 collect_attrs(module as &dyn ast::AttrsOwner) 392 return AttrSourceMap::new(InFile::new(file_id, attrs_owner));
397 }
398 ModuleSource::BlockExpr(block) => {
399 collect_attrs(block as &dyn ast::AttrsOwner)
400 }
401 }
402 .map(|attr| InFile::new(file_id, attr))
403 .collect()
404 } 393 }
405 }; 394 }
406 return AttrSourceMap { attrs };
407 } 395 }
408 AttrDefId::FieldId(id) => { 396 AttrDefId::FieldId(id) => {
409 let map = db.fields_attrs_source_map(id.parent); 397 let map = db.fields_attrs_source_map(id.parent);
@@ -458,11 +446,7 @@ impl AttrsWithOwner {
458 }, 446 },
459 }; 447 };
460 448
461 AttrSourceMap { 449 AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn AttrsOwner))
462 attrs: collect_attrs(&owner.value)
463 .map(|attr| InFile::new(owner.file_id, attr))
464 .collect(),
465 }
466 } 450 }
467 451
468 pub fn docs_with_rangemap( 452 pub fn docs_with_rangemap(
@@ -484,10 +468,10 @@ impl AttrsWithOwner {
484 let mut buf = String::new(); 468 let mut buf = String::new();
485 let mut mapping = Vec::new(); 469 let mut mapping = Vec::new();
486 for (doc, idx) in docs { 470 for (doc, idx) in docs {
487 // str::lines doesn't yield anything for the empty string
488 if !doc.is_empty() { 471 if !doc.is_empty() {
489 for line in doc.split('\n') { 472 let mut base_offset = 0;
490 let line = line.trim_end(); 473 for raw_line in doc.split('\n') {
474 let line = raw_line.trim_end();
491 let line_len = line.len(); 475 let line_len = line.len();
492 let (offset, line) = match line.char_indices().nth(indent) { 476 let (offset, line) = match line.char_indices().nth(indent) {
493 Some((offset, _)) => (offset, &line[offset..]), 477 Some((offset, _)) => (offset, &line[offset..]),
@@ -498,9 +482,13 @@ impl AttrsWithOwner {
498 mapping.push(( 482 mapping.push((
499 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?), 483 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
500 idx, 484 idx,
501 TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?), 485 TextRange::at(
486 (base_offset + offset).try_into().ok()?,
487 line_len.try_into().ok()?,
488 ),
502 )); 489 ));
503 buf.push('\n'); 490 buf.push('\n');
491 base_offset += raw_line.len() + 1;
504 } 492 }
505 } else { 493 } else {
506 buf.push('\n'); 494 buf.push('\n');
@@ -510,7 +498,7 @@ impl AttrsWithOwner {
510 if buf.is_empty() { 498 if buf.is_empty() {
511 None 499 None
512 } else { 500 } else {
513 Some((Documentation(buf), DocsRangeMap { mapping, source: self.source_map(db).attrs })) 501 Some((Documentation(buf), DocsRangeMap { mapping, source_map: self.source_map(db) }))
514 } 502 }
515 } 503 }
516} 504}
@@ -551,27 +539,59 @@ fn inner_attributes(
551} 539}
552 540
553pub struct AttrSourceMap { 541pub struct AttrSourceMap {
554 attrs: Vec<InFile<Either<ast::Attr, ast::Comment>>>, 542 attrs: Vec<InFile<ast::Attr>>,
543 doc_comments: Vec<InFile<ast::Comment>>,
555} 544}
556 545
557impl AttrSourceMap { 546impl AttrSourceMap {
547 fn new(owner: InFile<&dyn ast::AttrsOwner>) -> Self {
548 let mut attrs = Vec::new();
549 let mut doc_comments = Vec::new();
550 for (_, attr) in collect_attrs(owner.value) {
551 match attr {
552 Either::Left(attr) => attrs.push(owner.with_value(attr)),
553 Either::Right(comment) => doc_comments.push(owner.with_value(comment)),
554 }
555 }
556
557 Self { attrs, doc_comments }
558 }
559
560 fn merge(&mut self, other: Self) {
561 self.attrs.extend(other.attrs);
562 self.doc_comments.extend(other.doc_comments);
563 }
564
558 /// Maps the lowered `Attr` back to its original syntax node. 565 /// Maps the lowered `Attr` back to its original syntax node.
559 /// 566 ///
560 /// `attr` must come from the `owner` used for AttrSourceMap 567 /// `attr` must come from the `owner` used for AttrSourceMap
561 /// 568 ///
562 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of 569 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
563 /// the attribute represented by `Attr`. 570 /// the attribute represented by `Attr`.
564 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> { 571 pub fn source_of(&self, attr: &Attr) -> InFile<Either<ast::Attr, ast::Comment>> {
565 self.attrs 572 self.source_of_id(attr.id)
566 .get(attr.id.0 as usize) 573 }
567 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id)) 574
568 .as_ref() 575 fn source_of_id(&self, id: AttrId) -> InFile<Either<ast::Attr, ast::Comment>> {
576 if id.is_doc_comment {
577 self.doc_comments
578 .get(id.ast_index as usize)
579 .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id))
580 .clone()
581 .map(|attr| Either::Right(attr))
582 } else {
583 self.attrs
584 .get(id.ast_index as usize)
585 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id))
586 .clone()
587 .map(|attr| Either::Left(attr))
588 }
569 } 589 }
570} 590}
571 591
572/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree. 592/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
573pub struct DocsRangeMap { 593pub struct DocsRangeMap {
574 source: Vec<InFile<Either<ast::Attr, ast::Comment>>>, 594 source_map: AttrSourceMap,
575 // (docstring-line-range, attr_index, attr-string-range) 595 // (docstring-line-range, attr_index, attr-string-range)
576 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and 596 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
577 // the original (untrimmed) syntax doc line 597 // the original (untrimmed) syntax doc line
@@ -588,7 +608,7 @@ impl DocsRangeMap {
588 608
589 let relative_range = range - line_docs_range.start(); 609 let relative_range = range - line_docs_range.start();
590 610
591 let &InFile { file_id, value: ref source } = &self.source[idx.0 as usize]; 611 let &InFile { file_id, value: ref source } = &self.source_map.source_of_id(idx);
592 match source { 612 match source {
593 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here 613 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
594 // as well as for whats done in syntax highlight doc injection 614 // as well as for whats done in syntax highlight doc injection
@@ -607,6 +627,12 @@ impl DocsRangeMap {
607 } 627 }
608} 628}
609 629
630#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
631pub(crate) struct AttrId {
632 is_doc_comment: bool,
633 pub(crate) ast_index: u32,
634}
635
610#[derive(Debug, Clone, PartialEq, Eq)] 636#[derive(Debug, Clone, PartialEq, Eq)]
611pub struct Attr { 637pub struct Attr {
612 pub(crate) id: AttrId, 638 pub(crate) id: AttrId,
@@ -623,8 +649,13 @@ pub enum AttrInput {
623} 649}
624 650
625impl Attr { 651impl Attr {
626 fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> { 652 fn from_src(
627 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); 653 db: &dyn DefDatabase,
654 ast: ast::Attr,
655 hygiene: &Hygiene,
656 id: AttrId,
657 ) -> Option<Attr> {
658 let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?);
628 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 659 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
629 let value = match lit.kind() { 660 let value = match lit.kind() {
630 ast::LiteralKind::String(string) => string.value()?.into(), 661 ast::LiteralKind::String(string) => string.value()?.into(),
@@ -736,22 +767,32 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
736 767
737fn collect_attrs( 768fn collect_attrs(
738 owner: &dyn ast::AttrsOwner, 769 owner: &dyn ast::AttrsOwner,
739) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { 770) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
740 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 771 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
741 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); 772 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
742 773
743 let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer()); 774 let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer());
744 let attrs = outer_attrs 775 let attrs =
745 .chain(inner_attrs.into_iter().flatten()) 776 outer_attrs.chain(inner_attrs.into_iter().flatten()).enumerate().map(|(idx, attr)| {
746 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); 777 (
778 AttrId { ast_index: idx as u32, is_doc_comment: false },
779 attr.syntax().text_range().start(),
780 Either::Left(attr),
781 )
782 });
747 783
748 let outer_docs = 784 let outer_docs =
749 ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer); 785 ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer);
750 let docs = outer_docs 786 let docs =
751 .chain(inner_docs.into_iter().flatten()) 787 outer_docs.chain(inner_docs.into_iter().flatten()).enumerate().map(|(idx, docs_text)| {
752 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); 788 (
789 AttrId { ast_index: idx as u32, is_doc_comment: true },
790 docs_text.syntax().text_range().start(),
791 Either::Right(docs_text),
792 )
793 });
753 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved 794 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
754 docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).map(|(_, attr)| attr) 795 docs.chain(attrs).sorted_by_key(|&(_, offset, _)| offset).map(|(id, _, attr)| (id, attr))
755} 796}
756 797
757pub(crate) fn variants_attrs_source_map( 798pub(crate) fn variants_attrs_source_map(
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 131f424cc..8360426f1 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -72,7 +72,7 @@ impl CfgExpander {
72 } 72 }
73 73
74 pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { 74 pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
75 RawAttrs::new(owner, &self.hygiene).filter(db, self.krate) 75 RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
76 } 76 }
77 77
78 pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { 78 pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool {
@@ -192,8 +192,8 @@ impl Expander {
192 self.current_file_id 192 self.current_file_id
193 } 193 }
194 194
195 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 195 fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
196 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); 196 let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
197 Path::from_src(path, &ctx) 197 Path::from_src(path, &ctx)
198 } 198 }
199 199
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 820d5c17e..9f278d35b 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -40,23 +40,25 @@ use crate::{
40 40
41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
42 42
43pub struct LowerCtx { 43pub struct LowerCtx<'a> {
44 pub db: &'a dyn DefDatabase,
44 hygiene: Hygiene, 45 hygiene: Hygiene,
45 file_id: Option<HirFileId>, 46 file_id: Option<HirFileId>,
46 source_ast_id_map: Option<Arc<AstIdMap>>, 47 source_ast_id_map: Option<Arc<AstIdMap>>,
47} 48}
48 49
49impl LowerCtx { 50impl<'a> LowerCtx<'a> {
50 pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { 51 pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
51 LowerCtx { 52 LowerCtx {
53 db,
52 hygiene: Hygiene::new(db.upcast(), file_id), 54 hygiene: Hygiene::new(db.upcast(), file_id),
53 file_id: Some(file_id), 55 file_id: Some(file_id),
54 source_ast_id_map: Some(db.ast_id_map(file_id)), 56 source_ast_id_map: Some(db.ast_id_map(file_id)),
55 } 57 }
56 } 58 }
57 59
58 pub fn with_hygiene(hygiene: &Hygiene) -> Self { 60 pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
59 LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } 61 LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60 } 62 }
61 63
62 pub(crate) fn hygiene(&self) -> &Hygiene { 64 pub(crate) fn hygiene(&self) -> &Hygiene {
@@ -145,7 +147,7 @@ impl ExprCollector<'_> {
145 (self.body, self.source_map) 147 (self.body, self.source_map)
146 } 148 }
147 149
148 fn ctx(&self) -> LowerCtx { 150 fn ctx(&self) -> LowerCtx<'_> {
149 LowerCtx::new(self.db, self.expander.current_file_id) 151 LowerCtx::new(self.db, self.expander.current_file_id)
150 } 152 }
151 153
@@ -376,7 +378,7 @@ impl ExprCollector<'_> {
376 ast::Expr::PathExpr(e) => { 378 ast::Expr::PathExpr(e) => {
377 let path = e 379 let path = e
378 .path() 380 .path()
379 .and_then(|path| self.expander.parse_path(path)) 381 .and_then(|path| self.expander.parse_path(self.db, path))
380 .map(Expr::Path) 382 .map(Expr::Path)
381 .unwrap_or(Expr::Missing); 383 .unwrap_or(Expr::Missing);
382 self.alloc_expr(path, syntax_ptr) 384 self.alloc_expr(path, syntax_ptr)
@@ -408,7 +410,8 @@ impl ExprCollector<'_> {
408 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 410 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
409 } 411 }
410 ast::Expr::RecordExpr(e) => { 412 ast::Expr::RecordExpr(e) => {
411 let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); 413 let path =
414 e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
412 let record_lit = if let Some(nfl) = e.record_expr_field_list() { 415 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
413 let fields = nfl 416 let fields = nfl
414 .fields() 417 .fields()
@@ -801,7 +804,8 @@ impl ExprCollector<'_> {
801 } 804 }
802 } 805 }
803 ast::Pat::TupleStructPat(p) => { 806 ast::Pat::TupleStructPat(p) => {
804 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); 807 let path =
808 p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
805 let (args, ellipsis) = self.collect_tuple_pat(p.fields()); 809 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
806 Pat::TupleStruct { path, args, ellipsis } 810 Pat::TupleStruct { path, args, ellipsis }
807 } 811 }
@@ -811,7 +815,8 @@ impl ExprCollector<'_> {
811 Pat::Ref { pat, mutability } 815 Pat::Ref { pat, mutability }
812 } 816 }
813 ast::Pat::PathPat(p) => { 817 ast::Pat::PathPat(p) => {
814 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); 818 let path =
819 p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
815 path.map(Pat::Path).unwrap_or(Pat::Missing) 820 path.map(Pat::Path).unwrap_or(Pat::Missing)
816 } 821 }
817 ast::Pat::OrPat(p) => { 822 ast::Pat::OrPat(p) => {
@@ -825,7 +830,8 @@ impl ExprCollector<'_> {
825 } 830 }
826 ast::Pat::WildcardPat(_) => Pat::Wild, 831 ast::Pat::WildcardPat(_) => Pat::Wild,
827 ast::Pat::RecordPat(p) => { 832 ast::Pat::RecordPat(p) => {
828 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); 833 let path =
834 p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
829 let args: Vec<_> = p 835 let args: Vec<_> = p
830 .record_pat_field_list() 836 .record_pat_field_list()
831 .expect("every struct should have a field list") 837 .expect("every struct should have a field list")
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index c06a37294..858e88038 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -386,7 +386,7 @@ mod tests {
386 let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); 386 let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
387 let ast_path = 387 let ast_path =
388 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); 388 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
389 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); 389 let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap();
390 390
391 let def_map = module.def_map(&db); 391 let def_map = module.def_map(&db);
392 let resolved = def_map 392 let resolved = def_map
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index eaeca01bd..cad8a7479 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -18,7 +18,7 @@ use hir_expand::{
18 ast_id_map::FileAstId, 18 ast_id_map::FileAstId,
19 hygiene::Hygiene, 19 hygiene::Hygiene,
20 name::{name, AsName, Name}, 20 name::{name, AsName, Name},
21 HirFileId, InFile, 21 FragmentKind, HirFileId, InFile,
22}; 22};
23use la_arena::{Arena, Idx, RawIdx}; 23use la_arena::{Arena, Idx, RawIdx};
24use profile::Count; 24use profile::Count;
@@ -88,7 +88,7 @@ impl ItemTree {
88 let mut item_tree = match_ast! { 88 let mut item_tree = match_ast! {
89 match syntax { 89 match syntax {
90 ast::SourceFile(file) => { 90 ast::SourceFile(file) => {
91 top_attrs = Some(RawAttrs::new(&file, &hygiene)); 91 top_attrs = Some(RawAttrs::new(db, &file, &hygiene));
92 ctx.lower_module_items(&file) 92 ctx.lower_module_items(&file)
93 }, 93 },
94 ast::MacroItems(items) => { 94 ast::MacroItems(items) => {
@@ -656,6 +656,7 @@ pub struct MacroCall {
656 /// Path to the called macro. 656 /// Path to the called macro.
657 pub path: Interned<ModPath>, 657 pub path: Interned<ModPath>,
658 pub ast_id: FileAstId<ast::MacroCall>, 658 pub ast_id: FileAstId<ast::MacroCall>,
659 pub fragment: FragmentKind,
659} 660}
660 661
661#[derive(Debug, Clone, Eq, PartialEq)] 662#[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 45b099cf3..fe348091d 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -31,18 +31,20 @@ where
31 } 31 }
32} 32}
33 33
34pub(super) struct Ctx { 34pub(super) struct Ctx<'a> {
35 db: &'a dyn DefDatabase,
35 tree: ItemTree, 36 tree: ItemTree,
36 hygiene: Hygiene, 37 hygiene: Hygiene,
37 file: HirFileId, 38 file: HirFileId,
38 source_ast_id_map: Arc<AstIdMap>, 39 source_ast_id_map: Arc<AstIdMap>,
39 body_ctx: crate::body::LowerCtx, 40 body_ctx: crate::body::LowerCtx<'a>,
40 forced_visibility: Option<RawVisibilityId>, 41 forced_visibility: Option<RawVisibilityId>,
41} 42}
42 43
43impl Ctx { 44impl<'a> Ctx<'a> {
44 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { 45 pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
45 Self { 46 Self {
47 db,
46 tree: ItemTree::default(), 48 tree: ItemTree::default(),
47 hygiene, 49 hygiene,
48 file, 50 file,
@@ -126,7 +128,7 @@ impl Ctx {
126 | ast::Item::MacroDef(_) => {} 128 | ast::Item::MacroDef(_) => {}
127 }; 129 };
128 130
129 let attrs = RawAttrs::new(item, &self.hygiene); 131 let attrs = RawAttrs::new(self.db, item, &self.hygiene);
130 let items = match item { 132 let items = match item {
131 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), 133 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
132 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), 134 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
@@ -256,7 +258,7 @@ impl Ctx {
256 for field in fields.fields() { 258 for field in fields.fields() {
257 if let Some(data) = self.lower_record_field(&field) { 259 if let Some(data) = self.lower_record_field(&field) {
258 let idx = self.data().fields.alloc(data); 260 let idx = self.data().fields.alloc(data);
259 self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); 261 self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene));
260 } 262 }
261 } 263 }
262 let end = self.next_field_idx(); 264 let end = self.next_field_idx();
@@ -276,7 +278,7 @@ impl Ctx {
276 for (i, field) in fields.fields().enumerate() { 278 for (i, field) in fields.fields().enumerate() {
277 let data = self.lower_tuple_field(i, &field); 279 let data = self.lower_tuple_field(i, &field);
278 let idx = self.data().fields.alloc(data); 280 let idx = self.data().fields.alloc(data);
279 self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); 281 self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene));
280 } 282 }
281 let end = self.next_field_idx(); 283 let end = self.next_field_idx();
282 IdRange::new(start..end) 284 IdRange::new(start..end)
@@ -321,7 +323,7 @@ impl Ctx {
321 for variant in variants.variants() { 323 for variant in variants.variants() {
322 if let Some(data) = self.lower_variant(&variant) { 324 if let Some(data) = self.lower_variant(&variant) {
323 let idx = self.data().variants.alloc(data); 325 let idx = self.data().variants.alloc(data);
324 self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene)); 326 self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, &self.hygiene));
325 } 327 }
326 } 328 }
327 let end = self.next_variant_idx(); 329 let end = self.next_variant_idx();
@@ -364,7 +366,7 @@ impl Ctx {
364 }; 366 };
365 let ty = Interned::new(self_type); 367 let ty = Interned::new(self_type);
366 let idx = self.data().params.alloc(Param::Normal(ty)); 368 let idx = self.data().params.alloc(Param::Normal(ty));
367 self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); 369 self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, &self.hygiene));
368 has_self_param = true; 370 has_self_param = true;
369 } 371 }
370 for param in param_list.params() { 372 for param in param_list.params() {
@@ -376,7 +378,7 @@ impl Ctx {
376 self.data().params.alloc(Param::Normal(ty)) 378 self.data().params.alloc(Param::Normal(ty))
377 } 379 }
378 }; 380 };
379 self.add_attrs(idx.into(), RawAttrs::new(&param, &self.hygiene)); 381 self.add_attrs(idx.into(), RawAttrs::new(self.db, &param, &self.hygiene));
380 } 382 }
381 } 383 }
382 let end_param = self.next_param_idx(); 384 let end_param = self.next_param_idx();
@@ -522,10 +524,11 @@ impl Ctx {
522 let is_unsafe = trait_def.unsafe_token().is_some(); 524 let is_unsafe = trait_def.unsafe_token().is_some();
523 let bounds = self.lower_type_bounds(trait_def); 525 let bounds = self.lower_type_bounds(trait_def);
524 let items = trait_def.assoc_item_list().map(|list| { 526 let items = trait_def.assoc_item_list().map(|list| {
527 let db = self.db;
525 self.with_inherited_visibility(visibility, |this| { 528 self.with_inherited_visibility(visibility, |this| {
526 list.assoc_items() 529 list.assoc_items()
527 .filter_map(|item| { 530 .filter_map(|item| {
528 let attrs = RawAttrs::new(&item, &this.hygiene); 531 let attrs = RawAttrs::new(db, &item, &this.hygiene);
529 this.collect_inner_items(item.syntax()); 532 this.collect_inner_items(item.syntax());
530 this.lower_assoc_item(&item).map(|item| { 533 this.lower_assoc_item(&item).map(|item| {
531 this.add_attrs(ModItem::from(item).into(), attrs); 534 this.add_attrs(ModItem::from(item).into(), attrs);
@@ -567,7 +570,7 @@ impl Ctx {
567 .filter_map(|item| { 570 .filter_map(|item| {
568 self.collect_inner_items(item.syntax()); 571 self.collect_inner_items(item.syntax());
569 let assoc = self.lower_assoc_item(&item)?; 572 let assoc = self.lower_assoc_item(&item)?;
570 let attrs = RawAttrs::new(&item, &self.hygiene); 573 let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
571 self.add_attrs(ModItem::from(assoc).into(), attrs); 574 self.add_attrs(ModItem::from(assoc).into(), attrs);
572 Some(assoc) 575 Some(assoc)
573 }) 576 })
@@ -585,6 +588,7 @@ impl Ctx {
585 let mut imports = Vec::new(); 588 let mut imports = Vec::new();
586 let tree = self.tree.data_mut(); 589 let tree = self.tree.data_mut();
587 ModPath::expand_use_item( 590 ModPath::expand_use_item(
591 self.db,
588 InFile::new(self.file, use_item.clone()), 592 InFile::new(self.file, use_item.clone()),
589 &self.hygiene, 593 &self.hygiene,
590 |path, _use_tree, is_glob, alias| { 594 |path, _use_tree, is_glob, alias| {
@@ -618,9 +622,10 @@ impl Ctx {
618 } 622 }
619 623
620 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { 624 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
621 let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); 625 let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?);
622 let ast_id = self.source_ast_id_map.ast_id(m); 626 let ast_id = self.source_ast_id_map.ast_id(m);
623 let res = MacroCall { path, ast_id }; 627 let fragment = hir_expand::to_fragment_kind(m);
628 let res = MacroCall { path, ast_id, fragment };
624 Some(id(self.data().macro_calls.alloc(res))) 629 Some(id(self.data().macro_calls.alloc(res)))
625 } 630 }
626 631
@@ -647,7 +652,7 @@ impl Ctx {
647 list.extern_items() 652 list.extern_items()
648 .filter_map(|item| { 653 .filter_map(|item| {
649 self.collect_inner_items(item.syntax()); 654 self.collect_inner_items(item.syntax());
650 let attrs = RawAttrs::new(&item, &self.hygiene); 655 let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
651 let id: ModItem = match item { 656 let id: ModItem = match item {
652 ast::ExternItem::Fn(ast) => { 657 ast::ExternItem::Fn(ast) => {
653 let func_id = self.lower_function(&ast)?; 658 let func_id = self.lower_function(&ast)?;
@@ -755,7 +760,7 @@ impl Ctx {
755 fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { 760 fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
756 let vis = match self.forced_visibility { 761 let vis = match self.forced_visibility {
757 Some(vis) => return vis, 762 Some(vis) => return vis,
758 None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), 763 None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene),
759 }; 764 };
760 765
761 self.data().vis.alloc(vis) 766 self.data().vis.alloc(vis)
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 25694f037..a82ea5957 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -62,13 +62,14 @@ use hir_expand::{
62 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, 63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
64 hygiene::Hygiene, 64 hygiene::Hygiene,
65 AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 65 AstId, FragmentKind, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
66}; 66};
67use la_arena::Idx; 67use la_arena::Idx;
68use nameres::DefMap; 68use nameres::DefMap;
69use path::ModPath; 69use path::ModPath;
70use syntax::ast; 70use syntax::ast;
71 71
72use crate::attr::AttrId;
72use crate::builtin_type::BuiltinType; 73use crate::builtin_type::BuiltinType;
73use item_tree::{ 74use item_tree::{
74 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, 75 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
@@ -652,9 +653,10 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
652 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 653 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
653 mut error_sink: &mut dyn FnMut(mbe::ExpandError), 654 mut error_sink: &mut dyn FnMut(mbe::ExpandError),
654 ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 655 ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
656 let fragment = hir_expand::to_fragment_kind(self.value);
655 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); 657 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
656 let h = Hygiene::new(db.upcast(), self.file_id); 658 let h = Hygiene::new(db.upcast(), self.file_id);
657 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h)); 659 let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
658 660
659 let path = match error_sink 661 let path = match error_sink
660 .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) 662 .option(path, || mbe::ExpandError::Other("malformed macro invocation".into()))
@@ -667,6 +669,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
667 669
668 macro_call_as_call_id( 670 macro_call_as_call_id(
669 &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), 671 &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
672 fragment,
670 db, 673 db,
671 krate, 674 krate,
672 resolver, 675 resolver,
@@ -695,6 +698,7 @@ pub struct UnresolvedMacro {
695 698
696fn macro_call_as_call_id( 699fn macro_call_as_call_id(
697 call: &AstIdWithPath<ast::MacroCall>, 700 call: &AstIdWithPath<ast::MacroCall>,
701 fragment: FragmentKind,
698 db: &dyn db::DefDatabase, 702 db: &dyn db::DefDatabase,
699 krate: CrateId, 703 krate: CrateId,
700 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 704 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
@@ -712,13 +716,17 @@ fn macro_call_as_call_id(
712 krate, 716 krate,
713 macro_call, 717 macro_call,
714 def, 718 def,
715 &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), 719 &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?),
716 error_sink, 720 error_sink,
717 ) 721 )
718 .map(MacroCallId::from) 722 .map(MacroCallId::from)
719 } else { 723 } else {
720 Ok(def 724 Ok(def
721 .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id }) 725 .as_lazy_macro(
726 db.upcast(),
727 krate,
728 MacroCallKind::FnLike { ast_id: call.ast_id, fragment },
729 )
722 .into()) 730 .into())
723 }; 731 };
724 Ok(res) 732 Ok(res)
@@ -745,7 +753,7 @@ fn derive_macro_as_call_id(
745 MacroCallKind::Derive { 753 MacroCallKind::Derive {
746 ast_id: item_attr.ast_id, 754 ast_id: item_attr.ast_id,
747 derive_name: last_segment.to_string(), 755 derive_name: last_segment.to_string(),
748 derive_attr, 756 derive_attr_index: derive_attr.ast_index,
749 }, 757 },
750 ) 758 )
751 .into(); 759 .into();
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index ba027c44a..249af6fc8 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -599,6 +599,7 @@ mod diagnostics {
599 let mut cur = 0; 599 let mut cur = 0;
600 let mut tree = None; 600 let mut tree = None;
601 ModPath::expand_use_item( 601 ModPath::expand_use_item(
602 db,
602 InFile::new(ast.file_id, use_item), 603 InFile::new(ast.file_id, use_item),
603 &hygiene, 604 &hygiene,
604 |_mod_path, use_tree, _is_glob, _alias| { 605 |_mod_path, use_tree, _is_glob, _alias| {
@@ -628,7 +629,7 @@ mod diagnostics {
628 DiagnosticKind::UnresolvedProcMacro { ast } => { 629 DiagnosticKind::UnresolvedProcMacro { ast } => {
629 let mut precise_location = None; 630 let mut precise_location = None;
630 let (file, ast, name) = match ast { 631 let (file, ast, name) = match ast {
631 MacroCallKind::FnLike { ast_id } => { 632 MacroCallKind::FnLike { ast_id, .. } => {
632 let node = ast_id.to_node(db.upcast()); 633 let node = ast_id.to_node(db.upcast());
633 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 634 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
634 } 635 }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 05ceb1efb..adfb78c94 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,14 +13,14 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
20use syntax::ast; 20use syntax::ast;
21 21
22use crate::{ 22use crate::{
23 attr::Attrs, 23 attr::{AttrId, Attrs},
24 db::DefDatabase, 24 db::DefDatabase,
25 derive_macro_as_call_id, 25 derive_macro_as_call_id,
26 intern::Interned, 26 intern::Interned,
@@ -215,7 +215,7 @@ struct MacroDirective {
215 215
216#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
217enum MacroDirectiveKind { 217enum MacroDirectiveKind {
218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind },
219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
220} 220}
221 221
@@ -807,9 +807,10 @@ impl DefCollector<'_> {
807 let mut res = ReachedFixedPoint::Yes; 807 let mut res = ReachedFixedPoint::Yes;
808 macros.retain(|directive| { 808 macros.retain(|directive| {
809 match &directive.kind { 809 match &directive.kind {
810 MacroDirectiveKind::FnLike { ast_id } => { 810 MacroDirectiveKind::FnLike { ast_id, fragment } => {
811 match macro_call_as_call_id( 811 match macro_call_as_call_id(
812 ast_id, 812 ast_id,
813 *fragment,
813 self.db, 814 self.db,
814 self.def_map.krate, 815 self.def_map.krate,
815 |path| { 816 |path| {
@@ -926,8 +927,9 @@ impl DefCollector<'_> {
926 927
927 for directive in &self.unexpanded_macros { 928 for directive in &self.unexpanded_macros {
928 match &directive.kind { 929 match &directive.kind {
929 MacroDirectiveKind::FnLike { ast_id, .. } => match macro_call_as_call_id( 930 MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id(
930 ast_id, 931 ast_id,
932 *fragment,
931 self.db, 933 self.db,
932 self.def_map.krate, 934 self.def_map.krate,
933 |path| { 935 |path| {
@@ -1496,6 +1498,7 @@ impl ModCollector<'_, '_> {
1496 let mut error = None; 1498 let mut error = None;
1497 match macro_call_as_call_id( 1499 match macro_call_as_call_id(
1498 &ast_id, 1500 &ast_id,
1501 mac.fragment,
1499 self.def_collector.db, 1502 self.def_collector.db,
1500 self.def_collector.def_map.krate, 1503 self.def_collector.def_map.krate,
1501 |path| { 1504 |path| {
@@ -1524,9 +1527,14 @@ impl ModCollector<'_, '_> {
1524 } 1527 }
1525 Ok(Err(_)) => { 1528 Ok(Err(_)) => {
1526 // Built-in macro failed eager expansion. 1529 // Built-in macro failed eager expansion.
1530
1531 // FIXME: don't parse the file here
1532 let fragment = hir_expand::to_fragment_kind(
1533 &ast_id.ast_id.to_node(self.def_collector.db.upcast()),
1534 );
1527 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1535 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1528 self.module_id, 1536 self.module_id,
1529 MacroCallKind::FnLike { ast_id: ast_id.ast_id }, 1537 MacroCallKind::FnLike { ast_id: ast_id.ast_id, fragment },
1530 error.unwrap().to_string(), 1538 error.unwrap().to_string(),
1531 )); 1539 ));
1532 return; 1540 return;
@@ -1543,7 +1551,7 @@ impl ModCollector<'_, '_> {
1543 self.def_collector.unexpanded_macros.push(MacroDirective { 1551 self.def_collector.unexpanded_macros.push(MacroDirective {
1544 module_id: self.module_id, 1552 module_id: self.module_id,
1545 depth: self.macro_depth + 1, 1553 depth: self.macro_depth + 1,
1546 kind: MacroDirectiveKind::FnLike { ast_id }, 1554 kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment },
1547 }); 1555 });
1548 } 1556 }
1549 1557
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs
index 509e1bbbc..d884a6eb4 100644
--- a/crates/hir_def/src/nameres/tests/incremental.rs
+++ b/crates/hir_def/src/nameres/tests/incremental.rs
@@ -105,3 +105,61 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
105 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 105 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
106 } 106 }
107} 107}
108
109#[test]
110fn typing_inside_a_function_should_not_invalidate_expansions() {
111 let (mut db, pos) = TestDB::with_position(
112 r#"
113//- /lib.rs
114macro_rules! m {
115 ($ident:ident) => {
116 fn $ident() { };
117 }
118}
119mod foo;
120
121//- /foo/mod.rs
122pub mod bar;
123
124//- /foo/bar.rs
125m!(X);
126fn quux() { 1$0 }
127m!(Y);
128m!(Z);
129"#,
130 );
131 let krate = db.test_crate();
132 {
133 let events = db.log_executed(|| {
134 let crate_def_map = db.crate_def_map(krate);
135 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
136 assert_eq!(module_data.scope.resolutions().count(), 4);
137 });
138 let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
139 assert_eq!(n_recalculated_item_trees, 6);
140 let n_reparsed_macros =
141 events.iter().filter(|it| it.contains("parse_macro_expansion")).count();
142 assert_eq!(n_reparsed_macros, 3);
143 }
144
145 let new_text = r#"
146m!(X);
147fn quux() { 92 }
148m!(Y);
149m!(Z);
150"#;
151 db.set_file_text(pos.file_id, Arc::new(new_text.to_string()));
152
153 {
154 let events = db.log_executed(|| {
155 let crate_def_map = db.crate_def_map(krate);
156 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
157 assert_eq!(module_data.scope.resolutions().count(), 4);
158 });
159 let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
160 assert_eq!(n_recalculated_item_trees, 1);
161 let n_reparsed_macros =
162 events.iter().filter(|it| it.contains("parse_macro_expansion")).count();
163 assert_eq!(n_reparsed_macros, 0);
164 }
165}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 509f77850..a43441b1c 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -7,7 +7,7 @@ use std::{
7 sync::Arc, 7 sync::Arc,
8}; 8};
9 9
10use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
@@ -47,8 +47,8 @@ pub enum ImportAlias {
47} 47}
48 48
49impl ModPath { 49impl ModPath {
50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 50 pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
51 let ctx = LowerCtx::with_hygiene(hygiene); 51 let ctx = LowerCtx::with_hygiene(db, hygiene);
52 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) 52 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
53 } 53 }
54 54
@@ -64,12 +64,13 @@ impl ModPath {
64 64
65 /// Calls `cb` with all paths, represented by this use item. 65 /// Calls `cb` with all paths, represented by this use item.
66 pub(crate) fn expand_use_item( 66 pub(crate) fn expand_use_item(
67 db: &dyn DefDatabase,
67 item_src: InFile<ast::Use>, 68 item_src: InFile<ast::Use>,
68 hygiene: &Hygiene, 69 hygiene: &Hygiene,
69 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), 70 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
70 ) { 71 ) {
71 if let Some(tree) = item_src.value.use_tree() { 72 if let Some(tree) = item_src.value.use_tree() {
72 lower::lower_use_tree(None, tree, hygiene, &mut cb); 73 lower::lower_use_tree(db, None, tree, hygiene, &mut cb);
73 } 74 }
74 } 75 }
75 76
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 1df6db525..a873325b2 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -36,7 +36,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
36 match segment.kind()? { 36 match segment.kind()? {
37 ast::PathSegmentKind::Name(name_ref) => { 37 ast::PathSegmentKind::Name(name_ref) => {
38 // FIXME: this should just return name 38 // FIXME: this should just return name
39 match hygiene.name_ref_to_name(name_ref) { 39 match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) {
40 Either::Left(name) => { 40 Either::Left(name) => {
41 let args = segment 41 let args = segment
42 .generic_arg_list() 42 .generic_arg_list()
@@ -133,7 +133,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
133 // We follow what it did anyway :) 133 // We follow what it did anyway :)
134 if segments.len() == 1 && kind == PathKind::Plain { 134 if segments.len() == 1 && kind == PathKind::Plain {
135 if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { 135 if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
136 if let Some(crate_id) = hygiene.local_inner_macros(path) { 136 if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) {
137 kind = PathKind::DollarCrate(crate_id); 137 kind = PathKind::DollarCrate(crate_id);
138 } 138 }
139 } 139 }
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index e2965b033..ee80e3df3 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -7,9 +7,13 @@ use either::Either;
7use hir_expand::{hygiene::Hygiene, name::AsName}; 7use hir_expand::{hygiene::Hygiene, name::AsName};
8use syntax::ast::{self, NameOwner}; 8use syntax::ast::{self, NameOwner};
9 9
10use crate::path::{ImportAlias, ModPath, PathKind}; 10use crate::{
11 db::DefDatabase,
12 path::{ImportAlias, ModPath, PathKind},
13};
11 14
12pub(crate) fn lower_use_tree( 15pub(crate) fn lower_use_tree(
16 db: &dyn DefDatabase,
13 prefix: Option<ModPath>, 17 prefix: Option<ModPath>,
14 tree: ast::UseTree, 18 tree: ast::UseTree,
15 hygiene: &Hygiene, 19 hygiene: &Hygiene,
@@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree(
21 None => prefix, 25 None => prefix,
22 // E.g. `use something::{inner}` (prefix is `None`, path is `something`) 26 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
23 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) 27 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
24 Some(path) => match convert_path(prefix, path, hygiene) { 28 Some(path) => match convert_path(db, prefix, path, hygiene) {
25 Some(it) => Some(it), 29 Some(it) => Some(it),
26 None => return, // FIXME: report errors somewhere 30 None => return, // FIXME: report errors somewhere
27 }, 31 },
28 }; 32 };
29 for child_tree in use_tree_list.use_trees() { 33 for child_tree in use_tree_list.use_trees() {
30 lower_use_tree(prefix.clone(), child_tree, hygiene, cb); 34 lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb);
31 } 35 }
32 } else { 36 } else {
33 let alias = tree.rename().map(|a| { 37 let alias = tree.rename().map(|a| {
@@ -47,7 +51,7 @@ pub(crate) fn lower_use_tree(
47 } 51 }
48 } 52 }
49 } 53 }
50 if let Some(path) = convert_path(prefix, ast_path, hygiene) { 54 if let Some(path) = convert_path(db, prefix, ast_path, hygiene) {
51 cb(path, &tree, is_glob, alias) 55 cb(path, &tree, is_glob, alias)
52 } 56 }
53 // FIXME: report errors somewhere 57 // FIXME: report errors somewhere
@@ -61,9 +65,14 @@ pub(crate) fn lower_use_tree(
61 } 65 }
62} 66}
63 67
64fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 68fn convert_path(
69 db: &dyn DefDatabase,
70 prefix: Option<ModPath>,
71 path: ast::Path,
72 hygiene: &Hygiene,
73) -> Option<ModPath> {
65 let prefix = if let Some(qual) = path.qualifier() { 74 let prefix = if let Some(qual) = path.qualifier() {
66 Some(convert_path(prefix, qual, hygiene)?) 75 Some(convert_path(db, prefix, qual, hygiene)?)
67 } else { 76 } else {
68 prefix 77 prefix
69 }; 78 };
@@ -71,7 +80,7 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) ->
71 let segment = path.segment()?; 80 let segment = path.segment()?;
72 let res = match segment.kind()? { 81 let res = match segment.kind()? {
73 ast::PathSegmentKind::Name(name_ref) => { 82 ast::PathSegmentKind::Name(name_ref) => {
74 match hygiene.name_ref_to_name(name_ref) { 83 match hygiene.name_ref_to_name(db.upcast(), name_ref) {
75 Either::Left(name) => { 84 Either::Left(name) => {
76 // no type args in use 85 // no type args in use
77 let mut res = prefix.unwrap_or_else(|| { 86 let mut res = prefix.unwrap_or_else(|| {
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index d4b7c9970..83500f54e 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -33,17 +33,19 @@ impl RawVisibility {
33 db: &dyn DefDatabase, 33 db: &dyn DefDatabase,
34 node: InFile<Option<ast::Visibility>>, 34 node: InFile<Option<ast::Visibility>>,
35 ) -> RawVisibility { 35 ) -> RawVisibility {
36 Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id)) 36 Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id))
37 } 37 }
38 38
39 pub(crate) fn from_ast_with_hygiene( 39 pub(crate) fn from_ast_with_hygiene(
40 db: &dyn DefDatabase,
40 node: Option<ast::Visibility>, 41 node: Option<ast::Visibility>,
41 hygiene: &Hygiene, 42 hygiene: &Hygiene,
42 ) -> RawVisibility { 43 ) -> RawVisibility {
43 Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) 44 Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene)
44 } 45 }
45 46
46 pub(crate) fn from_ast_with_hygiene_and_default( 47 pub(crate) fn from_ast_with_hygiene_and_default(
48 db: &dyn DefDatabase,
47 node: Option<ast::Visibility>, 49 node: Option<ast::Visibility>,
48 default: RawVisibility, 50 default: RawVisibility,
49 hygiene: &Hygiene, 51 hygiene: &Hygiene,
@@ -54,7 +56,7 @@ impl RawVisibility {
54 }; 56 };
55 match node.kind() { 57 match node.kind() {
56 ast::VisibilityKind::In(path) => { 58 ast::VisibilityKind::In(path) => {
57 let path = ModPath::from_src(path, hygiene); 59 let path = ModPath::from_src(db, path, hygiene);
58 let path = match path { 60 let path = match path {
59 None => return RawVisibility::private(), 61 None => return RawVisibility::private(),
60 Some(path) => path, 62 Some(path) => path,