Skip to content

Commit

Permalink
Auto merge of rust-lang#73767 - P1n3appl3:rustdoc-formats, r=tmandry
Browse files Browse the repository at this point in the history
Refactor librustdoc html backend

This PR moves several types out of the librustdoc::html module so that they can be used by a future json backend. These changes are a re-implementation of [some work done 6 months ago](rust-lang/rust@master...GuillaumeGomez:multiple-output-formats) by @GuillaumeGomez. I'm currently working on said json backend and will put up an RFC soon with the proposed implementation.

There are a couple of changes that are more substantial than relocating structs to a different module:
1. The `Cache` is no longer part of the `html::render::Context` type and therefor it needs to be explicitly passed to any functions that access it.
2. The driving function `html::render::run` has been rewritten to use the `FormatRenderer` trait which should allow different backends to re-use the driving code.

r? @GuillaumeGomez

cc @tmandry @betamos
  • Loading branch information
bors committed Jul 29, 2020
2 parents db0492a + 29df050 commit 6b269e4
Show file tree
Hide file tree
Showing 15 changed files with 1,203 additions and 1,072 deletions.
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 {
fn new<S, P: AsRef<Path>>(e: S, path: P) -> Error
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

0 comments on commit 6b269e4

Please sign in to comment.