1
Fork 0

rustdoc tweaking

* Reuse memory
* simplify `next_def_id`, avoid multiple hashing and unnecessary lookups
* remove `all_fake_def_ids`, use the global map instead (probably not a good step toward parallelization, though...)
* convert `add_deref_target` to iterative implementation
* use `ArrayVec` where we know the max number of elements
* minor touchups here and there
* avoid building temporary vectors that get appended to other vectors

At most places I may or may not be doing the compiler's job is this PR.
This commit is contained in:
bors 2021-01-30 01:02:18 +00:00
parent c6bc46227a
commit 4b80687854
16 changed files with 521 additions and 512 deletions

View file

@ -4386,6 +4386,7 @@ dependencies = [
name = "rustdoc" name = "rustdoc"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec",
"expect-test", "expect-test",
"itertools 0.9.0", "itertools 0.9.0",
"minifier", "minifier",

View file

@ -8,6 +8,7 @@ edition = "2018"
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
arrayvec = { version = "0.5.1", default-features = false }
pulldown-cmark = { version = "0.8", default-features = false } pulldown-cmark = { version = "0.8", default-features = false }
minifier = "0.0.33" minifier = "0.0.33"
rayon = { version = "0.3.0", package = "rustc-rayon" } rayon = { version = "0.3.0", package = "rustc-rayon" }

View file

@ -56,7 +56,7 @@ crate fn try_inline(
let kind = match res { let kind = match res {
Res::Def(DefKind::Trait, did) => { Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Trait); record_extern_fqn(cx, did, clean::TypeKind::Trait);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::TraitItem(build_external_trait(cx, did)) clean::TraitItem(build_external_trait(cx, did))
} }
Res::Def(DefKind::Fn, did) => { Res::Def(DefKind::Fn, did) => {
@ -65,27 +65,27 @@ crate fn try_inline(
} }
Res::Def(DefKind::Struct, did) => { Res::Def(DefKind::Struct, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Struct); record_extern_fqn(cx, did, clean::TypeKind::Struct);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::StructItem(build_struct(cx, did)) clean::StructItem(build_struct(cx, did))
} }
Res::Def(DefKind::Union, did) => { Res::Def(DefKind::Union, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Union); record_extern_fqn(cx, did, clean::TypeKind::Union);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::UnionItem(build_union(cx, did)) clean::UnionItem(build_union(cx, did))
} }
Res::Def(DefKind::TyAlias, did) => { Res::Def(DefKind::TyAlias, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Typedef); record_extern_fqn(cx, did, clean::TypeKind::Typedef);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::TypedefItem(build_type_alias(cx, did), false) clean::TypedefItem(build_type_alias(cx, did), false)
} }
Res::Def(DefKind::Enum, did) => { Res::Def(DefKind::Enum, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Enum); record_extern_fqn(cx, did, clean::TypeKind::Enum);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::EnumItem(build_enum(cx, did)) clean::EnumItem(build_enum(cx, did))
} }
Res::Def(DefKind::ForeignTy, did) => { Res::Def(DefKind::ForeignTy, did) => {
record_extern_fqn(cx, did, clean::TypeKind::Foreign); record_extern_fqn(cx, did, clean::TypeKind::Foreign);
ret.extend(build_impls(cx, Some(parent_module), did, attrs)); build_impls(cx, Some(parent_module), did, attrs, &mut ret);
clean::ForeignTypeItem clean::ForeignTypeItem
} }
// Never inline enum variants but leave them shown as re-exports. // Never inline enum variants but leave them shown as re-exports.
@ -133,10 +133,7 @@ crate fn try_inline_glob(
res: Res, res: Res,
visited: &mut FxHashSet<DefId>, visited: &mut FxHashSet<DefId>,
) -> Option<Vec<clean::Item>> { ) -> Option<Vec<clean::Item>> {
if res == Res::Err { let did = res.opt_def_id()?;
return None;
}
let did = res.def_id();
if did.is_local() { if did.is_local() {
return None; return None;
} }
@ -280,16 +277,14 @@ crate fn build_impls(
parent_module: Option<DefId>, parent_module: Option<DefId>,
did: DefId, did: DefId,
attrs: Option<Attrs<'_>>, attrs: Option<Attrs<'_>>,
) -> Vec<clean::Item> { ret: &mut Vec<clean::Item>,
) {
let tcx = cx.tcx; let tcx = cx.tcx;
let mut impls = Vec::new();
// for each implementation of an item represented by `did`, build the clean::Item for that impl // for each implementation of an item represented by `did`, build the clean::Item for that impl
for &did in tcx.inherent_impls(did).iter() { for &did in tcx.inherent_impls(did).iter() {
build_impl(cx, parent_module, did, attrs, &mut impls); build_impl(cx, parent_module, did, attrs, ret);
} }
impls
} }
/// `parent_module` refers to the parent of the re-export, not the original item /// `parent_module` refers to the parent of the re-export, not the original item

