|
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