Skip to content

Commit e2f7957

Browse files
committed
Auto merge of #84176 - GuillaumeGomez:src-to-definition, r=jyn514
Generate links to definition in rustdoc source code pages ## Description This PR adds an option (disabled by default) to add links in the source code page on ident. So for for example: ```rust mod other_module; struct Foo; fn bar() {} fn x<T: other_module::Trait>(f: Foo, g: other_module::Whatever, t: &T) { let f: Foo = Foo; bar(); f.some_method(); } ``` In the example (mostly in the `x` function), `other_module::Trait`, `Foo`, `other_module::Whatever`, `bar` and `some_method` are now links (and `other_module` at the top too). In case there is a type coming from another crate, it'll link to its documentation page and not its definition (but you can then click on `[src]` so I guess it's fine). Another important detail: I voluntarily didn't add links for primitive types. I think we can discuss about adding links on them or not in a later PR (adding the support for them would require only a few lines). Here is a video summing up everything I wrote above: https://user-images.githubusercontent.com/3050060/114622354-21307b00-9cae-11eb-834d-f6d8178a37bd.mp4 ## Performance impact So, on my computer, the performance remains more or less the same (which is quite surprising but that's a nice surprise). Here are the numbers: Without the option: * core: 1m 21s * alloc: 26.78s * std: 27.30s * proc_macro: 4.50s With source to definition links generation (I enabled by default the option): * core: 1m 25s * alloc: 25.76s * std: 27.07s * proc_macro: 4.66s So no real change here (again, I'm very surprised by this fact). For the size of the generated source files (only taking into account the `src` folder here since it's the only one impacted) by running `du -shc .` (when I am in the source folder). Without the option: 11.939 MB With the option: 12.611 MB So not a big change here either. In all those docs, I ran `grep -nR '<a class=' . | wc -l` and got 43917. So there are quite a lot of links added. :) cc `@rust-lang/rustdoc` r? `@jyn514`
2 parents 2f07ae4 + ba11dc7 commit e2f7957

30 files changed

+707
-131
lines changed

compiler/rustc_errors/src/lib.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ struct HandlerInner {
342342
deduplicated_warn_count: usize,
343343

344344
future_breakage_diagnostics: Vec<Diagnostic>,
345+
346+
/// If set to `true`, no warning or error will be emitted.
347+
quiet: bool,
345348
}
346349

347350
/// A key denoting where from a diagnostic was stashed.
@@ -456,10 +459,19 @@ impl Handler {
456459
emitted_diagnostics: Default::default(),
457460
stashed_diagnostics: Default::default(),
458461
future_breakage_diagnostics: Vec::new(),
462+
quiet: false,
459463
}),
460464
}
461465
}
462466

