@@ -40,6 +40,7 @@ use std::collections::VecDeque;
4040use std:: default:: Default ;
4141use std:: fmt;
4242use std:: fs;
43+ use std:: iter:: Peekable ;
4344use std:: path:: PathBuf ;
4445use std:: str;
4546use std:: string:: ToString ;
@@ -53,7 +54,10 @@ use rustc_hir::def_id::DefId;
5354use rustc_hir:: Mutability ;
5455use rustc_middle:: middle:: stability;
5556use 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+ } ;
5761use serde:: ser:: SerializeSeq ;
5862use serde:: { Serialize , Serializer } ;
5963
@@ -590,7 +594,7 @@ fn document_full_inner(
590594
591595 match & * item. kind {
592596 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 ) ;
594598 }
595599 _ => { }
596600 }
@@ -2458,6 +2462,7 @@ fn render_call_locations(
24582462 w : & mut Buffer ,
24592463 cx : & Context < ' _ > ,
24602464 call_locations : & Option < FnCallLocations > ,
2465+ item : & clean:: Item ,
24612466) {
24622467 let call_locations = match call_locations. as_ref ( ) {
24632468 Some ( call_locations) if call_locations. len ( ) > 0 => call_locations,
@@ -2488,11 +2493,17 @@ fn render_call_locations(
24882493 } ;
24892494
24902495 // 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+ } ;
24962507
24972508 // To reduce file sizes, we only want to embed the source code needed to understand the example, not
24982509 // the entire file. So we find the smallest byte range that covers all items enclosing examples.
@@ -2522,23 +2533,42 @@ fn render_call_locations(
25222533 let edition = cx. shared . edition ( ) ;
25232534 write ! (
25242535 w,
2525- r#"<div class="scraped-example" data-code="{code}" data- locs="{locations}">
2536+ r#"<div class="scraped-example" data-locs="{locations}">
25262537 <div class="scraped-example-title">{title}</div>
25272538 <div class="code-wrapper">"# ,
25282539 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
25302541 // later by the JS for interactions.
2531- code = contents_subset. replace( "\" " , """ ) ,
25322542 locations = serde_json:: to_string( & line_ranges) . unwrap( ) ,
25332543 ) ;
25342544 write ! ( w, r#"<span class="prev">≺</span> <span class="next">≻</span>"# ) ;
25352545 write ! ( w, r#"<span class="expand">↕</span>"# ) ;
25362546
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+
25402569 let mut decoration_info = FxHashMap :: default ( ) ;
25412570 decoration_info. insert ( "highlight" , byte_ranges) ;
2571+
25422572 sources:: print_src (
25432573 w,
25442574 contents_subset,
@@ -2550,6 +2580,8 @@ fn render_call_locations(
25502580 Some ( decoration_info) ,
25512581 ) ;
25522582 write ! ( w, "</div></div>" ) ;
2583+
2584+ true
25532585 } ;
25542586
25552587 // The call locations are output in sequence, so that sequence needs to be determined.
@@ -2570,7 +2602,15 @@ fn render_call_locations(
25702602
25712603 // Write just one example that's visible by default in the method's description.
25722604 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) ;
25742614
25752615 // Then add the remaining examples in a hidden section.
25762616 if it. peek ( ) . is_some ( ) {
@@ -2582,13 +2622,15 @@ fn render_call_locations(
25822622 </summary>
25832623 <div class="more-scraped-examples">
25842624 <div class="toggle-line"><div class="toggle-line-inner"></div></div>
2585- <div>
2625+ <div class="more-scraped-examples-inner" >
25862626"#
25872627 ) ;
25882628
25892629 // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
25902630 // 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+ }
25922634
25932635 // For the remaining examples, generate a <ul /> containing links to the source files.
25942636 if it. peek ( ) . is_some ( ) {
0 commit comments