View file

@ -8,6 +8,7 @@ use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::{slice, vec}; use std::{slice, vec};
use arrayvec::ArrayVec;
use rustc_ast::attr; use rustc_ast::attr;
use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::util::comments::beautify_doc_string;
use rustc_ast::{self as ast, AttrStyle}; use rustc_ast::{self as ast, AttrStyle};
@ -16,7 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures; use rustc_feature::UnstableFeatures;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Res}; use rustc_hir::def::{CtorKind, Res};
use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
@ -28,7 +29,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
use rustc_span::{self, FileName, Loc}; use rustc_span::{self, FileName, Loc};
use rustc_target::abi::VariantIdx; use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use smallvec::{smallvec, SmallVec};
use crate::clean::cfg::Cfg; use crate::clean::cfg::Cfg;
use crate::clean::external_path; use crate::clean::external_path;
@ -45,7 +45,7 @@ use self::ItemKind::*;
use self::SelfTy::*; use self::SelfTy::*;
use self::Type::*; use self::Type::*;
thread_local!(crate static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default()); thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
crate struct Crate { crate struct Crate {
@ -293,8 +293,8 @@ impl Item {
/// ///
/// [`next_def_id()`]: DocContext::next_def_id() /// [`next_def_id()`]: DocContext::next_def_id()
crate fn is_fake(&self) -> bool { crate fn is_fake(&self) -> bool {
MAX_DEF_ID.with(|m| { MAX_DEF_IDX.with(|m| {
m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false) m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
}) })
} }
} }
@ -1539,12 +1539,12 @@ impl PrimitiveType {
} }
} }
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> { crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<[DefId; 4]> {
Self::all_impls(tcx).get(self).expect("missing impl for primitive type") Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
} }
crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> { crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>> {
static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new(); static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>>> = OnceCell::new();
CELL.get_or_init(move || { CELL.get_or_init(move || {
use self::PrimitiveType::*; use self::PrimitiveType::*;
@ -1568,7 +1568,7 @@ impl PrimitiveType {
} }
let single = |a: Option<DefId>| a.into_iter().collect(); let single = |a: Option<DefId>| a.into_iter().collect();
let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> { let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_> {
a.into_iter().chain(b).collect() a.into_iter().chain(b).collect()
}; };
@ -1601,8 +1601,8 @@ impl PrimitiveType {
.collect() .collect()
}, },
Array => single(lang_items.array_impl()), Array => single(lang_items.array_impl()),
Tuple => smallvec![], Tuple => ArrayVec::new(),
Unit => smallvec![], Unit => ArrayVec::new(),
RawPointer => { RawPointer => {
lang_items lang_items
.const_ptr_impl() .const_ptr_impl()
@ -1612,9 +1612,9 @@ impl PrimitiveType {
.chain(lang_items.mut_slice_ptr_impl()) .chain(lang_items.mut_slice_ptr_impl())
.collect() .collect()
}, },
Reference => smallvec![], Reference => ArrayVec::new(),
Fn => smallvec![], Fn => ArrayVec::new(),
Never => smallvec![], Never => ArrayVec::new(),
} }
}) })
} }

View file

