@@ -13,6 +13,7 @@ use rustc_span::source_map::SourceMap;
1313use rustc_span:: symbol:: sym;
1414use rustc_span:: { BytePos , FileName , Pos , Span , DUMMY_SP } ;
1515use rustc_target:: spec:: TargetTriple ;
16+ use std:: collections:: HashMap ;
1617use std:: env;
1718use std:: io:: { self , Write } ;
1819use std:: panic;
@@ -189,10 +190,23 @@ enum TestFailure {
189190 UnexpectedRunPass ,
190191}
191192
193+ enum DirState {
194+ Temp ( tempfile:: TempDir ) ,
195+ Perm ( PathBuf ) ,
196+ }
197+
198+ impl DirState {
199+ fn path ( & self ) -> & std:: path:: Path {
200+ match self {
201+ DirState :: Temp ( t) => t. path ( ) ,
202+ DirState :: Perm ( p) => p. as_path ( ) ,
203+ }
204+ }
205+ }
206+
192207fn run_test (
193208 test : & str ,
194209 cratename : & str ,
195- filename : & FileName ,
196210 line : usize ,
197211 options : Options ,
198212 should_panic : bool ,
@@ -205,47 +219,11 @@ fn run_test(
205219 mut error_codes : Vec < String > ,
206220 opts : & TestOptions ,
207221 edition : Edition ,
222+ outdir : DirState ,
223+ path : PathBuf ,
208224) -> Result < ( ) , TestFailure > {
209225 let ( test, line_offset) = make_test ( test, Some ( cratename) , as_test_harness, opts, edition) ;
210226
211- // FIXME(#44940): if doctests ever support path remapping, then this filename
212- // needs to be the result of `SourceMap::span_to_unmapped_path`.
213- let path = match filename {
214- FileName :: Real ( path) => path. clone ( ) ,
215- _ => PathBuf :: from ( r"doctest.rs" ) ,
216- } ;
217-
218- enum DirState {
219- Temp ( tempfile:: TempDir ) ,
220- Perm ( PathBuf ) ,
221- }
222-
223- impl DirState {
224- fn path ( & self ) -> & std:: path:: Path {
225- match self {
226- DirState :: Temp ( t) => t. path ( ) ,
227- DirState :: Perm ( p) => p. as_path ( ) ,
228- }
229- }
230- }
231-
232- let outdir = if let Some ( mut path) = options. persist_doctests {
233- path. push ( format ! (
234- "{}_{}" ,
235- filename. to_string( ) . rsplit( '/' ) . next( ) . unwrap( ) . replace( "." , "_" ) ,
236- line
237- ) ) ;
238- std:: fs:: create_dir_all ( & path) . expect ( "Couldn't create directory for doctest executables" ) ;
239-
240- DirState :: Perm ( path)
241- } else {
242- DirState :: Temp (
243- TempFileBuilder :: new ( )
244- . prefix ( "rustdoctest" )
245- . tempdir ( )
246- . expect ( "rustdoc needs a tempdir" ) ,
247- )
248- } ;
249227 let output_file = outdir. path ( ) . join ( "rust_out" ) ;
250228
251229 let rustc_binary = options
@@ -638,6 +616,7 @@ pub struct Collector {
638616 position : Span ,
639617 source_map : Option < Lrc < SourceMap > > ,
640618 filename : Option < PathBuf > ,
619+ visited_tests : HashMap < ( String , usize ) , usize > ,
641620}
642621
643622impl Collector {
@@ -661,6 +640,7 @@ impl Collector {
661640 position : DUMMY_SP ,
662641 source_map,
663642 filename,
643+ visited_tests : HashMap :: new ( ) ,
664644 }
665645 }
666646
@@ -704,6 +684,48 @@ impl Tester for Collector {
704684 let target = self . options . target . clone ( ) ;
705685 let target_str = target. to_string ( ) ;
706686
687+ // FIXME(#44940): if doctests ever support path remapping, then this filename
688+ // needs to be the result of `SourceMap::span_to_unmapped_path`.
689+ let path = match & filename {
690+ FileName :: Real ( path) => path. clone ( ) ,
691+ _ => PathBuf :: from ( r"doctest.rs" ) ,
692+ } ;
693+
694+ let outdir = if let Some ( mut path) = options. persist_doctests . clone ( ) {
695+ // For example `module/file.rs` would become `module_file_rs`
696+ let folder_name = filename
697+ . to_string ( )
698+ . chars ( )
699+ . map ( |c| if c == '/' || c == '.' { '_' } else { c } )
700+ . collect :: < String > ( ) ;
701+
702+ path. push ( format ! (
703+ "{name}_{line}_{number}" ,
704+ name = folder_name,
705+ number = {
706+ // Increases the current test number, if this file already
707+ // exists or it creates a new entry with a test number of 0.
708+ self . visited_tests
709+ . entry( ( folder_name. clone( ) , line) )
710+ . and_modify( |v| * v += 1 )
711+ . or_insert( 0 )
712+ } ,
713+ line = line,
714+ ) ) ;
715+
716+ std:: fs:: create_dir_all ( & path)
717+ . expect ( "Couldn't create directory for doctest executables" ) ;
718+
719+ DirState :: Perm ( path)
720+ } else {
721+ DirState :: Temp (
722+ TempFileBuilder :: new ( )
723+ . prefix ( "rustdoctest" )
724+ . tempdir ( )
725+ . expect ( "rustdoc needs a tempdir" ) ,
726+ )
727+ } ;
728+
707729 debug ! ( "creating test {}: {}" , name, test) ;
708730 self . tests . push ( testing:: TestDescAndFn {
709731 desc : testing:: TestDesc {
@@ -722,7 +744,6 @@ impl Tester for Collector {
722744 let res = run_test (
723745 & test,
724746 & cratename,
725- & filename,
726747 line,
727748 options,
728749 config. should_panic ,
@@ -735,6 +756,8 @@ impl Tester for Collector {
735756 config. error_codes ,
736757 & opts,
737758 edition,
759+ outdir,
760+ path,
738761 ) ;
739762
740763 if let Err ( err) = res {
0 commit comments