Skip to content
Merged
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
85 changes: 53 additions & 32 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
@@ -117,6 +117,57 @@ impl DocAccessLevels for AccessLevels<DefId> {
}
}

/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
///
/// If the given `error_format` is `ErrorOutputType::Json` and no `CodeMap` is given, a new one
/// will be created for the handler.
pub fn new_handler(error_format: ErrorOutputType, codemap: Option<Lrc<codemap::CodeMap>>)
-> errors::Handler
{
// rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
// stick to the defaults
let sessopts = config::basic_options();
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
ErrorOutputType::HumanReadable(color_config) => Box::new(
EmitterWriter::stderr(
color_config,
codemap.map(|cm| cm as _),
false,
sessopts.debugging_opts.teach,
).ui_testing(sessopts.debugging_opts.ui_testing)
),
ErrorOutputType::Json(pretty) => {
let codemap = codemap.unwrap_or_else(
|| Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())));
Box::new(
JsonEmitter::stderr(
None,
codemap,
pretty,
sessopts.debugging_opts.suggestion_applicability,
).ui_testing(sessopts.debugging_opts.ui_testing)
)
},
ErrorOutputType::Short(color_config) => Box::new(
EmitterWriter::stderr(
color_config,
codemap.map(|cm| cm as _),
true,
false)
),
};

errors::Handler::with_emitter_and_flags(
emitter,
errors::HandlerFlags {
can_emit_warnings: true,
treat_err_as_bug: false,
external_macro_backtrace: false,
..Default::default()
},
)
}

