Auto merge of #81398 - bugadani:rustdoc-perf, r=GuillaumeGomez

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
commit 0248c6f178
16 changed files with 521 additions and 512 deletions

View File

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

View File

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

View File

@ -56,7 +56,7 @@ crate fn try_inline(
let kind = match res {
Res::Def(DefKind::Trait, did) => {
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))
}
Res::Def(DefKind::Fn, did) => {
@ -65,27 +65,27 @@ crate fn try_inline(
}
Res::Def(DefKind::Struct, did) => {
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))
}
Res::Def(DefKind::Union, did) => {
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))
}
Res::Def(DefKind::TyAlias, did) => {
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)
}
Res::Def(DefKind::Enum, did) => {
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))
}
Res::Def(DefKind::ForeignTy, did) => {
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
}
// Never inline enum variants but leave them shown as re-exports.
@ -133,10 +133,7 @@ crate fn try_inline_glob(
res: Res,
visited: &mut FxHashSet<DefId>,
) -> Option<Vec<clean::Item>> {
if res == Res::Err {
return None;
}
let did = res.def_id();
let did = res.opt_def_id()?;
if did.is_local() {
return None;
}
@ -280,16 +277,14 @@ crate fn build_impls(
parent_module: Option<DefId>,
did: DefId,
attrs: Option<Attrs<'_>>,
) -> Vec<clean::Item> {
ret: &mut Vec<clean::Item>,
) {
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 &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

View File

@ -8,6 +8,7 @@ use std::rc::Rc;
use std::sync::Arc;
use std::{slice, vec};
use arrayvec::ArrayVec;
use rustc_ast::attr;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_ast::{self as ast, AttrStyle};
@ -16,7 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
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::Mutability;
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_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use smallvec::{smallvec, SmallVec};
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
@ -45,7 +45,7 @@ use self::ItemKind::*;
use self::SelfTy::*;
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)]
crate struct Crate {
@ -293,8 +293,8 @@ impl Item {
///
/// [`next_def_id()`]: DocContext::next_def_id()
crate fn is_fake(&self) -> bool {
MAX_DEF_ID.with(|m| {
m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false)
MAX_DEF_IDX.with(|m| {
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")
}
crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> {
static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new();
crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>> {
static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<[DefId; 4]>>> = OnceCell::new();
CELL.get_or_init(move || {
use self::PrimitiveType::*;
@ -1568,7 +1568,7 @@ impl PrimitiveType {
}
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()
};
@ -1601,8 +1601,8 @@ impl PrimitiveType {
.collect()
},
Array => single(lang_items.array_impl()),
Tuple => smallvec![],
Unit => smallvec![],
Tuple => ArrayVec::new(),
Unit => ArrayVec::new(),
RawPointer => {
lang_items
.const_ptr_impl()
@ -1612,9 +1612,9 @@ impl PrimitiveType {
.chain(lang_items.mut_slice_ptr_impl())
.collect()
},
Reference => smallvec![],
Fn => smallvec![],
Never => smallvec![],
Reference => ArrayVec::new(),
Fn => ArrayVec::new(),
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_,
_ => continue,
};
let primitive = match *target {
ResolvedPath { did, .. } if did.is_local() => continue,
ResolvedPath { did, .. } => {
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() {
if let Some(prim) = target.primitive_type() {
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
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();
id_map.populate(html::render::initial_ids());
id_map.populate(&html::render::INITIAL_IDS);
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-in-header"),
&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::DUMMY_SP;
use std::cell::{Cell, RefCell};
use std::mem;
use std::rc::Rc;
use std::{
cell::{Cell, RefCell},
collections::hash_map::Entry,
};
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::{OutputFormat, RenderInfo};
use crate::formats::cache::Cache;
@ -63,8 +66,7 @@ crate struct DocContext<'tcx> {
crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
crate all_fake_def_ids: RefCell<FxHashSet<DefId>>,
crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefIndex>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
@ -138,37 +140,38 @@ impl<'tcx> DocContext<'tcx> {
/// [`Debug`]: std::fmt::Debug
/// [`clean::Item`]: crate::clean::types::Item
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 def_id = *fake_ids.entry(crate_num).or_insert(start_def_id);
fake_ids.insert(
crate_num,
DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) },
);
let def_index = match fake_ids.entry(crate_num) {
Entry::Vacant(e) => {
let num_def_idx = {
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| {
m.borrow_mut().entry(def_id.krate).or_insert(start_def_id);
});
DefIndex::from_usize(num_def_idx)
};
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.
/// (This avoids a slice-index-out-of-bounds panic.)
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
} else {
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(),
impl_trait_bounds: Default::default(),
fake_def_ids: Default::default(),
all_fake_def_ids: Default::default(),
generated_synthetics: Default::default(),
auto_traits: tcx
.all_traits(LOCAL_CRATE)

View File

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

View File

@ -7,7 +7,7 @@
use crate::html::escape::Escape;
use std::fmt::{Display, Write};
use std::fmt::Display;
use std::iter::Peekable;
use rustc_lexer::{LiteralKind, TokenKind};
@ -15,16 +15,18 @@ use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::with_default_session_globals;
use super::format::Buffer;
/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
src: String,
src: &str,
out: &mut Buffer,
class: Option<&str>,
playground_button: Option<&str>,
tooltip: Option<(Option<Edition>, &str)>,
edition: Edition,
) -> String {
) {
debug!("highlighting: ================\n{}\n==============", src);
let mut out = String::with_capacity(src.len());
if let Some((edition_info, class)) = tooltip {
write!(
out,
@ -35,23 +37,19 @@ crate fn render_with_highlighting(
} else {
String::new()
},
)
.unwrap();
);
}
write_header(&mut out, class);
write_code(&mut out, &src, edition);
write_footer(&mut out, playground_button);
out
write_header(out, class);
write_code(out, &src, edition);
write_footer(out, playground_button);
}
fn write_header(out: &mut String, class: Option<&str>) {
write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default())
.unwrap()
fn write_header(out: &mut Buffer, class: Option<&str>) {
write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default());
}
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.
let src = src.replace("\r\n", "\n");
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>) {
write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default()).unwrap()
fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default());
}
/// 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.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut String, klass: Class) {
write!(out, "<span class=\"{}\">", klass.as_html()).unwrap()
fn enter_span(out: &mut Buffer, klass: Class) {
write!(out, "<span class=\"{}\">", klass.as_html());
}
/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut String) {
write!(out, "</span>").unwrap()
fn exit_span(out: &mut Buffer) {
out.write_str("</span>");
}
/// 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
/// 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 {
None => write!(out, "{}", text).unwrap(),
Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text).unwrap(),
None => write!(out, "{}", text),
Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text),
}
}

View File

@ -1,4 +1,5 @@
use super::write_code;
use crate::html::format::Buffer;
use expect_test::expect_file;
use rustc_span::edition::Edition;
@ -18,9 +19,9 @@ const STYLE: &str = r#"
fn test_html_highlighting() {
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = String::new();
let mut out = Buffer::new();
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);
}
@ -30,7 +31,7 @@ fn test_dos_backline() {
let src = "pub fn foo() {\r\n\
println!(\"foo\");\r\n\
}\r\n";
let mut html = String::new();
let mut html = Buffer::new();
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}\
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\"></div>
<script src=\"{static_root_path}main{suffix}.js\"></script>\
{static_extra_scripts}\
{extra_scripts}\
<script defer src=\"{root_path}search-index{suffix}.js\"></script>\
</body>\
@ -135,22 +134,23 @@ crate fn render<T: Print, S: Print>(
root_path = page.root_path,
css_class = page.css_class,
logo = {
let p = format!("{}{}", page.root_path, layout.krate);
let p = ensure_trailing_slash(&p);
if layout.logo.is_empty() {
format!(
"<a href='{path}index.html'>\
"<a href='{root}{path}index.html'>\
<div class='logo-container rust-logo'>\
<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,
suffix = page.resource_suffix
)
} else {
format!(
"<a href='{}index.html'>\
<div class='logo-container'><img src='{}' alt='logo'></div></a>",
p, layout.logo
"<a href='{root}{path}index.html'>\
<div class='logo-container'><img src='{logo}' alt='logo'></div></a>",
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>(),
suffix = page.resource_suffix,
static_extra_scripts = page
extra_scripts = page
.static_extra_scripts
.iter()
.map(|e| {
@ -204,17 +204,13 @@ crate fn render<T: Print, S: Print>(
extra_script = e
)
})
.collect::<String>(),
extra_scripts = page
.extra_scripts
.iter()
.map(|e| {
.chain(page.extra_scripts.iter().map(|e| {
format!(
"<script src=\"{root_path}{extra_script}.js\"></script>",
root_path = page.root_path,
extra_script = e
)
})
}))
.collect::<String>(),
filter_crates = if layout.generate_search_filter {
"<select id=\"crate-search\">\

View File

@ -41,6 +41,8 @@ use pulldown_cmark::{
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag,
};
use super::format::Buffer;
#[cfg(test)]
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 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 krate = &playground.crate_name;
let url = &playground.url;
@ -298,8 +298,13 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
None
};
s.push_str(&highlight::render_with_highlighting(
text,
// insert newline to clearly separate it from the
// 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!(
"rust-example-rendered{}",
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(),
tooltip,
edition,
));
Some(Event::Html(s.into()))
);
Some(Event::Html(s.into_inner().into()))
}
}
@ -1332,7 +1337,7 @@ impl IdMap {
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 {
let _ = self.derive(id);
}
@ -1342,11 +1347,11 @@ impl IdMap {
self.map = init_id_map();
}
crate fn derive(&mut self, candidate: String) -> String {
let id = match self.map.get_mut(&candidate) {
None => candidate,
crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
let id = match self.map.get_mut(candidate.as_ref()) {
None => candidate.to_string(),
Some(a) => {
let id = format!("{}-{}", candidate, *a);
let id = format!("{}-{}", candidate.as_ref(), *a);
*a += 1;
id
}

File diff suppressed because it is too large Load Diff

View File

@ -86,7 +86,7 @@ impl SourceCollector<'_, '_> {
return Ok(());
}
let mut contents = match fs::read_to_string(&p) {
let contents = match fs::read_to_string(&p) {
Ok(contents) => contents,
Err(e) => {
return Err(Error::new(e, &p));
@ -94,9 +94,7 @@ impl SourceCollector<'_, '_> {
};
// Remove the utf-8 BOM if any
if contents.starts_with('\u{feff}') {
contents.drain(..3);
}
let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
// Create the intermediate directories
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
/// 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 mut cols = 0;
let mut tmp = lines;
@ -179,10 +177,10 @@ fn print_src(buf: &mut Buffer, s: String, edition: Edition) {
cols += 1;
tmp /= 10;
}
write!(buf, "<pre class=\"line-numbers\">");
buf.write_str("<pre class=\"line-numbers\">");
for i in 1..=lines {
write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
}
write!(buf, "</pre>");
write!(buf, "{}", highlight::render_with_highlighting(s, None, None, None, edition));
buf.write_str("</pre>");
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`
// 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 &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(|| {
let mut extra_attrs = Vec::new();
let mut parent = cx.tcx.parent(impl_did.to_def_id());
let mut parent = cx.tcx.parent(impl_did);
while let Some(did) = parent {
extra_attrs.extend(
cx.tcx
@ -79,13 +79,8 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
);
parent = cx.tcx.parent(did);
}
inline::build_impl(
cx,
None,
impl_did.to_def_id(),
Some(&extra_attrs),
&mut new_items,
);
inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items);
extra_attrs.clear();
});
}
}
@ -137,25 +132,28 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
}
}
new_items.retain(|it| {
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 {
let items = if let Some(ref mut it) = krate.module {
if let ModuleItem(Module { ref mut items, .. }) = *it.kind {
items.extend(synth.impls);
items.extend(new_items);
items
} else {
panic!("collect-trait-impls can't run");
}
} else {
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