1
- use rustc_ast:: token;
2
1
use rustc_data_structures:: sync:: { Lock , Lrc } ;
3
2
use rustc_errors:: { emitter:: Emitter , Applicability , Diagnostic , Handler } ;
4
- use rustc_parse:: lexer :: StringReader as Lexer ;
3
+ use rustc_parse:: parse_stream_from_source_str ;
5
4
use rustc_session:: parse:: ParseSess ;
6
5
use rustc_span:: source_map:: { FilePathMapping , SourceMap } ;
7
6
use rustc_span:: { FileName , InnerSpan } ;
@@ -28,49 +27,34 @@ struct SyntaxChecker<'a, 'tcx> {
28
27
29
28
impl < ' a , ' tcx > SyntaxChecker < ' a , ' tcx > {
30
29
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) } ;
34
32
35
33
let sm = Lrc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
36
34
let handler = Handler :: with_emitter ( false , None , Box :: new ( emitter) ) ;
35
+ let source = dox[ code_block. code ] . to_owned ( ) ;
37
36
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
- }
56
37
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 ( )
64
46
} )
65
- . unwrap_or ( Some ( CodeBlockInvalid :: SyntaxError ) ) ;
47
+ . unwrap_or ( false ) ;
48
+ let buffer = buffer. borrow ( ) ;
66
49
67
- if let Some ( code_block_invalid ) = validation_status {
50
+ if buffer . has_errors || is_empty {
68
51
let mut diag = if let Some ( sp) =
69
52
super :: source_span_for_markdown_range ( self . cx , & dox, & code_block. range , & item. attrs )
70
53
{
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"
74
58
} ;
75
59
76
60
let mut diag = self . cx . sess ( ) . struct_span_warn ( sp, warning_message) ;
@@ -102,7 +86,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
102
86
} ;
103
87
104
88
// 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 ( ) {
106
90
diag. note ( & message) ;
107
91
}
108
92
@@ -125,21 +109,26 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
125
109
}
126
110
}
127
111
112
+ #[ derive( Default ) ]
113
+ struct Buffer {
114
+ messages : Vec < String > ,
115
+ has_errors : bool ,
116
+ }
117
+
128
118
struct BufferEmitter {
129
- messages : Lrc < Lock < Vec < String > > > ,
119
+ buffer : Lrc < Lock < Buffer > > ,
130
120
}
131
121
132
122
impl Emitter for BufferEmitter {
133
123
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
+ }
135
129
}
136
130
137
131
fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
138
132
None
139
133
}
140
134
}
141
-
142
- enum CodeBlockInvalid {
143
- SyntaxError ,
144
- Empty ,
145
- }
0 commit comments