@ -322,21 +322,15 @@ crate fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut
ItemKind::TypedefItem(ref t, true) => &t.type_, ItemKind::TypedefItem(ref t, true) => &t.type_,
_ => continue, _ => continue,
}; };
let primitive = match *target {
ResolvedPath { did, .. } if did.is_local() => continue, if let Some(prim) = target.primitive_type() {
ResolvedPath { did, .. } => { for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
ret.extend(inline::build_impls(cx, None, did, None));
continue;
}
_ => match target.primitive_type() {
Some(prim) => prim,
None => continue,
},
};
for &did in primitive.impls(tcx) {
if !did.is_local() {
inline::build_impl(cx, None, did, None, ret); inline::build_impl(cx, None, did, None, ret);
} }
} else if let ResolvedPath { did, .. } = *target {
if !did.is_local() {
inline::build_impls(cx, None, did, None, ret);
}
} }
} }
} }

View file

@ -474,7 +474,7 @@ impl Options {
}; };
let mut id_map = html::markdown::IdMap::new(); let mut id_map = html::markdown::IdMap::new();
id_map.populate(html::render::initial_ids()); id_map.populate(&html::render::INITIAL_IDS);
let external_html = match ExternalHtml::load( let external_html = match ExternalHtml::load(
&matches.opt_strs("html-in-header"), &matches.opt_strs("html-in-header"),
&matches.opt_strs("html-before-content"), &matches.opt_strs("html-before-content"),

View file

@ -24,12 +24,15 @@ use rustc_span::source_map;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use std::cell::{Cell, RefCell};
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::{
cell::{Cell, RefCell},
collections::hash_map::Entry,
};
use crate::clean; use crate::clean;
use crate::clean::{AttributesExt, MAX_DEF_ID}; use crate::clean::{AttributesExt, MAX_DEF_IDX};
use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::config::{Options as RustdocOptions, RenderOptions};
use crate::config::{OutputFormat, RenderInfo}; use crate::config::{OutputFormat, RenderInfo};
use crate::formats::cache::Cache; use crate::formats::cache::Cache;
@ -63,8 +66,7 @@ crate struct DocContext<'tcx> {
crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>, crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>, crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>, crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefIndex>>,
crate all_fake_def_ids: RefCell<FxHashSet<DefId>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>, crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
@ -138,37 +140,38 @@ impl<'tcx> DocContext<'tcx> {
/// [`Debug`]: std::fmt::Debug /// [`Debug`]: std::fmt::Debug
/// [`clean::Item`]: crate::clean::types::Item /// [`clean::Item`]: crate::clean::types::Item
crate fn next_def_id(&self, crate_num: CrateNum) -> DefId { crate fn next_def_id(&self, crate_num: CrateNum) -> DefId {
let start_def_id = {
let num_def_ids = if crate_num == LOCAL_CRATE {
self.tcx.hir().definitions().def_path_table().num_def_ids()
} else {
self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
};
DefId { krate: crate_num, index: DefIndex::from_usize(num_def_ids) }
};
let mut fake_ids = self.fake_def_ids.borrow_mut(); let mut fake_ids = self.fake_def_ids.borrow_mut();
let def_id = *fake_ids.entry(crate_num).or_insert(start_def_id); let def_index = match fake_ids.entry(crate_num) {
fake_ids.insert( Entry::Vacant(e) => {
crate_num, let num_def_idx = {
DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) }, let num_def_idx = if crate_num == LOCAL_CRATE {
); self.tcx.hir().definitions().def_path_table().num_def_ids()
} else {
self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
};
MAX_DEF_ID.with(|m| { DefIndex::from_usize(num_def_idx)
m.borrow_mut().entry(def_id.krate).or_insert(start_def_id); };
});
self.all_fake_def_ids.borrow_mut().insert(def_id); MAX_DEF_IDX.with(|m| {
m.borrow_mut().insert(crate_num, num_def_idx);
});
e.insert(num_def_idx)
}
Entry::Occupied(e) => e.into_mut(),
};
*def_index = DefIndex::from(*def_index + 1);
def_id DefId { krate: crate_num, index: *def_index }
} }
/// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds. /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
/// (This avoids a slice-index-out-of-bounds panic.) /// (This avoids a slice-index-out-of-bounds panic.)
crate fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> { crate fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> {
if self.all_fake_def_ids.borrow().contains(&def_id) { if MAX_DEF_IDX.with(|m| {
m.borrow().get(&def_id.krate).map(|&idx| idx <= def_id.index).unwrap_or(false)
}) {
None None
} else { } else {
def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
@ -517,7 +520,6 @@ crate fn run_global_ctxt(
ct_substs: Default::default(), ct_substs: Default::default(),
impl_trait_bounds: Default::default(), impl_trait_bounds: Default::default(),
fake_def_ids: Default::default(), fake_def_ids: Default::default(),
all_fake_def_ids: Default::default(),
generated_synthetics: Default::default(), generated_synthetics: Default::default(),
auto_traits: tcx auto_traits: tcx
.all_traits(LOCAL_CRATE) .all_traits(LOCAL_CRATE)

View file

@ -158,6 +158,6 @@ impl ItemType {
impl fmt::Display for ItemType { impl fmt::Display for ItemType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str()) f.write_str(self.as_str())
} }
} }

View file

@ -16,23 +16,20 @@ impl<'a> fmt::Display for Escape<'a> {
let Escape(s) = *self; let Escape(s) = *self;
let pile_o_bits = s; let pile_o_bits = s;
let mut last = 0; let mut last = 0;
for (i, ch) in s.bytes().enumerate() { for (i, ch) in s.char_indices() {
match ch as char { let s = match ch {
'<' | '>' | '&' | '\'' | '"' => { '>' => "&gt;",
fmt.write_str(&pile_o_bits[last..i])?; '<' => "&lt;",
let s = match ch as char { '&' => "&amp;",
'>' => "&gt;", '\'' => "&#39;",
'<' => "&lt;", '"' => "&quot;",
'&' => "&amp;", _ => continue,
'\'' => "&#39;", };
'"' => "&quot;", fmt.write_str(&pile_o_bits[last..i])?;
_ => unreachable!(), fmt.write_str(s)?;
}; // NOTE: we only expect single byte characters here - which is fine as long as we
fmt.write_str(s)?; // only match single byte characters
last = i + 1; last = i + 1;
}
_ => {}
}
} }
if last < s.len() { if last < s.len() {

View file

@ -7,7 +7,7 @@
use crate::html::escape::Escape; use crate::html::escape::Escape;
use std::fmt::{Display, Write}; use std::fmt::Display;
use std::iter::Peekable; use std::iter::Peekable;
use rustc_lexer::{LiteralKind, TokenKind}; use rustc_lexer::{LiteralKind, TokenKind};
@ -15,16 +15,18 @@ use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::with_default_session_globals; use rustc_span::with_default_session_globals;
use super::format::Buffer;
/// Highlights `src`, returning the HTML output. /// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting( crate fn render_with_highlighting(
src: String, src: &str,
out: &mut Buffer,
class: Option<&str>, class: Option<&str>,
playground_button: Option<&str>, playground_button: Option<&str>,
tooltip: Option<(Option<Edition>, &str)>, tooltip: Option<(Option<Edition>, &str)>,
edition: Edition, edition: Edition,
) -> String { ) {
debug!("highlighting: ================\n{}\n==============", src); debug!("highlighting: ================\n{}\n==============", src);
let mut out = String::with_capacity(src.len());
if let Some((edition_info, class)) = tooltip { if let Some((edition_info, class)) = tooltip {
write!( write!(
out, out,
@ -35,23 +37,19 @@ crate fn render_with_highlighting(
} else { } else {
String::new() String::new()
}, },
) );
.unwrap();
} }
write_header(&mut out, class); write_header(out, class);
write_code(&mut out, &src, edition); write_code(out, &src, edition);
write_footer(&mut out, playground_button); write_footer(out, playground_button);
out
} }
fn write_header(out: &mut String, class: Option<&str>) { fn write_header(out: &mut Buffer, class: Option<&str>) {
write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default()) write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default());
.unwrap()
} }
fn write_code(out: &mut String, src: &str, edition: Edition) { fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
// This replace allows to fix how the code source with DOS backline characters is displayed. // This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n"); let src = src.replace("\r\n", "\n");
Classifier::new(&src, edition).highlight(&mut |highlight| { Classifier::new(&src, edition).highlight(&mut |highlight| {
@ -63,8 +61,8 @@ fn write_code(out: &mut String, src: &str, edition: Edition) {
}); });
} }
fn write_footer(out: &mut String, playground_button: Option<&str>) { fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default()).unwrap() write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default());
} }
/// How a span of text is classified. Mostly corresponds to token kinds. /// How a span of text is classified. Mostly corresponds to token kinds.
@ -331,13 +329,13 @@ impl<'a> Classifier<'a> {
/// Called when we start processing a span of text that should be highlighted. /// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted. /// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut String, klass: Class) { fn enter_span(out: &mut Buffer, klass: Class) {
write!(out, "<span class=\"{}\">", klass.as_html()).unwrap() write!(out, "<span class=\"{}\">", klass.as_html());
} }
/// Called at the end of a span of highlighted text. /// Called at the end of a span of highlighted text.
fn exit_span(out: &mut String) { fn exit_span(out: &mut Buffer) {
write!(out, "</span>").unwrap() out.write_str("</span>");
} }
/// Called for a span of text. If the text should be highlighted differently /// Called for a span of text. If the text should be highlighted differently
@ -351,10 +349,10 @@ fn exit_span(out: &mut String) {
/// ``` /// ```
/// The latter can be thought of as a shorthand for the former, which is more /// The latter can be thought of as a shorthand for the former, which is more
/// flexible. /// flexible.
fn string<T: Display>(out: &mut String, text: T, klass: Option<Class>) { fn string<T: Display>(out: &mut Buffer, text: T, klass: Option<Class>) {
match klass { match klass {
None => write!(out, "{}", text).unwrap(), None => write!(out, "{}", text),
Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text).unwrap(), Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text),
} }
} }

