diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ba792a413b3c4..ed82c522779eb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -136,94 +136,88 @@ pub struct Crate { pub collapsed: bool, } -impl Clean for hir::Crate { - // note that self here is ignored in favor of `cx.tcx.hir().krate()` since - // that gets around tying self's lifetime to the '_ in cx. - fn clean(&self, cx: &DocContext<'_>) -> Crate { - use crate::visit_lib::LibEmbargoVisitor; - - let v = crate::visit_ast::RustdocVisitor::new(&cx); - let module = v.visit(cx.tcx.hir().krate()); - - { - let mut r = cx.renderinfo.borrow_mut(); - r.deref_trait_did = cx.tcx.lang_items().deref_trait(); - r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - r.owned_box_did = cx.tcx.lang_items().owned_box(); - } - - let mut externs = Vec::new(); - for &cnum in cx.tcx.crates().iter() { - externs.push((cnum, cnum.clean(cx))); - // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); - } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - - // Clean the crate, translating the entire libsyntax AST to one that is - // understood by rustdoc. - let mut module = module.clean(cx); - let mut masked_crates = FxHashSet::default(); - - match module.inner { - ModuleItem(ref module) => { - for it in &module.items { - // `compiler_builtins` should be masked too, but we can't apply - // `#[doc(masked)]` to the injected `extern crate` because it's unstable. - if it.is_extern_crate() - && (it.attrs.has_doc_flag(sym::masked) - || cx.tcx.is_compiler_builtins(it.def_id.krate)) - { - masked_crates.insert(it.def_id.krate); - } +pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { + use crate::visit_lib::LibEmbargoVisitor; + + let krate = cx.tcx.hir().krate(); + let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); + + let mut r = cx.renderinfo.get_mut(); + r.deref_trait_did = cx.tcx.lang_items().deref_trait(); + r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); + r.owned_box_did = cx.tcx.lang_items().owned_box(); + + let mut externs = Vec::new(); + for &cnum in cx.tcx.crates().iter() { + externs.push((cnum, cnum.clean(cx))); + // Analyze doc-reachability for extern items + LibEmbargoVisitor::new(&mut cx).visit_lib(cnum); + } + externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + + // Clean the crate, translating the entire libsyntax AST to one that is + // understood by rustdoc. + let mut module = module.clean(cx); + let mut masked_crates = FxHashSet::default(); + + match module.inner { + ModuleItem(ref module) => { + for it in &module.items { + // `compiler_builtins` should be masked too, but we can't apply + // `#[doc(masked)]` to the injected `extern crate` because it's unstable. + if it.is_extern_crate() + && (it.attrs.has_doc_flag(sym::masked) + || cx.tcx.is_compiler_builtins(it.def_id.krate)) + { + masked_crates.insert(it.def_id.krate); } } - _ => unreachable!(), } + _ => unreachable!(), + } - let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); - { - let m = match module.inner { - ModuleItem(ref mut m) => m, - _ => unreachable!(), - }; - m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { - Item { - source: Span::empty(), - name: Some(prim.to_url_str().to_string()), - attrs: attrs.clone(), - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: PrimitiveItem(prim), - } - })); - m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { - Item { - source: Span::empty(), - name: Some(kw.clone()), - attrs: attrs, - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: KeywordItem(kw), - } - })); - } + let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); + { + let m = match module.inner { + ModuleItem(ref mut m) => m, + _ => unreachable!(), + }; + m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { + Item { + source: Span::empty(), + name: Some(prim.to_url_str().to_string()), + attrs: attrs.clone(), + visibility: Some(Public), + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: PrimitiveItem(prim), + } + })); + m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { + Item { + source: Span::empty(), + name: Some(kw.clone()), + attrs: attrs, + visibility: Some(Public), + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: KeywordItem(kw), + } + })); + } - Crate { - name, - version: None, - src, - module: Some(module), - externs, - primitives, - external_traits: cx.external_traits.clone(), - masked_crates, - collapsed: false, - } + Crate { + name, + version: None, + src, + module: Some(module), + externs, + primitives, + external_traits: cx.external_traits.clone(), + masked_crates, + collapsed: false, } } @@ -572,23 +566,6 @@ pub enum ItemEnum { } impl ItemEnum { - pub fn generics(&self) -> Option<&Generics> { - Some(match *self { - ItemEnum::StructItem(ref s) => &s.generics, - ItemEnum::EnumItem(ref e) => &e.generics, - ItemEnum::FunctionItem(ref f) => &f.generics, - ItemEnum::TypedefItem(ref t, _) => &t.generics, - ItemEnum::OpaqueTyItem(ref t, _) => &t.generics, - ItemEnum::TraitItem(ref t) => &t.generics, - ItemEnum::ImplItem(ref i) => &i.generics, - ItemEnum::TyMethodItem(ref i) => &i.generics, - ItemEnum::MethodItem(ref i) => &i.generics, - ItemEnum::ForeignFunctionItem(ref f) => &f.generics, - ItemEnum::TraitAliasItem(ref ta) => &ta.generics, - _ => return None, - }) - } - pub fn is_associated(&self) -> bool { match *self { ItemEnum::TypedefItem(_, _) | @@ -1541,8 +1518,6 @@ impl Clean for ty::GenericParamDef { (self.name.to_string(), GenericParamDefKind::Lifetime) } ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { - cx.renderinfo.borrow_mut().external_param_names - .insert(self.def_id, self.name.clean(cx)); let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 04e69613d4b0f..45ebaa115063a 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -30,7 +30,7 @@ use std::rc::Rc; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{Clean, MAX_DEF_ID, AttributesExt}; +use crate::clean::{MAX_DEF_ID, AttributesExt}; use crate::html::render::RenderInfo; use crate::passes; @@ -363,7 +363,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut renderinfo = RenderInfo::default(); renderinfo.access_levels = access_levels; - let ctxt = DocContext { + let mut ctxt = DocContext { tcx, resolver, cstore: compiler.cstore().clone(), @@ -383,7 +383,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; debug!("crate: {:?}", tcx.hir().krate()); - let mut krate = tcx.hir().krate().clean(&ctxt); + let mut krate = clean::krate(&mut ctxt); fn report_deprecated_attr(name: &str, diag: &errors::Handler) { let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9c22837bdae87..313734e3fdd6b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -6,6 +6,7 @@ //! them in the future to instead emit any format desired. use std::borrow::Cow; +use std::cell::Cell; use std::fmt; use rustc::hir::def_id::DefId; @@ -15,7 +16,7 @@ use rustc::hir; use crate::clean::{self, PrimitiveType}; use crate::html::item_type::ItemType; -use crate::html::render::{self, cache, CURRENT_LOCATION_KEY}; +use crate::html::render::{self, cache, CURRENT_DEPTH}; /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) @@ -36,13 +37,8 @@ pub struct AsyncSpace(pub hir::IsAsync); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); -/// Similar to VisSpace, but used for mutability -#[derive(Copy, Clone)] -pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting type parameter bounds. pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]); -/// Wrapper struct for emitting a comma-separated list of items -pub struct CommaSep<'a, T>(pub &'a [T]); pub struct AbiSpace(pub Abi); pub struct DefaultSpace(pub bool); @@ -71,11 +67,6 @@ pub struct WhereClause<'a>{ pub end_newline: bool, } -pub struct HRef<'a> { - pub did: DefId, - pub text: &'a str, -} - impl<'a> VisSpace<'a> { pub fn get(self) -> &'a Option { let VisSpace(v) = self; v @@ -94,14 +85,14 @@ impl ConstnessSpace { } } -impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, item) in self.0.iter().enumerate() { +fn comma_sep(items: &[T]) -> impl fmt::Display + '_ { + display_fn(move |f| { + for (i, item) in items.iter().enumerate() { if i != 0 { write!(f, ", ")?; } fmt::Display::fmt(item, f)?; } Ok(()) - } + }) } impl<'a> fmt::Display for GenericBounds<'a> { @@ -168,9 +159,9 @@ impl fmt::Display for clean::Generics { return Ok(()); } if f.alternate() { - write!(f, "<{:#}>", CommaSep(&real_params)) + write!(f, "<{:#}>", comma_sep(&real_params)) } else { - write!(f, "<{}>", CommaSep(&real_params)) + write!(f, "<{}>", comma_sep(&real_params)) } } } @@ -268,9 +259,9 @@ impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if !self.generic_params.is_empty() { if f.alternate() { - write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?; + write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?; } else { - write!(f, "for<{}> ", CommaSep(&self.generic_params))?; + write!(f, "for<{}> ", comma_sep(&self.generic_params))?; } } if f.alternate() { @@ -407,16 +398,16 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { return None } - let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); + let depth = CURRENT_DEPTH.with(|l| l.get()); let (fqp, shortty, mut url) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => { - (fqp, shortty, "../".repeat(loc.len())) + (fqp, shortty, "../".repeat(depth)) } None => { let &(ref fqp, shortty) = cache.external_paths.get(&did)?; (fqp, shortty, match cache.extern_locations[&did.krate] { (.., render::Remote(ref s)) => s.to_string(), - (.., render::Local) => "../".repeat(loc.len()), + (.., render::Local) => "../".repeat(depth), (.., render::Unknown) => return None, }) } @@ -452,19 +443,18 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, } } if w.alternate() { - write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?; + write!(w, "{}{:#}", &last.name, last.args)?; } else { let path = if use_absolute { - match href(did) { - Some((_, _, fqp)) => { - format!("{}::{}", - fqp[..fqp.len() - 1].join("::"), - HRef::new(did, fqp.last().unwrap())) - } - None => HRef::new(did, &last.name).to_string(), + if let Some((_, _, fqp)) = href(did) { + format!("{}::{}", + fqp[..fqp.len() - 1].join("::"), + anchor(did, fqp.last().unwrap())) + } else { + last.name.to_string() } } else { - HRef::new(did, &last.name).to_string() + anchor(did, &last.name).to_string() }; write!(w, "{}{}", path, last.args)?; } @@ -479,7 +469,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, if !f.alternate() { match m.primitive_locations.get(&prim) { Some(&def_id) if def_id.is_local() => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); let len = if len == 0 {0} else {len - 1}; write!(f, "", "../".repeat(len), @@ -492,7 +482,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, Some((cname, s.to_string())) } (ref cname, _, render::Local) => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); Some((cname, "../".repeat(len))) } (.., render::Unknown) => None, @@ -516,38 +506,30 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, } /// Helper to render type parameters -fn tybounds(w: &mut fmt::Formatter<'_>, - param_names: &Option>) -> fmt::Result { - match *param_names { - Some(ref params) => { - for param in params { - write!(w, " + ")?; - fmt::Display::fmt(param, w)?; +fn tybounds(param_names: &Option>) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *param_names { + Some(ref params) => { + for param in params { + write!(f, " + ")?; + fmt::Display::fmt(param, f)?; + } + Ok(()) } - Ok(()) + None => Ok(()) } - None => Ok(()) - } -} - -impl<'a> HRef<'a> { - pub fn new(did: DefId, text: &'a str) -> HRef<'a> { - HRef { did: did, text: text } - } + }) } -impl<'a> fmt::Display for HRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match href(self.did) { - Some((url, shortty, fqp)) => if !f.alternate() { - write!(f, "{}", - shortty, url, shortty, fqp.join("::"), self.text) - } else { - write!(f, "{}", self.text) - }, - _ => write!(f, "{}", self.text), +pub fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ { + display_fn(move |f| { + if let Some((url, short_ty, fqp)) = href(did) { + write!(f, r#"{}"#, + short_ty, url, short_ty, fqp.join("::"), text) + } else { + write!(f, "{}", text) } - } + }) } fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result { @@ -561,7 +543,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } // Paths like `T::Output` and `Self::Output` should be rendered with all segments. resolved_path(f, did, path, is_generic, use_absolute)?; - tybounds(f, param_names) + fmt::Display::fmt(&tybounds(param_names), f) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), @@ -570,12 +552,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> write!(f, "{}{:#}fn{:#}{:#}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi), - CommaSep(&decl.generic_params), + comma_sep(&decl.generic_params), decl.decl) } else { write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; primitive_link(f, PrimitiveType::Fn, "fn")?; - write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl) + write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl) } } clean::Tuple(ref typs) => { @@ -589,7 +571,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } many => { primitive_link(f, PrimitiveType::Tuple, "(")?; - fmt::Display::fmt(&CommaSep(many), f)?; + fmt::Display::fmt(&comma_sep(many), f)?; primitive_link(f, PrimitiveType::Tuple, ")") } } @@ -607,19 +589,22 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Never => primitive_link(f, PrimitiveType::Never, "!"), clean::CVarArgs => primitive_link(f, PrimitiveType::CVarArgs, "..."), clean::RawPointer(m, ref t) => { + let m = match m { + clean::Immutable => "const", + clean::Mutable => "mut", + }; match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { if f.alternate() { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{:#}", RawMutableSpace(m), t)) + &format!("*{} {:#}", m, t)) } else { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{}", RawMutableSpace(m), t)) + &format!("*{} {}", m, t)) } } _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}", RawMutableSpace(m)))?; + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?; fmt::Display::fmt(t, f) } } @@ -1047,15 +1032,6 @@ impl fmt::Display for MutableSpace { } } -impl fmt::Display for RawMutableSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - RawMutableSpace(clean::Immutable) => write!(f, "const "), - RawMutableSpace(clean::Mutable) => write!(f, "mut "), - } - } -} - impl fmt::Display for AbiSpace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let quot = if f.alternate() { "\"" } else { """ }; @@ -1075,3 +1051,19 @@ impl fmt::Display for DefaultSpace { } } } + +crate fn display_fn( + f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +) -> impl fmt::Display { + WithFormatter(Cell::new(Some(f))) +} + +struct WithFormatter(Cell>); + +impl fmt::Display for WithFormatter + where F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0.take()).unwrap()(f) + } +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 5a7deb651b00d..74413a7f905d4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -785,10 +785,6 @@ impl MarkdownSummaryLine<'_> { } pub fn plain_summary_line(md: &str) -> String { - plain_summary_line_full(md, false) -} - -pub fn plain_summary_line_full(md: &str, limit_length: bool) -> String { struct ParserWrapper<'a> { inner: Parser<'a>, is_in: isize, @@ -834,21 +830,7 @@ pub fn plain_summary_line_full(md: &str, limit_length: bool) -> String { s.push_str(&t); } } - if limit_length && s.chars().count() > 60 { - let mut len = 0; - let mut ret = s.split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::>() - .join(" "); - ret.push('…'); - ret - } else { - s - } + s } pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b64e74468e6e9..2a4a2fcea5838 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -28,7 +28,7 @@ pub use self::ExternalLocation::*; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; use std::default::Default; @@ -72,6 +72,7 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::item_type::ItemType; use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap}; use crate::html::{highlight, layout, static_files}; +use crate::html::sources; use minifier; @@ -173,7 +174,7 @@ struct Context { playground: Option, } -struct SharedContext { +crate struct SharedContext { /// The path to the crate root source minus the file name. /// Used for simplifying paths to the highlighted source code files. pub src_root: PathBuf, @@ -218,7 +219,7 @@ struct SharedContext { } impl SharedContext { - fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { + crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { let mut dirs = self.created_dirs.borrow_mut(); if !dirs.contains(dst) { try_err!(self.fs.create_dir_all(dst), dst); @@ -281,11 +282,6 @@ impl Impl { /// rendering threads. #[derive(Default)] pub struct Cache { - /// Mapping of typaram ids to the name of the type parameter. This is used - /// when pretty-printing a type (so pretty-printing doesn't have to - /// painfully maintain a context like this) - pub param_names: FxHashMap, - /// Maps a type ID to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print /// out extra documentation on the page of an enum/struct. @@ -381,7 +377,6 @@ pub struct Cache { pub struct RenderInfo { pub inlined: FxHashSet, pub external_paths: crate::core::ExternalPaths, - pub external_param_names: FxHashMap, pub exact_paths: FxHashMap>, pub access_levels: AccessLevels, pub deref_trait_did: Option, @@ -389,18 +384,6 @@ pub struct RenderInfo { pub owned_box_did: Option, } -/// Helper struct to render all source code to HTML pages -struct SourceCollector<'a> { - scx: &'a mut SharedContext, - - /// Root destination to place all HTML output into - dst: PathBuf, -} - -/// Wrapper struct to render the source code of a file. This will do things like -/// adding line numbers to the left-hand side. -struct Source<'a>(&'a str); - // Helper structs for rendering items/sidebars and carrying along contextual // information @@ -496,7 +479,7 @@ impl ToJson for IndexItemFunctionType { } thread_local!(static CACHE_KEY: RefCell> = Default::default()); -thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = RefCell::new(Vec::new())); +thread_local!(pub static CURRENT_DEPTH: Cell = Cell::new(0)); pub fn initial_ids() -> Vec { [ @@ -612,7 +595,7 @@ pub fn run(mut krate: clean::Crate, } let dst = output; scx.ensure_dir(&dst)?; - krate = render_sources(&dst, &mut scx, krate)?; + krate = sources::render(&dst, &mut scx, krate)?; let mut cx = Context { current: Vec::new(), dst, @@ -628,7 +611,6 @@ pub fn run(mut krate: clean::Crate, let RenderInfo { inlined: _, external_paths, - external_param_names, exact_paths, access_levels, deref_trait_did, @@ -662,7 +644,6 @@ pub fn run(mut krate: clean::Crate, deref_mut_trait_did, owned_box_did, masked_crates: mem::take(&mut krate.masked_crates), - param_names: external_param_names, aliases: Default::default(), }; @@ -714,7 +695,7 @@ pub fn run(mut krate: clean::Crate, // for future parallelization opportunities let cache = Arc::new(cache); CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); - CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear()); + CURRENT_DEPTH.with(|s| s.set(0)); // Write shared runs within a flock; disable thread dispatching of IO temporarily. Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); @@ -751,7 +732,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -789,7 +770,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } let crate_doc = krate.module.as_ref().map(|module| { - plain_summary_line_short(module.doc_value()) + shorten(plain_summary_line(module.doc_value())) }).unwrap_or(String::new()); let mut crate_data = BTreeMap::new(); @@ -1293,18 +1274,6 @@ themePicker.onblur = handleThemeButtonsBlur; Ok(()) } -fn render_sources(dst: &Path, scx: &mut SharedContext, - krate: clean::Crate) -> Result { - info!("emitting source files"); - let dst = dst.join("src").join(&krate.name); - scx.ensure_dir(&dst)?; - let mut folder = SourceCollector { - dst, - scx, - }; - Ok(folder.fold_crate(krate)) -} - fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bool ) -> Result<(), Error> { if enable_minification { @@ -1384,33 +1353,6 @@ fn write_minify_replacer( } } -/// Takes a path to a source file and cleans the path to it. This canonicalizes -/// things like ".." to components which preserve the "top down" hierarchy of a -/// static HTML tree. Each component in the cleaned path will be passed as an -/// argument to `f`. The very last component of the path (ie the file name) will -/// be passed to `f` if `keep_filename` is true, and ignored otherwise. -fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) -where - F: FnMut(&OsStr), -{ - // make it relative, if possible - let p = p.strip_prefix(src_root).unwrap_or(p); - - let mut iter = p.components().peekable(); - - while let Some(c) = iter.next() { - if !keep_filename && iter.peek().is_none() { - break; - } - - match c { - Component::ParentDir => f("up".as_ref()), - Component::Normal(c) => f(c), - _ => continue, - } - } -} - /// Attempts to find where an external crate is located, given that we're /// rendering in to the specified source destination. fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path) @@ -1444,102 +1386,6 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat }).next().unwrap_or(Unknown) // Well, at least we tried. } -impl<'a> DocFolder for SourceCollector<'a> { - fn fold_item(&mut self, item: clean::Item) -> Option { - // If we're including source files, and we haven't seen this file yet, - // then we need to render it out to the filesystem. - if self.scx.include_sources - // skip all invalid or macro spans - && item.source.filename.is_real() - // skip non-local items - && item.def_id.is_local() { - - // If it turns out that we couldn't read this file, then we probably - // can't read any of the files (generating html output from json or - // something like that), so just don't include sources for the - // entire crate. The other option is maintaining this mapping on a - // per-file basis, but that's probably not worth it... - self.scx - .include_sources = match self.emit_source(&item.source.filename) { - Ok(()) => true, - Err(e) => { - println!("warning: source code was requested to be rendered, \ - but processing `{}` had an error: {}", - item.source.filename, e); - println!(" skipping rendering of source code"); - false - } - }; - } - self.fold_item_recur(item) - } -} - -impl<'a> SourceCollector<'a> { - /// Renders the given filename into its corresponding HTML source file. - fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { - let p = match *filename { - FileName::Real(ref file) => file, - _ => return Ok(()), - }; - if self.scx.local_sources.contains_key(&**p) { - // We've already emitted this source - return Ok(()); - } - - let contents = try_err!(fs::read_to_string(&p), &p); - - // Remove the utf-8 BOM if any - let contents = if contents.starts_with("\u{feff}") { - &contents[3..] - } else { - &contents[..] - }; - - // Create the intermediate directories - let mut cur = self.dst.clone(); - let mut root_path = String::from("../../"); - let mut href = String::new(); - clean_srcpath(&self.scx.src_root, &p, false, |component| { - cur.push(component); - root_path.push_str("../"); - href.push_str(&component.to_string_lossy()); - href.push('/'); - }); - self.scx.ensure_dir(&cur)?; - let mut fname = p.file_name() - .expect("source has no filename") - .to_os_string(); - fname.push(".html"); - cur.push(&fname); - href.push_str(&fname.to_string_lossy()); - - let mut v = Vec::new(); - let title = format!("{} -- source", cur.file_name().expect("failed to get file name") - .to_string_lossy()); - let desc = format!("Source to the Rust file `{}`.", filename); - let page = layout::Page { - title: &title, - css_class: "source", - root_path: &root_path, - static_root_path: self.scx.static_root_path.as_deref(), - description: &desc, - keywords: BASIC_KEYWORDS, - resource_suffix: &self.scx.resource_suffix, - extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], - static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], - }; - try_err!(layout::render(&mut v, &self.scx.layout, - &page, &(""), &Source(contents), - self.scx.css_file_extension.is_some(), - &self.scx.themes, - self.scx.generate_search_filter), &cur); - self.scx.fs.write(&cur, &v)?; - self.scx.local_sources.insert(p.clone(), href); - Ok(()) - } -} - impl DocFolder for Cache { fn fold_item(&mut self, item: clean::Item) -> Option { if item.def_id.is_local() { @@ -1565,12 +1411,6 @@ impl DocFolder for Cache { } } - // Register any generics to their corresponding string. This is used - // when pretty-printing types. - if let Some(generics) = item.inner.generics() { - self.generics(generics); - } - // Propagate a trait method's documentation to all implementors of the // trait. if let clean::TraitItem(ref t) = item.inner { @@ -1642,7 +1482,7 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent, parent_idx: None, search_type: get_index_search_type(&item), @@ -1803,18 +1643,6 @@ impl DocFolder for Cache { } impl Cache { - fn generics(&mut self, generics: &clean::Generics) { - for param in &generics.params { - match param.kind { - clean::GenericParamDefKind::Lifetime => {} - clean::GenericParamDefKind::Type { did, .. } | - clean::GenericParamDefKind::Const { did, .. } => { - self.param_names.insert(did, param.name.clone()); - } - } - } - } - fn add_aliases(&mut self, item: &clean::Item) { if item.def_id.index == CRATE_DEF_INDEX { return @@ -1836,7 +1664,7 @@ impl Cache { ty: item.type_(), name: item_name.to_string(), path: path.clone(), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent: None, parent_idx: None, search_type: get_index_search_type(&item), @@ -2057,31 +1885,6 @@ impl Context { "../".repeat(self.current.len()) } - /// Recurse in the directory structure and change the "root path" to make - /// sure it always points to the top (relatively). - fn recurse(&mut self, s: String, f: F) -> T where - F: FnOnce(&mut Context) -> T, - { - if s.is_empty() { - panic!("Unexpected empty destination: {:?}", self.current); - } - let prev = self.dst.clone(); - self.dst.push(&s); - self.current.push(s); - - info!("Recursing into {}", self.dst.display()); - - let ret = f(self); - - info!("Recursed; leaving {}", self.dst.display()); - - // Go back to where we were at - self.dst = prev; - self.current.pop().unwrap(); - - ret - } - /// Main method for rendering a crate. /// /// This currently isn't parallelized, but it'd be pretty easy to add @@ -2175,8 +1978,8 @@ impl Context { -> io::Result<()> { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. - CURRENT_LOCATION_KEY.with(|slot| { - *slot.borrow_mut() = self.current.clone(); + CURRENT_DEPTH.with(|slot| { + slot.set(self.current.len()); }); let mut title = if it.is_primitive() || it.is_keyword() { @@ -2262,42 +2065,50 @@ impl Context { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. let name = item.name.as_ref().unwrap().to_string(); - let mut item = Some(item); - let scx = self.shared.clone(); - self.recurse(name, |this| { - let item = item.take().unwrap(); - - let mut buf = Vec::new(); - this.render_item(&mut buf, &item, false).unwrap(); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - this.shared.ensure_dir(&this.dst)?; - let joint_dst = this.dst.join("index.html"); - scx.fs.write(&joint_dst, buf)?; - } + let scx = &self.shared; + if name.is_empty() { + panic!("Unexpected empty destination: {:?}", self.current); + } + let prev = self.dst.clone(); + self.dst.push(&name); + self.current.push(name); - let m = match item.inner { - clean::StrippedItem(box clean::ModuleItem(m)) | - clean::ModuleItem(m) => m, - _ => unreachable!() - }; + info!("Recursing into {}", self.dst.display()); - // Render sidebar-items.js used throughout this module. - if !this.render_redirect_pages { - let items = this.build_sidebar_items(&m); - let js_dst = this.dst.join("sidebar-items.js"); - let mut v = Vec::new(); - try_err!(write!(&mut v, "initSidebarItems({});", - as_json(&items)), &js_dst); - scx.fs.write(&js_dst, &v)?; - } + let mut buf = Vec::new(); + self.render_item(&mut buf, &item, false).unwrap(); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + scx.fs.write(&joint_dst, buf)?; + } - for item in m.items { - f(this, item); - } + let m = match item.inner { + clean::StrippedItem(box clean::ModuleItem(m)) | + clean::ModuleItem(m) => m, + _ => unreachable!() + }; + + // Render sidebar-items.js used throughout this module. + if !self.render_redirect_pages { + let items = self.build_sidebar_items(&m); + let js_dst = self.dst.join("sidebar-items.js"); + let mut v = Vec::new(); + try_err!(write!(&mut v, "initSidebarItems({});", + as_json(&items)), &js_dst); + scx.fs.write(&js_dst, &v)?; + } + + for item in m.items { + f(self, item); + } - Ok(()) - })?; + info!("Recursed; leaving {}", self.dst.display()); + + // Go back to where we were at + self.dst = prev; + self.current.pop().unwrap(); } else if item.name.is_some() { let mut buf = Vec::new(); self.render_item(&mut buf, &item, true).unwrap(); @@ -2399,7 +2210,7 @@ impl<'a> Item<'a> { (_, _, Unknown) => return None, }; - clean_srcpath(&src_root, file, false, |component| { + sources::clean_path(&src_root, file, false, |component| { path.push_str(&component.to_string_lossy()); path.push('/'); }); @@ -2549,29 +2360,39 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -fn shorter(s: Option<&str>) -> String { - match s { - Some(s) => s.lines() - .skip_while(|s| s.chars().all(|c| c.is_whitespace())) - .take_while(|line|{ - (*line).chars().any(|chr|{ - !chr.is_whitespace() - }) - }).collect::>().join("\n"), - None => String::new() - } -} - #[inline] fn plain_summary_line(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], false) -} - -#[inline] -fn plain_summary_line_short(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], true) + let s = s.unwrap_or(""); + // This essentially gets the first paragraph of text in one line. + let mut line = s.lines() + .skip_while(|line| line.chars().all(|c| c.is_whitespace())) + .take_while(|line| line.chars().any(|c| !c.is_whitespace())) + .fold(String::new(), |mut acc, line| { + acc.push_str(line); + acc.push(' '); + acc + }); + // remove final whitespace + line.pop(); + markdown::plain_summary_line(&line[..]) +} + +fn shorten(s: String) -> String { + if s.chars().count() > 60 { + let mut len = 0; + let mut ret = s.split_whitespace() + .take_while(|p| { + // + 1 for the added character after the word. + len += p.chars().count() + 1; + len < 60 + }) + .collect::>() + .join(" "); + ret.push('…'); + ret + } else { + s + } } fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result { @@ -2816,19 +2637,19 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, match myitem.inner { clean::ExternCrateItem(ref name, ref src) => { - use crate::html::format::HRef; + use crate::html::format::anchor; match *src { Some(ref src) => { write!(w, "{}extern crate {} as {};", VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, src), + anchor(myitem.def_id, src), name)? } None => { write!(w, "{}extern crate {};", VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, name))? + anchor(myitem.def_id, name))? } } write!(w, "")?; @@ -5048,27 +4869,6 @@ fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt:: Ok(()) } -impl<'a> fmt::Display for Source<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Source(s) = *self; - let lines = s.lines().count(); - let mut cols = 0; - let mut tmp = lines; - while tmp > 0 { - cols += 1; - tmp /= 10; - } - write!(fmt, "
")?;
-        for i in 1..=lines {
-            write!(fmt, "{0:1$}\n", i, cols)?;
-        }
-        write!(fmt, "
")?; - write!(fmt, "{}", - highlight::render_with_highlighting(s, None, None, None))?; - Ok(()) - } -} - fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::Macro) -> fmt::Result { wrap_into_docblock(w, |w| { @@ -5125,7 +4925,7 @@ fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context, document(w, cx, it) } -const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; +crate const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; fn make_item_keywords(it: &clean::Item) -> String { format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs new file mode 100644 index 0000000000000..c1f1f59d9149a --- /dev/null +++ b/src/librustdoc/html/sources.rs @@ -0,0 +1,187 @@ +use crate::clean; +use crate::docfs::PathError; +use crate::fold::DocFolder; +use crate::html::layout; +use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS}; +use crate::html::highlight; +use std::ffi::OsStr; +use std::fs; +use std::path::{Component, Path, PathBuf}; +use std::fmt; +use syntax::source_map::FileName; + +crate fn render(dst: &Path, scx: &mut SharedContext, + krate: clean::Crate) -> Result { + info!("emitting source files"); + let dst = dst.join("src").join(&krate.name); + scx.ensure_dir(&dst)?; + let mut folder = SourceCollector { + dst, + scx, + }; + Ok(folder.fold_crate(krate)) +} + +/// Helper struct to render all source code to HTML pages +struct SourceCollector<'a> { + scx: &'a mut SharedContext, + + /// Root destination to place all HTML output into + dst: PathBuf, +} + +impl<'a> DocFolder for SourceCollector<'a> { + fn fold_item(&mut self, item: clean::Item) -> Option { + // If we're including source files, and we haven't seen this file yet, + // then we need to render it out to the filesystem. + if self.scx.include_sources + // skip all invalid or macro spans + && item.source.filename.is_real() + // skip non-local items + && item.def_id.is_local() { + + // If it turns out that we couldn't read this file, then we probably + // can't read any of the files (generating html output from json or + // something like that), so just don't include sources for the + // entire crate. The other option is maintaining this mapping on a + // per-file basis, but that's probably not worth it... + self.scx + .include_sources = match self.emit_source(&item.source.filename) { + Ok(()) => true, + Err(e) => { + println!("warning: source code was requested to be rendered, \ + but processing `{}` had an error: {}", + item.source.filename, e); + println!(" skipping rendering of source code"); + false + } + }; + } + self.fold_item_recur(item) + } +} + +impl<'a> SourceCollector<'a> { + /// Renders the given filename into its corresponding HTML source file. + fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { + let p = match *filename { + FileName::Real(ref file) => file, + _ => return Ok(()), + }; + if self.scx.local_sources.contains_key(&**p) { + // We've already emitted this source + return Ok(()); + } + + let contents = match fs::read_to_string(&p) { + Ok(contents) => contents, + Err(e) => { + return Err(Error::new(e, &p)); + } + }; + + // Remove the utf-8 BOM if any + let contents = if contents.starts_with("\u{feff}") { + &contents[3..] + } else { + &contents[..] + }; + + // Create the intermediate directories + let mut cur = self.dst.clone(); + let mut root_path = String::from("../../"); + let mut href = String::new(); + clean_path(&self.scx.src_root, &p, false, |component| { + cur.push(component); + root_path.push_str("../"); + href.push_str(&component.to_string_lossy()); + href.push('/'); + }); + self.scx.ensure_dir(&cur)?; + let mut fname = p.file_name() + .expect("source has no filename") + .to_os_string(); + fname.push(".html"); + cur.push(&fname); + href.push_str(&fname.to_string_lossy()); + + let mut v = Vec::new(); + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") + .to_string_lossy()); + let desc = format!("Source to the Rust file `{}`.", filename); + let page = layout::Page { + title: &title, + css_class: "source", + root_path: &root_path, + static_root_path: self.scx.static_root_path.as_deref(), + description: &desc, + keywords: BASIC_KEYWORDS, + resource_suffix: &self.scx.resource_suffix, + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], + static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], + }; + let result = layout::render(&mut v, &self.scx.layout, + &page, &(""), &Source(contents), + self.scx.css_file_extension.is_some(), + &self.scx.themes, + self.scx.generate_search_filter); + if let Err(e) = result { + return Err(Error::new(e, &cur)); + } + self.scx.fs.write(&cur, &v)?; + self.scx.local_sources.insert(p.clone(), href); + Ok(()) + } +} + +/// Takes a path to a source file and cleans the path to it. This canonicalizes +/// things like ".." to components which preserve the "top down" hierarchy of a +/// static HTML tree. Each component in the cleaned path will be passed as an +/// argument to `f`. The very last component of the path (ie the file name) will +/// be passed to `f` if `keep_filename` is true, and ignored otherwise. +pub fn clean_path(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where + F: FnMut(&OsStr), +{ + // make it relative, if possible + let p = p.strip_prefix(src_root).unwrap_or(p); + + let mut iter = p.components().peekable(); + + while let Some(c) = iter.next() { + if !keep_filename && iter.peek().is_none() { + break; + } + + match c { + Component::ParentDir => f("up".as_ref()), + Component::Normal(c) => f(c), + _ => continue, + } + } +} + +/// Wrapper struct to render the source code of a file. This will do things like +/// adding line numbers to the left-hand side. +struct Source<'a>(&'a str); + +impl<'a> fmt::Display for Source<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let Source(s) = *self; + let lines = s.lines().count(); + let mut cols = 0; + let mut tmp = lines; + while tmp > 0 { + cols += 1; + tmp /= 10; + } + write!(fmt, "
")?;
+        for i in 1..=lines {
+            write!(fmt, "{0:1$}\n", i, cols)?;
+        }
+        write!(fmt, "
")?; + write!(fmt, "{}", + highlight::render_with_highlighting(s, None, None, None))?; + Ok(()) + } +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e30b35937db9f..968578f957c5c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -67,6 +67,7 @@ pub mod html { crate mod render; crate mod static_files; crate mod toc; + crate mod sources; } mod markdown; mod passes; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 903ed3aae1470..ee330cb32111e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -41,7 +41,7 @@ fn def_id_to_path( // framework from syntax?. pub struct RustdocVisitor<'a, 'tcx> { - cx: &'a core::DocContext<'tcx>, + cx: &'a mut core::DocContext<'tcx>, view_item_stack: FxHashSet, inlining: bool, /// Are the current module and all of its parents public? @@ -51,7 +51,7 @@ pub struct RustdocVisitor<'a, 'tcx> { impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new( - cx: &'a core::DocContext<'tcx> + cx: &'a mut core::DocContext<'tcx> ) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); @@ -84,7 +84,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ); module.is_crate = true; - self.cx.renderinfo.borrow_mut().exact_paths = self.exact_paths; + self.cx.renderinfo.get_mut().exact_paths = self.exact_paths; module } @@ -292,7 +292,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Res::Def(DefKind::ForeignTy, did) | Res::Def(DefKind::TyAlias, did) if !self_is_hidden => { self.cx.renderinfo - .borrow_mut() + .get_mut() .access_levels.map .insert(did, AccessLevel::Public); }, diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 2547e3a06e9ef..b229b5f6884d8 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,12 +1,10 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; -use rustc::ty::Visibility; +use rustc::ty::{TyCtxt, Visibility}; use rustc::util::nodemap::FxHashSet; use syntax::symbol::sym; -use std::cell::RefMut; - use crate::clean::{AttributesExt, NestedAttributesExt}; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -14,9 +12,9 @@ use crate::clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) pub struct LibEmbargoVisitor<'a, 'tcx> { - cx: &'a crate::core::DocContext<'tcx>, + tcx: TyCtxt<'tcx>, // Accessibility levels for reachable nodes - access_levels: RefMut<'a, AccessLevels>, + access_levels: &'a mut AccessLevels, // Previous accessibility level, None means unreachable prev_level: Option, // Keeps track of already visited modules, in case a module re-exports its parent @@ -25,13 +23,13 @@ pub struct LibEmbargoVisitor<'a, 'tcx> { impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { pub fn new( - cx: &'a crate::core::DocContext<'tcx> + cx: &'a mut crate::core::DocContext<'tcx> ) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { - cx, - access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), + tcx: cx.tcx, + access_levels: &mut cx.renderinfo.get_mut().access_levels, prev_level: Some(AccessLevel::Public), - visited_mods: FxHashSet::default() + visited_mods: FxHashSet::default(), } } @@ -43,7 +41,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); + let is_hidden = self.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow @@ -60,9 +58,9 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { return; } - for item in self.cx.tcx.item_children(def_id).iter() { + for item in self.tcx.item_children(def_id).iter() { if let Some(def_id) = item.res.opt_def_id() { - if self.cx.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || + if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || item.vis == Visibility::Public { self.visit_item(item.res); } @@ -72,7 +70,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { fn visit_item(&mut self, res: Res) { let def_id = res.def_id(); - let vis = self.cx.tcx.visibility(def_id); + let vis = self.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level } else {