From 5d4b63926fe1eea0d36828c05693a91a0dd2fc15 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:08:09 -0500 Subject: [PATCH 1/7] fmt data data structures --- .../obligation_forest/mod.rs | 119 ++++++++---------- 1 file changed, 51 insertions(+), 68 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index b1931ca459f61..92bd196aaa3cf 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -85,19 +85,20 @@ mod graphviz; #[cfg(test)] mod tests; -pub trait ForestObligation : Clone + Debug { - type Predicate : Clone + hash::Hash + Eq + Debug; +pub trait ForestObligation: Clone + Debug { + type Predicate: Clone + hash::Hash + Eq + Debug; fn as_predicate(&self) -> &Self::Predicate; } pub trait ObligationProcessor { - type Obligation : ForestObligation; - type Error : Debug; + type Obligation: ForestObligation; + type Error: Debug; - fn process_obligation(&mut self, - obligation: &mut Self::Obligation) - -> ProcessResult; + fn process_obligation( + &mut self, + obligation: &mut Self::Obligation, + ) -> ProcessResult; /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts @@ -107,10 +108,9 @@ pub trait ObligationProcessor { /// In other words, if we had O1 which required O2 which required /// O3 which required O1, we would give an iterator yielding O1, /// O2, O3 (O1 is not yielded twice). - fn process_backedge<'c, I>(&mut self, - cycle: I, - _marker: PhantomData<&'c Self::Obligation>) - where I: Clone + Iterator; + fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>) + where + I: Clone + Iterator; } /// The result type used by `process_obligation`. @@ -185,20 +185,11 @@ struct Node { } impl Node { - fn new( - parent: Option, - obligation: O, - obligation_tree_id: ObligationTreeId - ) -> Node { + fn new(parent: Option, obligation: O, obligation_tree_id: ObligationTreeId) -> Node { Node { obligation, state: Cell::new(NodeState::Pending), - dependents: - if let Some(parent_index) = parent { - vec![parent_index] - } else { - vec![] - }, + dependents: if let Some(parent_index) = parent { vec![parent_index] } else { vec![] }, has_parent: parent.is_some(), obligation_tree_id, } @@ -339,11 +330,7 @@ impl ObligationForest { node.dependents.push(parent_index); } } - if let NodeState::Error = node.state.get() { - Err(()) - } else { - Ok(()) - } + if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) } } Entry::Vacant(v) => { let obligation_tree_id = match parent { @@ -351,12 +338,12 @@ impl ObligationForest { None => self.obligation_tree_id_generator.next().unwrap(), }; - let already_failed = - parent.is_some() - && self.error_cache - .get(&obligation_tree_id) - .map(|errors| errors.contains(obligation.as_predicate())) - .unwrap_or(false); + let already_failed = parent.is_some() + && self + .error_cache + .get(&obligation_tree_id) + .map(|errors| errors.contains(obligation.as_predicate())) + .unwrap_or(false); if already_failed { Err(()) @@ -372,14 +359,12 @@ impl ObligationForest { /// Converts all remaining obligations to the given error. pub fn to_errors(&mut self, error: E) -> Vec> { - let errors = self.nodes.iter().enumerate() + let errors = self + .nodes + .iter() + .enumerate() .filter(|(_index, node)| node.state.get() == NodeState::Pending) - .map(|(index, _node)| { - Error { - error: error.clone(), - backtrace: self.error_at(index), - } - }) + .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); let successful_obligations = self.compress(DoCompleted::Yes); @@ -389,9 +374,11 @@ impl ObligationForest { /// Returns the set of obligations that are in a pending state. pub fn map_pending_obligations(&self, f: F) -> Vec

