Skip to content

Commit 829b1a9

Browse files
committed
Incorporate jyn's feedback
* Move call location logic from function constructor to rendering * Fix issue with macro spans in scraping examples * Clean up example loading logic Documentation / newtype for DecorationInfo Fix line number display Serialize edition of call site, other small cleanup
1 parent a1cb194 commit 829b1a9

File tree

12 files changed

+183
-132
lines changed

12 files changed

+183
-132
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi
235235
decl,
236236
generics,
237237
header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness },
238-
call_locations: None,
238+
def_id: did,
239239
}
240240
}
241241

src/librustdoc/clean/mod.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -801,10 +801,8 @@ impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::Bo
801801
fn clean(&self, cx: &mut DocContext<'_>) -> Function {
802802
let (generics, decl) =
803803
enter_impl_trait(cx, |cx| (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
804-
let mut function = Function { decl, generics, header: self.0.header, call_locations: None };
805804
let def_id = self.2.hir_id.owner.to_def_id();
806-
function.load_call_locations(def_id, cx);
807-
function
805+
Function { decl, generics, header: self.0.header, def_id }
808806
}
809807
}
810808

@@ -936,14 +934,13 @@ impl Clean<Item> for hir::TraitItem<'_> {
936934
let (generics, decl) = enter_impl_trait(cx, |cx| {
937935
(self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
938936
});
939-
let mut t =
940-
Function { header: sig.header, decl, generics, call_locations: None };
937+
let def_id = self.def_id.to_def_id();
938+
let mut t = Function { header: sig.header, decl, generics, def_id };
941939
if t.header.constness == hir::Constness::Const
942940
&& is_unstable_const_fn(cx.tcx, local_did).is_some()
943941
{
944942
t.header.constness = hir::Constness::NotConst;
945943
}
946-
t.load_call_locations(self.def_id.to_def_id(), cx);
947944
TyMethodItem(t)
948945
}
949946
hir::TraitItemKind::Type(ref bounds, ref default) => {
@@ -1062,7 +1059,7 @@ impl Clean<Item> for ty::AssocItem {
10621059
ty::ImplContainer(_) => Some(self.defaultness),
10631060
ty::TraitContainer(_) => None,
10641061
};
1065-
let mut function = Function {
1062+
let function = Function {
10661063
generics,
10671064
decl,
10681065
header: hir::FnHeader {
@@ -1071,12 +1068,11 @@ impl Clean<Item> for ty::AssocItem {
10711068
constness,
10721069
asyncness,
10731070
},
1074-
call_locations: None,
1071+
def_id: self.def_id,
10751072
};
1076-
function.load_call_locations(self.def_id, cx);
10771073
MethodItem(function, defaultness)
10781074
} else {
1079-
let mut function = Function {
1075+
let function = Function {
10801076
generics,
10811077
decl,
10821078
header: hir::FnHeader {
@@ -1085,9 +1081,8 @@ impl Clean<Item> for ty::AssocItem {
10851081
constness: hir::Constness::NotConst,
10861082
asyncness: hir::IsAsync::NotAsync,
10871083
},
1088-
call_locations: None,
1084+
def_id: self.def_id,
10891085
};
1090-
function.load_call_locations(self.def_id, cx);
10911086
TyMethodItem(function)
10921087
}
10931088
}
@@ -2086,7 +2081,8 @@ fn clean_use_statement(
20862081
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
20872082
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
20882083
let (item, renamed) = self;
2089-
cx.with_param_env(item.def_id.to_def_id(), |cx| {
2084+
let def_id = item.def_id.to_def_id();
2085+
cx.with_param_env(def_id, |cx| {
20902086
let kind = match item.kind {
20912087
hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
20922088
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
@@ -2106,7 +2102,7 @@ impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
21062102
constness: hir::Constness::NotConst,
21072103
asyncness: hir::IsAsync::NotAsync,
21082104
},
2109-
call_locations: None,
2105+
def_id,
21102106
})
21112107
}
21122108
hir::ForeignItemKind::Static(ref ty, mutability) => {

src/librustdoc/clean/types.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ use crate::formats::cache::Cache;
4242
use crate::formats::item_type::ItemType;
4343
use crate::html::render::cache::ExternalLocation;
4444
use crate::html::render::Context;
45-
use crate::scrape_examples::{self, FnCallLocations};
4645

4746
use self::FnRetTy::*;
4847
use self::ItemKind::*;
@@ -1255,19 +1254,7 @@ crate struct Function {
12551254
crate decl: FnDecl,
12561255
crate generics: Generics,
12571256
crate header: hir::FnHeader,
1258-
crate call_locations: Option<FnCallLocations>,
1259-
}
1260-
1261-
impl Function {
1262-
/// If --scrape-examples is used, then this function attempts to find call locations
1263-
/// for `self` within `RenderOptions::call_locations` and store them in `Function::call_locations`.
1264-
crate fn load_call_locations(&mut self, def_id: hir::def_id::DefId, cx: &DocContext<'_>) {
1265-
if let Some(call_locations) = cx.render_options.call_locations.as_ref() {
1266-
let key = scrape_examples::def_id_call_key(cx.tcx, def_id);
1267-
self.call_locations = call_locations.get(&key).cloned();
1268-
debug!("call_locations: {:?} -- {:?}", key, self.call_locations);
1269-
}
1270-
}
1257+
crate def_id: DefId,
12711258
}
12721259

12731260
#[derive(Clone, PartialEq, Eq, Debug, Hash)]

src/librustdoc/config.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ impl fmt::Debug for Options {
207207
.field("run_check", &self.run_check)
208208
.field("no_run", &self.no_run)
209209
.field("nocapture", &self.nocapture)
210+
.field("scrape_examples", &self.scrape_examples)
210211
.finish()
211212
}
212213
}
@@ -285,7 +286,7 @@ crate struct RenderOptions {
285286
crate emit: Vec<EmitType>,
286287
/// If `true`, HTML source pages will generate links for items to their definition.
287288
crate generate_link_to_definition: bool,
288-
crate call_locations: Option<AllCallLocations>,
289+
crate call_locations: AllCallLocations,
289290
}
290291

291292
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

src/librustdoc/html/highlight.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ crate struct ContextInfo<'a, 'b, 'c> {
3131
crate root_path: &'c str,
3232
}
3333

34-
crate type DecorationInfo = FxHashMap<&'static str, Vec<(u32, u32)>>;
34+
/// Decorations are represented as a map from CSS class to vector of character ranges.
35+
/// Each range will be wrapped in a span with that class.
36+
crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
3537

3638
/// Highlights `src`, returning the HTML output.
3739
crate fn render_with_highlighting(
@@ -273,6 +275,7 @@ struct Decorations {
273275
impl Decorations {
274276
fn new(info: DecorationInfo) -> Self {
275277
let (starts, ends) = info
278+
.0
276279
.into_iter()
277280
.map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
278281
.flatten()
@@ -305,6 +308,7 @@ impl<'a> Classifier<'a> {
305308
decoration_info: Option<DecorationInfo>,
306309
) -> Classifier<'_> {
307310
let tokens = PeekIter::new(TokenIter { src });
311+
let decorations = decoration_info.map(Decorations::new);
308312
Classifier {
309313
tokens,
310314
in_attribute: false,

src/librustdoc/html/render/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use crate::html::format::Buffer;
3535
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
3636
use crate::html::static_files::PAGE;
3737
use crate::html::{layout, sources};
38+
use crate::scrape_examples::AllCallLocations;
3839

3940
/// Major driving force in all rustdoc rendering. This contains information
4041
/// about where in the tree-like hierarchy rendering is occurring and controls
@@ -124,6 +125,8 @@ crate struct SharedContext<'tcx> {
124125
crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
125126
/// The [`Cache`] used during rendering.
126127
crate cache: Cache,
128+
129+
crate call_locations: AllCallLocations,
127130
}
128131

129132
impl SharedContext<'_> {
@@ -389,6 +392,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
389392
generate_redirect_map,
390393
show_type_layout,
391394
generate_link_to_definition,
395+
call_locations,
392396
..
393397
} = options;
394398

@@ -480,6 +484,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
480484
templates,
481485
span_correspondance_map: matches,
482486
cache,
487+
call_locations,
483488
};
484489

485490
// Add the default themes to the `Vec` of stylepaths

src/librustdoc/html/render/mod.rs

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ use crate::html::format::{
7373
print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
7474
};
7575
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
76+
use crate::html::highlight;
7677
use crate::html::sources;
77-
use crate::scrape_examples::{CallData, FnCallLocations};
78+
use crate::scrape_examples::CallData;
7879

7980
/// A pair of name and its optional document.
8081
crate type NameDoc = (String, Option<String>);
@@ -592,9 +593,13 @@ fn document_full_inner(
592593
}
593594
}
594595

595-
match &*item.kind {
596+
let kind = match &*item.kind {
597+
clean::ItemKind::StrippedItem(box kind) | kind => kind,
598+
};
599+
600+
match kind {
596601
clean::ItemKind::FunctionItem(f) | clean::ItemKind::MethodItem(f, _) => {
597-
render_call_locations(w, cx, &f.call_locations, item);
602+
render_call_locations(w, cx, f.def_id, item);
598603
}
599604
_ => {}
600605
}
@@ -2458,14 +2463,11 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
24582463
const MAX_FULL_EXAMPLES: usize = 5;
24592464

24602465
/// Generates the HTML for example call locations generated via the --scrape-examples flag.
2461-
fn render_call_locations(
2462-
w: &mut Buffer,
2463-
cx: &Context<'_>,
2464-
call_locations: &Option<FnCallLocations>,
2465-
item: &clean::Item,
2466-
) {
2467-
let call_locations = match call_locations.as_ref() {
2468-
Some(call_locations) if call_locations.len() > 0 => call_locations,
2466+
fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, def_id: DefId, item: &clean::Item) {
2467+
let tcx = cx.tcx();
2468+
let key = crate::scrape_examples::def_id_call_key(tcx, def_id);
2469+
let call_locations = match cx.shared.call_locations.get(&key) {
2470+
Some(call_locations) => call_locations,
24692471
_ => {
24702472
return;
24712473
}
@@ -2483,7 +2485,6 @@ fn render_call_locations(
24832485
);
24842486

24852487
// Generate the HTML for a single example, being the title and code block
2486-
let tcx = cx.tcx();
24872488
let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
24882489
let contents = match fs::read_to_string(&path) {
24892490
Ok(contents) => contents,
@@ -2497,40 +2498,51 @@ fn render_call_locations(
24972498

24982499
// To reduce file sizes, we only want to embed the source code needed to understand the example, not
24992500
// the entire file. So we find the smallest byte range that covers all items enclosing examples.
2500-
assert!(call_data.locations.len() > 0);
2501+
assert!(!call_data.locations.is_empty());
25012502
let min_loc =
25022503
call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2503-
let min_byte = min_loc.enclosing_item.byte_span.0;
2504-
let min_line = min_loc.enclosing_item.line_span.0;
2505-
let max_byte =
2504+
let (byte_offset, _) = min_loc.enclosing_item.byte_span;
2505+
let (line_offset, _) = min_loc.enclosing_item.line_span;
2506+
let byte_ceiling =
25062507
call_data.locations.iter().map(|loc| loc.enclosing_item.byte_span.1).max().unwrap();
25072508

25082509
// The output code is limited to that byte range.
2509-
let contents_subset = &contents[(min_byte as usize)..(max_byte as usize)];
2510+
let contents_subset = &contents[(byte_offset as usize)..(byte_ceiling as usize)];
25102511

25112512
// The call locations need to be updated to reflect that the size of the program has changed.
2512-
// Specifically, the ranges are all subtracted by `min_byte` since that's the new zero point.
2513+
// Specifically, the ranges are all subtracted by `byte_offset` since that's the new zero point.
25132514
let (byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
25142515
.locations
25152516
.iter()
25162517
.map(|loc| {
25172518
let (byte_lo, byte_hi) = loc.call_expr.byte_span;
25182519
let (line_lo, line_hi) = loc.call_expr.line_span;
2519-
((byte_lo - min_byte, byte_hi - min_byte), (line_lo - min_line, line_hi - min_line))
2520+
(
2521+
(byte_lo - byte_offset, byte_hi - byte_offset),
2522+
(line_lo - line_offset, line_hi - line_offset),
2523+
)
25202524
})
25212525
.unzip();
25222526

2523-
let edition = cx.shared.edition();
2527+
let (init_min, init_max) = line_ranges[0];
2528+
let line_range = if init_min == init_max {
2529+
format!("line {}", init_min + line_offset + 1)
2530+
} else {
2531+
format!("lines {}-{}", init_min + line_offset + 1, init_max + line_offset + 1)
2532+
};
2533+
25242534
write!(
25252535
w,
2526-
r#"<div class="scraped-example" data-locs="{locations}">
2536+
r#"<div class="scraped-example" data-locs="{locations}" data-offset="{offset}">
25272537
<div class="scraped-example-title">
2528-
{name} <a href="{root}{url}" target="_blank">[src]</a>
2538+
{name} (<a href="{root}{url}" target="_blank">{line_range}</a>)
25292539
</div>
25302540
<div class="code-wrapper">"#,
25312541
root = cx.root_path(),
25322542
url = call_data.url,
25332543
name = call_data.display_name,
2544+
line_range = line_range,
2545+
offset = line_offset,
25342546
// The locations are encoded as a data attribute, so they can be read
25352547
// later by the JS for interactions.
25362548
locations = serde_json::to_string(&line_ranges).unwrap(),
@@ -2551,8 +2563,8 @@ fn render_call_locations(
25512563
_ => false,
25522564
})?;
25532565
Some(rustc_span::Span::with_root_ctxt(
2554-
file.start_pos + BytePos(min_byte),
2555-
file.start_pos + BytePos(max_byte),
2566+
file.start_pos + BytePos(byte_offset),
2567+
file.start_pos + BytePos(byte_ceiling),
25562568
))
25572569
})()
25582570
.unwrap_or(rustc_span::DUMMY_SP);
@@ -2566,12 +2578,12 @@ fn render_call_locations(
25662578
sources::print_src(
25672579
w,
25682580
contents_subset,
2569-
edition,
2581+
call_data.edition,
25702582
file_span,
25712583
cx,
25722584
&root_path,
2573-
Some(min_line),
2574-
Some(decoration_info),
2585+
Some(line_offset),
2586+
Some(highlight::DecorationInfo(decoration_info)),
25752587
);
25762588
write!(w, "</div></div>");
25772589

@@ -2590,12 +2602,14 @@ fn render_call_locations(
25902602
};
25912603

25922604
let mut locs = call_locations.into_iter().collect::<Vec<_>>();
2593-
locs.sort_by_key(|x| sort_criterion(x));
2605+
locs.sort_by_key(sort_criterion);
25942606
locs
25952607
};
25962608

2597-
// Write just one example that's visible by default in the method's description.
25982609
let mut it = ordered_locations.into_iter().peekable();
2610+
2611+
// An example may fail to write if its source can't be read for some reason, so this method
2612+
// continues iterating until a write suceeds
25992613
let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
26002614
while let Some(example) = it.next() {
26012615
if write_example(&mut *w, example) {
@@ -2604,6 +2618,7 @@ fn render_call_locations(
26042618
}
26052619
};
26062620

2621+
// Write just one example that's visible by default in the method's description.
26072622
write_and_skip_failure(w, &mut it);
26082623

26092624
// Then add the remaining examples in a hidden section.
@@ -2626,7 +2641,7 @@ fn render_call_locations(
26262641
write_and_skip_failure(w, &mut it);
26272642
}
26282643

2629-
// For the remaining examples, generate a <ul /> containing links to the source files.
2644+
// For the remaining examples, generate a <ul> containing links to the source files.
26302645
if it.peek().is_some() {
26312646
write!(
26322647
w,
@@ -2635,7 +2650,7 @@ fn render_call_locations(
26352650
it.for_each(|(_, call_data)| {
26362651
write!(
26372652
w,
2638-
r#"<li><a href="{}{}" target="_blank">{}</a></li>"#,
2653+
r#"<li><a href="{root}{url}" target="_blank">{name}</a></li>"#,
26392654
root = cx.root_path(),
26402655
url = call_data.url,
26412656
name = call_data.display_name

src/librustdoc/html/static/css/rustdoc.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,10 +1978,6 @@ details.undocumented[open] > summary::before {
19781978
font-family: 'Fira Sans';
19791979
}
19801980

1981-
.scraped-example-title a {
1982-
margin-left: 5px;
1983-
}
1984-
19851981
.scraped-example:not(.expanded) .code-wrapper pre.line-numbers,
19861982
.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
19871983
overflow: hidden;

0 commit comments

Comments
 (0)