1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::clean;
use crate::core::ResolverCaches;
use crate::html::markdown::markdown_links;
use crate::passes::collect_intra_doc_links::preprocess_link;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, ItemKind};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_hir::def::Namespace::TypeNS;
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_resolve::Resolver;
use rustc_session::config::Externs;
use rustc_span::{Span, DUMMY_SP};
use std::mem;
crate fn early_resolve_intra_doc_links(
resolver: &mut Resolver<'_>,
krate: &ast::Crate,
externs: Externs,
) -> ResolverCaches {
let mut loader = IntraLinkCrateLoader {
resolver,
current_mod: CRATE_DEF_ID,
all_traits: Default::default(),
all_trait_impls: Default::default(),
};
loader.load_links_in_attrs(&krate.attrs, krate.span);
visit::walk_crate(&mut loader, krate);
loader.fill_resolver_caches();
for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
let _ = loader.resolver.resolve_str_path_error(
DUMMY_SP,
extern_name,
TypeNS,
CRATE_DEF_ID.to_def_id(),
);
}
ResolverCaches {
all_traits: Some(loader.all_traits),
all_trait_impls: Some(loader.all_trait_impls),
}
}
struct IntraLinkCrateLoader<'r, 'ra> {
resolver: &'r mut Resolver<'ra>,
current_mod: LocalDefId,
all_traits: Vec<DefId>,
all_trait_impls: Vec<DefId>,
}
impl IntraLinkCrateLoader<'_, '_> {
fn fill_resolver_caches(&mut self) {
for cnum in self.resolver.cstore().crates_untracked() {
let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum);
let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum);
self.all_traits.extend(all_traits);
self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id));
}
}
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
let attrs = clean::Attributes::from_ast(attrs, None);
for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
for link in markdown_links(&doc.as_str()) {
let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
x.path_str
} else {
continue;
};
let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
}
}
}
}
impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
fn visit_item(&mut self, item: &ast::Item) {
if let ItemKind::Mod(..) = item.kind {
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item);
self.current_mod = old_mod;
} else {
match item.kind {
ItemKind::Trait(..) => {
self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
}
ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
}
_ => {}
}
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item);
}
}
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_assoc_item(self, item, ctxt)
}
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_foreign_item(self, item)
}
fn visit_variant(&mut self, v: &ast::Variant) {
self.load_links_in_attrs(&v.attrs, v.span);
visit::walk_variant(self, v)
}
fn visit_field_def(&mut self, field: &ast::FieldDef) {
self.load_links_in_attrs(&field.attrs, field.span);
visit::walk_field_def(self, field)
}
}