|
1 | 1 | use rustc_ast as ast; |
2 | 2 | use rustc_hir::def::Namespace::TypeNS; |
3 | | -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; |
| 3 | +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; |
4 | 4 | use rustc_interface::interface; |
| 5 | +use rustc_span::Span; |
5 | 6 |
|
6 | 7 | use std::cell::RefCell; |
7 | 8 | use std::mem; |
8 | 9 | use std::rc::Rc; |
9 | 10 |
|
| 11 | +type Resolver = Rc<RefCell<interface::BoxedResolver>>; |
10 | 12 | // Letting the resolver escape at the end of the function leads to inconsistencies between the |
11 | 13 | // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates |
12 | 14 | // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ... |
13 | | -crate struct IntraLinkCrateLoader { |
14 | | - current_mod: DefId, |
15 | | - crate resolver: Rc<RefCell<interface::BoxedResolver>>, |
| 15 | +crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver { |
| 16 | + let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver }; |
| 17 | + // `walk_crate` doesn't visit the crate itself for some reason. |
| 18 | + loader.load_links_in_attrs(&krate.attrs, krate.span); |
| 19 | + ast::visit::walk_crate(&mut loader, krate); |
| 20 | + loader.resolver |
16 | 21 | } |
17 | 22 |
|
18 | | -impl IntraLinkCrateLoader { |
19 | | - crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self { |
20 | | - let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(); |
21 | | - Self { current_mod: crate_id, resolver } |
22 | | - } |
| 23 | +struct IntraLinkCrateLoader { |
| 24 | + current_mod: LocalDefId, |
| 25 | + resolver: Rc<RefCell<interface::BoxedResolver>>, |
23 | 26 | } |
24 | 27 |
|
25 | | -impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { |
26 | | - fn visit_attribute(&mut self, attr: &ast::Attribute) { |
| 28 | +impl IntraLinkCrateLoader { |
| 29 | + fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { |
27 | 30 | use crate::html::markdown::markdown_links; |
28 | 31 | use crate::passes::collect_intra_doc_links::preprocess_link; |
29 | 32 |
|
30 | | - if let Some(doc) = attr.doc_str() { |
| 33 | + // FIXME: this probably needs to consider inlining |
| 34 | + let attrs = crate::clean::Attributes::from_ast(attrs, None); |
| 35 | + for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() { |
| 36 | + debug!(?doc); |
31 | 37 | for link in markdown_links(&doc.as_str()) { |
| 38 | + debug!(?link.link); |
32 | 39 | let path_str = if let Some(Ok(x)) = preprocess_link(&link) { |
33 | 40 | x.path_str |
34 | 41 | } else { |
35 | 42 | continue; |
36 | 43 | }; |
37 | 44 | self.resolver.borrow_mut().access(|resolver| { |
38 | 45 | let _ = resolver.resolve_str_path_error( |
39 | | - attr.span, |
| 46 | + span, |
40 | 47 | &path_str, |
41 | 48 | TypeNS, |
42 | | - self.current_mod, |
| 49 | + parent_module.unwrap_or(self.current_mod.to_def_id()), |
43 | 50 | ); |
44 | 51 | }); |
45 | 52 | } |
46 | 53 | } |
47 | | - ast::visit::walk_attribute(self, attr); |
48 | 54 | } |
| 55 | +} |
49 | 56 |
|
| 57 | +impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { |
50 | 58 | fn visit_item(&mut self, item: &ast::Item) { |
51 | 59 | use rustc_ast_lowering::ResolverAstLowering; |
52 | 60 |
|
53 | 61 | if let ast::ItemKind::Mod(..) = item.kind { |
54 | 62 | let new_mod = |
55 | 63 | self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id)); |
56 | | - let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id()); |
| 64 | + let old_mod = mem::replace(&mut self.current_mod, new_mod); |
| 65 | + |
| 66 | + self.load_links_in_attrs(&item.attrs, item.span); |
57 | 67 | ast::visit::walk_item(self, item); |
| 68 | + |
58 | 69 | self.current_mod = old_mod; |
59 | 70 | } else { |
| 71 | + self.load_links_in_attrs(&item.attrs, item.span); |
60 | 72 | ast::visit::walk_item(self, item); |
61 | 73 | } |
62 | 74 | } |
|
0 commit comments