Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor librustdoc html backend #73767

Merged
merged 9 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ use crate::clean::inline;
use crate::clean::types::Type::{QPath, ResolvedPath};
use crate::core::DocContext;
use crate::doctree;
use crate::html::item_type::ItemType;
use crate::html::render::{cache, ExternalLocation};
use crate::formats::cache::cache;
use crate::formats::item_type::ItemType;
use crate::html::render::cache::ExternalLocation;

use self::FnRetTy::*;
use self::ItemEnum::*;
Expand Down Expand Up @@ -1172,7 +1173,7 @@ impl GetDefId for Type {
fn def_id(&self) -> Option<DefId> {
match *self {
ResolvedPath { did, .. } => Some(did),
Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
Primitive(p) => cache().primitive_locations.get(&p).cloned(),
BorrowedRef { type_: box Generic(..), .. } => {
Primitive(PrimitiveType::Reference).def_id()
}
Expand Down
17 changes: 17 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use std::ffi::OsStr;
use std::fmt;
use std::path::PathBuf;

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::DefId;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
use rustc_session::config::{
build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple,
Expand Down Expand Up @@ -249,6 +252,20 @@ pub struct RenderOptions {
pub document_hidden: bool,
}

/// Temporary storage for data obtained during `RustdocVisitor::clean()`.
/// Later on moved into `CACHE_KEY`.
#[derive(Default, Clone)]
pub struct RenderInfo {
pub inlined: FxHashSet<DefId>,
pub external_paths: crate::core::ExternalPaths,
pub exact_paths: FxHashMap<DefId, Vec<String>>,
pub access_levels: AccessLevels<DefId>,
pub deref_trait_did: Option<DefId>,
pub deref_mut_trait_did: Option<DefId>,
pub owned_box_did: Option<DefId>,
pub output_format: Option<OutputFormat>,
}

impl Options {
/// Parses the given command-line for options. If an error message or other early-return has
/// been printed, returns `Err` with the exit code.
Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use std::rc::Rc;

use crate::clean;
use crate::clean::{AttributesExt, MAX_DEF_ID};
use crate::config::RenderInfo;
use crate::config::{Options as RustdocOptions, RenderOptions};
use crate::html::render::RenderInfo;
use crate::passes::{self, Condition::*, ConditionalPass};

pub use rustc_session::config::{CodegenOptions, DebuggingOptions, Input, Options};
Expand All @@ -44,9 +44,9 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
pub struct DocContext<'tcx> {
pub tcx: TyCtxt<'tcx>,
pub resolver: Rc<RefCell<interface::BoxedResolver>>,
/// Later on moved into `html::render::CACHE_KEY`
/// Later on moved into `CACHE_KEY`
pub renderinfo: RefCell<RenderInfo>,
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
/// Later on moved through `clean::Crate` into `CACHE_KEY`
pub external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
Expand Down
61 changes: 16 additions & 45 deletions src/librustdoc/docfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ use std::fs;
use std::io;
use std::path::Path;
use std::string::ToString;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::sync::mpsc::Sender;

macro_rules! try_err {
($e:expr, $file:expr) => {
Expand All @@ -31,47 +30,24 @@ pub trait PathError {
S: ToString + Sized;
}

pub struct ErrorStorage {
sender: Option<Sender<Option<String>>>,
receiver: Receiver<Option<String>>,
}

impl ErrorStorage {
pub fn new() -> ErrorStorage {
let (sender, receiver) = channel();
ErrorStorage { sender: Some(sender), receiver }
}

/// Prints all stored errors. Returns the number of printed errors.
pub fn write_errors(&mut self, diag: &rustc_errors::Handler) -> usize {
let mut printed = 0;
// In order to drop the sender part of the channel.
self.sender = None;

for msg in self.receiver.iter() {
if let Some(ref error) = msg {
diag.struct_err(&error).emit();
printed += 1;
}
}
printed
}
}

pub struct DocFS {
sync_only: bool,
errors: Arc<ErrorStorage>,
errors: Option<Sender<String>>,
}

impl DocFS {
pub fn new(errors: &Arc<ErrorStorage>) -> DocFS {
DocFS { sync_only: false, errors: Arc::clone(errors) }
pub fn new(errors: Sender<String>) -> DocFS {
DocFS { sync_only: false, errors: Some(errors) }
}

pub fn set_sync_only(&mut self, sync_only: bool) {
self.sync_only = sync_only;
}

pub fn close(&mut self) {
self.errors = None;
}

pub fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
// For now, dir creation isn't a huge time consideration, do it
// synchronously, which avoids needing ordering between write() actions
Expand All @@ -88,20 +64,15 @@ impl DocFS {
if !self.sync_only && cfg!(windows) {
// A possible future enhancement after more detailed profiling would
// be to create the file sync so errors are reported eagerly.
let contents = contents.as_ref().to_vec();
let path = path.as_ref().to_path_buf();
let sender = self.errors.sender.clone().unwrap();
rayon::spawn(move || match fs::write(&path, &contents) {
Ok(_) => {
sender.send(None).unwrap_or_else(|_| {
panic!("failed to send error on \"{}\"", path.display())
});
}
Err(e) => {
sender.send(Some(format!("\"{}\": {}", path.display(), e))).unwrap_or_else(
|_| panic!("failed to send non-error on \"{}\"", path.display()),
);
}
let contents = contents.as_ref().to_vec();
let sender = self.errors.clone().expect("can't write after closing");
rayon::spawn(move || {
fs::write(&path, contents).unwrap_or_else(|e| {
sender
.send(format!("\"{}\": {}", path.display(), e))
.expect(&format!("failed to send error on \"{}\"", path.display()));
});
});
Ok(())
} else {
Expand Down
56 changes: 56 additions & 0 deletions src/librustdoc/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::error;
use std::fmt::{self, Formatter};
use std::path::{Path, PathBuf};

use crate::docfs::PathError;

#[derive(Debug)]
pub struct Error {
pub file: PathBuf,
pub error: String,
}

impl error::Error for Error {}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let file = self.file.display().to_string();
if file.is_empty() {
write!(f, "{}", self.error)
} else {
write!(f, "\"{}\": {}", self.file.display(), self.error)
}
}
}

impl PathError for Error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but do you know why rustdoc uses a separate error type and trait here? It has wrappers around both io::Error and std::error::Error.

fn new<S, P: AsRef<Path>>(e: S, path: P) -> Error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but this would be better taking P: Into<PathBuf> instead which avoids an unnecessary allocation if passing a PathBuf.

where
S: ToString + Sized,
{
Error { file: path.as_ref().to_path_buf(), error: e.to_string() }
}
}

#[macro_export]
macro_rules! try_none {
($e:expr, $file:expr) => {{
use std::io;
match $e {
Some(e) => e,
None => {
return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file));
}
}
}};
}

#[macro_export]
macro_rules! try_err {
($e:expr, $file:expr) => {{
match $e {
Ok(e) => e,
Err(e) => return Err(Error::new(e, $file)),
}
}};
}
Loading