pub fn run_core(search_paths: SearchPaths,
cfgs: Vec<String>,
externs: config::Externs,
@@ -159,41 +210,11 @@ pub fn run_core(search_paths: SearchPaths,
},
error_format,
edition,
..config::basic_options().clone()
..config::basic_options()
};
driver::spawn_thread_pool(sessopts, move |sessopts| {
let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
ErrorOutputType::HumanReadable(color_config) => Box::new(
EmitterWriter::stderr(
color_config,
Some(codemap.clone()),
false,
sessopts.debugging_opts.teach,
).ui_testing(sessopts.debugging_opts.ui_testing)
),
ErrorOutputType::Json(pretty) => Box::new(
JsonEmitter::stderr(
None,
codemap.clone(),
pretty,
sessopts.debugging_opts.suggestion_applicability,
).ui_testing(sessopts.debugging_opts.ui_testing)
),
ErrorOutputType::Short(color_config) => Box::new(
EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
),
};

let diagnostic_handler = errors::Handler::with_emitter_and_flags(
emitter,
errors::HandlerFlags {
can_emit_warnings: true,
treat_err_as_bug: false,
external_macro_backtrace: false,
..Default::default()
},
);
let diagnostic_handler = new_handler(error_format, Some(codemap.clone()));

let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, codemap,
25 changes: 14 additions & 11 deletions src/librustdoc/externalfiles.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
use std::fs;
use std::path::Path;
use std::str;
use errors;
use html::markdown::Markdown;

#[derive(Clone)]
@@ -28,23 +29,23 @@ pub struct ExternalHtml {

impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
md_before_content: &[String], md_after_content: &[String])
md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler)
-> Option<ExternalHtml> {
load_external_files(in_header)
load_external_files(in_header, diag)
.and_then(|ih|
load_external_files(before_content)
load_external_files(before_content, diag)
.map(|bc| (ih, bc))
)
.and_then(|(ih, bc)|
load_external_files(md_before_content)
load_external_files(md_before_content, diag)
.map(|m_bc| (ih, format!("{}{}", bc, Markdown(&m_bc, &[]))))
)
.and_then(|(ih, bc)|
load_external_files(after_content)
load_external_files(after_content, diag)
.map(|ac| (ih, bc, ac))
)
.and_then(|(ih, bc, ac)|
load_external_files(md_after_content)
load_external_files(md_after_content, diag)
.map(|m_ac| (ih, bc, format!("{}{}", ac, Markdown(&m_ac, &[]))))
)
.map(|(ih, bc, ac)|
@@ -62,28 +63,30 @@ pub enum LoadStringError {
BadUtf8,
}

pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
pub fn load_string<P: AsRef<Path>>(file_path: P, diag: &errors::Handler)
-> Result<String, LoadStringError>
{
let file_path = file_path.as_ref();
let contents = match fs::read(file_path) {
Ok(bytes) => bytes,
Err(e) => {
eprintln!("error reading `{}`: {}", file_path.display(), e);
diag.struct_err(&format!("error reading `{}`: {}", file_path.display(), e)).emit();
return Err(LoadStringError::ReadFail);
}
};
match str::from_utf8(&contents) {
Ok(s) => Ok(s.to_string()),
Err(_) => {
eprintln!("error reading `{}`: not UTF-8", file_path.display());
diag.struct_err(&format!("error reading `{}`: not UTF-8", file_path.display())).emit();
Err(LoadStringError::BadUtf8)
}
}
}

fn load_external_files(names: &[String]) -> Option<String> {
fn load_external_files(names: &[String], diag: &errors::Handler) -> Option<String> {
let mut out = String::new();
for name in names {
let s = match load_string(name) {
let s = match load_string(name, diag) {
Ok(s) => s,
Err(_) => return None,
};
127 changes: 60 additions & 67 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
@@ -56,15 +56,13 @@ use errors::ColorConfig;
use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
use std::fmt::Display;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::mpsc::channel;

use syntax::edition::Edition;
use externalfiles::ExternalHtml;
use rustc::session::{early_warn, early_error};
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
use rustc::session::config::{nightly_options, build_codegen_options};
@@ -118,7 +116,8 @@ pub fn main() {
fn get_args() -> Option<Vec<String>> {
env::args_os().enumerate()
.map(|(i, arg)| arg.into_string().map_err(|arg| {
print_error(format!("Argument {} is not valid Unicode: {:?}", i, arg));
early_warn(ErrorOutputType::default(),
&format!("Argument {} is not valid Unicode: {:?}", i, arg));
}).ok())
.collect()
}
@@ -318,16 +317,12 @@ pub fn main_args(args: &[String]) -> isize {
let matches = match options.parse(&args[1..]) {
Ok(m) => m,
Err(err) => {
print_error(err);
return 1;
early_error(ErrorOutputType::default(), &err.to_string());
}
};
// Check for unstable options.
nightly_options::check_nightly_options(&matches, &opts());

// check for deprecated options
check_deprecated_options(&matches);

if matches.opt_present("h") || matches.opt_present("help") {
usage("rustdoc");
return 0;
@@ -348,6 +343,35 @@ pub fn main_args(args: &[String]) -> isize {
return 0;
}

let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
Some("never") => ColorConfig::Never,
None => ColorConfig::Auto,
Some(arg) => {
early_error(ErrorOutputType::default(),
&format!("argument for --color must be `auto`, `always` or `never` \
(instead was `{}`)", arg));
}
};
let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
Some("human") => ErrorOutputType::HumanReadable(color),
Some("json") => ErrorOutputType::Json(false),
Some("pretty-json") => ErrorOutputType::Json(true),
Some("short") => ErrorOutputType::Short(color),
None => ErrorOutputType::HumanReadable(color),
Some(arg) => {
early_error(ErrorOutputType::default(),
&format!("argument for --error-format must be `human`, `json` or \
`short` (instead was `{}`)", arg));
}
};

let diag = core::new_handler(error_format, None);

// check for deprecated options
check_deprecated_options(&matches, &diag);

let to_check = matches.opt_strs("theme-checker");
if !to_check.is_empty() {
let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
@@ -356,7 +380,7 @@ pub fn main_args(args: &[String]) -> isize {
println!("rustdoc: [theme-checker] Starting tests!");
for theme_file in to_check.iter() {
print!(" - Checking \"{}\"...", theme_file);
let (success, differences) = theme::test_theme_against(theme_file, &paths);
let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
if !differences.is_empty() || !success {
println!(" FAILED");
errors += 1;
@@ -374,47 +398,23 @@ pub fn main_args(args: &[String]) -> isize {
}

if matches.free.is_empty() {
print_error("missing file operand");
diag.struct_err("missing file operand").emit();
return 1;
}
if matches.free.len() > 1 {
print_error("too many file operands");
diag.struct_err("too many file operands").emit();
return 1;
}
let input = &matches.free[0];

let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
Some("never") => ColorConfig::Never,
None => ColorConfig::Auto,
Some(arg) => {
print_error(&format!("argument for --color must be `auto`, `always` or `never` \
(instead was `{}`)", arg));
return 1;
}
};
let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
Some("human") => ErrorOutputType::HumanReadable(color),
Some("json") => ErrorOutputType::Json(false),
Some("pretty-json") => ErrorOutputType::Json(true),
Some("short") => ErrorOutputType::Short(color),
None => ErrorOutputType::HumanReadable(color),
Some(arg) => {
print_error(&format!("argument for --error-format must be `human`, `json` or \
`short` (instead was `{}`)", arg));
return 1;
}
};

let mut libs = SearchPaths::new();
for s in &matches.opt_strs("L") {
libs.add_path(s, error_format);
}
let externs = match parse_externs(&matches) {
Ok(ex) => ex,
Err(err) => {
print_error(err);
diag.struct_err(&err.to_string()).emit();
return 1;
}
};
@@ -435,10 +435,7 @@ pub fn main_args(args: &[String]) -> isize {

if let Some(ref p) = css_file_extension {
if !p.is_file() {
writeln!(
&mut io::stderr(),
"rustdoc: option --extend-css argument must be a file."
).unwrap();
diag.struct_err("option --extend-css argument must be a file").emit();
return 1;
}
}
@@ -451,13 +448,14 @@ pub fn main_args(args: &[String]) -> isize {
.iter()
.map(|s| (PathBuf::from(&s), s.to_owned())) {
if !theme_file.is_file() {
println!("rustdoc: option --themes arguments must all be files");
diag.struct_err("option --themes arguments must all be files").emit();
return 1;
}
let (success, ret) = theme::test_theme_against(&theme_file, &paths);
let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
if !success || !ret.is_empty() {
println!("rustdoc: invalid theme: \"{}\"", theme_s);
println!(" Check what's wrong with the \"theme-checker\" option");
diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
.help("check what's wrong with the --theme-checker option")
.emit();
return 1;
}
themes.push(theme_file);
@@ -469,7 +467,7 @@ pub fn main_args(args: &[String]) -> isize {
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content")) {
&matches.opt_strs("markdown-after-content"), &diag) {
Some(eh) => eh,
None => return 3,
};
@@ -485,7 +483,7 @@ pub fn main_args(args: &[String]) -> isize {
let edition = match edition.parse() {
Ok(e) => e,
Err(_) => {
print_error("could not parse edition");
diag.struct_err("could not parse edition").emit();
return 1;
}
};
@@ -495,7 +493,7 @@ pub fn main_args(args: &[String]) -> isize {
match (should_test, markdown_input) {
(true, true) => {
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot,
display_warnings, linker, edition, cg)
display_warnings, linker, edition, cg, &diag)
}
(true, false) => {
return test::run(Path::new(input), cfgs, libs, externs, test_args, crate_name,
@@ -504,7 +502,7 @@ pub fn main_args(args: &[String]) -> isize {
(false, true) => return markdown::render(Path::new(input),
output.unwrap_or(PathBuf::from("doc")),
&matches, &external_html,
!matches.opt_present("markdown-no-toc")),
!matches.opt_present("markdown-no-toc"), &diag),
(false, false) => {}
}

@@ -513,6 +511,7 @@ pub fn main_args(args: &[String]) -> isize {
let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
move |out| {
let Output { krate, passes, renderinfo } = out;
let diag = core::new_handler(error_format, None);
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
Some("html") | None => {
@@ -528,26 +527,17 @@ pub fn main_args(args: &[String]) -> isize {
0
}
Some(s) => {
print_error(format!("unknown output format: {}", s));
diag.struct_err(&format!("unknown output format: {}", s)).emit();
1
}
}
});
res.unwrap_or_else(|s| {
print_error(format!("input error: {}", s));
diag.struct_err(&format!("input error: {}", s)).emit();
1
})
}

/// Prints an uniformized error message on the standard error output
fn print_error<T>(error_message: T) where T: Display {
writeln!(
&mut io::stderr(),
"rustdoc: {}\nTry 'rustdoc --help' for more information.",
error_message
).unwrap();
}

/// Looks inside the command line arguments to extract the relevant input format
/// and files and then generates the necessary rustdoc output for formatting.
fn acquire_input<R, F>(input: PathBuf,
@@ -714,7 +704,7 @@ where R: 'static + Send,
}

/// Prints deprecation warnings for deprecated options
fn check_deprecated_options(matches: &getopts::Matches) {
fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
let deprecated_flags = [
"input-format",
"output-format",
@@ -726,12 +716,15 @@ fn check_deprecated_options(matches: &getopts::Matches) {

for flag in deprecated_flags.into_iter() {
if matches.opt_present(flag) {
eprintln!("WARNING: the '{}' flag is considered deprecated", flag);
eprintln!("WARNING: please see https://github.com/rust-lang/rust/issues/44136");
}
}
let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
flag));
err.warn("please see https://github.com/rust-lang/rust/issues/44136");

if matches.opt_present("no-defaults") {
eprintln!("WARNING: (you may want to use --document-private-items)");
if *flag == "no-defaults" {
err.help("you may want to use --document-private-items");
}

err.emit();
}
}
}
15 changes: 8 additions & 7 deletions src/librustdoc/markdown.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ use std::fs::File;
use std::io::prelude::*;
use std::path::{PathBuf, Path};

use errors;
use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
@@ -50,7 +51,7 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
external_html: &ExternalHtml, include_toc: bool) -> isize {
external_html: &ExternalHtml, include_toc: bool, diag: &errors::Handler) -> isize {
output.push(input.file_stem().unwrap());
output.set_extension("html");

@@ -60,7 +61,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
css.push_str(&s)
}

let input_str = match load_string(input) {
let input_str = match load_string(input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
@@ -72,15 +73,15 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,

let mut out = match File::create(&output) {
Err(e) => {
eprintln!("rustdoc: {}: {}", output.display(), e);
diag.struct_err(&format!("{}: {}", output.display(), e)).emit();
return 4;
}
Ok(f) => f
};

let (metadata, text) = extract_leading_metadata(&input_str);
if metadata.is_empty() {
eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`");
diag.struct_err("invalid markdown file: no initial lines starting with `# ` or `%`").emit();
return 5;
}
let title = metadata[0];
@@ -130,7 +131,7 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,

match err {
Err(e) => {
eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e);
diag.struct_err(&format!("cannot write to `{}`: {}", output.display(), e)).emit();
6
}
Ok(_) => 0,
@@ -141,8 +142,8 @@ pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
display_warnings: bool, linker: Option<PathBuf>, edition: Edition,
cg: CodegenOptions) -> isize {
let input_str = match load_string(input) {
cg: CodegenOptions, diag: &errors::Handler) -> isize {
let input_str = match load_string(input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
14 changes: 9 additions & 5 deletions src/librustdoc/theme.rs
Original file line number Diff line number Diff line change
@@ -14,12 +14,14 @@ use std::hash::{Hash, Hasher};
use std::io::Read;
use std::path::Path;

use errors::Handler;

macro_rules! try_something {
($e:expr, $out:expr) => ({
($e:expr, $diag:expr, $out:expr) => ({
match $e {
Ok(c) => c,
Err(e) => {
eprintln!("rustdoc: got an error: {}", e);
$diag.struct_err(&e.to_string()).emit();
return $out;
}
}
@@ -273,11 +275,13 @@ pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec<String>)
}
}

pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath) -> (bool, Vec<String>) {
let mut file = try_something!(File::open(f), (false, Vec::new()));
pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath, diag: &Handler)
-> (bool, Vec<String>)
{
let mut file = try_something!(File::open(f), diag, (false, Vec::new()));
let mut data = Vec::with_capacity(1000);

try_something!(file.read_to_end(&mut data), (false, Vec::new()));
try_something!(file.read_to_end(&mut data), diag, (false, Vec::new()));
let paths = load_css_paths(&data);
let mut ret = Vec::new();
get_differences(against, &paths, &mut ret);