View file

@ -1,4 +1,5 @@
use super::write_code; use super::write_code;
use crate::html::format::Buffer;
use expect_test::expect_file; use expect_test::expect_file;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -18,9 +19,9 @@ const STYLE: &str = r#"
fn test_html_highlighting() { fn test_html_highlighting() {
let src = include_str!("fixtures/sample.rs"); let src = include_str!("fixtures/sample.rs");
let html = { let html = {
let mut out = String::new(); let mut out = Buffer::new();
write_code(&mut out, src, Edition::Edition2018); write_code(&mut out, src, Edition::Edition2018);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out) format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
}; };
expect_file!["fixtures/sample.html"].assert_eq(&html); expect_file!["fixtures/sample.html"].assert_eq(&html);
} }
@ -30,7 +31,7 @@ fn test_dos_backline() {
let src = "pub fn foo() {\r\n\ let src = "pub fn foo() {\r\n\
println!(\"foo\");\r\n\ println!(\"foo\");\r\n\
}\r\n"; }\r\n";
let mut html = String::new(); let mut html = Buffer::new();
write_code(&mut html, src, Edition::Edition2018); write_code(&mut html, src, Edition::Edition2018);
expect_file!["fixtures/dos_line.html"].assert_eq(&html); expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
} }

View file

