Skip to content

Commit 3fd36bc

Browse files
Add jump to doc
1 parent b12ff66 commit 3fd36bc

File tree

3 files changed

+84
-25
lines changed

3 files changed

+84
-25
lines changed

Diff for: src/librustdoc/html/highlight.rs

+5
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,11 @@ fn string_without_closing_tag<T: Display>(
988988
)
989989
.ok()
990990
.map(|(url, _, _)| url),
991+
LinkFromSrc::Doc(def_id) => {
992+
format::href_with_root_path(*def_id, context, Some(&href_context.root_path))
993+
.ok()
994+
.map(|(doc_link, _, _)| doc_link)
995+
}
991996
}
992997
})
993998
{

Diff for: src/librustdoc/html/render/context.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,12 @@ impl<'tcx> Context<'tcx> {
349349
let e = ExternalCrate { crate_num: cnum };
350350
(e.name(self.tcx()), e.src_root(self.tcx()))
351351
}
352-
ExternalLocation::Unknown => return None,
352+
ExternalLocation::Unknown => {
353+
let e = ExternalCrate { crate_num: cnum };
354+
let name = e.name(self.tcx());
355+
root = name.to_string();
356+
(name, e.src_root(self.tcx()))
357+
}
353358
};
354359

355360
let href = RefCell::new(PathBuf::new());

Diff for: src/librustdoc/html/render/span_map.rs

+73-24
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use crate::clean::{self, PrimitiveType};
1+
use crate::clean::{self, rustc_span, PrimitiveType};
22
use crate::html::sources;
33

44
use rustc_data_structures::fx::FxHashMap;
55
use rustc_hir::def::{DefKind, Res};
6-
use rustc_hir::def_id::DefId;
6+
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
77
use rustc_hir::intravisit::{self, Visitor};
8-
use rustc_hir::{ExprKind, HirId, Mod, Node};
8+
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node};
99
use rustc_middle::hir::nested_filter;
1010
use rustc_middle::ty::TyCtxt;
1111
use rustc_span::hygiene::MacroKind;
@@ -25,6 +25,7 @@ pub(crate) enum LinkFromSrc {
2525
Local(clean::Span),
2626
External(DefId),
2727
Primitive(PrimitiveType),
28+
Doc(DefId),
2829
}
2930

3031
/// This function will do at most two things:
@@ -65,24 +66,43 @@ struct SpanMapVisitor<'tcx> {
6566
impl<'tcx> SpanMapVisitor<'tcx> {
6667
/// This function is where we handle `hir::Path` elements and add them into the "span map".
6768
fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
68-
let info = match path.res {
69+
match path.res {
6970
// FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
7071
// Would be nice to support them too alongside the other `DefKind`
7172
// (such as primitive types!).
72-
Res::Def(kind, def_id) if kind != DefKind::TyParam => Some(def_id),
73-
Res::Local(_) => None,
73+
Res::Def(kind, def_id) if kind != DefKind::TyParam => {
74+
let link = if def_id.as_local().is_some() {
75+
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
76+
} else {
77+
LinkFromSrc::External(def_id)
78+
};
79+
self.matches.insert(path.span, link);
80+
}
81+
Res::Local(_) => {
82+
if let Some(span) = self.tcx.hir().res_span(path.res) {
83+
self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
84+
}
85+
}
7486
Res::PrimTy(p) => {
7587
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
7688
self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
77-
return;
7889
}
79-
Res::Err => return,
80-
_ => return,
81-
};
82-
if let Some(span) = self.tcx.hir().res_span(path.res) {
83-
self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
84-
} else if let Some(def_id) = info {
85-
self.matches.insert(path.span, LinkFromSrc::External(def_id));
90+
Res::Err => {}
91+
_ => {}
92+
}
93+
}
94+
95+
/// Used to generate links on items' definition to go to their documentation page.
96+
pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
97+
if let Some(Node::Item(item)) = self.tcx.hir().find(hir_id) {
98+
if let Some(span) = self.tcx.def_ident_span(item.owner_id) {
99+
let cspan = clean::Span::new(span);
100+
// If the span isn't from the current crate, we ignore it.
101+
if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
102+
return;
103+
}
104+
self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
105+
}
86106
}
87107
}
88108

@@ -117,10 +137,13 @@ impl<'tcx> SpanMapVisitor<'tcx> {
117137
_ => return true,
118138
};
119139
let link_from_src = match data.macro_def_id {
120-
Some(macro_def_id) if macro_def_id.is_local() => {
121-
LinkFromSrc::Local(clean::Span::new(data.def_site))
140+
Some(macro_def_id) => {
141+
if macro_def_id.is_local() {
142+
LinkFromSrc::Local(clean::Span::new(data.def_site))
143+
} else {
144+
LinkFromSrc::External(macro_def_id)
145+
}
122146
}
123-
Some(macro_def_id) => LinkFromSrc::External(macro_def_id),
124147
None => return true,
125148
};
126149
let new_span = data.call_site;
@@ -160,6 +183,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
160183
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
161184
);
162185
}
186+
} else {
187+
// If it's a "mod foo {}", we want to look to its documentation page.
188+
self.extract_info_from_hir_id(id);
163189
}
164190
intravisit::walk_mod(self, m, id);
165191
}
@@ -176,18 +202,41 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
176202
.tcx
177203
.typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
178204
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
179-
self.matches.insert(
180-
segment.ident.span,
181-
match hir.span_if_local(def_id) {
182-
Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
183-
None => LinkFromSrc::External(def_id),
184-
},
185-
);
205+
let link = if def_id.as_local().is_some() {
206+
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
207+
} else {
208+
LinkFromSrc::External(def_id)
209+
};
210+
self.matches.insert(segment.ident.span, link);
186211
}
187212
} else if self.handle_macro(expr.span) {
188213
// We don't want to go deeper into the macro.
189214
return;
190215
}
191216
intravisit::walk_expr(self, expr);
192217
}
218+
219+
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
220+
match item.kind {
221+
ItemKind::Static(_, _, _)
222+
| ItemKind::Const(_, _)
223+
| ItemKind::Fn(_, _, _)
224+
| ItemKind::Macro(_, _)
225+
| ItemKind::TyAlias(_, _)
226+
| ItemKind::Enum(_, _)
227+
| ItemKind::Struct(_, _)
228+
| ItemKind::Union(_, _)
229+
| ItemKind::Trait(_, _, _, _, _)
230+
| ItemKind::TraitAlias(_, _) => self.extract_info_from_hir_id(item.hir_id()),
231+
ItemKind::Impl(_)
232+
| ItemKind::Use(_, _)
233+
| ItemKind::ExternCrate(_)
234+
| ItemKind::ForeignMod { .. }
235+
| ItemKind::GlobalAsm(_)
236+
| ItemKind::OpaqueTy(_)
237+
// We already have "visit_mod" above so no need to check it here.
238+
| ItemKind::Mod(_) => {}
239+
}
240+
intravisit::walk_item(self, item);
241+
}
193242
}

0 commit comments

Comments
 (0)