Skip to content

Commit 7efc097

Browse files
committed
Auto merge of rust-lang#79957 - jyn514:smaller-span, r=GuillaumeGomez
[rustdoc] Calculate span information on demand instead of storing it ahead of time This brings `size_of<clean::types::Span>()` down from over 100 bytes (!!) to only 12, the same as rustc. It brings `Item` down even more, from `784` to `680`. ~~TODO: I need to figure out how to do this for the JSON backend too. That uses `From` impls everywhere, which don't allow passing in the `Session` as an argument. `@P1n3appl3,` `@tmandry,` maybe one of you have ideas?~~ Figured it out, fortunately only two functions needed to be changed. I like the `convert_x()` format better than `From` everywhere but I'm open to feedback. Helps with rust-lang#79103
2 parents 388eb24 + 9684557 commit 7efc097

File tree

11 files changed

+116
-95
lines changed

11 files changed

+116
-95
lines changed

src/librustdoc/clean/auto_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
118118
};
119119

120120
Some(Item {
121-
source: Span::empty(),
121+
source: Span::dummy(),
122122
name: None,
123123
attrs: Default::default(),
124124
visibility: Inherited,

src/librustdoc/clean/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
479479
items.push(clean::Item {
480480
name: None,
481481
attrs: clean::Attributes::default(),
482-
source: clean::Span::empty(),
482+
source: clean::Span::dummy(),
483483
def_id: DefId::local(CRATE_DEF_INDEX),
484484
visibility: clean::Public,
485485
stability: None,

src/librustdoc/clean/mod.rs

+3-24
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
2525
use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn};
2626
use rustc_span::hygiene::{AstPass, MacroKind};
2727
use rustc_span::symbol::{kw, sym, Ident, Symbol};
28-
use rustc_span::{self, ExpnKind, Pos};
28+
use rustc_span::{self, ExpnKind};
2929
use rustc_typeck::hir_ty_to_ty;
3030

3131
use std::collections::hash_map::Entry;
@@ -1881,29 +1881,8 @@ impl Clean<VariantKind> for hir::VariantData<'_> {
18811881
}
18821882

18831883
impl Clean<Span> for rustc_span::Span {
1884-
fn clean(&self, cx: &DocContext<'_>) -> Span {
1885-
if self.is_dummy() {
1886-
return Span::empty();
1887-
}
1888-
1889-
// Get the macro invocation instead of the definition,
1890-
// in case the span is result of a macro expansion.
1891-
// (See rust-lang/rust#39726)
1892-
let span = self.source_callsite();
1893-
1894-
let sm = cx.sess().source_map();
1895-
let filename = sm.span_to_filename(span);
1896-
let lo = sm.lookup_char_pos(span.lo());
1897-
let hi = sm.lookup_char_pos(span.hi());
1898-
Span {
1899-
filename,
1900-
cnum: lo.file.cnum,
1901-
loline: lo.line,
1902-
locol: lo.col.to_usize(),
1903-
hiline: hi.line,
1904-
hicol: hi.col.to_usize(),
1905-
original: span,
1906-
}
1884+
fn clean(&self, _cx: &DocContext<'_>) -> Span {
1885+
Span::from_rustc_span(*self)
19071886
}
19081887
}
19091888

src/librustdoc/clean/types.rs

+32-22
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1717
use rustc_feature::UnstableFeatures;
1818
use rustc_hir as hir;
1919
use rustc_hir::def::Res;
20-
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
20+
use rustc_hir::def_id::{CrateNum, DefId};
2121
use rustc_hir::lang_items::LangItem;
2222
use rustc_hir::Mutability;
2323
use rustc_index::vec::IndexVec;
2424
use rustc_middle::ty::{AssocKind, TyCtxt};
25+
use rustc_session::Session;
2526
use rustc_span::hygiene::MacroKind;
2627
use rustc_span::source_map::DUMMY_SP;
2728
use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
28-
use rustc_span::{self, FileName};
29+
use rustc_span::{self, FileName, Loc};
2930
use rustc_target::abi::VariantIdx;
3031
use rustc_target::spec::abi::Abi;
3132
use smallvec::{smallvec, SmallVec};
@@ -1609,32 +1610,41 @@ crate enum VariantKind {
16091610
Struct(VariantStruct),
16101611
}
16111612

1613+
/// Small wrapper around `rustc_span::Span` that adds helper methods and enforces calling `source_callsite`.
16121614
#[derive(Clone, Debug)]
1613-
crate struct Span {
1614-
crate filename: FileName,
1615-
crate cnum: CrateNum,
1616-
crate loline: usize,
1617-
crate locol: usize,
1618-
crate hiline: usize,
1619-
crate hicol: usize,
1620-
crate original: rustc_span::Span,
1621-
}
1615+
crate struct Span(rustc_span::Span);
16221616

16231617
impl Span {
1624-
crate fn empty() -> Span {
1625-
Span {
1626-
filename: FileName::Anon(0),
1627-
cnum: LOCAL_CRATE,
1628-
loline: 0,
1629-
locol: 0,
1630-
hiline: 0,
1631-
hicol: 0,
1632-
original: rustc_span::DUMMY_SP,
1633-
}
1618+
crate fn from_rustc_span(sp: rustc_span::Span) -> Self {
1619+
// Get the macro invocation instead of the definition,
1620+
// in case the span is result of a macro expansion.
1621+
// (See rust-lang/rust#39726)
1622+
Self(sp.source_callsite())
1623+
}
1624+
1625+
crate fn dummy() -> Self {
1626+
Self(rustc_span::DUMMY_SP)
16341627
}
16351628

16361629
crate fn span(&self) -> rustc_span::Span {
1637-
self.original
1630+
self.0
1631+
}
1632+
1633+
crate fn filename(&self, sess: &Session) -> FileName {
1634+
sess.source_map().span_to_filename(self.0)
1635+
}
1636+
1637+
crate fn lo(&self, sess: &Session) -> Loc {
1638+
sess.source_map().lookup_char_pos(self.0.lo())
1639+
}
1640+
1641+
crate fn hi(&self, sess: &Session) -> Loc {
1642+
sess.source_map().lookup_char_pos(self.0.hi())
1643+
}
1644+
1645+
crate fn cnum(&self, sess: &Session) -> CrateNum {
1646+
// FIXME: is there a time when the lo and hi crate would be different?
1647+
self.lo(sess).file.cnum
16381648
}
16391649
}
16401650

src/librustdoc/formats/renderer.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::sync::Arc;
22

3+
use rustc_data_structures::sync::Lrc;
4+
use rustc_session::Session;
35
use rustc_span::edition::Edition;
46

57
use crate::clean;
@@ -19,6 +21,7 @@ crate trait FormatRenderer: Clone {
1921
render_info: RenderInfo,
2022
edition: Edition,
2123
cache: &mut Cache,
24+
sess: Lrc<Session>,
2225
) -> Result<(Self, clean::Crate), Error>;
2326

2427
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
@@ -49,6 +52,7 @@ crate fn run_format<T: FormatRenderer>(
4952
render_info: RenderInfo,
5053
diag: &rustc_errors::Handler,
5154
edition: Edition,
55+
sess: Lrc<Session>,
5256
) -> Result<(), Error> {
5357
let (krate, mut cache) = Cache::from_krate(
5458
render_info.clone(),
@@ -59,7 +63,7 @@ crate fn run_format<T: FormatRenderer>(
5963
);
6064

6165
let (mut format_renderer, mut krate) =
62-
T::init(krate, options, render_info, edition, &mut cache)?;
66+
T::init(krate, options, render_info, edition, &mut cache, sess)?;
6367

6468
let cache = Arc::new(cache);
6569
// Freeze the cache now that the index has been built. Put an Arc into TLS for future

src/librustdoc/html/render/mod.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ use rustc_ast_pretty::pprust;
5252
use rustc_attr::StabilityLevel;
5353
use rustc_data_structures::flock;
5454
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
55+
use rustc_data_structures::sync::Lrc;
5556
use rustc_hir as hir;
5657
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
5758
use rustc_hir::Mutability;
5859
use rustc_middle::middle::stability;
60+
use rustc_session::Session;
5961
use rustc_span::edition::Edition;
6062
use rustc_span::hygiene::MacroKind;
6163
use rustc_span::source_map::FileName;
@@ -121,6 +123,7 @@ crate struct Context {
121123
}
122124

123125
crate struct SharedContext {
126+
crate sess: Lrc<Session>,
124127
/// The path to the crate root source minus the file name.
125128
/// Used for simplifying paths to the highlighted source code files.
126129
crate src_root: PathBuf,
@@ -171,6 +174,10 @@ impl Context {
171174
let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext);
172175
self.dst.join(&filename)
173176
}
177+
178+
fn sess(&self) -> &Session {
179+
&self.shared.sess
180+
}
174181
}
175182

176183
impl SharedContext {
@@ -381,6 +388,7 @@ impl FormatRenderer for Context {
381388
_render_info: RenderInfo,
382389
edition: Edition,
383390
cache: &mut Cache,
391+
sess: Lrc<Session>,
384392
) -> Result<(Context, clean::Crate), Error> {
385393
// need to save a copy of the options for rendering the index page
386394
let md_opts = options.clone();
@@ -453,6 +461,7 @@ impl FormatRenderer for Context {
453461
}
454462
let (sender, receiver) = channel();
455463
let mut scx = SharedContext {
464+
sess,
456465
collapsed: krate.collapsed,
457466
src_root,
458467
include_sources,
@@ -1629,24 +1638,24 @@ impl Context {
16291638
/// of their crate documentation isn't known.
16301639
fn src_href(&self, item: &clean::Item, cache: &Cache) -> Option<String> {
16311640
let mut root = self.root_path();
1632-
16331641
let mut path = String::new();
1642+
let cnum = item.source.cnum(self.sess());
16341643

16351644
// We can safely ignore synthetic `SourceFile`s.
1636-
let file = match item.source.filename {
1645+
let file = match item.source.filename(self.sess()) {
16371646
FileName::Real(ref path) => path.local_path().to_path_buf(),
16381647
_ => return None,
16391648
};
16401649
let file = &file;
16411650

1642-
let (krate, path) = if item.source.cnum == LOCAL_CRATE {
1651+
let (krate, path) = if cnum == LOCAL_CRATE {
16431652
if let Some(path) = self.shared.local_sources.get(file) {
16441653
(&self.shared.layout.krate, path)
16451654
} else {
16461655
return None;
16471656
}
16481657
} else {
1649-
let (krate, src_root) = match *cache.extern_locations.get(&item.source.cnum)? {
1658+
let (krate, src_root) = match *cache.extern_locations.get(&cnum)? {
16501659
(ref name, ref src, ExternalLocation::Local) => (name, src),
16511660
(ref name, ref src, ExternalLocation::Remote(ref s)) => {
16521661
root = s.to_string();
@@ -1665,11 +1674,10 @@ impl Context {
16651674
(krate, &path)
16661675
};
16671676

1668-
let lines = if item.source.loline == item.source.hiline {
1669-
item.source.loline.to_string()
1670-
} else {
1671-
format!("{}-{}", item.source.loline, item.source.hiline)
1672-
};
1677+
let loline = item.source.lo(self.sess()).line;
1678+
let hiline = item.source.hi(self.sess()).line;
1679+
let lines =
1680+
if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
16731681
Some(format!(
16741682
"{root}src/{krate}/{path}#{lines}",
16751683
root = Escape(&root),

src/librustdoc/html/sources.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::html::highlight;
77
use crate::html::layout;
88
use crate::html::render::{SharedContext, BASIC_KEYWORDS};
99
use rustc_hir::def_id::LOCAL_CRATE;
10+
use rustc_session::Session;
1011
use rustc_span::source_map::FileName;
1112
use std::ffi::OsStr;
1213
use std::fs;
@@ -34,37 +35,45 @@ struct SourceCollector<'a> {
3435

3536
impl<'a> DocFolder for SourceCollector<'a> {
3637
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
38+
// If we're not rendering sources, there's nothing to do.
3739
// If we're including source files, and we haven't seen this file yet,
3840
// then we need to render it out to the filesystem.
3941
if self.scx.include_sources
4042
// skip all synthetic "files"
41-
&& item.source.filename.is_real()
43+
&& item.source.filename(self.sess()).is_real()
4244
// skip non-local files
43-
&& item.source.cnum == LOCAL_CRATE
45+
&& item.source.cnum(self.sess()) == LOCAL_CRATE
4446
{
47+
let filename = item.source.filename(self.sess());
4548
// If it turns out that we couldn't read this file, then we probably
4649
// can't read any of the files (generating html output from json or
4750
// something like that), so just don't include sources for the
4851
// entire crate. The other option is maintaining this mapping on a
4952
// per-file basis, but that's probably not worth it...
50-
self.scx.include_sources = match self.emit_source(&item.source.filename) {
53+
self.scx.include_sources = match self.emit_source(&filename) {
5154
Ok(()) => true,
5255
Err(e) => {
5356
println!(
5457
"warning: source code was requested to be rendered, \
5558
but processing `{}` had an error: {}",
56-
item.source.filename, e
59+
filename, e
5760
);
5861
println!(" skipping rendering of source code");
5962
false
6063
}
6164
};
6265
}
66+
// FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
67+
// we could return None here without having to walk the rest of the crate.
6368
Some(self.fold_item_recur(item))
6469
}
6570
}
6671

6772
impl<'a> SourceCollector<'a> {
73+
fn sess(&self) -> &Session {
74+
&self.scx.sess
75+
}
76+
6877
/// Renders the given filename into its corresponding HTML source file.
6978
fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
7079
let p = match *filename {

src/librustdoc/json/conversions.rs

+21-18
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ use std::convert::From;
66

77
use rustc_ast::ast;
88
use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
9+
use rustc_span::Pos;
910

1011
use crate::clean;
1112
use crate::doctree;
1213
use crate::formats::item_type::ItemType;
1314
use crate::json::types::*;
15+
use crate::json::JsonRenderer;
1416

15-
impl From<clean::Item> for Option<Item> {
16-
fn from(item: clean::Item) -> Self {
17+
impl JsonRenderer {
18+
pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
1719
let item_type = ItemType::from(&item);
1820
let clean::Item {
1921
source,
@@ -32,7 +34,7 @@ impl From<clean::Item> for Option<Item> {
3234
id: def_id.into(),
3335
crate_id: def_id.krate.as_u32(),
3436
name,
35-
source: source.into(),
37+
source: self.convert_span(source),
3638
visibility: visibility.into(),
3739
docs: attrs.collapsed_doc_value().unwrap_or_default(),
3840
links: attrs
@@ -53,22 +55,23 @@ impl From<clean::Item> for Option<Item> {
5355
}),
5456
}
5557
}
56-
}
5758

58-
impl From<clean::Span> for Option<Span> {
59-
fn from(span: clean::Span) -> Self {
60-
let clean::Span { loline, locol, hiline, hicol, .. } = span;
61-
match span.filename {
62-
rustc_span::FileName::Real(name) => Some(Span {
63-
filename: match name {
64-
rustc_span::RealFileName::Named(path) => path,
65-
rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => {
66-
local_path
67-
}
68-
},
69-
begin: (loline, locol),
70-
end: (hiline, hicol),
71-
}),
59+
fn convert_span(&self, span: clean::Span) -> Option<Span> {
60+
match span.filename(&self.sess) {
61+
rustc_span::FileName::Real(name) => {
62+
let hi = span.hi(&self.sess);
63+
let lo = span.lo(&self.sess);
64+
Some(Span {
65+
filename: match name {
66+
rustc_span::RealFileName::Named(path) => path,
67+
rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => {
68+
local_path
69+
}
70+
},
71+
begin: (lo.line, lo.col.to_usize()),
72+
end: (hi.line, hi.col.to_usize()),
73+
})
74+
}
7275
_ => None,
7376
}
7477
}

0 commit comments

Comments
 (0)