about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs75
1 files changed, 32 insertions, 43 deletions
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index d1f2c12ccd6..beb1f13ca6f 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,7 +1,6 @@
-use rustc_ast::token;
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
-use rustc_parse::lexer::StringReader as Lexer;
+use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{FileName, InnerSpan};
@@ -28,49 +27,34 @@ struct SyntaxChecker<'a, 'tcx> {
 
 impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
     fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
-        let buffered_messages = Lrc::new(Lock::new(vec![]));
-
-        let emitter = BufferEmitter { messages: Lrc::clone(&buffered_messages) };
+        let buffer = Lrc::new(Lock::new(Buffer::default()));
+        let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) };
 
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let handler = Handler::with_emitter(false, None, Box::new(emitter));
+        let source = dox[code_block.code].to_owned();
         let sess = ParseSess::with_span_handler(handler, sm);
-        let source_file = sess.source_map().new_source_file(
-            FileName::Custom(String::from("doctest")),
-            dox[code_block.code].to_owned(),
-        );
-
-        let validation_status = rustc_driver::catch_fatal_errors(|| {
-            let mut has_syntax_errors = false;
-            let mut only_whitespace = true;
-            // even if there is a syntax error, we need to run the lexer over the whole file
-            let mut lexer = Lexer::new(&sess, source_file, None);
-            loop {
-                match lexer.next_token().kind {
-                    token::Eof => break,
-                    token::Whitespace => (),
-                    token::Unknown(..) => has_syntax_errors = true,
-                    _ => only_whitespace = false,
-                }
-            }
 
-            if has_syntax_errors {
-                Some(CodeBlockInvalid::SyntaxError)
-            } else if only_whitespace {
-                Some(CodeBlockInvalid::Empty)
-            } else {
-                None
-            }
+        let is_empty = rustc_driver::catch_fatal_errors(|| {
+            parse_stream_from_source_str(
+                FileName::Custom(String::from("doctest")),
+                source,
+                &sess,
+                None,
+            )
+            .is_empty()
         })
-        .unwrap_or(Some(CodeBlockInvalid::SyntaxError));
+        .unwrap_or(false);
+        let buffer = buffer.borrow();
 
-        if let Some(code_block_invalid) = validation_status {
+        if buffer.has_errors || is_empty {
             let mut diag = if let Some(sp) =
                 super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs)
             {
-                let warning_message = match code_block_invalid {
-                    CodeBlockInvalid::SyntaxError => "could not parse code block as Rust code",
-                    CodeBlockInvalid::Empty => "Rust code block is empty",
+                let warning_message = if buffer.has_errors {
+                    "could not parse code block as Rust code"
+                } else {
+                    "Rust code block is empty"
                 };
 
                 let mut diag = self.cx.sess().struct_span_warn(sp, warning_message);
@@ -102,7 +86,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
             };
 
             // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
-            for message in buffered_messages.borrow().iter() {
+            for message in buffer.messages.iter() {
                 diag.note(&message);
             }
 
@@ -125,21 +109,26 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
     }
 }
 
+#[derive(Default)]
+struct Buffer {
+    messages: Vec<String>,
+    has_errors: bool,
+}
+
 struct BufferEmitter {
-    messages: Lrc<Lock<Vec<String>>>,
+    buffer: Lrc<Lock<Buffer>>,
 }
 
 impl Emitter for BufferEmitter {
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
-        self.messages.borrow_mut().push(format!("error from rustc: {}", diag.message[0].0));
+        let mut buffer = self.buffer.borrow_mut();
+        buffer.messages.push(format!("error from rustc: {}", diag.message[0].0));
+        if diag.is_error() {
+            buffer.has_errors = true;
+        }
     }
 
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
         None
     }
 }
-
-enum CodeBlockInvalid {
-    SyntaxError,
-    Empty,
-}