]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/collect_intra_doc_links/early.rs
Rollup merge of #85766 - workingjubilee:file-options, r=yaahc
[rust.git] / src / librustdoc / passes / collect_intra_doc_links / early.rs
1 use ast::visit;
2 use rustc_ast as ast;
3 use rustc_hir::def::Namespace::TypeNS;
4 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
5 use rustc_interface::interface;
6 use rustc_span::Span;
7
8 use std::cell::RefCell;
9 use std::mem;
10 use std::rc::Rc;
11
12 type Resolver = Rc<RefCell<interface::BoxedResolver>>;
13 // Letting the resolver escape at the end of the function leads to inconsistencies between the
14 // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
15 // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
16 crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver {
17     let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
18     // `walk_crate` doesn't visit the crate itself for some reason.
19     loader.load_links_in_attrs(&krate.attrs, krate.span);
20     visit::walk_crate(&mut loader, krate);
21     loader.resolver
22 }
23
24 struct IntraLinkCrateLoader {
25     current_mod: LocalDefId,
26     resolver: Rc<RefCell<interface::BoxedResolver>>,
27 }
28
29 impl IntraLinkCrateLoader {
30     fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
31         use crate::html::markdown::markdown_links;
32         use crate::passes::collect_intra_doc_links::preprocess_link;
33
34         // FIXME: this probably needs to consider inlining
35         let attrs = crate::clean::Attributes::from_ast(attrs, None);
36         for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
37             debug!(?doc);
38             for link in markdown_links(doc.as_str()) {
39                 debug!(?link.link);
40                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
41                     x.path_str
42                 } else {
43                     continue;
44                 };
45                 self.resolver.borrow_mut().access(|resolver| {
46                     let _ = resolver.resolve_str_path_error(
47                         span,
48                         &path_str,
49                         TypeNS,
50                         parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
51                     );
52                 });
53             }
54         }
55     }
56 }
57
58 impl visit::Visitor<'_> for IntraLinkCrateLoader {
59     fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
60         self.load_links_in_attrs(&item.attrs, item.span);
61         visit::walk_foreign_item(self, item)
62     }
63
64     fn visit_item(&mut self, item: &ast::Item) {
65         use rustc_ast_lowering::ResolverAstLowering;
66
67         if let ast::ItemKind::Mod(..) = item.kind {
68             let new_mod =
69                 self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
70             let old_mod = mem::replace(&mut self.current_mod, new_mod);
71
72             self.load_links_in_attrs(&item.attrs, item.span);
73             visit::walk_item(self, item);
74
75             self.current_mod = old_mod;
76         } else {
77             self.load_links_in_attrs(&item.attrs, item.span);
78             visit::walk_item(self, item);
79         }
80     }
81
82     // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too.
83
84     fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
85         self.load_links_in_attrs(&item.attrs, item.span);
86         visit::walk_assoc_item(self, item, ctxt)
87     }
88
89     fn visit_field_def(&mut self, field: &ast::FieldDef) {
90         self.load_links_in_attrs(&field.attrs, field.span);
91         visit::walk_field_def(self, field)
92     }
93
94     fn visit_variant(&mut self, v: &ast::Variant) {
95         self.load_links_in_attrs(&v.attrs, v.span);
96         visit::walk_variant(self, v)
97     }
98 }