diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index f84850c0fe1f1..65cd71307aa3f 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -46,24 +46,40 @@ crate trait DocFolder: Sized { i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect(); ImplItem(i) } - VariantItem(i) => { - let i2 = i.clone(); // this clone is small - match i { - Variant::Struct(mut j) => { - let num_fields = j.fields.len(); - j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - j.fields_stripped |= num_fields != j.fields.len() - || j.fields.iter().any(|f| f.is_stripped()); - VariantItem(Variant::Struct(j)) - } - Variant::Tuple(fields) => { - let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); - VariantItem(Variant::Tuple(fields)) - } - _ => VariantItem(i2), + VariantItem(i) => match i { + Variant::Struct(mut j) => { + let num_fields = j.fields.len(); + j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + j.fields_stripped |= + num_fields != j.fields.len() || j.fields.iter().any(|f| f.is_stripped()); + VariantItem(Variant::Struct(j)) } - } - x => x, + Variant::Tuple(fields) => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + VariantItem(Variant::Tuple(fields)) + } + Variant::CLike => VariantItem(Variant::CLike), + }, + ExternCrateItem { src: _ } + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | KeywordItem(_) => kind, } } @@ -86,14 +102,12 @@ crate trait DocFolder: Sized { fn fold_crate(&mut self, mut c: Crate) -> Crate { c.module = self.fold_item(c.module).unwrap(); - { - let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; - for (k, mut v) in external_traits { - v.trait_.items = - v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - c.external_traits.borrow_mut().insert(k, v); - } + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, mut v) in external_traits { + v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); + c.external_traits.borrow_mut().insert(k, v); } + c } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 76e46fa0aa354..069862efde640 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -461,9 +461,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - let (mut krate, local_sources, matches) = collect_spans_and_sources( + let (local_sources, matches) = collect_spans_and_sources( tcx, - krate, + &krate, &src_root, include_sources, generate_link_to_definition, @@ -522,7 +522,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { }; if emit_crate { - krate = sources::render(&mut cx, krate)?; + sources::render(&mut cx, &krate)?; } // Build our search index diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 1a8562d05eab7..7803a779727c5 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -37,21 +37,21 @@ crate enum LinkFromSrc { /// only keep the `lo` and `hi`. crate fn collect_spans_and_sources( tcx: TyCtxt<'_>, - krate: clean::Crate, + krate: &clean::Crate, src_root: &Path, include_sources: bool, generate_link_to_definition: bool, -) -> (clean::Crate, FxHashMap, FxHashMap) { +) -> (FxHashMap, FxHashMap) { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; if include_sources { if generate_link_to_definition { tcx.hir().walk_toplevel_module(&mut visitor); } - let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate); - (krate, sources, visitor.matches) + let sources = sources::collect_local_sources(tcx, src_root, &krate); + (sources, visitor.matches) } else { - (krate, Default::default(), Default::default()) + (Default::default(), Default::default()) } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9422f84f99775..c8e93374e63cc 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,11 +1,11 @@ use crate::clean; use crate::docfs::PathError; use crate::error::Error; -use crate::fold::DocFolder; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::layout; use crate::html::render::{Context, BASIC_KEYWORDS}; +use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -16,23 +16,25 @@ use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; -crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result { +crate fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> { info!("emitting source files"); + let dst = cx.dst.join("src").join(&*krate.name(cx.tcx()).as_str()); cx.shared.ensure_dir(&dst)?; - let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() }; - Ok(folder.fold_crate(krate)) + + let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() }; + collector.visit_crate(krate); + Ok(()) } crate fn collect_local_sources<'tcx>( tcx: TyCtxt<'tcx>, src_root: &Path, - krate: clean::Crate, -) -> (clean::Crate, FxHashMap) { + krate: &clean::Crate, +) -> FxHashMap { let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root }; - - let krate = lsc.fold_crate(krate); - (krate, lsc.local_sources) + lsc.visit_crate(krate); + lsc.local_sources } struct LocalSourcesCollector<'a, 'tcx> { @@ -42,7 +44,7 @@ struct LocalSourcesCollector<'a, 'tcx> { } fn is_real_and_local(span: clean::Span, sess: &Session) -> bool { - span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE + span.cnum(sess) == LOCAL_CRATE && span.filename(sess).is_real() } impl LocalSourcesCollector<'_, '_> { @@ -54,12 +56,13 @@ impl LocalSourcesCollector<'_, '_> { return; } let filename = span.filename(sess); - let p = match filename { - FileName::Real(ref file) => match file.local_path() { - Some(p) => p.to_path_buf(), - _ => return, - }, - _ => return, + let p = if let FileName::Real(file) = filename { + match file.into_local_path() { + Some(p) => p, + None => return, + } + } else { + return; }; if self.local_sources.contains_key(&*p) { // We've already emitted this source @@ -79,13 +82,11 @@ impl LocalSourcesCollector<'_, '_> { } } -impl DocFolder for LocalSourcesCollector<'_, '_> { - fn fold_item(&mut self, item: clean::Item) -> Option { - self.add_local_source(&item); +impl DocVisitor for LocalSourcesCollector<'_, '_> { + fn visit_item(&mut self, item: &clean::Item) { + self.add_local_source(item); - // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value, - // we could return None here without having to walk the rest of the crate. - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } @@ -98,8 +99,12 @@ struct SourceCollector<'a, 'tcx> { emitted_local_sources: FxHashSet, } -impl DocFolder for SourceCollector<'_, '_> { - fn fold_item(&mut self, item: clean::Item) -> Option { +impl DocVisitor for SourceCollector<'_, '_> { + fn visit_item(&mut self, item: &clean::Item) { + if !self.cx.include_sources { + return; + } + let tcx = self.cx.tcx(); let span = item.span(tcx); let sess = tcx.sess; @@ -107,7 +112,7 @@ impl DocFolder for SourceCollector<'_, '_> { // If we're not rendering sources, there's nothing to do. // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem. - if self.cx.include_sources && is_real_and_local(span, sess) { + if is_real_and_local(span, sess) { let filename = span.filename(sess); let span = span.inner(); let pos = sess.source_map().lookup_source_file(span.lo()); @@ -132,9 +137,8 @@ impl DocFolder for SourceCollector<'_, '_> { } }; } - // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value, - // we could return None here without having to walk the rest of the crate. - Some(self.fold_item_recur(item)) + + self.visit_item_recur(item) } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b50fbf58bae29..7eeb9d1fcaa55 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -121,6 +121,7 @@ mod markdown; mod passes; mod scrape_examples; mod theme; +mod visit; mod visit_ast; mod visit_lib; diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs index 4501914fe0c07..4e146a07d154a 100644 --- a/src/librustdoc/passes/bare_urls.rs +++ b/src/librustdoc/passes/bare_urls.rs @@ -1,8 +1,8 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::main_body_opts; +use crate::visit::DocVisitor; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use regex::Regex; @@ -53,16 +53,17 @@ impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> { } crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - BareUrlsLinter { cx }.fold_crate(krate) + BareUrlsLinter { cx }.visit_crate(&krate); + krate } -impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option { +impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return Some(self.fold_item_recur(item)); + return; } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -106,6 +107,6 @@ impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 5e3bd41b85c7e..85542ebd9ac55 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,9 +1,9 @@ use crate::clean; use crate::core::DocContext; -use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests}; use crate::passes::Pass; +use crate::visit::DocVisitor; use rustc_hir as hir; use rustc_lint::builtin::MISSING_DOCS; use rustc_middle::lint::LintLevelSource; @@ -23,7 +23,7 @@ crate const CALCULATE_DOC_COVERAGE: Pass = Pass { fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate { let mut calc = CoverageCalculator { items: Default::default(), ctx }; - let krate = calc.fold_crate(krate); + calc.visit_crate(&krate); calc.print_results(); @@ -182,17 +182,18 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { } } -impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { - fn fold_item(&mut self, i: clean::Item) -> Option { +impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> { + fn visit_item(&mut self, i: &clean::Item) { + if !i.def_id.is_local() { + // non-local items are skipped because they can be out of the users control, + // especially in the case of trait impls, which rustdoc eagerly inlines + return; + } + match *i.kind { - _ if !i.def_id.is_local() => { - // non-local items are skipped because they can be out of the users control, - // especially in the case of trait impls, which rustdoc eagerly inlines - return Some(i); - } clean::StrippedItem(..) => { // don't count items in stripped modules - return Some(i); + return; } // docs on `use` and `extern crate` statements are not displayed, so they're not // worth counting @@ -269,6 +270,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { } } - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index b18208d26e2c4..fd2ab0dc97cb2 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -8,9 +8,9 @@ use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMM use crate::clean; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{self, RustCodeBlock}; use crate::passes::Pass; +use crate::visit::DocVisitor; crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { name: "check-code-block-syntax", @@ -19,7 +19,8 @@ crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { }; crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { - SyntaxChecker { cx }.fold_crate(krate) + SyntaxChecker { cx }.visit_crate(&krate); + krate } struct SyntaxChecker<'a, 'tcx> { @@ -141,8 +142,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { } } -impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { - fn fold_item(&mut self, item: clean::Item) -> Option { +impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> { + fn visit_item(&mut self, item: &clean::Item) { if let Some(dox) = &item.attrs.collapsed_doc_value() { let sp = item.attr_span(self.cx.tcx); let extra = crate::html::markdown::ExtraInfo::new_did( @@ -155,7 +156,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 69a526d461810..7d3010cf3325b 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -7,8 +7,8 @@ use super::Pass; use crate::clean; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use crate::visit::DocVisitor; use crate::visit_ast::inherits_doc_hidden; use rustc_hir as hir; use rustc_middle::lint::LintLevelSource; @@ -27,17 +27,17 @@ struct DocTestVisibilityLinter<'a, 'tcx> { crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate { let mut coll = DocTestVisibilityLinter { cx }; - - coll.fold_crate(krate) + coll.visit_crate(&krate); + krate } -impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option { +impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); look_for_tests(self.cx, &dox, &item); - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9b2fe0c77e6cf..8541e6e18816f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -32,10 +32,10 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; +use crate::visit::DocVisitor; mod early; crate use early::load_intra_link_crates; @@ -47,13 +47,14 @@ crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - LinkCollector { + let mut collector = LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None), visited_links: FxHashMap::default(), - } - .fold_crate(krate) + }; + collector.visit_crate(&krate); + krate } /// Top-level errors emitted by this pass. @@ -816,8 +817,8 @@ fn is_derive_trait_collision(ns: &PerNS DocFolder for LinkCollector<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option { +impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { use rustc_middle::ty::DefIdTree; let parent_node = @@ -911,17 +912,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - Some(if item.is_mod() { + if item.is_mod() { if !inner_docs { self.mod_ids.push(item.def_id.expect_def_id()); } - let ret = self.fold_item_recur(item); + self.visit_item_recur(item); self.mod_ids.pop(); - ret } else { - self.fold_item_recur(item) - }) + self.visit_item_recur(item) + } } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 7a4198198fa69..77513b05ff2f9 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -1,7 +1,7 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; +use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefId; @@ -14,17 +14,18 @@ crate const COLLECT_TRAIT_IMPLS: Pass = Pass { description: "retrieves trait impls for items in the crate", }; -crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || { +crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let synth_impls = cx.sess().time("collect_synthetic_impls", || { let mut synth = SyntheticImplCollector { cx, impls: Vec::new() }; - (synth.fold_crate(krate), synth.impls) + synth.visit_crate(&krate); + synth.impls }); let prims: FxHashSet = krate.primitives.iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); - krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate)); + cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate)); coll.items }; @@ -152,14 +153,13 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { } } - let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind { - items + if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind { + items.extend(synth_impls); + items.extend(new_items); } else { panic!("collect-trait-impls can't run"); }; - items.extend(synth_impls); - items.extend(new_items); krate } @@ -168,8 +168,8 @@ struct SyntheticImplCollector<'a, 'tcx> { impls: Vec, } -impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { - fn fold_item(&mut self, i: Item) -> Option { +impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { + fn visit_item(&mut self, i: &Item) { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? if !self @@ -184,7 +184,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { } } - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } @@ -199,11 +199,11 @@ impl ItemCollector { } } -impl DocFolder for ItemCollector { - fn fold_item(&mut self, i: Item) -> Option { +impl DocVisitor for ItemCollector { + fn visit_item(&mut self, i: &Item) { self.items.insert(i.def_id); - Some(self.fold_item_recur(i)) + self.visit_item_recur(i) } } diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index a3fde92d7655d..56b222d893262 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -1,11 +1,13 @@ use super::Pass; use crate::clean::*; use crate::core::DocContext; -use crate::fold::DocFolder; use crate::html::markdown::main_body_opts; -use core::ops::Range; +use crate::visit::DocVisitor; + use pulldown_cmark::{Event, Parser, Tag}; + use std::iter::Peekable; +use std::ops::Range; use std::str::CharIndices; crate const CHECK_INVALID_HTML_TAGS: Pass = Pass { @@ -19,13 +21,11 @@ struct InvalidHtmlTagsLinter<'a, 'tcx> { } crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - if !cx.tcx.sess.is_nightly_build() { - krate - } else { + if cx.tcx.sess.is_nightly_build() { let mut coll = InvalidHtmlTagsLinter { cx }; - - coll.fold_crate(krate) + coll.visit_crate(&krate); } + krate } const ALLOWED_UNCLOSED: &[&str] = &[ @@ -165,14 +165,14 @@ fn extract_tags( } } -impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { - fn fold_item(&mut self, item: Item) -> Option { +impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> { + fn visit_item(&mut self, item: &Item) { let tcx = self.cx.tcx; let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return Some(self.fold_item_recur(item)); + return; } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -217,6 +217,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { } } - Some(self.fold_item_recur(item)) + self.visit_item_recur(item) } } diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs new file mode 100644 index 0000000000000..df4d1558ebdf4 --- /dev/null +++ b/src/librustdoc/visit.rs @@ -0,0 +1,71 @@ +use crate::clean::*; + +crate trait DocVisitor: Sized { + fn visit_item(&mut self, item: &Item) { + self.visit_item_recur(item) + } + + /// don't override! + fn visit_inner_recur(&mut self, kind: &ItemKind) { + match kind { + StrippedItem(..) => unreachable!(), + ModuleItem(i) => { + self.visit_mod(i); + return; + } + StructItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)), + UnionItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)), + EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)), + TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)), + ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)), + VariantItem(i) => match i { + Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)), + Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)), + Variant::CLike => {} + }, + ExternCrateItem { src: _ } + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | KeywordItem(_) => {} + } + } + + /// don't override! + fn visit_item_recur(&mut self, item: &Item) { + match &*item.kind { + StrippedItem(i) => self.visit_inner_recur(i), + _ => self.visit_inner_recur(&item.kind), + } + } + + fn visit_mod(&mut self, m: &Module) { + m.items.iter().for_each(|i| self.visit_item(i)) + } + + fn visit_crate(&mut self, c: &Crate) { + self.visit_item(&c.module); + + // FIXME: make this a simple by-ref for loop once external_traits is cleaned up + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, v) in external_traits { + v.trait_.items.iter().for_each(|i| self.visit_item(i)); + c.external_traits.borrow_mut().insert(k, v); + } + } +}