@@ -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;
@@ -190,10 +191,23 @@ enum TestFailure {
190191 UnexpectedRunPass ,
191192}
192193
194+ enum DirState {
195+ Temp ( tempfile:: TempDir ) ,
196+ Perm ( PathBuf ) ,
197+ }
198+
199+ impl DirState {
200+ fn path ( & self ) -> & std:: path:: Path {
201+ match self {
202+ DirState :: Temp ( t) => t. path ( ) ,
203+ DirState :: Perm ( p) => p. as_path ( ) ,
204+ }
205+ }
206+ }
207+
193208fn run_test (
194209 test : & str ,
195210 cratename : & str ,
196- filename : & FileName ,
197211 line : usize ,
198212 options : Options ,
199213 should_panic : bool ,
@@ -206,47 +220,11 @@ fn run_test(
206220 mut error_codes : Vec < String > ,
207221 opts : & TestOptions ,
208222 edition : Edition ,
223+ outdir : DirState ,
224+ path : PathBuf ,
209225) -> Result < ( ) , TestFailure > {
210226 let ( test, line_offset) = make_test ( test, Some ( cratename) , as_test_harness, opts, edition) ;
211227
212- // FIXME(#44940): if doctests ever support path remapping, then this filename
213- // needs to be the result of `SourceMap::span_to_unmapped_path`.
214- let path = match filename {
215- FileName :: Real ( path) => path. clone ( ) ,
216- _ => PathBuf :: from ( r"doctest.rs" ) ,
217- } ;
218-
219- enum DirState {
220- Temp ( tempfile:: TempDir ) ,
221- Perm ( PathBuf ) ,
222- }
223-
224- impl DirState {
225- fn path ( & self ) -> & std:: path:: Path {
226- match self {
227- DirState :: Temp ( t) => t. path ( ) ,
228- DirState :: Perm ( p) => p. as_path ( ) ,
229- }
230- }
231- }
232-
233- let outdir = if let Some ( mut path) = options. persist_doctests {
234- path. push ( format ! (
235- "{}_{}" ,
236- filename. to_string( ) . rsplit( '/' ) . next( ) . unwrap( ) . replace( "." , "_" ) ,
237- line
238- ) ) ;
239- std:: fs:: create_dir_all ( & path) . expect ( "Couldn't create directory for doctest executables" ) ;
240-
241- DirState :: Perm ( path)
242- } else {
243- DirState :: Temp (
244- TempFileBuilder :: new ( )
245- . prefix ( "rustdoctest" )
246- . tempdir ( )
247- . expect ( "rustdoc needs a tempdir" ) ,
248- )
249- } ;
250228 let output_file = outdir. path ( ) . join ( "rust_out" ) ;
251229
252230 let rustc_binary = options
@@ -639,6 +617,7 @@ pub struct Collector {
639617 position : Span ,
640618 source_map : Option < Lrc < SourceMap > > ,
641619 filename : Option < PathBuf > ,
620+ visited_tests : HashMap < ( String , usize ) , usize > ,
642621}
643622
644623impl Collector {
@@ -662,6 +641,7 @@ impl Collector {
662641 position : DUMMY_SP ,
663642 source_map,
664643 filename,
644+ visited_tests : HashMap :: new ( ) ,
665645 }
666646 }
667647
@@ -705,6 +685,48 @@ impl Tester for Collector {
705685 let target = self . options . target . clone ( ) ;
706686 let target_str = target. to_string ( ) ;
707687
688+ // FIXME(#44940): if doctests ever support path remapping, then this filename
689+ // needs to be the result of `SourceMap::span_to_unmapped_path`.
690+ let path = match & filename {
691+ FileName :: Real ( path) => path. clone ( ) ,
692+ _ => PathBuf :: from ( r"doctest.rs" ) ,
693+ } ;
694+
695+ let outdir = if let Some ( mut path) = options. persist_doctests . clone ( ) {
696+ // For example `module/file.rs` would become `module_file_rs`
697+ let folder_name = filename
698+ . to_string ( )
699+ . chars ( )
700+ . map ( |c| if c == '/' || c == '.' { '_' } else { c } )
701+ . collect :: < String > ( ) ;
702+
703+ path. push ( format ! (
704+ "{name}_{line}_{number}" ,
705+ name = folder_name,
706+ number = {
707+ // Increases the current test number, if this file already
708+ // exists or it creates a new entry with a test number of 0.
709+ self . visited_tests
710+ . entry( ( folder_name. clone( ) , line) )
711+ . and_modify( |v| * v += 1 )
712+ . or_insert( 0 )
713+ } ,
714+ line = line,
715+ ) ) ;
716+
717+ std:: fs:: create_dir_all ( & path)
718+ . expect ( "Couldn't create directory for doctest executables" ) ;
719+
720+ DirState :: Perm ( path)
721+ } else {
722+ DirState :: Temp (
723+ TempFileBuilder :: new ( )
724+ . prefix ( "rustdoctest" )
725+ . tempdir ( )
726+ . expect ( "rustdoc needs a tempdir" ) ,
727+ )
728+ } ;
729+
708730 debug ! ( "creating test {}: {}" , name, test) ;
709731 self . tests . push ( testing:: TestDescAndFn {
710732 desc : testing:: TestDesc {
@@ -723,7 +745,6 @@ impl Tester for Collector {
723745 let res = run_test (
724746 & test,
725747 & cratename,
726- & filename,
727748 line,
728749 options,
729750 config. should_panic ,
@@ -736,6 +757,8 @@ impl Tester for Collector {
736757 config. error_codes ,
737758 & opts,
738759 edition,
760+ outdir,
761+ path,
739762 ) ;
740763
741764 if let Err ( err) = res {
0 commit comments