]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/collect_intra_doc_links/early.rs
Rollup merge of #90349 - willcrichton:example-analyzer, r=jyn514
[rust.git] / src / librustdoc / passes / collect_intra_doc_links / early.rs
1 use rustc_ast as ast;
2 use rustc_hir::def::Namespace::TypeNS;
3 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
4 use rustc_interface::interface;
5 use rustc_span::Span;
6
7 use std::cell::RefCell;
8 use std::mem;
9 use std::rc::Rc;
10
11 type Resolver = Rc<RefCell<interface::BoxedResolver>>;
12 // Letting the resolver escape at the end of the function leads to inconsistencies between the
13 // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
14 // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
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
21 }
22
23 struct IntraLinkCrateLoader {
24     current_mod: LocalDefId,
25     resolver: Rc<RefCell<interface::BoxedResolver>>,
26 }
27
28 impl IntraLinkCrateLoader {
29     fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
30         use crate::html::markdown::markdown_links;
31         use crate::passes::collect_intra_doc_links::preprocess_link;
32
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);
37             for link in markdown_links(doc.as_str()) {
38                 debug!(?link.link);
39                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
40                     x.path_str
41                 } else {
42                     continue;
43                 };
44                 self.resolver.borrow_mut().access(|resolver| {
45                     let _ = resolver.resolve_str_path_error(
46                         span,
47                         &path_str,
48                         TypeNS,
49                         parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
50                     );
51                 });
52             }
53         }
54     }
55 }
56
57 impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
58     fn visit_item(&mut self, item: &ast::Item) {
59         use rustc_ast_lowering::ResolverAstLowering;
60
61         if let ast::ItemKind::Mod(..) = item.kind {
62             let new_mod =
63                 self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
64             let old_mod = mem::replace(&mut self.current_mod, new_mod);
65
66             self.load_links_in_attrs(&item.attrs, item.span);
67             ast::visit::walk_item(self, item);
68
69             self.current_mod = old_mod;
70         } else {
71             self.load_links_in_attrs(&item.attrs, item.span);
72             ast::visit::walk_item(self, item);
73         }
74     }
75 }