467+
pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
468+
let prev = self.inner.borrow_mut().quiet;
469+
self.inner.borrow_mut().quiet = true;
470+
let ret = f();
471+
self.inner.borrow_mut().quiet = prev;
472+
ret
473+
}
474+
463475
// This is here to not allow mutation of flags;
464476
// as of this writing it's only used in tests in librustc_middle.
465477
pub fn can_emit_warnings(&self) -> bool {
@@ -818,7 +830,7 @@ impl HandlerInner {
818830
}
819831

820832
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
821-
if diagnostic.cancelled() {
833+
if diagnostic.cancelled() || self.quiet {
822834
return;
823835
}
824836

@@ -1035,6 +1047,9 @@ impl HandlerInner {
10351047
}
10361048

10371049
fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
1050+
if self.quiet {
1051+
return;
1052+
}
10381053
if self.flags.report_delayed_bugs {
10391054
self.emit_diagnostic(&diagnostic);
10401055
}

compiler/rustc_session/src/session.rs

+4
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,10 @@ impl Session {
500500
&self.parse_sess.span_diagnostic
501501
}
502502

503+
pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
504+
self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
505+
}
506+
503507
/// Analogous to calling methods on the given `DiagnosticBuilder`, but
504508
/// deduplicates on lint ID, span (if any), and message for this `Session`
505509
fn diag_once<'a, 'b>(

src/librustdoc/clean/blanket_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
9898
visibility: Inherited,
9999
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
100100
kind: box ImplItem(Impl {
101-
span: Span::from_rustc_span(self.cx.tcx.def_span(impl_def_id)),
101+
span: Span::new(self.cx.tcx.def_span(impl_def_id)),
102102
unsafety: hir::Unsafety::Normal,
103103
generics: (
104104
self.cx.tcx.generics_of(impl_def_id),

src/librustdoc/clean/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ fn build_module(
517517
}
518518
}
519519

520-
let span = clean::Span::from_rustc_span(cx.tcx.def_span(did));
520+
let span = clean::Span::new(cx.tcx.def_span(did));
521521
clean::Module { items, span }
522522
}
523523

src/librustdoc/clean/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ impl Clean<Item> for doctree::Module<'_> {
9595

9696
// determine if we should display the inner contents or
9797
// the outer `mod` item for the source code.
98-
let span = Span::from_rustc_span({
98+
99+
let span = Span::new({
99100
let where_outer = self.where_outer(cx.tcx);
100101
let sm = cx.sess().source_map();
101102
let outer = sm.lookup_char_pos(where_outer.lo());

src/librustdoc/clean/types.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ crate struct Item {
343343
rustc_data_structures::static_assert_size!(Item, 56);
344344

345345
crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
346-
Span::from_rustc_span(def_id.as_local().map_or_else(
346+
Span::new(def_id.as_local().map_or_else(
347347
|| tcx.def_span(def_id),
348348
|local| {
349349
let hir = tcx.hir();
@@ -1943,10 +1943,11 @@ crate enum Variant {
19431943
crate struct Span(rustc_span::Span);
19441944

19451945
impl Span {
1946-
crate fn from_rustc_span(sp: rustc_span::Span) -> Self {
1947-
// Get the macro invocation instead of the definition,
1948-
// in case the span is result of a macro expansion.
1949-
// (See rust-lang/rust#39726)
1946+
/// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1947+
/// span will be updated to point to the macro invocation instead of the macro definition.
1948+
///
1949+
/// (See rust-lang/rust#39726)
1950+
crate fn new(sp: rustc_span::Span) -> Self {
19501951
Self(sp.source_callsite())
19511952
}
19521953

src/librustdoc/config.rs

+12
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ crate struct RenderOptions {
276276
crate show_type_layout: bool,
277277
crate unstable_features: rustc_feature::UnstableFeatures,
278278
crate emit: Vec<EmitType>,
279+
/// If `true`, HTML source pages will generate links for items to their definition.
280+
crate generate_link_to_definition: bool,
279281
}
280282

281283
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -655,6 +657,15 @@ impl Options {
655657
let generate_redirect_map = matches.opt_present("generate-redirect-map");
656658
let show_type_layout = matches.opt_present("show-type-layout");
657659
let nocapture = matches.opt_present("nocapture");
660+
let generate_link_to_definition = matches.opt_present("generate-link-to-definition");
661+
662+
if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
663+
diag.struct_err(
664+
"--generate-link-to-definition option can only be used with HTML output format",
665+
)
666+
.emit();
667+
return Err(1);
668+
}
658669

659670
let (lint_opts, describe_lints, lint_cap) =
660671
get_cmd_lint_options(matches, error_format, &debugging_opts);
@@ -721,6 +732,7 @@ impl Options {
721732
crate_name.as_deref(),
722733
),
723734
emit,
735+
generate_link_to_definition,
724736
},
725737
crate_name,
726738
output_format,

src/librustdoc/html/format.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,11 @@ crate enum HrefError {
484484
NotInExternalCache,
485485
}
486486

487-
crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
487+
crate fn href_with_root_path(
488+
did: DefId,
489+
cx: &Context<'_>,
490+
root_path: Option<&str>,
491+
) -> Result<(String, ItemType, Vec<String>), HrefError> {
488492
let cache = &cx.cache();
489493
let relative_to = &cx.current;
490494
fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
@@ -495,6 +499,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
495499
return Err(HrefError::Private);
496500
}
497501

502+
let mut is_remote = false;
498503
let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
499504
Some(&(ref fqp, shortty)) => (fqp, shortty, {
500505
let module_fqp = to_module_fqp(shortty, fqp);
@@ -508,6 +513,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
508513
shortty,
509514
match cache.extern_locations[&did.krate] {
510515
ExternalLocation::Remote(ref s) => {
516+
is_remote = true;
511517
let s = s.trim_end_matches('/');
512518
let mut s = vec![s];
513519
s.extend(module_fqp[..].iter().map(String::as_str));
@@ -522,6 +528,12 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
522528
}
523529
}
524530
};
531+
if !is_remote {
532+
if let Some(root_path) = root_path {
533+
let root = root_path.trim_end_matches('/');
534+
url_parts.insert(0, root);
535+
}
536+
}
525537
let last = &fqp.last().unwrap()[..];
526538
let filename;
527539
match shortty {
@@ -536,6 +548,10 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
536548
Ok((url_parts.join("/"), shortty, fqp.to_vec()))
537549
}
538550

551+
crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
552+
href_with_root_path(did, cx, None)
553+
}
554+
539555
/// Both paths should only be modules.
540556
/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
541557
/// both need `../iter/trait.Iterator.html` to get at the iterator trait.

0 commit comments

Comments
 (0)