@@ -40,6 +40,7 @@ use std::collections::VecDeque;
40
40
use std:: default:: Default ;
41
41
use std:: fmt;
42
42
use std:: fs;
43
+ use std:: iter:: Peekable ;
43
44
use std:: path:: PathBuf ;
44
45
use std:: str;
45
46
use std:: string:: ToString ;
@@ -53,7 +54,10 @@ use rustc_hir::def_id::DefId;
53
54
use rustc_hir:: Mutability ;
54
55
use rustc_middle:: middle:: stability;
55
56
use rustc_middle:: ty:: TyCtxt ;
56
- use rustc_span:: symbol:: { kw, sym, Symbol } ;
57
+ use rustc_span:: {
58
+ symbol:: { kw, sym, Symbol } ,
59
+ BytePos , FileName , RealFileName ,
60
+ } ;
57
61
use serde:: ser:: SerializeSeq ;
58
62
use serde:: { Serialize , Serializer } ;
59
63
@@ -590,7 +594,7 @@ fn document_full_inner(
590
594
591
595
match & * item. kind {
592
596
clean:: ItemKind :: FunctionItem ( f) | clean:: ItemKind :: MethodItem ( f, _) => {
593
- render_call_locations ( w, cx, & f. call_locations ) ;
597
+ render_call_locations ( w, cx, & f. call_locations , item ) ;
594
598
}
595
599
_ => { }
596
600
}
@@ -2458,6 +2462,7 @@ fn render_call_locations(
2458
2462
w : & mut Buffer ,
2459
2463
cx : & Context < ' _ > ,
2460
2464
call_locations : & Option < FnCallLocations > ,
2465
+ item : & clean:: Item ,
2461
2466
) {
2462
2467
let call_locations = match call_locations. as_ref ( ) {
2463
2468
Some ( call_locations) if call_locations. len ( ) > 0 => call_locations,
@@ -2488,11 +2493,17 @@ fn render_call_locations(
2488
2493
} ;
2489
2494
2490
2495
// Generate the HTML for a single example, being the title and code block
2491
- let write_example = |w : & mut Buffer , ( path, call_data) : ( & PathBuf , & CallData ) | {
2492
- // FIXME(wcrichto): is there a better way to handle an I/O error than a panic?
2493
- // When would such an error arise?
2494
- let contents =
2495
- fs:: read_to_string ( & path) . expect ( & format ! ( "Failed to read file: {}" , path. display( ) ) ) ;
2496
+ let tcx = cx. tcx ( ) ;
2497
+ let write_example = |w : & mut Buffer , ( path, call_data) : ( & PathBuf , & CallData ) | -> bool {
2498
+ let contents = match fs:: read_to_string ( & path) {
2499
+ Ok ( contents) => contents,
2500
+ Err ( err) => {
2501
+ let span = item. span ( tcx) . inner ( ) ;
2502
+ tcx. sess
2503
+ . span_err ( span, & format ! ( "failed to read file {}: {}" , path. display( ) , err) ) ;
2504
+ return false ;
2505
+ }
2506
+ } ;
2496
2507
2497
2508
// To reduce file sizes, we only want to embed the source code needed to understand the example, not
2498
2509
// the entire file. So we find the smallest byte range that covers all items enclosing examples.
@@ -2522,23 +2533,42 @@ fn render_call_locations(
2522
2533
let edition = cx. shared . edition ( ) ;
2523
2534
write ! (
2524
2535
w,
2525
- r#"<div class="scraped-example" data-code="{code}" data- locs="{locations}">
2536
+ r#"<div class="scraped-example" data-locs="{locations}">
2526
2537
<div class="scraped-example-title">{title}</div>
2527
2538
<div class="code-wrapper">"# ,
2528
2539
title = example_url( call_data) ,
2529
- // The code and locations are encoded as data attributes , so they can be read
2540
+ // The locations are encoded as a data attribute , so they can be read
2530
2541
// later by the JS for interactions.
2531
- code = contents_subset. replace( "\" " , """ ) ,
2532
2542
locations = serde_json:: to_string( & line_ranges) . unwrap( ) ,
2533
2543
) ;
2534
2544
write ! ( w, r#"<span class="prev">≺</span> <span class="next">≻</span>"# ) ;
2535
2545
write ! ( w, r#"<span class="expand">↕</span>"# ) ;
2536
2546
2537
- // FIXME(wcrichto): where should file_span and root_path come from?
2538
- let file_span = rustc_span:: DUMMY_SP ;
2539
- let root_path = "" . to_string ( ) ;
2547
+ // Look for the example file in the source map if it exists, otherwise return a dummy span
2548
+ let file_span = ( || {
2549
+ let source_map = tcx. sess . source_map ( ) ;
2550
+ let crate_src = tcx. sess . local_crate_source_file . as_ref ( ) ?;
2551
+ let abs_crate_src = crate_src. canonicalize ( ) . ok ( ) ?;
2552
+ let crate_root = abs_crate_src. parent ( ) ?. parent ( ) ?;
2553
+ let rel_path = path. strip_prefix ( crate_root) . ok ( ) ?;
2554
+ let files = source_map. files ( ) ;
2555
+ let file = files. iter ( ) . find ( |file| match & file. name {
2556
+ FileName :: Real ( RealFileName :: LocalPath ( other_path) ) => rel_path == other_path,
2557
+ _ => false ,
2558
+ } ) ?;
2559
+ Some ( rustc_span:: Span :: with_root_ctxt (
2560
+ file. start_pos + BytePos ( min_byte) ,
2561
+ file. start_pos + BytePos ( max_byte) ,
2562
+ ) )
2563
+ } ) ( )
2564
+ . unwrap_or ( rustc_span:: DUMMY_SP ) ;
2565
+
2566
+ // The root path is the inverse of Context::current
2567
+ let root_path = vec ! [ "../" ; cx. current. len( ) - 1 ] . join ( "" ) ;
2568
+
2540
2569
let mut decoration_info = FxHashMap :: default ( ) ;
2541
2570
decoration_info. insert ( "highlight" , byte_ranges) ;
2571
+
2542
2572
sources:: print_src (
2543
2573
w,
2544
2574
contents_subset,
@@ -2550,6 +2580,8 @@ fn render_call_locations(
2550
2580
Some ( decoration_info) ,
2551
2581
) ;
2552
2582
write ! ( w, "</div></div>" ) ;
2583
+
2584
+ true
2553
2585
} ;
2554
2586
2555
2587
// The call locations are output in sequence, so that sequence needs to be determined.
@@ -2570,7 +2602,15 @@ fn render_call_locations(
2570
2602
2571
2603
// Write just one example that's visible by default in the method's description.
2572
2604
let mut it = ordered_locations. into_iter ( ) . peekable ( ) ;
2573
- write_example ( w, it. next ( ) . unwrap ( ) ) ;
2605
+ let write_and_skip_failure = |w : & mut Buffer , it : & mut Peekable < _ > | {
2606
+ while let Some ( example) = it. next ( ) {
2607
+ if write_example ( & mut * w, example) {
2608
+ break ;
2609
+ }
2610
+ }
2611
+ } ;
2612
+
2613
+ write_and_skip_failure ( w, & mut it) ;
2574
2614
2575
2615
// Then add the remaining examples in a hidden section.
2576
2616
if it. peek ( ) . is_some ( ) {
@@ -2582,13 +2622,15 @@ fn render_call_locations(
2582
2622
</summary>
2583
2623
<div class="more-scraped-examples">
2584
2624
<div class="toggle-line"><div class="toggle-line-inner"></div></div>
2585
- <div>
2625
+ <div class="more-scraped-examples-inner" >
2586
2626
"#
2587
2627
) ;
2588
2628
2589
2629
// Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
2590
2630
// make the page arbitrarily huge!
2591
- ( & mut it) . take ( MAX_FULL_EXAMPLES ) . for_each ( |ex| write_example ( w, ex) ) ;
2631
+ for _ in 0 ..MAX_FULL_EXAMPLES {
2632
+ write_and_skip_failure ( w, & mut it) ;
2633
+ }
2592
2634
2593
2635
// For the remaining examples, generate a <ul /> containing links to the source files.
2594
2636
if it. peek ( ) . is_some ( ) {
0 commit comments