1- use rustc_ast:: token;
21use rustc_data_structures:: sync:: { Lock , Lrc } ;
32use rustc_errors:: { emitter:: Emitter , Applicability , Diagnostic , Handler } ;
4- use rustc_parse:: lexer :: StringReader as Lexer ;
3+ use rustc_parse:: parse_stream_from_source_str ;
54use rustc_session:: parse:: ParseSess ;
65use rustc_span:: source_map:: { FilePathMapping , SourceMap } ;
76use rustc_span:: { FileName , InnerSpan } ;
@@ -28,49 +27,34 @@ struct SyntaxChecker<'a, 'tcx> {
2827
2928impl < ' a , ' tcx > SyntaxChecker < ' a , ' tcx > {
3029 fn check_rust_syntax ( & self , item : & clean:: Item , dox : & str , code_block : RustCodeBlock ) {
31- let buffered_messages = Lrc :: new ( Lock :: new ( vec ! [ ] ) ) ;
32-
33- let emitter = BufferEmitter { messages : Lrc :: clone ( & buffered_messages) } ;
30+ let buffer = Lrc :: new ( Lock :: new ( Buffer :: default ( ) ) ) ;
31+ let emitter = BufferEmitter { buffer : Lrc :: clone ( & buffer) } ;
3432
3533 let sm = Lrc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
3634 let handler = Handler :: with_emitter ( false , None , Box :: new ( emitter) ) ;
35+ let source = dox[ code_block. code ] . to_owned ( ) ;
3736 let sess = ParseSess :: with_span_handler ( handler, sm) ;
38- let source_file = sess. source_map ( ) . new_source_file (
39- FileName :: Custom ( String :: from ( "doctest" ) ) ,
40- dox[ code_block. code ] . to_owned ( ) ,
41- ) ;
42-
43- let validation_status = rustc_driver:: catch_fatal_errors ( || {
44- let mut has_syntax_errors = false ;
45- let mut only_whitespace = true ;
46- // even if there is a syntax error, we need to run the lexer over the whole file
47- let mut lexer = Lexer :: new ( & sess, source_file, None ) ;
48- loop {
49- match lexer. next_token ( ) . kind {
50- token:: Eof => break ,
51- token:: Whitespace => ( ) ,
52- token:: Unknown ( ..) => has_syntax_errors = true ,
53- _ => only_whitespace = false ,
54- }
55- }
5637
57- if has_syntax_errors {
58- Some ( CodeBlockInvalid :: SyntaxError )
59- } else if only_whitespace {
60- Some ( CodeBlockInvalid :: Empty )
61- } else {
62- None
63- }
38+ let is_empty = rustc_driver:: catch_fatal_errors ( || {
39+ parse_stream_from_source_str (
40+ FileName :: Custom ( String :: from ( "doctest" ) ) ,
41+ source,
42+ & sess,
43+ None ,
44+ )
45+ . is_empty ( )
6446 } )
65- . unwrap_or ( Some ( CodeBlockInvalid :: SyntaxError ) ) ;
47+ . unwrap_or ( false ) ;
48+ let buffer = buffer. borrow ( ) ;
6649
67- if let Some ( code_block_invalid ) = validation_status {
50+ if buffer . has_errors || is_empty {
6851 let mut diag = if let Some ( sp) =
6952 super :: source_span_for_markdown_range ( self . cx , & dox, & code_block. range , & item. attrs )
7053 {
71- let warning_message = match code_block_invalid {
72- CodeBlockInvalid :: SyntaxError => "could not parse code block as Rust code" ,
73- CodeBlockInvalid :: Empty => "Rust code block is empty" ,
54+ let warning_message = if buffer. has_errors {
55+ "could not parse code block as Rust code"
56+ } else {
57+ "Rust code block is empty"
7458 } ;
7559
7660 let mut diag = self . cx . sess ( ) . struct_span_warn ( sp, warning_message) ;
@@ -102,7 +86,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
10286 } ;
10387
10488 // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
105- for message in buffered_messages . borrow ( ) . iter ( ) {
89+ for message in buffer . messages . iter ( ) {
10690 diag. note ( & message) ;
10791 }
10892
@@ -125,21 +109,26 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
125109 }
126110}
127111
112+ #[ derive( Default ) ]
113+ struct Buffer {
114+ messages : Vec < String > ,
115+ has_errors : bool ,
116+ }
117+
128118struct BufferEmitter {
129- messages : Lrc < Lock < Vec < String > > > ,
119+ buffer : Lrc < Lock < Buffer > > ,
130120}
131121
132122impl Emitter for BufferEmitter {
133123 fn emit_diagnostic ( & mut self , diag : & Diagnostic ) {
134- self . messages . borrow_mut ( ) . push ( format ! ( "error from rustc: {}" , diag. message[ 0 ] . 0 ) ) ;
124+ let mut buffer = self . buffer . borrow_mut ( ) ;
125+ buffer. messages . push ( format ! ( "error from rustc: {}" , diag. message[ 0 ] . 0 ) ) ;
126+ if diag. is_error ( ) {
127+ buffer. has_errors = true ;
128+ }
135129 }
136130
137131 fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
138132 None
139133 }
140134}
141-
142- enum CodeBlockInvalid {
143- SyntaxError ,
144- Empty ,
145- }
0 commit comments