mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Do macro expansion at AST level rather than HIR
This commit is contained in:
+11
-2
@@ -31,6 +31,7 @@
|
||||
use crate::clean::{self, ItemId};
|
||||
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::html::macro_expansion::{ExpandedCode, source_macro_expansion};
|
||||
use crate::passes;
|
||||
use crate::passes::Condition::*;
|
||||
use crate::passes::collect_intra_doc_links::LinkCollector;
|
||||
@@ -334,11 +335,19 @@ pub(crate) fn run_global_ctxt(
|
||||
show_coverage: bool,
|
||||
render_options: RenderOptions,
|
||||
output_format: OutputFormat,
|
||||
) -> (clean::Crate, RenderOptions, Cache) {
|
||||
) -> (clean::Crate, RenderOptions, Cache, FxHashMap<rustc_span::BytePos, Vec<ExpandedCode>>) {
|
||||
// Certain queries assume that some checks were run elsewhere
|
||||
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
|
||||
// so type-check everything other than function bodies in this crate before running lints.
|
||||
|
||||
let expanded_macros = {
|
||||
// We need for these variables to be removed to ensure that the `Crate` won't be "stolen"
|
||||
// anymore.
|
||||
let (_resolver, krate) = &*tcx.resolver_for_lowering().borrow();
|
||||
|
||||
source_macro_expansion(&krate, &render_options, output_format, tcx.sess.source_map())
|
||||
};
|
||||
|
||||
// NOTE: this does not call `tcx.analysis()` so that we won't
|
||||
// typeck function bodies or run the default rustc lints.
|
||||
// (see `override_queries` in the `config`)
|
||||
@@ -448,7 +457,7 @@ pub(crate) fn run_global_ctxt(
|
||||
|
||||
tcx.dcx().abort_if_errors();
|
||||
|
||||
(krate, ctxt.render_options, ctxt.cache)
|
||||
(krate, ctxt.render_options, ctxt.cache, expanded_macros)
|
||||
}
|
||||
|
||||
/// Due to <https://github.com/rust-lang/rust/pull/73566>,
|
||||
|
||||
@@ -31,15 +31,6 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
|
||||
/// reset the information between each call to `item` by using `restore_module_data`.
|
||||
type ModuleData;
|
||||
|
||||
/// Sets up any state required for the renderer. When this is called the cache has already been
|
||||
/// populated.
|
||||
fn init(
|
||||
krate: clean::Crate,
|
||||
options: RenderOptions,
|
||||
cache: Cache,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Result<(Self, clean::Crate), Error>;
|
||||
|
||||
/// This method is called right before call [`Self::item`]. This method returns a type
|
||||
/// containing information that needs to be reset after the [`Self::item`] method has been
|
||||
/// called with the [`Self::restore_module_data`] method.
|
||||
@@ -105,18 +96,23 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>(
|
||||
}
|
||||
|
||||
/// Main method for rendering a crate.
|
||||
pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
|
||||
pub(crate) fn run_format<
|
||||
'tcx,
|
||||
T: FormatRenderer<'tcx>,
|
||||
F: FnOnce(clean::Crate, RenderOptions, Cache, TyCtxt<'tcx>) -> Result<(T, clean::Crate), Error>,
|
||||
>(
|
||||
krate: clean::Crate,
|
||||
options: RenderOptions,
|
||||
cache: Cache,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
init: F,
|
||||
) -> Result<(), Error> {
|
||||
let prof = &tcx.sess.prof;
|
||||
|
||||
let emit_crate = options.should_emit_crate();
|
||||
let (mut format_renderer, krate) = prof
|
||||
.verbose_generic_activity_with_arg("create_renderer", T::descr())
|
||||
.run(|| T::init(krate, options, cache, tcx))?;
|
||||
.run(|| init(krate, options, cache, tcx))?;
|
||||
|
||||
if !emit_crate {
|
||||
return Ok(());
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
use super::format::{self, write_str};
|
||||
use crate::clean::PrimitiveType;
|
||||
use crate::html::escape::EscapeBodyText;
|
||||
use crate::html::render::{Context, ExpandedCode, LinkFromSrc};
|
||||
use crate::html::macro_expansion::ExpandedCode;
|
||||
use crate::html::render::{Context, LinkFromSrc};
|
||||
|
||||
/// This type is needed in case we want to render links on items to allow to go to their definition.
|
||||
pub(crate) struct HrefContext<'a, 'tcx> {
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item};
|
||||
use rustc_ast::{Crate, Expr, Item};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::config::{OutputFormat, RenderOptions};
|
||||
|
||||
/// It returns the expanded macros correspondence map.
|
||||
pub(crate) fn source_macro_expansion(
|
||||
krate: &Crate,
|
||||
render_options: &RenderOptions,
|
||||
output_format: OutputFormat,
|
||||
source_map: &SourceMap,
|
||||
) -> FxHashMap<BytePos, Vec<ExpandedCode>> {
|
||||
if output_format == OutputFormat::Html
|
||||
&& !render_options.html_no_source
|
||||
&& render_options.generate_macro_expansion
|
||||
{
|
||||
let mut expanded_visitor = ExpandedCodeVisitor { expanded_codes: Vec::new(), source_map };
|
||||
walk_crate(&mut expanded_visitor, krate);
|
||||
expanded_visitor.compute_expanded()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains information about macro expansion in the source code pages.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ExpandedCode {
|
||||
/// The line where the macro expansion starts.
|
||||
pub(crate) start_line: u32,
|
||||
/// The line where the macro expansion ends.
|
||||
pub(crate) end_line: u32,
|
||||
/// The source code of the expanded macro.
|
||||
pub(crate) code: String,
|
||||
/// The span of macro callsite.
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
/// Contains temporary information of macro expanded code.
|
||||
///
|
||||
/// As we go through the HIR visitor, if any span overlaps with another, they will
|
||||
/// both be merged.
|
||||
struct ExpandedCodeInfo {
|
||||
/// Callsite of the macro.
|
||||
span: Span,
|
||||
/// Expanded macro source code.
|
||||
code: String,
|
||||
/// Expanded span
|
||||
expanded_span: Span,
|
||||
}
|
||||
|
||||
/// HIR visitor which retrieves expanded macro.
|
||||
///
|
||||
/// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`]
|
||||
/// which contains more information needed when running the source code highlighter.
|
||||
pub(crate) struct ExpandedCodeVisitor<'ast> {
|
||||
expanded_codes: Vec<ExpandedCodeInfo>,
|
||||
source_map: &'ast SourceMap,
|
||||
}
|
||||
|
||||
impl<'ast> ExpandedCodeVisitor<'ast> {
|
||||
fn handle_new_span<F: Fn() -> String>(&mut self, new_span: Span, f: F) {
|
||||
if new_span.is_dummy() || !new_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
let callsite_span = new_span.source_callsite();
|
||||
if let Some(index) =
|
||||
self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span))
|
||||
{
|
||||
let info = &mut self.expanded_codes[index];
|
||||
if new_span.contains(info.expanded_span) {
|
||||
// We replace the item.
|
||||
info.span = callsite_span;
|
||||
info.expanded_span = new_span;
|
||||
info.code = f();
|
||||
} else {
|
||||
// We push the new item after the existing one.
|
||||
let expanded_code = &mut self.expanded_codes[index];
|
||||
expanded_code.code.push('\n');
|
||||
expanded_code.code.push_str(&f());
|
||||
let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0));
|
||||
let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0));
|
||||
expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi);
|
||||
}
|
||||
} else {
|
||||
// We add a new item.
|
||||
self.expanded_codes.push(ExpandedCodeInfo {
|
||||
span: callsite_span,
|
||||
code: f(),
|
||||
expanded_span: new_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_expanded(mut self) -> FxHashMap<BytePos, Vec<ExpandedCode>> {
|
||||
self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span));
|
||||
let mut expanded: FxHashMap<BytePos, Vec<ExpandedCode>> = FxHashMap::default();
|
||||
for ExpandedCodeInfo { span, code, .. } in self.expanded_codes {
|
||||
if let Ok(lines) = self.source_map.span_to_lines(span)
|
||||
&& !lines.lines.is_empty()
|
||||
{
|
||||
let mut out = String::new();
|
||||
super::highlight::write_code(&mut out, &code, None, None, None);
|
||||
let first = lines.lines.first().unwrap();
|
||||
let end = lines.lines.last().unwrap();
|
||||
expanded.entry(lines.file.start_pos).or_default().push(ExpandedCode {
|
||||
start_line: first.line_index as u32 + 1,
|
||||
end_line: end.line_index as u32 + 1,
|
||||
code: out,
|
||||
span,
|
||||
});
|
||||
}
|
||||
}
|
||||
expanded
|
||||
}
|
||||
}
|
||||
|
||||
// We need to use the AST pretty printing because:
|
||||
//
|
||||
// 1. HIR pretty printing doesn't display accurately the code (like `impl Trait`).
|
||||
// 2. `SourceMap::snippet_opt` might fail if the source is not available.
|
||||
impl<'ast> Visitor<'ast> for ExpandedCodeVisitor<'ast> {
|
||||
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||
if expr.span.from_expansion() {
|
||||
self.handle_new_span(expr.span, || rustc_ast_pretty::pprust::expr_to_string(expr));
|
||||
} else {
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'ast Item) {
|
||||
if item.span.from_expansion() {
|
||||
self.handle_new_span(item.span, || rustc_ast_pretty::pprust::item_to_string(item));
|
||||
} else {
|
||||
walk_item(self, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
pub(crate) mod layout;
|
||||
mod length_limit;
|
||||
// used by the error-index generator, so it needs to be public
|
||||
pub(crate) mod macro_expansion;
|
||||
pub mod markdown;
|
||||
pub(crate) mod render;
|
||||
pub(crate) mod sources;
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::macro_expansion::ExpandedCode;
|
||||
use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
|
||||
use crate::html::render::ExpandedCode;
|
||||
use crate::html::render::write_shared::write_shared;
|
||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||
use crate::html::{layout, sources, static_files};
|
||||
@@ -460,20 +460,13 @@ pub(crate) fn href_from_span_relative(
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the documentation for `crate` into the directory `dst`
|
||||
impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"html"
|
||||
}
|
||||
|
||||
const RUN_ON_MODULE: bool = true;
|
||||
type ModuleData = ContextInfo;
|
||||
|
||||
fn init(
|
||||
impl<'tcx> Context<'tcx> {
|
||||
pub(crate) fn init(
|
||||
krate: clean::Crate,
|
||||
options: RenderOptions,
|
||||
cache: Cache,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
expanded_codes: FxHashMap<BytePos, Vec<ExpandedCode>>,
|
||||
) -> Result<(Self, clean::Crate), Error> {
|
||||
// need to save a copy of the options for rendering the index page
|
||||
let md_opts = options.clone();
|
||||
@@ -492,7 +485,6 @@ fn init(
|
||||
generate_redirect_map,
|
||||
show_type_layout,
|
||||
generate_link_to_definition,
|
||||
generate_macro_expansion,
|
||||
call_locations,
|
||||
no_emit_shared,
|
||||
html_no_source,
|
||||
@@ -551,13 +543,12 @@ fn init(
|
||||
}
|
||||
}
|
||||
|
||||
let (local_sources, matches, expanded_codes) = collect_spans_and_sources(
|
||||
let (local_sources, matches) = collect_spans_and_sources(
|
||||
tcx,
|
||||
&krate,
|
||||
&src_root,
|
||||
include_sources,
|
||||
generate_link_to_definition,
|
||||
generate_macro_expansion,
|
||||
);
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
@@ -609,6 +600,16 @@ fn init(
|
||||
|
||||
Ok((cx, krate))
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the documentation for `crate` into the directory `dst`
|
||||
impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"html"
|
||||
}
|
||||
|
||||
const RUN_ON_MODULE: bool = true;
|
||||
type ModuleData = ContextInfo;
|
||||
|
||||
fn save_module_data(&mut self) -> Self::ModuleData {
|
||||
self.deref_id_map.borrow_mut().clear();
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
use tracing::{debug, info};
|
||||
|
||||
pub(crate) use self::context::*;
|
||||
pub(crate) use self::span_map::{ExpandedCode, LinkFromSrc, collect_spans_and_sources};
|
||||
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
|
||||
pub(crate) use self::write_shared::*;
|
||||
use crate::clean::{self, ItemId, RenderedLink};
|
||||
use crate::display::{Joined as _, MaybeDisplay as _};
|
||||
|
||||
@@ -30,26 +30,12 @@ pub(crate) enum LinkFromSrc {
|
||||
Doc(DefId),
|
||||
}
|
||||
|
||||
/// Contains information about macro expansion in the source code pages.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ExpandedCode {
|
||||
/// The line where the macro expansion starts.
|
||||
pub(crate) start_line: u32,
|
||||
/// The line where the macro expansion ends.
|
||||
pub(crate) end_line: u32,
|
||||
/// The source code of the expanded macro.
|
||||
pub(crate) code: String,
|
||||
/// The span of macro callsite.
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
/// This function will do at most two things:
|
||||
///
|
||||
/// 1. Generate a `span` correspondence map which links an item `span` to its definition `span`.
|
||||
/// 2. Collect the source code files.
|
||||
///
|
||||
/// It returns the source code files, the `span` correspondence map and the expanded macros
|
||||
/// correspondence map.
|
||||
/// It returns the source code files and the `span` correspondence map.
|
||||
///
|
||||
/// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't
|
||||
/// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we
|
||||
@@ -60,26 +46,17 @@ pub(crate) fn collect_spans_and_sources(
|
||||
src_root: &Path,
|
||||
include_sources: bool,
|
||||
generate_link_to_definition: bool,
|
||||
generate_macro_expansion: bool,
|
||||
) -> (
|
||||
FxIndexMap<PathBuf, String>,
|
||||
FxHashMap<Span, LinkFromSrc>,
|
||||
FxHashMap<BytePos, Vec<ExpandedCode>>,
|
||||
) {
|
||||
) -> (FxIndexMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
|
||||
if include_sources {
|
||||
let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
|
||||
let mut expanded_visitor = ExpandedCodeVisitor { tcx, expanded_codes: Vec::new() };
|
||||
|
||||
if generate_macro_expansion {
|
||||
tcx.hir_walk_toplevel_module(&mut expanded_visitor);
|
||||
}
|
||||
if generate_link_to_definition {
|
||||
tcx.hir_walk_toplevel_module(&mut visitor);
|
||||
}
|
||||
let sources = sources::collect_local_sources(tcx, src_root, krate);
|
||||
(sources, visitor.matches, expanded_visitor.compute_expanded())
|
||||
(sources, visitor.matches)
|
||||
} else {
|
||||
(Default::default(), Default::default(), Default::default())
|
||||
(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,107 +292,3 @@ fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains temporary information of macro expanded code.
|
||||
///
|
||||
/// As we go through the HIR visitor, if any span overlaps with another, they will
|
||||
/// both be merged.
|
||||
struct ExpandedCodeInfo {
|
||||
/// Callsite of the macro.
|
||||
span: Span,
|
||||
/// Expanded macro source code.
|
||||
code: String,
|
||||
/// Expanded span
|
||||
expanded_span: Span,
|
||||
}
|
||||
|
||||
/// HIR visitor which retrieves expanded macro.
|
||||
///
|
||||
/// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`]
|
||||
/// which contains more information needed when running the source code highlighter.
|
||||
pub struct ExpandedCodeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
expanded_codes: Vec<ExpandedCodeInfo>,
|
||||
}
|
||||
|
||||
impl<'tcx> ExpandedCodeVisitor<'tcx> {
|
||||
fn handle_new_span<F: Fn(TyCtxt<'_>) -> String>(&mut self, new_span: Span, f: F) {
|
||||
if new_span.is_dummy() || !new_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
let callsite_span = new_span.source_callsite();
|
||||
if let Some(index) =
|
||||
self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span))
|
||||
{
|
||||
let info = &mut self.expanded_codes[index];
|
||||
if new_span.contains(info.expanded_span) {
|
||||
// We replace the item.
|
||||
info.span = callsite_span;
|
||||
info.expanded_span = new_span;
|
||||
info.code = f(self.tcx);
|
||||
} else {
|
||||
// We push the new item after the existing one.
|
||||
let expanded_code = &mut self.expanded_codes[index];
|
||||
expanded_code.code.push('\n');
|
||||
expanded_code.code.push_str(&f(self.tcx));
|
||||
let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0));
|
||||
let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0));
|
||||
expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi);
|
||||
}
|
||||
} else {
|
||||
// We add a new item.
|
||||
self.expanded_codes.push(ExpandedCodeInfo {
|
||||
span: callsite_span,
|
||||
code: f(self.tcx),
|
||||
expanded_span: new_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_expanded(mut self) -> FxHashMap<BytePos, Vec<ExpandedCode>> {
|
||||
self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span));
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let mut expanded: FxHashMap<BytePos, Vec<ExpandedCode>> = FxHashMap::default();
|
||||
for ExpandedCodeInfo { span, code, .. } in self.expanded_codes {
|
||||
if let Ok(lines) = source_map.span_to_lines(span)
|
||||
&& !lines.lines.is_empty()
|
||||
{
|
||||
let mut out = String::new();
|
||||
super::highlight::write_code(&mut out, &code, None, None, None);
|
||||
let first = lines.lines.first().unwrap();
|
||||
let end = lines.lines.last().unwrap();
|
||||
expanded.entry(lines.file.start_pos).or_default().push(ExpandedCode {
|
||||
start_line: first.line_index as u32 + 1,
|
||||
end_line: end.line_index as u32 + 1,
|
||||
code: out,
|
||||
span,
|
||||
});
|
||||
}
|
||||
}
|
||||
expanded
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ExpandedCodeVisitor<'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
|
||||
if expr.span.from_expansion() {
|
||||
self.handle_new_span(expr.span, |tcx| rustc_hir_pretty::expr_to_string(&tcx, expr));
|
||||
} else {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx rustc_hir::Item<'tcx>) {
|
||||
if item.span.from_expansion() {
|
||||
self.handle_new_span(item.span, |tcx| rustc_hir_pretty::item_to_string(&tcx, item));
|
||||
} else {
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,15 +175,8 @@ fn target(sess: &rustc_session::Session) -> types::Target {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"json"
|
||||
}
|
||||
|
||||
const RUN_ON_MODULE: bool = false;
|
||||
type ModuleData = ();
|
||||
|
||||
fn init(
|
||||
impl<'tcx> JsonRenderer<'tcx> {
|
||||
pub(crate) fn init(
|
||||
krate: clean::Crate,
|
||||
options: RenderOptions,
|
||||
cache: Cache,
|
||||
@@ -205,6 +198,15 @@ fn init(
|
||||
krate,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"json"
|
||||
}
|
||||
|
||||
const RUN_ON_MODULE: bool = false;
|
||||
type ModuleData = ();
|
||||
|
||||
fn save_module_data(&mut self) -> Self::ModuleData {
|
||||
unreachable!("RUN_ON_MODULE = false, should never call save_module_data")
|
||||
|
||||
+43
-7
@@ -80,6 +80,8 @@
|
||||
use tracing::info;
|
||||
|
||||
use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
|
||||
/// A macro to create a FxHashMap.
|
||||
///
|
||||
@@ -734,13 +736,23 @@ pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
|
||||
fn run_renderer<
|
||||
'tcx,
|
||||
T: formats::FormatRenderer<'tcx>,
|
||||
F: FnOnce(
|
||||
clean::Crate,
|
||||
config::RenderOptions,
|
||||
Cache,
|
||||
TyCtxt<'tcx>,
|
||||
) -> Result<(T, clean::Crate), Error>,
|
||||
>(
|
||||
krate: clean::Crate,
|
||||
renderopts: config::RenderOptions,
|
||||
cache: formats::cache::Cache,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
init: F,
|
||||
) {
|
||||
match formats::run_format::<T>(krate, renderopts, cache, tcx) {
|
||||
match formats::run_format::<T, F>(krate, renderopts, cache, tcx, init) {
|
||||
Ok(_) => tcx.dcx().abort_if_errors(),
|
||||
Err(e) => {
|
||||
let mut msg =
|
||||
@@ -870,6 +882,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
|
||||
let scrape_examples_options = options.scrape_examples_options.clone();
|
||||
let bin_crate = options.bin_crate;
|
||||
|
||||
let output_format = options.output_format;
|
||||
let config = core::create_config(input, options, &render_options);
|
||||
|
||||
let registered_lints = config.register_lints.is_some();
|
||||
@@ -894,9 +907,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
|
||||
sess.dcx().fatal("Compilation failed, aborting rustdoc");
|
||||
}
|
||||
|
||||
let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
|
||||
core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
|
||||
});
|
||||
let (krate, render_opts, mut cache, expanded_macros) = sess
|
||||
.time("run_global_ctxt", || {
|
||||
core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
|
||||
});
|
||||
info!("finished with rustc");
|
||||
|
||||
if let Some(options) = scrape_examples_options {
|
||||
@@ -927,10 +941,32 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
|
||||
info!("going to format");
|
||||
match output_format {
|
||||
config::OutputFormat::Html => sess.time("render_html", || {
|
||||
run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx)
|
||||
run_renderer(
|
||||
krate,
|
||||
render_opts,
|
||||
cache,
|
||||
tcx,
|
||||
|krate, render_opts, cache, tcx| {
|
||||
html::render::Context::init(
|
||||
krate,
|
||||
render_opts,
|
||||
cache,
|
||||
tcx,
|
||||
expanded_macros,
|
||||
)
|
||||
},
|
||||
)
|
||||
}),
|
||||
config::OutputFormat::Json => sess.time("render_json", || {
|
||||
run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx)
|
||||
run_renderer(
|
||||
krate,
|
||||
render_opts,
|
||||
cache,
|
||||
tcx,
|
||||
|krate, render_opts, cache, tcx| {
|
||||
json::JsonRenderer::init(krate, render_opts, cache, tcx)
|
||||
},
|
||||
)
|
||||
}),
|
||||
// Already handled above with doctest runners.
|
||||
config::OutputFormat::Doctest => unreachable!(),
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
use rustc_span::{BytePos, FileName, SourceFile};
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
use crate::formats::renderer::FormatRenderer;
|
||||
use crate::html::render::Context;
|
||||
use crate::{clean, config, formats};
|
||||
|
||||
@@ -276,7 +275,8 @@ pub(crate) fn run(
|
||||
let inner = move || -> Result<(), String> {
|
||||
// Generates source files for examples
|
||||
renderopts.no_emit_shared = true;
|
||||
let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
|
||||
let (cx, _) = Context::init(krate, renderopts, cache, tcx, Default::default())
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Collect CrateIds corresponding to provided target crates
|
||||
// If two different versions of the crate in the dependency tree, then examples will be
|
||||
|
||||
@@ -27,48 +27,48 @@ define-function: (
|
||||
}
|
||||
)
|
||||
|
||||
// First we check the derive macro expansion at line 12.
|
||||
call-function: ("check-expansion", {"line": 12, "original_content": "Debug"})
|
||||
// Then we check the `bar` macro expansion at line 22.
|
||||
call-function: ("check-expansion", {"line": 22, "original_content": "bar!(y)"})
|
||||
// First we check the derive macro expansion at line 33.
|
||||
call-function: ("check-expansion", {"line": 33, "original_content": "Debug"})
|
||||
// Then we check the `bar` macro expansion at line 41.
|
||||
call-function: ("check-expansion", {"line": 41, "original_content": "bar!(y)"})
|
||||
// Then we check the `println` macro expansion at line 23-25.
|
||||
call-function: ("check-expansion", {"line": 23, "original_content": 'println!("
|
||||
24 {y}
|
||||
25 ")'})
|
||||
call-function: ("check-expansion", {"line": 42, "original_content": 'println!("
|
||||
43 {y}
|
||||
44 ")'})
|
||||
|
||||
// Then finally we check when there are two macro calls on a same line.
|
||||
assert-count: ("#expand-27 ~ .original", 2)
|
||||
assert-count: ("#expand-27 ~ .expanded", 2)
|
||||
assert-count: ("#expand-50 ~ .original", 2)
|
||||
assert-count: ("#expand-50 ~ .expanded", 2)
|
||||
|
||||
store-value: (repeat_o, '/following-sibling::*[@class="original"]')
|
||||
store-value: (repeat_e, '/following-sibling::*[@class="expanded"]')
|
||||
assert-text: ('//*[@id="expand-27"]' + |repeat_o|, "stringify!(foo)")
|
||||
assert-text: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, "stringify!(bar)")
|
||||
assert-text: ('//*[@id="expand-27"]' + |repeat_e|, '"foo"')
|
||||
assert-text: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, '"bar"')
|
||||
assert-text: ('//*[@id="expand-50"]' + |repeat_o|, "stringify!(foo)")
|
||||
assert-text: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, "stringify!(bar)")
|
||||
assert-text: ('//*[@id="expand-50"]' + |repeat_e|, '"foo"')
|
||||
assert-text: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, '"bar"')
|
||||
|
||||
// The "original" content should be expanded.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
|
||||
// The expanded macro should be hidden.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"})
|
||||
|
||||
// We "expand" the macro (because the line starts with a string, the label is not at the "top
|
||||
// level" of the `<code>`, so we need to use a different selector).
|
||||
click: ".expansion label[for='expand-27']"
|
||||
click: ".expansion label[for='expand-50']"
|
||||
// The "original" content is hidden.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "none"})
|
||||
// The expanded macro is visible.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "inline"})
|
||||
|
||||
// We collapse the macro.
|
||||
click: ".expansion label[for='expand-27']"
|
||||
click: ".expansion label[for='expand-50']"
|
||||
// The "original" content is expanded.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
|
||||
// The expanded macro is hidden.
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"})
|
||||
assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"})
|
||||
|
||||
Reference in New Issue
Block a user