- where F: Fn(&O) -> P + where + F: Fn(&O) -> P, { - self.nodes.iter() + self.nodes + .iter() .filter(|node| node.state.get() == NodeState::Pending) .map(|node| f(&node.obligation)) .collect() @@ -421,9 +408,13 @@ impl ObligationForest { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). - pub fn process_obligations

(&mut self, processor: &mut P, do_completed: DoCompleted) - -> Outcome - where P: ObligationProcessor + pub fn process_obligations

( + &mut self, + processor: &mut P, + do_completed: DoCompleted, + ) -> Outcome + where + P: ObligationProcessor, { self.gen += 1; @@ -462,10 +453,7 @@ impl ObligationForest { node.state.set(NodeState::Success(Self::not_waiting())); for child in children { - let st = self.register_obligation_at( - child, - Some(index) - ); + let st = self.register_obligation_at(child, Some(index)); if let Err(()) = st { // Error already reported - propagate it // to our node. @@ -475,10 +463,7 @@ impl ObligationForest { } ProcessResult::Error(err) => { stalled = false; - errors.push(Error { - error: err, - backtrace: self.error_at(index), - }); + errors.push(Error { error: err, backtrace: self.error_at(index) }); } } index += 1; @@ -498,11 +483,7 @@ impl ObligationForest { self.process_cycles(processor); let completed = self.compress(do_completed); - Outcome { - completed, - errors, - stalled, - } + Outcome { completed, errors, stalled } } /// Returns a vector of obligations for `p` and all of its @@ -574,7 +555,8 @@ impl ObligationForest { /// Report cycles between all `Success` nodes that aren't still waiting. /// This must be called after `mark_still_waiting_nodes`. fn process_cycles

(&self, processor: &mut P) - where P: ObligationProcessor + where + P: ObligationProcessor, { let mut stack = vec![]; @@ -592,9 +574,14 @@ impl ObligationForest { debug_assert!(stack.is_empty()); } - fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, min_index: usize, - index: usize) - where P: ObligationProcessor + fn find_cycles_from_node

( + &self, + stack: &mut Vec, + processor: &mut P, + min_index: usize, + index: usize, + ) where + P: ObligationProcessor, { let node = &self.nodes[index]; if let NodeState::Success(waiting) = node.state.get() { @@ -614,7 +601,7 @@ impl ObligationForest { // Cycle detected. processor.process_backedge( stack[rpos..].iter().map(GetObligation(&self.nodes)), - PhantomData + PhantomData, ); } } @@ -697,11 +684,7 @@ impl ObligationForest { node_rewrites.truncate(0); self.node_rewrites.replace(node_rewrites); - if do_completed == DoCompleted::Yes { - Some(removed_success_obligations) - } else { - None - } + if do_completed == DoCompleted::Yes { Some(removed_success_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { From 6a835ea8658be7c8f3109503dbbf7f90a60a3eb2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 21 Dec 2019 10:53:41 +1100 Subject: [PATCH 2/7] Revert parts of #66405. Because it caused major performance regressions in some cases. That PR had five commits, two of which affected performance, and three of which were refactorings. This change undoes the performance-affecting changes, while keeping the refactorings in place. Fixes #67454. --- .../obligation_forest/mod.rs | 191 ++++++++---------- 1 file changed, 80 insertions(+), 111 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 92bd196aaa3cf..974d9dcfae408 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -129,7 +129,7 @@ type ObligationTreeIdGenerator = pub struct ObligationForest { /// The list of obligations. In between calls to `process_obligations`, - /// this list only contains nodes in the `Pending` or `Success` state. + /// this list only contains nodes in the `Pending` or `Waiting` state. /// /// `usize` indices are used here and throughout this module, rather than /// `rustc_index::newtype_index!` indices, because this code is hot enough @@ -137,10 +137,6 @@ pub struct ObligationForest { /// significant, and space considerations are not important. nodes: Vec>, - /// The process generation is 1 on the first call to `process_obligations`, - /// 2 on the second call, etc. - gen: u32, - /// A cache of predicates that have been successfully completed. done_cache: FxHashSet, @@ -196,9 +192,9 @@ impl Node { } } -/// The state of one node in some tree within the forest. This -/// represents the current state of processing for the obligation (of -/// type `O`) associated with this node. +/// The state of one node in some tree within the forest. This represents the +/// current state of processing for the obligation (of type `O`) associated +/// with this node. /// /// The non-`Error` state transitions are as follows. /// ``` @@ -210,51 +206,47 @@ impl Node { /// | /// | process_obligations() /// v -/// Success(not_waiting()) -/// | | -/// | | mark_still_waiting_nodes() +/// Success +/// | ^ +/// | | mark_successes() /// | v -/// | Success(still_waiting()) -/// | | -/// | | compress() -/// v v +/// | Waiting +/// | +/// | process_cycles() +/// v +/// Done +/// | +/// | compress() +/// v /// (Removed) /// ``` /// The `Error` state can be introduced in several places, via `error_at()`. /// /// Outside of `ObligationForest` methods, nodes should be either `Pending` or -/// `Success`. +/// `Waiting`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum NodeState { /// This obligation has not yet been selected successfully. Cannot have /// subobligations. Pending, - /// This obligation was selected successfully, but it may be waiting on one - /// or more pending subobligations, as indicated by the `WaitingState`. - Success(WaitingState), + /// This obligation was selected successfully, but may or may not have + /// subobligations. + Success, + + /// This obligation was selected successfully, but it has a pending + /// subobligation. + Waiting, + + /// This obligation, along with its subobligations, are complete, and will + /// be removed in the next collection. + Done, /// This obligation was resolved to an error. It will be removed by the /// next compression step. Error, } -/// Indicates when a `Success` node was last (if ever) waiting on one or more -/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`. -/// - 0: "Not waiting". This is a special value, set by `process_obligation`, -/// and usable because generation counting starts at 1. -/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but -/// waiting no longer. In other words, finished. -/// - ObligationForest::gen: "Still waiting" in this generation. -/// -/// Things to note about this encoding: -/// - Every time `ObligationForest::gen` is incremented, all the "still -/// waiting" nodes automatically become "was waiting". -/// - `ObligationForest::is_still_waiting` is very cheap. -/// -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)] -struct WaitingState(u32); - #[derive(Debug)] pub struct Outcome { /// Obligations that were completely evaluated, including all @@ -291,7 +283,6 @@ impl ObligationForest { pub fn new() -> ObligationForest { ObligationForest { nodes: vec![], - gen: 0, done_cache: Default::default(), active_cache: Default::default(), node_rewrites: RefCell::new(vec![]), @@ -392,18 +383,6 @@ impl ObligationForest { .insert(node.obligation.as_predicate().clone()); } - fn not_waiting() -> WaitingState { - WaitingState(0) - } - - fn still_waiting(&self) -> WaitingState { - WaitingState(self.gen) - } - - fn is_still_waiting(&self, waiting: WaitingState) -> bool { - waiting.0 == self.gen - } - /// Performs a pass through the obligation list. This must /// be called in a loop until `outcome.stalled` is false. /// @@ -416,8 +395,6 @@ impl ObligationForest { where P: ObligationProcessor, { - self.gen += 1; - let mut errors = vec![]; let mut stalled = true; @@ -450,7 +427,7 @@ impl ObligationForest { ProcessResult::Changed(children) => { // We are not (yet) stalled. stalled = false; - node.state.set(NodeState::Success(Self::not_waiting())); + node.state.set(NodeState::Success); for child in children { let st = self.register_obligation_at(child, Some(index)); @@ -479,7 +456,7 @@ impl ObligationForest { }; } - self.mark_still_waiting_nodes(); + self.mark_successes(); self.process_cycles(processor); let completed = self.compress(do_completed); @@ -519,41 +496,50 @@ impl ObligationForest { trace } - /// Mark all `Success` nodes that depend on a pending node as still - /// waiting. Upon completion, any `Success` nodes that aren't still waiting - /// can be removed by `compress`. - fn mark_still_waiting_nodes(&self) { + /// Mark all `Waiting` nodes as `Success`, except those that depend on a + /// pending node. + fn mark_successes(&self) { + // Convert all `Waiting` nodes to `Success`. + for node in &self.nodes { + if node.state.get() == NodeState::Waiting { + node.state.set(NodeState::Success); + } + } + + // Convert `Success` nodes that depend on a pending node back to + // `Waiting`. for node in &self.nodes { if node.state.get() == NodeState::Pending { // This call site is hot. - self.inlined_mark_dependents_as_still_waiting(node); + self.inlined_mark_dependents_as_waiting(node); } } } // This always-inlined function is for the hot call site. #[inline(always)] - fn inlined_mark_dependents_as_still_waiting(&self, node: &Node) { + fn inlined_mark_dependents_as_waiting(&self, node: &Node) { for &index in node.dependents.iter() { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - node.state.set(NodeState::Success(self.still_waiting())); - // This call site is cold. - self.uninlined_mark_dependents_as_still_waiting(node); - } + let state = node.state.get(); + if state == NodeState::Success { + node.state.set(NodeState::Waiting); + // This call site is cold. + self.uninlined_mark_dependents_as_waiting(node); + } else { + debug_assert!(state == NodeState::Waiting || state == NodeState::Error) } } } // This never-inlined function is for the cold call site. #[inline(never)] - fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node) { - self.inlined_mark_dependents_as_still_waiting(node) + fn uninlined_mark_dependents_as_waiting(&self, node: &Node) { + self.inlined_mark_dependents_as_waiting(node) } - /// Report cycles between all `Success` nodes that aren't still waiting. - /// This must be called after `mark_still_waiting_nodes`. + /// Report cycles between all `Success` nodes, and convert all `Success` + /// nodes to `Done`. This must be called after `mark_successes`. fn process_cycles

(&self, processor: &mut P) where P: ObligationProcessor, @@ -564,46 +550,35 @@ impl ObligationForest { // For some benchmarks this state test is extremely hot. It's a win // to handle the no-op cases immediately to avoid the cost of the // function call. - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - self.find_cycles_from_node(&mut stack, processor, index, index); - } + if node.state.get() == NodeState::Success { + self.find_cycles_from_node(&mut stack, processor, index); } } debug_assert!(stack.is_empty()); } - fn find_cycles_from_node

( - &self, - stack: &mut Vec, - processor: &mut P, - min_index: usize, - index: usize, - ) where + fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) + where P: ObligationProcessor, { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - match stack.iter().rposition(|&n| n == index) { - None => { - stack.push(index); - for &dep_index in node.dependents.iter() { - // The index check avoids re-considering a node. - if dep_index >= min_index { - self.find_cycles_from_node(stack, processor, min_index, dep_index); - } - } - stack.pop(); - } - Some(rpos) => { - // Cycle detected. - processor.process_backedge( - stack[rpos..].iter().map(GetObligation(&self.nodes)), - PhantomData, - ); + if node.state.get() == NodeState::Success { + match stack.iter().rposition(|&n| n == index) { + None => { + stack.push(index); + for &dep_index in node.dependents.iter() { + self.find_cycles_from_node(stack, processor, dep_index); } + stack.pop(); + node.state.set(NodeState::Done); + } + Some(rpos) => { + // Cycle detected. + processor.process_backedge( + stack[rpos..].iter().map(GetObligation(&self.nodes)), + PhantomData, + ); } } } @@ -611,8 +586,7 @@ impl ObligationForest { /// Compresses the vector, removing all popped nodes. This adjusts the /// indices and hence invalidates any outstanding indices. `process_cycles` - /// must be run beforehand to remove any cycles on not-still-waiting - /// `Success` nodes. + /// must be run beforehand to remove any cycles on `Success` nodes. #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option> { let orig_nodes_len = self.nodes.len(); @@ -620,7 +594,7 @@ impl ObligationForest { debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; - let mut removed_success_obligations: Vec = vec![]; + let mut removed_done_obligations: Vec = vec![]; // Move removable nodes to the end, preserving the order of the // remaining nodes. @@ -632,19 +606,13 @@ impl ObligationForest { for index in 0..orig_nodes_len { let node = &self.nodes[index]; match node.state.get() { - NodeState::Pending => { - if dead_nodes > 0 { - self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; - } - } - NodeState::Success(waiting) if self.is_still_waiting(waiting) => { + NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); node_rewrites[index] -= dead_nodes; } } - NodeState::Success(_) => { + NodeState::Done => { // This lookup can fail because the contents of // `self.active_cache` are not guaranteed to match those of // `self.nodes`. See the comment in `process_obligation` @@ -658,7 +626,7 @@ impl ObligationForest { } if do_completed == DoCompleted::Yes { // Extract the success stories. - removed_success_obligations.push(node.obligation.clone()); + removed_done_obligations.push(node.obligation.clone()); } node_rewrites[index] = orig_nodes_len; dead_nodes += 1; @@ -672,6 +640,7 @@ impl ObligationForest { node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } + NodeState::Success => unreachable!(), } } @@ -684,7 +653,7 @@ impl ObligationForest { node_rewrites.truncate(0); self.node_rewrites.replace(node_rewrites); - if do_completed == DoCompleted::Yes { Some(removed_success_obligations) } else { None } + if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { From 5386cbdca4200b50572bbe7b5869584efaf62476 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:10:46 -0500 Subject: [PATCH 3/7] format librustdoc --- src/librustdoc/config.rs | 129 +++-- src/librustdoc/core.rs | 440 +++++++++--------- src/librustdoc/lib.rs | 420 +++++++++-------- .../passes/calculate_doc_coverage.rs | 36 +- .../passes/check_code_block_syntax.rs | 8 +- src/librustdoc/passes/collapse_docs.rs | 20 +- .../passes/collect_intra_doc_links.rs | 410 +++++++++------- src/librustdoc/passes/collect_trait_impls.rs | 33 +- src/librustdoc/passes/mod.rs | 55 +-- .../passes/private_items_doc_tests.rs | 4 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 4 +- src/librustdoc/passes/strip_priv_imports.rs | 4 +- src/librustdoc/passes/strip_private.rs | 4 +- src/librustdoc/passes/unindent_comments.rs | 45 +- 15 files changed, 839 insertions(+), 775 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 0db3d28bf0e37..7a3cf88f65e21 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -7,10 +7,12 @@ use errors; use getopts; use rustc::lint::Level; use rustc::session; -use rustc::session::config::{CrateType, parse_crate_types_from_list, parse_externs}; +use rustc::session::config::{ + build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple, + nightly_options, +}; +use rustc::session::config::{parse_crate_types_from_list, parse_externs, CrateType}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; -use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options, host_triple}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; @@ -19,8 +21,8 @@ use syntax::edition::{Edition, DEFAULT_EDITION}; use crate::core::new_handler; use crate::externalfiles::ExternalHtml; use crate::html; -use crate::html::{static_files}; -use crate::html::markdown::{IdMap}; +use crate::html::markdown::IdMap; +use crate::html::static_files; use crate::opts; use crate::passes::{self, DefaultPassOption}; use crate::theme; @@ -29,7 +31,6 @@ use crate::theme; #[derive(Clone)] pub struct Options { // Basic options / Options passed directly to rustc - /// The crate root or Markdown file to load. pub input: PathBuf, /// The name of the crate being documented. @@ -72,7 +73,6 @@ pub struct Options { pub lint_cap: Option, // Options specific to running doctests - /// Whether we should run doctests instead of generating docs. pub should_test: bool, /// List of arguments to pass to the test harness, if running tests. @@ -94,7 +94,6 @@ pub struct Options { pub test_builder: Option, // Options that affect the documentation process - /// The selected default set of passes to use. /// /// Be aware: This option can come both from the CLI and from crate attributes! @@ -111,7 +110,6 @@ pub struct Options { pub show_coverage: bool, // Options that alter generated documentation pages - /// Crate version to note on the sidebar of generated docs. pub crate_version: Option, /// Collected options specific to outputting final pages. @@ -124,9 +122,7 @@ impl fmt::Debug for Options { impl<'a> fmt::Debug for FmtExterns<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_map() - .entries(self.0.iter()) - .finish() + f.debug_map().entries(self.0.iter()).finish() } } @@ -208,7 +204,6 @@ pub struct RenderOptions { pub static_root_path: Option, // Options specific to reading standalone Markdown files - /// Whether to generate a table of contents on the output file when reading a standalone /// Markdown file. pub markdown_no_toc: bool, @@ -274,10 +269,12 @@ impl Options { let codegen_options = build_codegen_options(matches, error_format); let debugging_options = build_debugging_options(matches, error_format); - let diag = new_handler(error_format, - None, - debugging_options.treat_err_as_bug, - debugging_options.ui_testing); + let diag = new_handler( + error_format, + None, + debugging_options.treat_err_as_bug, + debugging_options.ui_testing, + ); // check for deprecated options check_deprecated_options(&matches, &diag); @@ -317,7 +314,9 @@ impl Options { } let input = PathBuf::from(&matches.free[0]); - let libs = matches.opt_strs("L").iter() + let libs = matches + .opt_strs("L") + .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); let externs = parse_externs(&matches, &debugging_options, error_format); @@ -330,16 +329,13 @@ impl Options { }; let test_args = matches.opt_strs("test-args"); - let test_args: Vec = test_args.iter() - .flat_map(|s| s.split_whitespace()) - .map(|s| s.to_string()) - .collect(); + let test_args: Vec = + test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); let should_test = matches.opt_present("test"); - let output = matches.opt_str("o") - .map(|s| PathBuf::from(&s)) - .unwrap_or_else(|| PathBuf::from("doc")); + let output = + matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc")); let cfgs = matches.opt_strs("cfg"); let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); @@ -355,9 +351,9 @@ impl Options { if matches.opt_present("theme") { let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); - for (theme_file, theme_s) in matches.opt_strs("theme") - .iter() - .map(|s| (PathBuf::from(&s), s.to_owned())) { + for (theme_file, theme_s) in + matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) + { if !theme_file.is_file() { diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)) .help("arguments to --theme must be files") @@ -365,8 +361,7 @@ impl Options { return Err(1); } if theme_file.extension() != Some(OsStr::new("css")) { - diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)) - .emit(); + diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)).emit(); return Err(1); } let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag); @@ -374,12 +369,18 @@ impl Options { diag.struct_err(&format!("error loading theme file: \"{}\"", theme_s)).emit(); return Err(1); } else if !ret.is_empty() { - diag.struct_warn(&format!("theme file \"{}\" is missing CSS rules from the \ - default theme", theme_s)) - .warn("the theme may appear incorrect when loaded") - .help(&format!("to see what rules are missing, call `rustdoc \ - --check-theme \"{}\"`", theme_s)) - .emit(); + diag.struct_warn(&format!( + "theme file \"{}\" is missing CSS rules from the \ + default theme", + theme_s + )) + .warn("the theme may appear incorrect when loaded") + .help(&format!( + "to see what rules are missing, call `rustdoc \ + --check-theme \"{}\"`", + theme_s + )) + .emit(); } themes.push(theme_file); } @@ -400,12 +401,16 @@ impl Options { let mut id_map = html::markdown::IdMap::new(); 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"), - &matches.opt_strs("html-after-content"), - &matches.opt_strs("markdown-before-content"), - &matches.opt_strs("markdown-after-content"), - &diag, &mut id_map, edition, &None) { + &matches.opt_strs("html-in-header"), + &matches.opt_strs("html-before-content"), + &matches.opt_strs("html-after-content"), + &matches.opt_strs("markdown-before-content"), + &matches.opt_strs("markdown-after-content"), + &diag, + &mut id_map, + edition, + &None, + ) { Some(eh) => eh, None => return Err(3), }; @@ -434,15 +439,14 @@ impl Options { } } - let target = matches.opt_str("target").map_or( - TargetTriple::from_triple(host_triple()), - |target| { - if target.ends_with(".json") { - TargetTriple::TargetPath(PathBuf::from(target)) - } else { - TargetTriple::TargetTriple(target) - } - }); + let target = + matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| { + if target.ends_with(".json") { + TargetTriple::TargetPath(PathBuf::from(target)) + } else { + TargetTriple::TargetTriple(target) + } + }); let show_coverage = matches.opt_present("show-coverage"); let document_private = matches.opt_present("document-private-items"); @@ -462,7 +466,7 @@ impl Options { let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { Ok(types) => types, - Err(e) =>{ + Err(e) => { diag.struct_err(&format!("unknown crate type: {}", e)).emit(); return Err(1); } @@ -547,30 +551,24 @@ impl Options { markdown_playground_url, generate_search_filter, generate_redirect_pages, - } + }, }) } /// Returns `true` if the file given as `self.input` is a Markdown file. pub fn markdown_input(&self) -> bool { - self.input.extension() - .map_or(false, |e| e == "md" || e == "markdown") + self.input.extension().map_or(false, |e| e == "md" || e == "markdown") } } /// Prints deprecation warnings for deprecated options fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) { - let deprecated_flags = [ - "input-format", - "output-format", - "no-defaults", - "passes", - ]; + let deprecated_flags = ["input-format", "output-format", "no-defaults", "passes"]; for flag in deprecated_flags.iter() { if matches.opt_present(flag) { - let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", - flag)); + 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 *flag == "no-defaults" { @@ -581,10 +579,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) } } - let removed_flags = [ - "plugins", - "plugin-path", - ]; + let removed_flags = ["plugins", "plugin-path"]; for &flag in removed_flags.iter() { if matches.opt_present(flag) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index dd2e1144301ec..80dd9ad7739b2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,47 +1,46 @@ -use rustc_lint; -use rustc::session::{self, config}; use rustc::hir::def::Namespace::TypeNS; -use rustc::hir::def_id::{DefId, DefIndex, CrateNum, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::hir::HirId; +use rustc::lint; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{Ty, TyCtxt}; -use rustc::lint; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; +use rustc::session::{self, config}; +use rustc::ty::{Ty, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::interface; use rustc_driver::abort_on_err; use rustc_feature::UnstableFeatures; +use rustc_interface::interface; +use rustc_lint; use rustc_resolve as resolve; +use errors::emitter::{Emitter, EmitterWriter}; +use errors::json::JsonEmitter; use syntax::ast::CRATE_NODE_ID; -use syntax::source_map; use syntax::attr; -use errors::json::JsonEmitter; +use syntax::source_map; use syntax::symbol::sym; use syntax_pos::DUMMY_SP; -use errors::emitter::{Emitter, EmitterWriter}; +use rustc_data_structures::sync::{self, Lrc}; use std::cell::RefCell; use std::mem; -use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; -use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{MAX_DEF_ID, AttributesExt}; +use crate::clean::{AttributesExt, MAX_DEF_ID}; +use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::html::render::RenderInfo; use crate::passes; -pub use rustc::session::config::{Input, Options, CodegenOptions}; +pub use rustc::session::config::{CodegenOptions, Input, Options}; pub use rustc::session::search_paths::SearchPath; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'tcx> { - pub tcx: TyCtxt<'tcx>, pub resolver: Rc>, /// Later on moved into `html::render::CACHE_KEY` @@ -53,7 +52,6 @@ pub struct DocContext<'tcx> { pub active_extern_traits: RefCell>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: - /// Table `DefId` of type parameter -> substituted type pub ty_substs: RefCell>, /// Table `DefId` of lifetime parameter -> substituted lifetime @@ -76,18 +74,24 @@ impl<'tcx> DocContext<'tcx> { } pub fn enter_resolver(&self, f: F) -> R - where F: FnOnce(&mut resolve::Resolver<'_>) -> R { + where + F: FnOnce(&mut resolve::Resolver<'_>) -> R, + { self.resolver.borrow_mut().access(f) } /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. - pub fn enter_alias(&self, - ty_substs: FxHashMap, - lt_substs: FxHashMap, - ct_substs: FxHashMap, - f: F) -> R - where F: FnOnce() -> R { + pub fn enter_alias( + &self, + ty_substs: FxHashMap, + lt_substs: FxHashMap, + ct_substs: FxHashMap, + f: F, + ) -> R + where + F: FnOnce() -> R, + { let (old_tys, old_lts, old_cts) = ( mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs), mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs), @@ -111,19 +115,12 @@ impl<'tcx> DocContext<'tcx> { pub fn next_def_id(&self, crate_num: CrateNum) -> DefId { let start_def_id = { let next_id = if crate_num == LOCAL_CRATE { - self.tcx - .hir() - .definitions() - .def_path_table() - .next_id() + self.tcx.hir().definitions().def_path_table().next_id() } else { self.enter_resolver(|r| r.cstore().def_path_table(crate_num).next_id()) }; - DefId { - krate: crate_num, - index: next_id, - } + DefId { krate: crate_num, index: next_id } }; let mut fake_ids = self.fake_def_ids.borrow_mut(); @@ -131,16 +128,11 @@ impl<'tcx> DocContext<'tcx> { let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone(); fake_ids.insert( crate_num, - DefId { - krate: crate_num, - index: DefIndex::from(def_id.index.index() + 1), - }, + DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) }, ); MAX_DEF_ID.with(|m| { - m.borrow_mut() - .entry(def_id.krate.clone()) - .or_insert(start_def_id); + m.borrow_mut().entry(def_id.krate.clone()).or_insert(start_def_id); }); self.all_fake_def_ids.borrow_mut().insert(def_id); @@ -159,13 +151,15 @@ impl<'tcx> DocContext<'tcx> { } pub fn stability(&self, id: HirId) -> Option { - self.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_stability(def_id)).cloned() + self.tcx + .hir() + .opt_local_def_id(id) + .and_then(|def_id| self.tcx.lookup_stability(def_id)) + .cloned() } pub fn deprecation(&self, id: HirId) -> Option { - self.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_deprecation(def_id)) + self.tcx.hir().opt_local_def_id(id).and_then(|def_id| self.tcx.lookup_deprecation(def_id)) } } @@ -173,10 +167,11 @@ impl<'tcx> DocContext<'tcx> { /// /// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one /// will be created for the handler. -pub fn new_handler(error_format: ErrorOutputType, - source_map: Option>, - treat_err_as_bug: Option, - ui_testing: bool, +pub fn new_handler( + error_format: ErrorOutputType, + source_map: Option>, + treat_err_as_bug: Option, + ui_testing: bool, ) -> errors::Handler { // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so // stick to the defaults @@ -192,22 +187,19 @@ pub fn new_handler(error_format: ErrorOutputType, sessopts.debugging_opts.teach, sessopts.debugging_opts.terminal_width, false, - ).ui_testing(ui_testing) + ) + .ui_testing(ui_testing), ) - }, + } ErrorOutputType::Json { pretty, json_rendered } => { - let source_map = source_map.unwrap_or_else( - || Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()))); + let source_map = source_map.unwrap_or_else(|| { + Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())) + }); Box::new( - JsonEmitter::stderr( - None, - source_map, - pretty, - json_rendered, - false, - ).ui_testing(ui_testing) + JsonEmitter::stderr(None, source_map, pretty, json_rendered, false) + .ui_testing(ui_testing), ) - }, + } }; errors::Handler::with_emitter_and_flags( @@ -248,9 +240,12 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .. } = options; - let extern_names: Vec = externs.iter() + let extern_names: Vec = externs + .iter() .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| name).cloned().collect(); + .map(|(name, _)| name) + .cloned() + .collect(); // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -266,11 +261,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // In addition to those specific lints, we also need to whitelist those given through // command line, otherwise they'll get ignored and we don't want that. - let mut whitelisted_lints = vec![warnings_lint_name.to_owned(), - intra_link_resolution_failure_name.to_owned(), - missing_docs.to_owned(), - missing_doc_example.to_owned(), - private_doc_tests.to_owned()]; + let mut whitelisted_lints = vec![ + warnings_lint_name.to_owned(), + intra_link_resolution_failure_name.to_owned(), + missing_docs.to_owned(), + missing_doc_example.to_owned(), + private_doc_tests.to_owned(), + ]; whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); @@ -280,24 +277,28 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .chain(rustc_lint::SoftLints::get_lints().into_iter()) }; - let lint_opts = lints().filter_map(|lint| { - if lint.name == warnings_lint_name || - lint.name == intra_link_resolution_failure_name { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }).chain(lint_opts.into_iter()).collect::>(); - - let lint_caps = lints().filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }).collect(); + let lint_opts = lints() + .filter_map(|lint| { + if lint.name == warnings_lint_name || lint.name == intra_link_resolution_failure_name { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }) + .chain(lint_opts.into_iter()) + .collect::>(); + + let lint_caps = lints() + .filter_map(|lint| { + // We don't want to whitelist *all* lints so let's + // ignore those ones. + if whitelisted_lints.iter().any(|l| &lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }) + .collect(); let crate_types = if proc_macro_crate { vec![config::CrateType::ProcMacro] @@ -309,11 +310,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt maybe_sysroot, search_paths: libs, crate_types, - lint_opts: if !display_warnings { - lint_opts - } else { - vec![] - }, + lint_opts: if !display_warnings { lint_opts } else { vec![] }, lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), cg: codegen_options, externs, @@ -344,151 +341,164 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt registry: rustc_driver::diagnostics_registry(), }; - interface::run_compiler_in_existing_thread_pool(config, |compiler| compiler.enter(|queries| { - let sess = compiler.session(); - - // We need to hold on to the complete resolver, so we cause everything to be - // cloned for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let resolver = { - let parts = abort_on_err(queries.expansion(), sess).peek(); - let resolver = parts.1.borrow(); - - // Before we actually clone it, let's force all the extern'd crates to - // actually be loaded, just in case they're only referred to inside - // intra-doc-links - resolver.borrow_mut().access(|resolver| { - for extern_name in &extern_names { - resolver.resolve_str_path_error( - DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID - ).unwrap_or_else( - |()| panic!("Unable to resolve external crate {}", extern_name) - ); - } - }); - - // Now we're good to clone the resolver because everything should be loaded - resolver.clone() - }; - - if sess.has_errors() { - sess.fatal("Compilation failed, aborting rustdoc"); - } - - let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); - - global_ctxt.enter(|tcx| { - tcx.analysis(LOCAL_CRATE).ok(); - - // Abort if there were any errors so far - sess.abort_if_errors(); - - let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); - // Convert from a HirId set to a DefId set since we don't always have easy access - // to the map from defid -> hirid - let access_levels = AccessLevels { - map: access_levels.map.iter() - .map(|(&k, &v)| (tcx.hir().local_def_id(k), v)) - .collect() - }; + interface::run_compiler_in_existing_thread_pool(config, |compiler| { + compiler.enter(|queries| { + let sess = compiler.session(); + + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let resolver = { + let parts = abort_on_err(queries.expansion(), sess).peek(); + let resolver = parts.1.borrow(); + + // Before we actually clone it, let's force all the extern'd crates to + // actually be loaded, just in case they're only referred to inside + // intra-doc-links + resolver.borrow_mut().access(|resolver| { + for extern_name in &extern_names { + resolver + .resolve_str_path_error(DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID) + .unwrap_or_else(|()| { + panic!("Unable to resolve external crate {}", extern_name) + }); + } + }); - let mut renderinfo = RenderInfo::default(); - renderinfo.access_levels = access_levels; - - let mut ctxt = DocContext { - tcx, - resolver, - external_traits: Default::default(), - active_extern_traits: Default::default(), - renderinfo: RefCell::new(renderinfo), - ty_substs: Default::default(), - lt_substs: Default::default(), - 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).iter().cloned().filter(|trait_def_id| { - tcx.trait_is_auto(*trait_def_id) - }).collect(), + // Now we're good to clone the resolver because everything should be loaded + resolver.clone() }; - debug!("crate: {:?}", tcx.hir().krate()); - let mut krate = clean::krate(&mut ctxt); + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - fn report_deprecated_attr(name: &str, diag: &errors::Handler) { - let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ - considered deprecated", name)); - msg.warn("please see https://github.com/rust-lang/rust/issues/44136"); + let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); + + global_ctxt.enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); + + // Abort if there were any errors so far + sess.abort_if_errors(); + + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + // Convert from a HirId set to a DefId set since we don't always have easy access + // to the map from defid -> hirid + let access_levels = AccessLevels { + map: access_levels + .map + .iter() + .map(|(&k, &v)| (tcx.hir().local_def_id(k), v)) + .collect(), + }; + + let mut renderinfo = RenderInfo::default(); + renderinfo.access_levels = access_levels; + + let mut ctxt = DocContext { + tcx, + resolver, + external_traits: Default::default(), + active_extern_traits: Default::default(), + renderinfo: RefCell::new(renderinfo), + ty_substs: Default::default(), + lt_substs: Default::default(), + 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) + .iter() + .cloned() + .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) + .collect(), + }; + debug!("crate: {:?}", tcx.hir().krate()); + + 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 \ + considered deprecated", + name + )); + msg.warn("please see https://github.com/rust-lang/rust/issues/44136"); + + if name == "no_default_passes" { + msg.help("you may want to use `#![doc(document_private_items)]`"); + } - if name == "no_default_passes" { - msg.help("you may want to use `#![doc(document_private_items)]`"); + msg.emit(); } - msg.emit(); - } - - // Process all of the crate attributes, extracting plugin metadata along - // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { - let diag = ctxt.sess().diagnostic(); - - let name = attr.name_or_empty(); - if attr.is_word() { - if name == sym::no_default_passes { - report_deprecated_attr("no_default_passes", diag); - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::None; + // Process all of the crate attributes, extracting plugin metadata along + // with the passes which we are supposed to run. + for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { + let diag = ctxt.sess().diagnostic(); + + let name = attr.name_or_empty(); + if attr.is_word() { + if name == sym::no_default_passes { + report_deprecated_attr("no_default_passes", diag); + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::None; + } + } + } else if let Some(value) = attr.value_str() { + let sink = match name { + sym::passes => { + report_deprecated_attr("passes = \"...\"", diag); + &mut manual_passes + } + sym::plugins => { + report_deprecated_attr("plugins = \"...\"", diag); + eprintln!( + "WARNING: `#![doc(plugins = \"...\")]` \ + no longer functions; see CVE-2018-1000622" + ); + continue; + } + _ => continue, + }; + for name in value.as_str().split_whitespace() { + sink.push(name.to_string()); } } - } else if let Some(value) = attr.value_str() { - let sink = match name { - sym::passes => { - report_deprecated_attr("passes = \"...\"", diag); - &mut manual_passes - }, - sym::plugins => { - report_deprecated_attr("plugins = \"...\"", diag); - eprintln!("WARNING: `#![doc(plugins = \"...\")]` \ - no longer functions; see CVE-2018-1000622"); - continue - }, - _ => continue, - }; - for name in value.as_str().split_whitespace() { - sink.push(name.to_string()); - } - } - if attr.is_word() && name == sym::document_private_items { - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::Private; + if attr.is_word() && name == sym::document_private_items { + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::Private; + } } } - } - let passes = passes::defaults(default_passes).iter().chain(manual_passes.into_iter() - .flat_map(|name| { - if let Some(pass) = passes::find_pass(&name) { - Some(pass) - } else { - error!("unknown pass {}, skipping", name); - None - } - })); + let passes = passes::defaults(default_passes).iter().chain( + manual_passes.into_iter().flat_map(|name| { + if let Some(pass) = passes::find_pass(&name) { + Some(pass) + } else { + error!("unknown pass {}, skipping", name); + None + } + }), + ); - info!("Executing passes"); + info!("Executing passes"); - for pass in passes { - debug!("running pass {}", pass.name); - krate = (pass.pass)(krate, &ctxt); - } + for pass in passes { + debug!("running pass {}", pass.name); + krate = (pass.pass)(krate, &ctxt); + } - ctxt.sess().abort_if_errors(); + ctxt.sess().abort_if_errors(); - (krate, ctxt.renderinfo.into_inner(), render_options) + (krate, ctxt.renderinfo.into_inner(), render_options) + }) }) - })) + }) } /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 11d50cb7ce628..0b4abe0a22e3b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,6 +1,7 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/")] - +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/" +)] #![feature(rustc_private)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] @@ -16,30 +17,30 @@ #![feature(drain_filter)] #![feature(never_type)] #![feature(unicode_internals)] +#![recursion_limit = "256"] -#![recursion_limit="256"] - -extern crate getopts; extern crate env_logger; +extern crate getopts; extern crate rustc; extern crate rustc_data_structures; extern crate rustc_driver; -extern crate rustc_feature; extern crate rustc_error_codes; +extern crate rustc_feature; extern crate rustc_index; -extern crate rustc_resolve; -extern crate rustc_lint; extern crate rustc_interface; +extern crate rustc_lexer; +extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_parse; +extern crate rustc_resolve; extern crate rustc_target; extern crate rustc_typeck; -extern crate rustc_lexer; extern crate syntax; extern crate syntax_expand; extern crate syntax_pos; extern crate test as testing; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; extern crate rustc_errors as errors; use std::default::Default; @@ -47,8 +48,8 @@ use std::env; use std::panic; use std::process; -use rustc::session::{early_warn, early_error}; -use rustc::session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; +use rustc::session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; +use rustc::session::{early_error, early_warn}; #[macro_use] mod externalfiles; @@ -60,23 +61,23 @@ mod docfs; mod doctree; mod fold; pub mod html { - crate mod highlight; crate mod escape; - crate mod item_type; crate mod format; + crate mod highlight; + crate mod item_type; crate mod layout; pub mod markdown; crate mod render; + crate mod sources; crate mod static_files; crate mod toc; - crate mod sources; } mod markdown; mod passes; -mod visit_ast; -mod visit_lib; mod test; mod theme; +mod visit_ast; +mod visit_lib; struct Output { krate: clean::Crate, @@ -92,29 +93,41 @@ pub fn main() { }; rustc_driver::set_sigpipe_handler(); env_logger::init_from_env("RUSTDOC_LOG"); - let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { - get_args().map(|args| main_args(&args)).unwrap_or(1) - }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE); + let res = std::thread::Builder::new() + .stack_size(thread_stack_size) + .spawn(move || get_args().map(|args| main_args(&args)).unwrap_or(1)) + .unwrap() + .join() + .unwrap_or(rustc_driver::EXIT_FAILURE); process::exit(res); } fn get_args() -> Option> { - env::args_os().enumerate() - .map(|(i, arg)| arg.into_string().map_err(|arg| { - early_warn(ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg)); - }).ok()) + env::args_os() + .enumerate() + .map(|(i, arg)| { + arg.into_string() + .map_err(|arg| { + early_warn( + ErrorOutputType::default(), + &format!("Argument {} is not valid Unicode: {:?}", i, arg), + ); + }) + .ok() + }) .collect() } fn stable(name: &'static str, f: F) -> RustcOptGroup - where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static +where + F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup::stable(name, f) } fn unstable(name: &'static str, f: F) -> RustcOptGroup - where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static +where + F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup::unstable(name, f) } @@ -125,118 +138,127 @@ fn opts() -> Vec { stable("V", |o| o.optflag("V", "version", "print rustdoc's version")), stable("v", |o| o.optflag("v", "verbose", "use verbose output")), stable("r", |o| { - o.optopt("r", "input-format", "the input type of the specified file", - "[rust]") - }), - stable("w", |o| { - o.optopt("w", "output-format", "the output type to write", "[html]") + o.optopt("r", "input-format", "the input type of the specified file", "[rust]") }), + stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")), stable("o", |o| o.optopt("o", "output", "where to place the output", "PATH")), stable("crate-name", |o| { o.optopt("", "crate-name", "specify the name of this crate", "NAME") }), make_crate_type_option(), stable("L", |o| { - o.optmulti("L", "library-path", "directory to add to crate search path", - "DIR") + o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") }), stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), - stable("extern", |o| { - o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]") - }), + stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")), unstable("extern-html-root-url", |o| { - o.optmulti("", "extern-html-root-url", - "base URL to use for dependencies", "NAME=URL") - }), - stable("plugin-path", |o| { - o.optmulti("", "plugin-path", "removed", "DIR") + o.optmulti("", "extern-html-root-url", "base URL to use for dependencies", "NAME=URL") }), + stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")), stable("C", |o| { o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]") }), stable("passes", |o| { - o.optmulti("", "passes", - "list of passes to also run, you might want \ + o.optmulti( + "", + "passes", + "list of passes to also run, you might want \ to pass it multiple times; a value of `list` \ will print available passes", - "PASSES") - }), - stable("plugins", |o| { - o.optmulti("", "plugins", "removed", - "PLUGINS") - }), - stable("no-default", |o| { - o.optflag("", "no-defaults", "don't run the default passes") + "PASSES", + ) }), + stable("plugins", |o| o.optmulti("", "plugins", "removed", "PLUGINS")), + stable("no-default", |o| o.optflag("", "no-defaults", "don't run the default passes")), stable("document-private-items", |o| { o.optflag("", "document-private-items", "document private items") }), stable("test", |o| o.optflag("", "test", "run code examples as tests")), stable("test-args", |o| { - o.optmulti("", "test-args", "arguments to pass to the test runner", - "ARGS") + o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") }), stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), stable("markdown-css", |o| { - o.optmulti("", "markdown-css", - "CSS files to include via in a rendered Markdown file", - "FILES") + o.optmulti( + "", + "markdown-css", + "CSS files to include via in a rendered Markdown file", + "FILES", + ) }), - stable("html-in-header", |o| { - o.optmulti("", "html-in-header", - "files to include inline in the section of a rendered Markdown file \ + stable("html-in-header", |o| { + o.optmulti( + "", + "html-in-header", + "files to include inline in the section of a rendered Markdown file \ or generated documentation", - "FILES") + "FILES", + ) }), stable("html-before-content", |o| { - o.optmulti("", "html-before-content", - "files to include inline between and the content of a rendered \ + o.optmulti( + "", + "html-before-content", + "files to include inline between and the content of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), stable("html-after-content", |o| { - o.optmulti("", "html-after-content", - "files to include inline between the content and of a rendered \ + o.optmulti( + "", + "html-after-content", + "files to include inline between the content and of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), unstable("markdown-before-content", |o| { - o.optmulti("", "markdown-before-content", - "files to include inline between and the content of a rendered \ + o.optmulti( + "", + "markdown-before-content", + "files to include inline between and the content of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), unstable("markdown-after-content", |o| { - o.optmulti("", "markdown-after-content", - "files to include inline between the content and of a rendered \ + o.optmulti( + "", + "markdown-after-content", + "files to include inline between the content and of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), stable("markdown-playground-url", |o| { - o.optopt("", "markdown-playground-url", - "URL to send code snippets to", "URL") + o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL") }), stable("markdown-no-toc", |o| { o.optflag("", "markdown-no-toc", "don't include table of contents") }), stable("e", |o| { - o.optopt("e", "extend-css", - "To add some CSS rules with a given file to generate doc with your \ + o.optopt( + "e", + "extend-css", + "To add some CSS rules with a given file to generate doc with your \ own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", "PATH") + changes, so be careful!", + "PATH", + ) }), unstable("Z", |o| { - o.optmulti("Z", "", - "internal and debugging options (only on nightly build)", "FLAG") - }), - stable("sysroot", |o| { - o.optopt("", "sysroot", "Override the system root", "PATH") + o.optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG") }), + stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")), unstable("playground-url", |o| { - o.optopt("", "playground-url", - "URL to send code snippets to, may be reset by --markdown-playground-url \ + o.optopt( + "", + "playground-url", + "URL to send code snippets to, may be reset by --markdown-playground-url \ or `#![doc(html_playground_url=...)]`", - "URL") + "URL", + ) }), unstable("display-warnings", |o| { o.optflag("", "display-warnings", "to print code warnings when testing doc") @@ -245,69 +267,70 @@ fn opts() -> Vec { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), unstable("sort-modules-by-appearance", |o| { - o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \ - program, rather than alphabetically") + o.optflag( + "", + "sort-modules-by-appearance", + "sort modules by where they appear in the \ + program, rather than alphabetically", + ) }), stable("theme", |o| { - o.optmulti("", "theme", - "additional themes which will be added to the generated docs", - "FILES") + o.optmulti( + "", + "theme", + "additional themes which will be added to the generated docs", + "FILES", + ) }), stable("check-theme", |o| { - o.optmulti("", "check-theme", - "check if given theme is valid", - "FILES") + o.optmulti("", "check-theme", "check if given theme is valid", "FILES") }), unstable("resource-suffix", |o| { - o.optopt("", - "resource-suffix", - "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ + o.optopt( + "", + "resource-suffix", + "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ \"light-suffix.css\"", - "PATH") + "PATH", + ) }), stable("edition", |o| { - o.optopt("", "edition", - "edition to use when compiling rust code (default: 2015)", - "EDITION") + o.optopt( + "", + "edition", + "edition to use when compiling rust code (default: 2015)", + "EDITION", + ) }), stable("color", |o| { - o.optopt("", - "color", - "Configure coloring of output: + o.optopt( + "", + "color", + "Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output", - "auto|always|never") + "auto|always|never", + ) }), stable("error-format", |o| { - o.optopt("", - "error-format", - "How errors and other messages are produced", - "human|json|short") + o.optopt( + "", + "error-format", + "How errors and other messages are produced", + "human|json|short", + ) }), stable("json", |o| { - o.optopt("", - "json", - "Configure the structure of JSON diagnostics", - "CONFIG") + o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG") }), unstable("disable-minification", |o| { - o.optflag("", - "disable-minification", - "Disable minification applied on JS files") - }), - stable("warn", |o| { - o.optmulti("W", "warn", "Set lint warnings", "OPT") - }), - stable("allow", |o| { - o.optmulti("A", "allow", "Set lint allowed", "OPT") - }), - stable("deny", |o| { - o.optmulti("D", "deny", "Set lint denied", "OPT") - }), - stable("forbid", |o| { - o.optmulti("F", "forbid", "Set lint forbidden", "OPT") + o.optflag("", "disable-minification", "Disable minification applied on JS files") }), + stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "OPT")), + stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "OPT")), + stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "OPT")), + stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "OPT")), stable("cap-lints", |o| { o.optmulti( "", @@ -319,65 +342,78 @@ fn opts() -> Vec { ) }), unstable("index-page", |o| { - o.optopt("", - "index-page", - "Markdown file to be used as index page", - "PATH") + o.optopt("", "index-page", "Markdown file to be used as index page", "PATH") }), unstable("enable-index-page", |o| { - o.optflag("", - "enable-index-page", - "To enable generation of the index page") + o.optflag("", "enable-index-page", "To enable generation of the index page") }), unstable("static-root-path", |o| { - o.optopt("", - "static-root-path", - "Path string to force loading static files from in output pages. \ + o.optopt( + "", + "static-root-path", + "Path string to force loading static files from in output pages. \ If not set, uses combinations of '../' to reach the documentation root.", - "PATH") + "PATH", + ) }), unstable("disable-per-crate-search", |o| { - o.optflag("", - "disable-per-crate-search", - "disables generating the crate selector on the search box") + o.optflag( + "", + "disable-per-crate-search", + "disables generating the crate selector on the search box", + ) }), unstable("persist-doctests", |o| { - o.optopt("", - "persist-doctests", - "Directory to persist doctest executables into", - "PATH") + o.optopt( + "", + "persist-doctests", + "Directory to persist doctest executables into", + "PATH", + ) }), unstable("generate-redirect-pages", |o| { - o.optflag("", - "generate-redirect-pages", - "Generate extra pages to support legacy URLs and tool links") + o.optflag( + "", + "generate-redirect-pages", + "Generate extra pages to support legacy URLs and tool links", + ) }), unstable("show-coverage", |o| { - o.optflag("", - "show-coverage", - "calculate percentage of public items with documentation") + o.optflag( + "", + "show-coverage", + "calculate percentage of public items with documentation", + ) }), unstable("enable-per-target-ignores", |o| { - o.optflag("", - "enable-per-target-ignores", - "parse ignore-foo for ignoring doctests on a per-target basis") + o.optflag( + "", + "enable-per-target-ignores", + "parse ignore-foo for ignoring doctests on a per-target basis", + ) }), unstable("runtool", |o| { - o.optopt("", - "runtool", - "", - "The tool to run tests with when building for a different target than host") + o.optopt( + "", + "runtool", + "", + "The tool to run tests with when building for a different target than host", + ) }), unstable("runtool-arg", |o| { - o.optmulti("", - "runtool-arg", - "", - "One (of possibly many) arguments to pass to the runtool") + o.optmulti( + "", + "runtool-arg", + "", + "One (of possibly many) arguments to pass to the runtool", + ) }), unstable("test-builder", |o| { - o.optflag("", - "test-builder", - "specified the rustc-like binary to use as the test builder") + o.optflag( + "", + "test-builder", + "specified the rustc-like binary to use as the test builder", + ) }), ] } @@ -405,33 +441,34 @@ fn main_args(args: &[String]) -> i32 { Ok(opts) => opts, Err(code) => return code, }; - rustc_interface::interface::default_thread_pool(options.edition, move || { - main_options(options) - }) + rustc_interface::interface::default_thread_pool(options.edition, move || main_options(options)) } fn main_options(options: config::Options) -> i32 { - let diag = core::new_handler(options.error_format, - None, - options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing); + let diag = core::new_handler( + options.error_format, + None, + options.debugging_options.treat_err_as_bug, + options.debugging_options.ui_testing, + ); match (options.should_test, options.markdown_input()) { (true, true) => return markdown::test(options, &diag), (true, false) => return test::run(options), - (false, true) => return markdown::render(options.input, - options.render_options, - &diag, - options.edition), + (false, true) => { + return markdown::render(options.input, options.render_options, &diag, options.edition); + } (false, false) => {} } // need to move these items separately because we lose them by the time the closure is called, // but we can't crates the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, - options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing, - options.edition); + let diag_opts = ( + options.error_format, + options.debugging_options.treat_err_as_bug, + options.debugging_options.ui_testing, + options.edition, + ); let show_coverage = options.show_coverage; rust_input(options, move |out| { if show_coverage { @@ -444,13 +481,7 @@ fn main_options(options: config::Options) -> i32 { info!("going to format"); let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts; let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing); - match html::render::run( - krate, - renderopts, - renderinfo, - &diag, - edition, - ) { + match html::render::run(krate, renderopts, renderinfo, &diag, edition) { Ok(_) => rustc_driver::EXIT_SUCCESS, Err(e) => { diag.struct_err(&format!("couldn't generate documentation: {}", e.error)) @@ -468,8 +499,9 @@ fn main_options(options: config::Options) -> i32 { /// /// This form of input will run all of the plug/cleaning passes fn rust_input(options: config::Options, f: F) -> R -where R: 'static + Send, - F: 'static + Send + FnOnce(Output) -> R +where + R: 'static + Send, + F: 'static + Send + FnOnce(Output) -> R, { // First, parse the crate and extract all relevant information. info!("starting to run rustc"); @@ -487,11 +519,7 @@ where R: 'static + Send, krate.version = crate_version; - f(Output { - krate, - renderinfo, - renderopts, - }) + f(Output { krate, renderinfo, renderopts }) }); match result { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index dc1ca8d7668ae..75f874d83274e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -4,8 +4,8 @@ use crate::fold::{self, DocFolder}; use crate::passes::Pass; use syntax::attr; -use syntax_pos::FileName; use syntax::symbol::sym; +use syntax_pos::FileName; use std::collections::BTreeMap; use std::ops; @@ -53,10 +53,7 @@ impl ops::Sub for ItemCount { type Output = Self; fn sub(self, rhs: Self) -> Self { - ItemCount { - total: self.total - rhs.total, - with_docs: self.with_docs - rhs.with_docs, - } + ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs } } } @@ -81,13 +78,17 @@ impl CoverageCalculator { } fn print_table_record(name: &str, count: ItemCount, percentage: f64) { - println!("| {:<35} | {:>10} | {:>10} | {:>9.1}% |", - name, count.with_docs, count.total, percentage); + println!( + "| {:<35} | {:>10} | {:>10} | {:>9.1}% |", + name, count.with_docs, count.total, percentage + ); } print_table_line(); - println!("| {:<35} | {:>10} | {:>10} | {:>10} |", - "File", "Documented", "Total", "Percentage"); + println!( + "| {:<35} | {:>10} | {:>10} | {:>10} |", + "File", "Documented", "Total", "Percentage" + ); print_table_line(); for (file, &count) in &self.items { @@ -97,7 +98,7 @@ impl CoverageCalculator { // FIXME(misdreavus): this needs to count graphemes, and probably also track // double-wide characters... if name.len() > 35 { - name = "...".to_string() + &name[name.len()-32..]; + name = "...".to_string() + &name[name.len() - 32..]; } print_table_record(&name, count, percentage); @@ -133,7 +134,8 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived) - || impl_.synthetic || impl_.blanket_impl.is_some() => + || impl_.synthetic + || impl_.blanket_impl.is_some() => { // built-in derives get the `#[automatically_derived]` attribute, and // synthetic/blanket impls are made up by rustdoc and can't be documented @@ -142,8 +144,12 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) => { if let Some(ref tr) = impl_.trait_ { - debug!("impl {:#} for {:#} in {}", - tr.print(), impl_.for_.print(), i.source.filename); + debug!( + "impl {:#} for {:#} in {}", + tr.print(), + impl_.for_.print(), + i.source.filename + ); // don't count trait impls, the missing-docs lint doesn't so we shouldn't // either @@ -157,9 +163,7 @@ impl fold::DocFolder for CoverageCalculator { } _ => { debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); - self.items.entry(i.source.filename.clone()) - .or_default() - .count_item(has_docs); + self.items.entry(i.source.filename.clone()).or_default().count_item(has_docs); } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 8d5463ddbd764..7bbed4af23838 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,9 +1,9 @@ use errors::Applicability; -use rustc_parse::lexer::{StringReader as Lexer}; -use syntax::token; +use rustc_parse::lexer::StringReader as Lexer; use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; -use syntax_pos::{InnerSpan, FileName}; +use syntax::token; +use syntax_pos::{FileName, InnerSpan}; use crate::clean; use crate::core::DocContext; @@ -38,7 +38,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { let mut only_whitespace = true; // even if there is a syntax error, we need to run the lexer over the whole file let mut lexer = Lexer::new(&sess, source_file, None); - loop { + loop { match lexer.next_token().kind { token::Eof => break, token::Whitespace => (), diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 31288345ce57b..c6b22883e9723 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -1,7 +1,7 @@ use crate::clean::{self, DocFragment, Item}; use crate::core::DocContext; use crate::fold; -use crate::fold::{DocFolder}; +use crate::fold::DocFolder; use crate::passes::Pass; use std::mem::take; @@ -56,10 +56,10 @@ fn collapse(doc_strings: &mut Vec) { if curr_kind == DocFragmentKind::Include || curr_kind != new_kind { match curr_frag { DocFragment::SugaredDoc(_, _, ref mut doc_string) - | DocFragment::RawDoc(_, _, ref mut doc_string) => { - // add a newline for extra padding between segments - doc_string.push('\n'); - } + | DocFragment::RawDoc(_, _, ref mut doc_string) => { + // add a newline for extra padding between segments + doc_string.push('\n'); + } _ => {} } docs.push(curr_frag); @@ -67,11 +67,11 @@ fn collapse(doc_strings: &mut Vec) { } else { match curr_frag { DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string) - | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { - doc_string.push('\n'); - doc_string.push_str(frag.as_str()); - *span = span.to(frag.span()); - } + | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { + doc_string.push('\n'); + doc_string.push_str(frag.as_str()); + *span = span.to(frag.span()); + } _ => unreachable!(), } last_frag = Some(curr_frag); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3c021ae746523..af850a3446799 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,23 +1,27 @@ use errors::Applicability; -use rustc::hir::def::{Res, DefKind, Namespace::{self, *}, PerNS}; -use rustc::hir::def_id::DefId; use rustc::hir; -use rustc::lint as lint; +use rustc::hir::def::{ + DefKind, + Namespace::{self, *}, + PerNS, Res, +}; +use rustc::hir::def_id::DefId; +use rustc::lint; use rustc::ty; -use rustc_resolve::ParentScope; use rustc_feature::UnstableFeatures; +use rustc_resolve::ParentScope; use syntax; use syntax::ast::{self, Ident}; -use syntax_expand::base::SyntaxExtensionKind; use syntax::symbol::Symbol; +use syntax_expand::base::SyntaxExtensionKind; use syntax_pos::DUMMY_SP; use std::ops::Range; +use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; -use crate::clean::*; use crate::passes::{look_for_tests, Pass}; use super::span_of_attrs; @@ -50,10 +54,7 @@ struct LinkCollector<'a, 'tcx> { impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - LinkCollector { - cx, - mod_ids: Vec::new(), - } + LinkCollector { cx, mod_ids: Vec::new() } } fn variant_field( @@ -65,44 +66,51 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let cx = self.cx; let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = split + let variant_field_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let variant_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let path = split .next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let variant_name = split - .next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let path = split.next().map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); + } } - } - f.to_owned() - }).ok_or(ErrorKind::ResolutionFailure)?; - let (_, ty_res) = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }).map_err(|_| ErrorKind::ResolutionFailure)?; + f.to_owned() + }) + .ok_or(ErrorKind::ResolutionFailure)?; + let (_, ty_res) = cx + .enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + }) + .map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { return Err(ErrorKind::ResolutionFailure); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { Res::Def(DefKind::Enum, did) => { - if cx.tcx.inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) - .any(|item| item.ident.name == variant_name) { + if cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp)) + .any(|item| item.ident.name == variant_name) + { return Err(ErrorKind::ResolutionFailure); } match cx.tcx.type_of(did).kind { ty::Adt(def, _) if def.is_enum() => { - if def.all_fields() - .any(|item| item.ident.name == variant_field_name) { - Ok((ty_res, - Some(format!("variant.{}.field.{}", - variant_name, variant_field_name)))) + if def.all_fields().any(|item| item.ident.name == variant_field_name) { + Ok(( + ty_res, + Some(format!( + "variant.{}.field.{}", + variant_name, variant_field_name + )), + )) } else { Err(ErrorKind::ResolutionFailure) } @@ -110,7 +118,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => Err(ErrorKind::ResolutionFailure), } } - _ => Err(ErrorKind::ResolutionFailure) + _ => Err(ErrorKind::ResolutionFailure), } } @@ -150,50 +158,55 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err( - ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure( + "primitive types cannot be followed by anchors", + )); } return Ok((res, Some(path_str.to_owned()))); } - _ => return Ok((res, extra_fragment.clone())) + _ => return Ok((res, extra_fragment.clone())), }; if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure) + return Err(ErrorKind::ResolutionFailure); } } else if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err( - ErrorKind::AnchorFailure("primitive types cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure( + "primitive types cannot be followed by anchors", + )); } - return Ok((prim, Some(path_str.to_owned()))) + return Ok((prim, Some(path_str.to_owned()))); } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver // If so, bail when we're not looking for a value. if ns != ValueNS { - return Err(ErrorKind::ResolutionFailure) + return Err(ErrorKind::ResolutionFailure); } } // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - let item_name = split.next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let path = split.next().map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); + let item_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let path = split + .next() + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); + } } - } - f.to_owned() - }).ok_or(ErrorKind::ResolutionFailure)?; + f.to_owned() + }) + .ok_or(ErrorKind::ResolutionFailure)?; if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?; - return cx.tcx.associated_items(did) + return cx + .tcx + .associated_items(did) .find(|item| item.ident.name == item_name) .and_then(|item| match item.kind { ty::AssocKind::Method => Some("method"), @@ -203,9 +216,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(ErrorKind::ResolutionFailure); } - let (_, ty_res) = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }).map_err(|_| ErrorKind::ResolutionFailure)?; + let (_, ty_res) = cx + .enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + }) + .map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { return self.variant_field(path_str, current_item, module_id); } @@ -215,10 +230,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { | Res::Def(DefKind::Union, did) | Res::Def(DefKind::Enum, did) | Res::Def(DefKind::TyAlias, did) => { - let item = cx.tcx.inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) - .find(|item| item.ident.name == item_name); + let item = cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp)) + .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { ty::AssocKind::Method if ns == ValueNS => "method", @@ -226,12 +243,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => return self.variant_field(path_str, current_item, module_id), }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if item.kind == ty::AssocKind::Method { - "methods cannot be followed by anchors" - } else { - "associated constants cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Method { + "methods cannot be followed by anchors" + } else { + "associated constants cannot be followed by anchors" + })) } else { Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } @@ -242,26 +258,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { def.all_fields().find(|item| item.ident.name == item_name) } else { def.non_enum_variant() - .fields - .iter() - .find(|item| item.ident.name == item_name) + .fields + .iter() + .find(|item| item.ident.name == item_name) } { if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if def.is_enum() { - "enum variants cannot be followed by anchors" - } else { - "struct fields cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if def.is_enum() { + "enum variants cannot be followed by anchors" + } else { + "struct fields cannot be followed by anchors" + })) } else { - Ok((ty_res, - Some(format!("{}.{}", - if def.is_enum() { - "variant" - } else { - "structfield" - }, - item.ident)))) + Ok(( + ty_res, + Some(format!( + "{}.{}", + if def.is_enum() { + "variant" + } else { + "structfield" + }, + item.ident + )), + )) } } else { self.variant_field(path_str, current_item, module_id) @@ -272,32 +291,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } Res::Def(DefKind::Trait, did) => { - let item = cx.tcx.associated_item_def_ids(did).iter() - .map(|item| cx.tcx.associated_item(*item)) - .find(|item| item.ident.name == item_name); + let item = cx + .tcx + .associated_item_def_ids(did) + .iter() + .map(|item| cx.tcx.associated_item(*item)) + .find(|item| item.ident.name == item_name); if let Some(item) = item { let kind = match item.kind { ty::AssocKind::Const if ns == ValueNS => "associatedconstant", ty::AssocKind::Type if ns == TypeNS => "associatedtype", ty::AssocKind::Method if ns == ValueNS => { - if item.defaultness.has_value() { - "method" - } else { - "tymethod" - } + if item.defaultness.has_value() { "method" } else { "tymethod" } } _ => return self.variant_field(path_str, current_item, module_id), }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if item.kind == ty::AssocKind::Const { - "associated constants cannot be followed by anchors" - } else if item.kind == ty::AssocKind::Type { - "associated types cannot be followed by anchors" - } else { - "methods cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { + "associated constants cannot be followed by anchors" + } else if item.kind == ty::AssocKind::Type { + "associated types cannot be followed by anchors" + } else { + "methods cannot be followed by anchors" + })) } else { Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) } @@ -344,11 +361,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let current_item = match item.inner { ModuleItem(..) => { if item.attrs.inner_docs { - if item_hir_id.unwrap() != hir::CRATE_HIR_ID { - item.name.clone() - } else { - None - } + if item_hir_id.unwrap() != hir::CRATE_HIR_ID { item.name.clone() } else { None } } else { match parent_node.or(self.mod_ids.last().cloned()) { Some(parent) if parent != hir::CRATE_HIR_ID => { @@ -392,10 +405,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let link = ori_link.replace("`", ""); let parts = link.split('#').collect::>(); let (link, extra_fragment) = if parts.len() > 2 { - build_diagnostic(cx, &item, &link, &dox, link_range, - "has an issue with the link anchor.", - "only one `#` is allowed in a link", - None); + build_diagnostic( + cx, + &item, + &link, + &dox, + link_range, + "has an issue with the link anchor.", + "only one `#` is allowed in a link", + None, + ); continue; } else if parts.len() == 2 { if parts[0].trim().is_empty() { @@ -409,16 +428,25 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let (res, fragment) = { let mut kind = None; let path_str = if let Some(prefix) = - ["struct@", "enum@", "type@", - "trait@", "union@"].iter() - .find(|p| link.starts_with(**p)) { + ["struct@", "enum@", "type@", "trait@", "union@"] + .iter() + .find(|p| link.starts_with(**p)) + { kind = Some(TypeNS); link.trim_start_matches(prefix) - } else if let Some(prefix) = - ["const@", "static@", - "value@", "function@", "mod@", - "fn@", "module@", "method@"] - .iter().find(|p| link.starts_with(**p)) { + } else if let Some(prefix) = [ + "const@", + "static@", + "value@", + "function@", + "mod@", + "fn@", + "module@", + "method@", + ] + .iter() + .find(|p| link.starts_with(**p)) + { kind = Some(ValueNS); link.trim_start_matches(prefix) } else if link.ends_with("()") { @@ -432,10 +460,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { link.trim_end_matches('!') } else { &link[..] - }.trim(); + } + .trim(); - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || - ch == ':' || ch == '_')) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { continue; } @@ -450,16 +478,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // we've already pushed this node onto the resolution stack but // for outer comments we explicitly try and resolve against the // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - None - } else { - parent_node - }; + let base_node = + if item.is_mod() && item.attrs.inner_docs { None } else { parent_node }; match kind { Some(ns @ ValueNS) => { - match self.resolve(path_str, ns, ¤t_item, base_node, - &extra_fragment) { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -470,13 +495,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue + continue; } } } Some(ns @ TypeNS) => { - match self.resolve(path_str, ns, ¤t_item, base_node, - &extra_fragment) { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -485,7 +510,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue + continue; } } } @@ -493,17 +518,27 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // Try everything! let candidates = PerNS { macro_ns: macro_resolve(cx, path_str) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve(path_str, TypeNS, ¤t_item, base_node, - &extra_fragment) { + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } x => x.ok(), }, - value_ns: match self.resolve(path_str, ValueNS, ¤t_item, - base_node, &extra_fragment) { + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; @@ -553,7 +588,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { (res, extra_fragment) } else { resolution_failure(cx, &item, path_str, &dox, link_range); - continue + continue; } } } @@ -597,7 +632,11 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { if let Ok((Some(ext), res)) = resolver.resolve_macro_path( - &path, None, &ParentScope::module(resolver.graph_root()), false, false + &path, + None, + &ParentScope::module(resolver.graph_root()), + false, + false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { return Some(res.map_id(|_| panic!("unexpected id"))); @@ -652,10 +691,10 @@ fn build_diagnostic( diag.note(&format!( "the link appears in this line:\n\n{line}\n\ {indicator: >, ) { - build_diagnostic(cx, item, path_str, dox, link_range, - "cannot be resolved, ignoring it.", - "cannot be resolved, ignoring", - Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`")); + build_diagnostic( + cx, + item, + path_str, + dox, + link_range, + "cannot be resolved, ignoring it.", + "cannot be resolved, ignoring", + Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"), + ); } fn anchor_failure( @@ -691,10 +736,16 @@ fn anchor_failure( link_range: Option>, msg: &str, ) { - build_diagnostic(cx, item, path_str, dox, link_range, - "has an issue with the link anchor.", - msg, - None); + build_diagnostic( + cx, + item, + path_str, + dox, + link_range, + "has an issue with the link anchor.", + msg, + None, + ); } fn ambiguity_error( @@ -717,9 +768,10 @@ fn ambiguity_error( let mut msg = format!("`{}` is ", path_str); - let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| { - candidates[ns].map(|res| (res, ns)) - }).collect::>(); + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) + .collect::>(); match candidates.as_slice() { [(first_def, _), (second_def, _)] => { msg += &format!( @@ -804,10 +856,10 @@ fn ambiguity_error( diag.note(&format!( "the link appears in this line:\n\n{line}\n\ {indicator: Option { - if ns == TypeNS { - PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) - } else { - None - } + if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None } } fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 28c64d0b9638e..4e0d1a101917d 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -1,10 +1,10 @@ +use super::Pass; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use super::Pass; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::util::nodemap::FxHashSet; -use rustc::hir::def_id::{LOCAL_CRATE, DefId}; use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { @@ -17,8 +17,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut synth = SyntheticImplCollector::new(cx); let mut krate = synth.fold_crate(krate); - let prims: FxHashSet = - krate.primitives.iter().map(|p| p.1).collect(); + let prims: FxHashSet = krate.primitives.iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); @@ -80,21 +79,20 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { } } - let mut cleaner = BadImplStripper { - prims, - items: crate_items, - }; + let mut cleaner = BadImplStripper { prims, items: crate_items }; // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in &new_items { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner { if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { - let target = items.iter().filter_map(|item| { - match item.inner { + let target = items + .iter() + .filter_map(|item| match item.inner { TypedefItem(ref t, true) => Some(&t.type_), _ => None, - } - }).next().expect("Deref impl without Target type"); + }) + .next() + .expect("Deref impl without Target type"); if let Some(prim) = target.primitive_type() { cleaner.prims.insert(prim); @@ -107,9 +105,9 @@ pub 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.inner { - cleaner.keep_item(for_) || - trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) || - blanket_impl.is_some() + cleaner.keep_item(for_) + || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) + || blanket_impl.is_some() } else { true } @@ -145,10 +143,7 @@ struct SyntheticImplCollector<'a, 'tcx> { impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - SyntheticImplCollector { - cx, - impls: Vec::new(), - } + SyntheticImplCollector { cx, impls: Vec::new() } } } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 0a95d4209ac6a..b69207be3fb36 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -2,12 +2,12 @@ //! process. use rustc::hir::def_id::DefId; -use rustc::lint as lint; +use rustc::lint; use rustc::middle::privacy::AccessLevels; use rustc::util::nodemap::DefIdSet; use std::mem; -use syntax_pos::{DUMMY_SP, InnerSpan, Span}; use std::ops::Range; +use syntax_pos::{InnerSpan, Span, DUMMY_SP}; use crate::clean::{self, GetDefId, Item}; use crate::core::DocContext; @@ -57,7 +57,6 @@ pub struct Pass { pub description: &'static str, } - /// The full list of passes. pub const PASSES: &[Pass] = &[ CHECK_PRIVATE_ITEMS_DOC_TESTS, @@ -99,19 +98,12 @@ pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[ ]; /// The list of default passes run when `--doc-coverage` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - STRIP_HIDDEN, - STRIP_PRIVATE, - CALCULATE_DOC_COVERAGE, -]; +pub const DEFAULT_COVERAGE_PASSES: &[Pass] = + &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE]; /// The list of default passes run when `--doc-coverage --document-private-items` is passed to /// rustdoc. -pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - CALCULATE_DOC_COVERAGE, -]; +pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE]; /// A shorthand way to refer to which set of passes to use, based on the presence of /// `--no-defaults` or `--document-private-items`. @@ -229,9 +221,7 @@ impl<'a> DocFolder for Stripper<'a> { // implementations of traits are always public. clean::ImplItem(ref imp) if imp.trait_.is_some() => true, // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant { - kind: clean::VariantKind::Struct(..), - }) => true, + clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, _ => false, }; @@ -281,8 +271,10 @@ impl<'a> DocFolder for ImplStripper<'a> { for typaram in generics { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { - debug!("ImplStripper: stripped item in trait's generics; \ - removing impl"); + debug!( + "ImplStripper: stripped item in trait's generics; \ + removing impl" + ); return None; } } @@ -298,9 +290,7 @@ struct ImportStripper; impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.inner { - clean::ExternCrateItem(..) | clean::ImportItem(..) - if i.visibility != clean::Public => - { + clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { None } _ => self.fold_item_recur(i), @@ -332,9 +322,7 @@ pub fn look_for_tests<'tcx>( } } - let mut tests = Tests { - found_tests: 0, - }; + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false); @@ -344,16 +332,19 @@ pub fn look_for_tests<'tcx>( lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, - "missing code example in this documentation"); + "missing code example in this documentation", + ); diag.emit(); - } else if check_missing_code == false && - tests.found_tests > 0 && - !cx.renderinfo.borrow().access_levels.is_public(item.def_id) { + } else if check_missing_code == false + && tests.found_tests > 0 + && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) + { let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, hir_id, span_of_attrs(&item.attrs).unwrap_or(item.source.span()), - "documentation test in private item"); + "documentation test in private item", + ); diag.emit(); } } @@ -391,11 +382,7 @@ crate fn source_span_for_markdown_range( return None; } - let snippet = cx - .sess() - .source_map() - .span_to_snippet(span_of_attrs(attrs)?) - .ok()?; + let snippet = cx.sess().source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?; let starting_line = markdown[..md_range.start].matches('\n').count(); let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count(); diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 5560ebed9ae69..23e272709705d 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -15,9 +15,7 @@ struct PrivateItemDocTestLinter<'a, 'tcx> { impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - PrivateItemDocTestLinter { - cx, - } + PrivateItemDocTestLinter { cx } } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index a71a1e001fc69..a296e73e3b5fd 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use crate::clean::{Crate, Item}; use crate::clean::cfg::Cfg; +use crate::clean::{Crate, Item}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 0159e03f6f299..379e2496a0a41 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,8 +2,8 @@ use rustc::util::nodemap::DefIdSet; use std::mem; use syntax::symbol::sym; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::clean::Item; +use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; use crate::passes::{ImplStripper, Pass}; @@ -20,7 +20,7 @@ pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { // strip all #[doc(hidden)] items let krate = { - let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; + let mut stripper = Stripper { retained: &mut retained, update_retained: true }; stripper.fold_crate(krate) }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 516760ade6667..af34842ad0f89 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -1,6 +1,6 @@ use crate::clean; -use crate::fold::{DocFolder}; use crate::core::DocContext; +use crate::fold::DocFolder; use crate::passes::{ImportStripper, Pass}; pub const STRIP_PRIV_IMPORTS: Pass = Pass { @@ -9,6 +9,6 @@ pub const STRIP_PRIV_IMPORTS: Pass = Pass { description: "strips all private import statements (`use`, `extern crate`) from a crate", }; -pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { +pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { ImportStripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index fc742bf74d006..5113afa48402c 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -1,9 +1,9 @@ use rustc::util::nodemap::DefIdSet; use crate::clean; -use crate::fold::{DocFolder}; use crate::core::DocContext; -use crate::passes::{ImplStripper, ImportStripper, Stripper, Pass}; +use crate::fold::DocFolder; +use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper}; pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 7ad98242fdc92..3212af055efc5 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -38,34 +38,28 @@ impl clean::Attributes { fn unindent_fragments(docs: &mut Vec) { for fragment in docs { match *fragment { - DocFragment::SugaredDoc(_, _, ref mut doc_string) | - DocFragment::RawDoc(_, _, ref mut doc_string) | - DocFragment::Include(_, _, _, ref mut doc_string) => - *doc_string = unindent(doc_string), + DocFragment::SugaredDoc(_, _, ref mut doc_string) + | DocFragment::RawDoc(_, _, ref mut doc_string) + | DocFragment::Include(_, _, _, ref mut doc_string) => { + *doc_string = unindent(doc_string) + } } } } fn unindent(s: &str) -> String { - let lines = s.lines().collect:: >(); + let lines = s.lines().collect::>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { - // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = - saw_first_line && - !saw_second_line && - !line.chars().all(|c| c.is_whitespace()); + saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); - let min_indent = if ignore_previous_indents { - usize::MAX - } else { - min_indent - }; + let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; if saw_first_line { saw_second_line = true; @@ -91,15 +85,20 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim_start().to_string() ]; - unindented.extend_from_slice(&lines[1..].iter().map(|&line| { - if line.chars().all(|c| c.is_whitespace()) { - line.to_string() - } else { - assert!(line.len() >= min_indent); - line[min_indent..].to_string() - } - }).collect::>()); + let mut unindented = vec![lines[0].trim_start().to_string()]; + unindented.extend_from_slice( + &lines[1..] + .iter() + .map(|&line| { + if line.chars().all(|c| c.is_whitespace()) { + line.to_string() + } else { + assert!(line.len() >= min_indent); + line[min_indent..].to_string() + } + }) + .collect::>(), + ); unindented.join("\n") } else { s.to_string() From 4bed1c7b9e98babe6de07ed075a7ee354dd18c28 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 4 Jan 2020 10:58:32 -0800 Subject: [PATCH 4/7] Distinguish between private items and hidden items in rustdoc I believe rustdoc should not be conflating private items (visibility lower than `pub`) and hidden items (attribute `doc(hidden)`). This matters now that Cargo is passing --document-private-items by default for bin crates. In bin crates that rely on macros, intentionally hidden implementation details of the macros can overwhelm the actual useful internal API that one would want to document. This PR restores the strip-hidden pass when documenting private items, and introduces a separate unstable --document-hidden-items option to skip the strip-hidden pass. The two options are orthogonal to one another. --- src/librustdoc/config.rs | 43 +++++---- src/librustdoc/core.rs | 26 ++++-- src/librustdoc/lib.rs | 3 + .../passes/calculate_doc_coverage.rs | 2 +- .../passes/check_code_block_syntax.rs | 2 +- src/librustdoc/passes/collapse_docs.rs | 2 +- .../passes/collect_intra_doc_links.rs | 2 +- src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/passes/mod.rs | 87 +++++++++++-------- .../passes/private_items_doc_tests.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/passes/unindent_comments.rs | 2 +- src/test/rustdoc/issue-46380.rs | 5 -- src/test/rustdoc/issue-67851-both.rs | 8 ++ src/test/rustdoc/issue-67851-hidden.rs | 8 ++ src/test/rustdoc/issue-67851-neither.rs | 6 ++ src/test/rustdoc/issue-67851-private.rs | 8 ++ 20 files changed, 138 insertions(+), 78 deletions(-) delete mode 100644 src/test/rustdoc/issue-46380.rs create mode 100644 src/test/rustdoc/issue-67851-both.rs create mode 100644 src/test/rustdoc/issue-67851-hidden.rs create mode 100644 src/test/rustdoc/issue-67851-neither.rs create mode 100644 src/test/rustdoc/issue-67851-private.rs diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7a3cf88f65e21..eec1ffd75c502 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -24,7 +24,7 @@ use crate::html; use crate::html::markdown::IdMap; use crate::html::static_files; use crate::opts; -use crate::passes::{self, DefaultPassOption}; +use crate::passes::{self, Condition, DefaultPassOption}; use crate::theme; /// Configuration options for rustdoc. @@ -98,6 +98,10 @@ pub struct Options { /// /// Be aware: This option can come both from the CLI and from crate attributes! pub default_passes: DefaultPassOption, + /// Document items that have lower than `pub` visibility. + pub document_private: bool, + /// Document items that have `doc(hidden)`. + pub document_hidden: bool, /// Any passes manually selected by the user. /// /// Be aware: This option can come both from the CLI and from crate attributes! @@ -146,6 +150,8 @@ impl fmt::Debug for Options { .field("test_args", &self.test_args) .field("persist_doctests", &self.persist_doctests) .field("default_passes", &self.default_passes) + .field("document_private", &self.document_private) + .field("document_hidden", &self.document_hidden) .field("manual_passes", &self.manual_passes) .field("display_warnings", &self.display_warnings) .field("show_coverage", &self.show_coverage) @@ -240,22 +246,26 @@ impl Options { println!("{:>20} - {}", pass.name, pass.description); } println!("\nDefault passes for rustdoc:"); - for pass in passes::DEFAULT_PASSES { - println!("{:>20}", pass.name); - } - println!("\nPasses run with `--document-private-items`:"); - for pass in passes::DEFAULT_PRIVATE_PASSES { - println!("{:>20}", pass.name); + for p in passes::DEFAULT_PASSES { + print!("{:>20}", p.pass.name); + println_condition(p.condition); } if nightly_options::is_nightly_build() { println!("\nPasses run with `--show-coverage`:"); - for pass in passes::DEFAULT_COVERAGE_PASSES { - println!("{:>20}", pass.name); + for p in passes::COVERAGE_PASSES { + print!("{:>20}", p.pass.name); + println_condition(p.condition); } - println!("\nPasses run with `--show-coverage --document-private-items`:"); - for pass in passes::PRIVATE_COVERAGE_PASSES { - println!("{:>20}", pass.name); + } + + fn println_condition(condition: Condition) { + use Condition::*; + match condition { + Always => println!(), + WhenDocumentPrivate => println!(" (when --document-private-items)"), + WhenNotDocumentPrivate => println!(" (when not --document-private-items)"), + WhenNotDocumentHidden => println!(" (when not --document-hidden-items)"), } } @@ -449,16 +459,11 @@ impl Options { }); let show_coverage = matches.opt_present("show-coverage"); - let document_private = matches.opt_present("document-private-items"); let default_passes = if matches.opt_present("no-defaults") { passes::DefaultPassOption::None - } else if show_coverage && document_private { - passes::DefaultPassOption::PrivateCoverage } else if show_coverage { passes::DefaultPassOption::Coverage - } else if document_private { - passes::DefaultPassOption::Private } else { passes::DefaultPassOption::Default }; @@ -497,6 +502,8 @@ impl Options { let runtool = matches.opt_str("runtool"); let runtool_args = matches.opt_strs("runtool-arg"); let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); + let document_private = matches.opt_present("document-private-items"); + let document_hidden = matches.opt_present("document-hidden-items"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -523,6 +530,8 @@ impl Options { should_test, test_args, default_passes, + document_private, + document_hidden, manual_passes, display_warnings, show_coverage, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 80dd9ad7739b2..9dab2b82cb68e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID}; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::html::render::RenderInfo; -use crate::passes; +use crate::passes::{self, Condition::*, ConditionalPass}; pub use rustc::session::config::{CodegenOptions, Input, Options}; pub use rustc::session::search_paths::SearchPath; @@ -234,6 +234,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt describe_lints, lint_cap, mut default_passes, + mut document_private, + document_hidden, mut manual_passes, display_warnings, render_options, @@ -469,16 +471,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } if attr.is_word() && name == sym::document_private_items { - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::Private; - } + document_private = true; } } - let passes = passes::defaults(default_passes).iter().chain( + let passes = passes::defaults(default_passes).iter().copied().chain( manual_passes.into_iter().flat_map(|name| { if let Some(pass) = passes::find_pass(&name) { - Some(pass) + Some(ConditionalPass::always(pass)) } else { error!("unknown pass {}, skipping", name); None @@ -488,9 +488,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt info!("Executing passes"); - for pass in passes { - debug!("running pass {}", pass.name); - krate = (pass.pass)(krate, &ctxt); + for p in passes { + let run = match p.condition { + Always => true, + WhenDocumentPrivate => document_private, + WhenNotDocumentPrivate => !document_private, + WhenNotDocumentHidden => !document_hidden, + }; + if run { + debug!("running pass {}", p.pass.name); + krate = (p.pass.run)(krate, &ctxt); + } } ctxt.sess().abort_if_errors(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0b4abe0a22e3b..0a71deca0dc61 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -173,6 +173,9 @@ fn opts() -> Vec { stable("document-private-items", |o| { o.optflag("", "document-private-items", "document private items") }), + unstable("document-hidden-items", |o| { + o.optflag("", "document-hidden-items", "document items that have doc(hidden)") + }), stable("test", |o| o.optflag("", "test", "run code examples as tests")), stable("test-args", |o| { o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 75f874d83274e..72f98026f8b2d 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -12,7 +12,7 @@ use std::ops; pub const CALCULATE_DOC_COVERAGE: Pass = Pass { name: "calculate-doc-coverage", - pass: calculate_doc_coverage, + run: calculate_doc_coverage, description: "counts the number of items with and without documentation", }; diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 7bbed4af23838..3cb3a8003cee0 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -13,7 +13,7 @@ use crate::passes::Pass; pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { name: "check-code-block-syntax", - pass: check_code_block_syntax, + run: check_code_block_syntax, description: "validates syntax inside Rust code blocks", }; diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index c6b22883e9723..c2185592d1483 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -8,7 +8,7 @@ use std::mem::take; pub const COLLAPSE_DOCS: Pass = Pass { name: "collapse-docs", - pass: collapse_docs, + run: collapse_docs, description: "concatenates all document attributes into one document attribute", }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index af850a3446799..a92a6152c726a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -28,7 +28,7 @@ use super::span_of_attrs; pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { name: "collect-intra-doc-links", - pass: collect_intra_doc_links, + run: collect_intra_doc_links, description: "reads a crate's documentation to resolve intra-doc-links", }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 4e0d1a101917d..bec352fe1558f 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -9,7 +9,7 @@ use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { name: "collect-trait-impls", - pass: collect_trait_impls, + run: collect_trait_impls, description: "retrieves trait impls for items in the crate", }; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index b69207be3fb36..985aaa66b31d0 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -9,6 +9,7 @@ use std::mem; use std::ops::Range; use syntax_pos::{InnerSpan, Span, DUMMY_SP}; +use self::Condition::*; use crate::clean::{self, GetDefId, Item}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; @@ -53,10 +54,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; #[derive(Copy, Clone)] pub struct Pass { pub name: &'static str, - pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, + pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, pub description: &'static str, } +/// In a list of passes, a pass that may or may not need to be run depending on options. +#[derive(Copy, Clone)] +pub struct ConditionalPass { + pub pass: Pass, + pub condition: Condition, +} + +/// How to decide whether to run a conditional pass. +#[derive(Copy, Clone)] +pub enum Condition { + Always, + /// When `--document-private-items` is passed. + WhenDocumentPrivate, + /// When `--document-private-items` is not passed. + WhenNotDocumentPrivate, + /// When `--document-hidden-items` is not passed. + WhenNotDocumentHidden, +} + /// The full list of passes. pub const PASSES: &[Pass] = &[ CHECK_PRIVATE_ITEMS_DOC_TESTS, @@ -73,63 +93,58 @@ pub const PASSES: &[Pass] = &[ ]; /// The list of passes run by default. -pub const DEFAULT_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - COLLAPSE_DOCS, - UNINDENT_COMMENTS, - CHECK_PRIVATE_ITEMS_DOC_TESTS, - STRIP_HIDDEN, - STRIP_PRIVATE, - COLLECT_INTRA_DOC_LINKS, - CHECK_CODE_BLOCK_SYNTAX, - PROPAGATE_DOC_CFG, +pub const DEFAULT_PASSES: &[ConditionalPass] = &[ + ConditionalPass::always(COLLECT_TRAIT_IMPLS), + ConditionalPass::always(COLLAPSE_DOCS), + ConditionalPass::always(UNINDENT_COMMENTS), + ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS), + ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), + ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), + ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), + ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), + ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX), + ConditionalPass::always(PROPAGATE_DOC_CFG), ]; -/// The list of default passes run with `--document-private-items` is passed to rustdoc. -pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - COLLAPSE_DOCS, - UNINDENT_COMMENTS, - CHECK_PRIVATE_ITEMS_DOC_TESTS, - STRIP_PRIV_IMPORTS, - COLLECT_INTRA_DOC_LINKS, - CHECK_CODE_BLOCK_SYNTAX, - PROPAGATE_DOC_CFG, +/// The list of default passes run when `--doc-coverage` is passed to rustdoc. +pub const COVERAGE_PASSES: &[ConditionalPass] = &[ + ConditionalPass::always(COLLECT_TRAIT_IMPLS), + ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), + ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), + ConditionalPass::always(CALCULATE_DOC_COVERAGE), ]; -/// The list of default passes run when `--doc-coverage` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &[Pass] = - &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE]; +impl ConditionalPass { + pub const fn always(pass: Pass) -> Self { + Self::new(pass, Always) + } -/// The list of default passes run when `--doc-coverage --document-private-items` is passed to -/// rustdoc. -pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE]; + pub const fn new(pass: Pass, condition: Condition) -> Self { + ConditionalPass { pass, condition } + } +} /// A shorthand way to refer to which set of passes to use, based on the presence of -/// `--no-defaults` or `--document-private-items`. +/// `--no-defaults` and `--show-coverage`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DefaultPassOption { Default, - Private, Coverage, - PrivateCoverage, None, } /// Returns the given default set of passes. -pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] { +pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] { match default_set { DefaultPassOption::Default => DEFAULT_PASSES, - DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES, - DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES, - DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES, + DefaultPassOption::Coverage => COVERAGE_PASSES, DefaultPassOption::None => &[], } } /// If the given name matches a known pass, returns its information. -pub fn find_pass(pass_name: &str) -> Option<&'static Pass> { - PASSES.iter().find(|p| p.name == pass_name) +pub fn find_pass(pass_name: &str) -> Option { + PASSES.iter().find(|p| p.name == pass_name).copied() } struct Stripper<'a> { diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 23e272709705d..aec5a6bd4e221 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass}; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { name: "check-private-items-doc-tests", - pass: check_private_items_doc_tests, + run: check_private_items_doc_tests, description: "check private items doc tests", }; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index a296e73e3b5fd..64b0c45ba65d3 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -8,7 +8,7 @@ use crate::passes::Pass; pub const PROPAGATE_DOC_CFG: Pass = Pass { name: "propagate-doc-cfg", - pass: propagate_doc_cfg, + run: propagate_doc_cfg, description: "propagates `#[doc(cfg(...))]` to child items", }; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 379e2496a0a41..2b4de3c063f38 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass}; pub const STRIP_HIDDEN: Pass = Pass { name: "strip-hidden", - pass: strip_hidden, + run: strip_hidden, description: "strips all doc(hidden) items from the output", }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index af34842ad0f89..35b26fb8ab0be 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass}; pub const STRIP_PRIV_IMPORTS: Pass = Pass { name: "strip-priv-imports", - pass: strip_priv_imports, + run: strip_priv_imports, description: "strips all private import statements (`use`, `extern crate`) from a crate", }; diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 5113afa48402c..e0379d7ffe2c5 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper}; pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", - pass: strip_private, + run: strip_private, description: "strips all private items from a crate which cannot be seen externally, \ implies strip-priv-imports", }; diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 3212af055efc5..d4e09ce47a3c1 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -12,7 +12,7 @@ mod tests; pub const UNINDENT_COMMENTS: Pass = Pass { name: "unindent-comments", - pass: unindent_comments, + run: unindent_comments, description: "removes excess indentation on comments in order for markdown to like it", }; diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs deleted file mode 100644 index 8837a6b463e88..0000000000000 --- a/src/test/rustdoc/issue-46380.rs +++ /dev/null @@ -1,5 +0,0 @@ -// compile-flags: --document-private-items - -// @has issue_46380/struct.Hidden.html -#[doc(hidden)] -pub struct Hidden; diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs new file mode 100644 index 0000000000000..d69b943173412 --- /dev/null +++ b/src/test/rustdoc/issue-67851-both.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-private-items --document-hidden-items + +// @has issue_67851_both/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_both/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs new file mode 100644 index 0000000000000..8a3cafe4c3dc7 --- /dev/null +++ b/src/test/rustdoc/issue-67851-hidden.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-hidden-items + +// @has issue_67851_hidden/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_hidden/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs new file mode 100644 index 0000000000000..4e3cd83285388 --- /dev/null +++ b/src/test/rustdoc/issue-67851-neither.rs @@ -0,0 +1,6 @@ +// @!has issue_67851_neither/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_neither/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs new file mode 100644 index 0000000000000..8addc7f3e4b53 --- /dev/null +++ b/src/test/rustdoc/issue-67851-private.rs @@ -0,0 +1,8 @@ +// compile-flags: --document-private-items + +// @!has issue_67851_private/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_private/struct.Private.html +struct Private; From d97ae997a4f60efcc04030e9b0ea2e9509475fc3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:12:53 -0500 Subject: [PATCH 5/7] format librustc_errors --- src/librustc_errors/emitter.rs | 603 +++++++++++++++++---------------- src/librustc_errors/lib.rs | 222 ++++++------ 2 files changed, 421 insertions(+), 404 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 451913757482a..985fd54449e9e 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -9,26 +9,25 @@ use Destination::*; -use syntax_pos::{SourceFile, Span, MultiSpan}; use syntax_pos::source_map::SourceMap; +use syntax_pos::{MultiSpan, SourceFile, Span}; +use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; +use crate::styled_buffer::StyledBuffer; +use crate::Level::Error; use crate::{ - Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralize, - SuggestionStyle, DiagnosticId, + pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle, }; -use crate::Level::Error; -use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; -use crate::styled_buffer::StyledBuffer; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::borrow::Cow; -use std::io::prelude::*; +use std::cmp::{max, min, Reverse}; use std::io; -use std::cmp::{min, max, Reverse}; +use std::io::prelude::*; use std::path::Path; -use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; -use termcolor::{WriteColor, Color, Buffer}; +use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; +use termcolor::{Buffer, Color, WriteColor}; /// Describes the way the content of the `rendered` field of the json output is generated #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -57,8 +56,15 @@ impl HumanReadableErrorType { ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); - EmitterWriter::new(dst, source_map, short, teach, color, terminal_width, - external_macro_backtrace) + EmitterWriter::new( + dst, + source_map, + short, + teach, + color, + terminal_width, + external_macro_backtrace, + ) } } @@ -117,15 +123,15 @@ impl Margin { } fn was_cut_right(&self, line_len: usize) -> bool { - let right = if self.computed_right == self.span_right || - self.computed_right == self.label_right - { - // Account for the "..." padding given above. Otherwise we end up with code lines that - // do fit but end in "..." as if they were trimmed. - self.computed_right - 6 - } else { - self.computed_right - }; + let right = + if self.computed_right == self.span_right || self.computed_right == self.label_right { + // Account for the "..." padding given above. Otherwise we end + // up with code lines that do fit but end in "..." as if they + // were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; right < line_len && self.computed_left + self.column_width < line_len } @@ -156,7 +162,8 @@ impl Margin { let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; self.computed_left = self.span_left.saturating_sub(padding_left); self.computed_right = self.computed_left + self.column_width; - } else { // Mostly give up but still don't show the full line. + } else { + // Mostly give up but still don't show the full line. self.computed_left = self.span_left; self.computed_right = self.span_right; } @@ -240,11 +247,15 @@ pub trait Emitter { format!( "help: {}{}: `{}`", sugg.msg, - if self.source_map().map(|sm| is_case_difference( - &**sm, - substitution, - sugg.substitutions[0].parts[0].span, - )).unwrap_or(false) { + if self + .source_map() + .map(|sm| is_case_difference( + &**sm, + substitution, + sugg.substitutions[0].parts[0].span, + )) + .unwrap_or(false) + { " (notice the capitalization)" } else { "" @@ -271,37 +282,35 @@ pub trait Emitter { // This does a small "fix" for multispans by looking to see if it can find any that // point directly at <*macros>. Since these are often difficult to read, this // will change the span to point at the use site. - fn fix_multispans_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool) { + fn fix_multispans_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + children: &mut Vec, + level: &Level, + backtrace: bool, + ) { let mut spans_updated = self.fix_multispan_in_std_macros(source_map, span, backtrace); for child in children.iter_mut() { - spans_updated |= self.fix_multispan_in_std_macros( - source_map, - &mut child.span, - backtrace - ); + spans_updated |= + self.fix_multispan_in_std_macros(source_map, &mut child.span, backtrace); } let msg = if level == &Error { "this error originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() } else { "this warning originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() }; if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message: vec![ - (msg, - Style::NoStyle), - ], + message: vec![(msg, Style::NoStyle)], span: MultiSpan::new(), render_span: None, }); @@ -311,10 +320,12 @@ pub trait Emitter { // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of // <*macros>. Since these locations are often difficult to read, we move these Spans from // <*macros> to their corresponding use site. - fn fix_multispan_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - always_backtrace: bool) -> bool { + fn fix_multispan_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + always_backtrace: bool, + ) -> bool { let sm = match source_map { Some(ref sm) => sm, None => return false, @@ -340,31 +351,40 @@ pub trait Emitter { continue; } if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); + new_labels.push(( + trace.def_site_span, + format!( + "in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); } // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); + if !sm.span_to_filename(trace.def_site_span).is_macros() + && !trace.macro_decl_name.starts_with("desugaring of ") + && !trace.macro_decl_name.starts_with("#[") + || always_backtrace + { + new_labels.push(( + trace.call_site, + format!( + "in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); if !always_backtrace { break; } @@ -378,9 +398,7 @@ pub trait Emitter { if sp_label.span.is_dummy() { continue; } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { + if sm.span_to_filename(sp_label.span.clone()).is_macros() && !always_backtrace { let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); @@ -406,18 +424,22 @@ impl Emitter for EmitterWriter { let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag); - self.fix_multispans_in_std_macros(&self.sm, - &mut primary_span, - &mut children, - &diag.level, - self.external_macro_backtrace); - - self.emit_messages_default(&diag.level, - &diag.styled_message(), - &diag.code, - &primary_span, - &children, - &suggestions); + self.fix_multispans_in_std_macros( + &self.sm, + &mut primary_span, + &mut children, + &diag.level, + self.external_macro_backtrace, + ); + + self.emit_messages_default( + &diag.level, + &diag.styled_message(), + &diag.code, + &primary_span, + &children, + &suggestions, + ); } fn should_show_explain(&self) -> bool { @@ -429,7 +451,9 @@ impl Emitter for EmitterWriter { pub struct SilentEmitter; impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { None } + fn source_map(&self) -> Option<&Lrc> { + None + } fn emit_diagnostic(&mut self, _: &Diagnostic) {} } @@ -458,17 +482,13 @@ impl ColorConfig { } } ColorConfig::Never => ColorChoice::Never, - ColorConfig::Auto if atty::is(atty::Stream::Stderr) => { - ColorChoice::Auto - } + ColorConfig::Auto if atty::is(atty::Stream::Stderr) => ColorChoice::Auto, ColorConfig::Auto => ColorChoice::Never, } } fn suggests_using_colors(self) -> bool { match self { - | ColorConfig::Always - | ColorConfig::Auto - => true, + ColorConfig::Always | ColorConfig::Auto => true, ColorConfig::Never => false, } } @@ -540,11 +560,7 @@ impl EmitterWriter { } fn maybe_anonymized(&self, line_num: usize) -> String { - if self.ui_testing { - ANONYMIZED_LINE_NUM.to_string() - } else { - line_num.to_string() - } + if self.ui_testing { ANONYMIZED_LINE_NUM.to_string() } else { line_num.to_string() } } fn draw_line( @@ -563,17 +579,22 @@ impl EmitterWriter { let right = margin.right(line_len); // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; - let code: String = source_string.chars().skip(left).take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. - // For now, just accept that sometimes the code line will be longer than desired. - let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); - if taken + next > right - left { - return false; - } - taken += next; - true - }).collect(); + let code: String = source_string + .chars() + .skip(left) + .take_while(|ch| { + // Make sure that the trimming on the right will fall within the + // terminal width. FIXME: `unicode_width` sometimes disagrees + // with terminals on how wide a `char` is. For now, just accept + // that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }) + .collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. @@ -624,7 +645,9 @@ impl EmitterWriter { let left = margin.left(source_string.len()); // Left trim // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left) + let left = source_string + .chars() + .take(left) .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) .sum(); @@ -773,13 +796,14 @@ impl EmitterWriter { if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). - && p == 0 // We're currently on the first line, move the label one line down + && p == 0 + // We're currently on the first line, move the label one line down { // If we're overlapping with an un-labelled annotation with the same span // we can just merge them in the output if next.start_col == annotation.start_col - && next.end_col == annotation.end_col - && !next.has_label() + && next.end_col == annotation.end_col + && !next.has_label() { continue; } @@ -791,7 +815,7 @@ impl EmitterWriter { } annotations_position.push((p, annotation)); for (j, next) in annotations.iter().enumerate() { - if j > i { + if j > i { let l = next.label.as_ref().map_or(0, |label| label.len() + 2); if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to @@ -814,7 +838,8 @@ impl EmitterWriter { || (overlaps(next, annotation, l) && next.end_col <= annotation.end_col && next.has_label() - && p == 0) // Avoid #42595. + && p == 0) + // Avoid #42595. { // This annotation needs a new line in the output. p += 1; @@ -848,10 +873,7 @@ impl EmitterWriter { // | for pos in 0..=line_len { draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); - buffer.putc(line_offset + pos + 1, - width_offset - 2, - '|', - Style::LineNumber); + buffer.putc(line_offset + pos + 1, width_offset - 2, '|', Style::LineNumber); } // Write the horizontal lines for multiline annotations @@ -874,8 +896,7 @@ impl EmitterWriter { }; let pos = pos + 1; match annotation.annotation_type { - AnnotationType::MultilineStart(depth) | - AnnotationType::MultilineEnd(depth) => { + AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { draw_range( buffer, '_', @@ -919,27 +940,23 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { - buffer.putc(p, - (code_offset + annotation.start_col).saturating_sub(left), - '|', - style); + buffer.putc( + p, + (code_offset + annotation.start_col).saturating_sub(left), + '|', + style, + ); } } match annotation.annotation_type { AnnotationType::MultilineStart(depth) => { for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } AnnotationType::MultilineEnd(depth) => { for p in line_offset..=line_offset + pos { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } _ => (), @@ -958,11 +975,8 @@ impl EmitterWriter { // 4 | } // | _ test for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::LabelPrimary - } else { - Style::LabelSecondary - }; + let style = + if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { (pos + 1, (annotation.end_col + 1).saturating_sub(left)) } else { @@ -1012,8 +1026,9 @@ impl EmitterWriter { ); } } - annotations_position.iter().filter_map(|&(_, annotation)| { - match annotation.annotation_type { + annotations_position + .iter() + .filter_map(|&(_, annotation)| match annotation.annotation_type { AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { let style = if annotation.is_primary { Style::LabelPrimary @@ -1022,10 +1037,9 @@ impl EmitterWriter { }; Some((p, style)) } - _ => None - } - - }).collect::>() + _ => None, + }) + .collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { @@ -1055,7 +1069,8 @@ impl EmitterWriter { fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { let primary = self.get_multispan_max_line_num(span); - children.iter() + children + .iter() .map(|sub| self.get_multispan_max_line_num(&sub.span)) .max() .unwrap_or(0) @@ -1064,13 +1079,14 @@ impl EmitterWriter { /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. - fn msg_to_buffer(&self, - buffer: &mut StyledBuffer, - msg: &[(String, Style)], - padding: usize, - label: &str, - override_style: Option