@ -114,7 +114,6 @@ crate fn render<T: Print, S: Print>(
{after_content}\ {after_content}\
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\"></div> <div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\"></div>
<script src=\"{static_root_path}main{suffix}.js\"></script>\ <script src=\"{static_root_path}main{suffix}.js\"></script>\
{static_extra_scripts}\
{extra_scripts}\ {extra_scripts}\
<script defer src=\"{root_path}search-index{suffix}.js\"></script>\ <script defer src=\"{root_path}search-index{suffix}.js\"></script>\
</body>\ </body>\
@ -135,22 +134,23 @@ crate fn render<T: Print, S: Print>(
root_path = page.root_path, root_path = page.root_path,
css_class = page.css_class, css_class = page.css_class,
logo = { logo = {
let p = format!("{}{}", page.root_path, layout.krate);
let p = ensure_trailing_slash(&p);
if layout.logo.is_empty() { if layout.logo.is_empty() {
format!( format!(
"<a href='{path}index.html'>\ "<a href='{root}{path}index.html'>\
<div class='logo-container rust-logo'>\ <div class='logo-container rust-logo'>\
<img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>", <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
path = p, root = page.root_path,
path = ensure_trailing_slash(&layout.krate),
static_root_path = static_root_path, static_root_path = static_root_path,
suffix = page.resource_suffix suffix = page.resource_suffix
) )
} else { } else {
format!( format!(
"<a href='{}index.html'>\ "<a href='{root}{path}index.html'>\
<div class='logo-container'><img src='{}' alt='logo'></div></a>", <div class='logo-container'><img src='{logo}' alt='logo'></div></a>",
p, layout.logo root = page.root_path,
path = ensure_trailing_slash(&layout.krate),
logo = layout.logo
) )
} }
}, },
@ -194,7 +194,7 @@ crate fn render<T: Print, S: Print>(
)) ))
.collect::<String>(), .collect::<String>(),
suffix = page.resource_suffix, suffix = page.resource_suffix,
static_extra_scripts = page extra_scripts = page
.static_extra_scripts .static_extra_scripts
.iter() .iter()
.map(|e| { .map(|e| {
@ -204,17 +204,13 @@ crate fn render<T: Print, S: Print>(
extra_script = e extra_script = e
) )
}) })
.collect::<String>(), .chain(page.extra_scripts.iter().map(|e| {
extra_scripts = page
.extra_scripts
.iter()
.map(|e| {
format!( format!(
"<script src=\"{root_path}{extra_script}.js\"></script>", "<script src=\"{root_path}{extra_script}.js\"></script>",
root_path = page.root_path, root_path = page.root_path,
extra_script = e extra_script = e
) )
}) }))
.collect::<String>(), .collect::<String>(),
filter_crates = if layout.generate_search_filter { filter_crates = if layout.generate_search_filter {
"<select id=\"crate-search\">\ "<select id=\"crate-search\">\

View file

@ -41,6 +41,8 @@ use pulldown_cmark::{
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag,
}; };
use super::format::Buffer;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -235,9 +237,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
} }
let lines = origtext.lines().filter_map(|l| map_line(l).for_html()); let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<Cow<'_, str>>>().join("\n"); let text = lines.collect::<Vec<Cow<'_, str>>>().join("\n");
// insert newline to clearly separate it from the
// previous block so we can shorten the html output
let mut s = String::from("\n");
let playground_button = self.playground.as_ref().and_then(|playground| { let playground_button = self.playground.as_ref().and_then(|playground| {
let krate = &playground.crate_name; let krate = &playground.crate_name;
let url = &playground.url; let url = &playground.url;
@ -298,8 +298,13 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
None None
}; };
s.push_str(&highlight::render_with_highlighting( // insert newline to clearly separate it from the
text, // previous block so we can shorten the html output
let mut s = Buffer::new();
s.push_str("\n");
highlight::render_with_highlighting(
&text,
&mut s,
Some(&format!( Some(&format!(
"rust-example-rendered{}", "rust-example-rendered{}",
if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() } if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
@ -307,8 +312,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
playground_button.as_deref(), playground_button.as_deref(),
tooltip, tooltip,
edition, edition,
)); );
Some(Event::Html(s.into())) Some(Event::Html(s.into_inner().into()))
} }
} }
@ -1332,7 +1337,7 @@ impl IdMap {
IdMap { map: init_id_map() } IdMap { map: init_id_map() }
} }
crate fn populate<I: IntoIterator<Item = String>>(&mut self, ids: I) { crate fn populate<I: IntoIterator<Item = S>, S: AsRef<str> + ToString>(&mut self, ids: I) {
for id in ids { for id in ids {
let _ = self.derive(id); let _ = self.derive(id);
} }
@ -1342,11 +1347,11 @@ impl IdMap {
self.map = init_id_map(); self.map = init_id_map();
} }
crate fn derive(&mut self, candidate: String) -> String { crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
let id = match self.map.get_mut(&candidate) { let id = match self.map.get_mut(candidate.as_ref()) {
None => candidate, None => candidate.to_string(),
Some(a) => { Some(a) => {
let id = format!("{}-{}", candidate, *a); let id = format!("{}-{}", candidate.as_ref(), *a);
*a += 1; *a += 1;
id id
} }

File diff suppressed because it is too large Load diff

View file

@ -86,7 +86,7 @@ impl SourceCollector<'_, '_> {
return Ok(()); return Ok(());
} }
let mut contents = match fs::read_to_string(&p) { let contents = match fs::read_to_string(&p) {
Ok(contents) => contents, Ok(contents) => contents,
Err(e) => { Err(e) => {
return Err(Error::new(e, &p)); return Err(Error::new(e, &p));
@ -94,9 +94,7 @@ impl SourceCollector<'_, '_> {
}; };
// Remove the utf-8 BOM if any // Remove the utf-8 BOM if any
if contents.starts_with('\u{feff}') { let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
contents.drain(..3);
}
// Create the intermediate directories // Create the intermediate directories
let mut cur = self.dst.clone(); let mut cur = self.dst.clone();
@ -171,7 +169,7 @@ where
/// Wrapper struct to render the source code of a file. This will do things like /// Wrapper struct to render the source code of a file. This will do things like
/// adding line numbers to the left-hand side. /// adding line numbers to the left-hand side.
fn print_src(buf: &mut Buffer, s: String, edition: Edition) { fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
let lines = s.lines().count(); let lines = s.lines().count();
let mut cols = 0; let mut cols = 0;
let mut tmp = lines; let mut tmp = lines;
@ -179,10 +177,10 @@ fn print_src(buf: &mut Buffer, s: String, edition: Edition) {
cols += 1; cols += 1;
tmp /= 10; tmp /= 10;
} }
write!(buf, "<pre class=\"line-numbers\">"); buf.write_str("<pre class=\"line-numbers\">");
for i in 1..=lines { for i in 1..=lines {
write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols); write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
} }
write!(buf, "</pre>"); buf.write_str("</pre>");
write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None, edition)); highlight::render_with_highlighting(s, buf, None, None, None, edition);
} }

View file

@ -56,12 +56,12 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations` // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
// doesn't work with it anyway, so pull them from the HIR map instead // doesn't work with it anyway, so pull them from the HIR map instead
let mut extra_attrs = Vec::new();
for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() { for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() {
for &impl_node in cx.tcx.hir().trait_impls(trait_did) { for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
let impl_did = cx.tcx.hir().local_def_id(impl_node); let impl_did = cx.tcx.hir().local_def_id(impl_node).to_def_id();
cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| { cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {
let mut extra_attrs = Vec::new(); let mut parent = cx.tcx.parent(impl_did);
let mut parent = cx.tcx.parent(impl_did.to_def_id());
while let Some(did) = parent { while let Some(did) = parent {
extra_attrs.extend( extra_attrs.extend(
cx.tcx cx.tcx
@ -79,13 +79,8 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
); );
parent = cx.tcx.parent(did); parent = cx.tcx.parent(did);
} }
inline::build_impl( inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items);
cx, extra_attrs.clear();
None,
impl_did.to_def_id(),
Some(&extra_attrs),
&mut new_items,
);
}); });
} }
} }
@ -137,25 +132,28 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
} }
} }
new_items.retain(|it| { let items = if let Some(ref mut it) = krate.module {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
cleaner.keep_impl(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
|| blanket_impl.is_some()
} else {
true
}
});
if let Some(ref mut it) = krate.module {
if let ModuleItem(Module { ref mut items, .. }) = *it.kind { if let ModuleItem(Module { ref mut items, .. }) = *it.kind {
items.extend(synth.impls); items
items.extend(new_items);
} else { } else {
panic!("collect-trait-impls can't run"); panic!("collect-trait-impls can't run");
} }
} else { } else {
panic!("collect-trait-impls can't run"); panic!("collect-trait-impls can't run");
};
items.extend(synth.impls);
for it in new_items.drain(..) {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
if !(cleaner.keep_impl(for_)
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
|| blanket_impl.is_some())
{
continue;
}
}
items.push(it);
} }
krate krate