1 use errors
::Applicability
;
2 use syntax
::parse
::lexer
::{TokenAndSpan, StringReader as Lexer}
;
3 use syntax
::parse
::{ParseSess, token}
;
4 use syntax
::source_map
::FilePathMapping
;
5 use syntax_pos
::FileName
;
8 use crate::core
::DocContext
;
9 use crate::fold
::DocFolder
;
10 use crate::html
::markdown
::{self, RustCodeBlock}
;
11 use crate::passes
::Pass
;
13 pub const CHECK_CODE_BLOCK_SYNTAX
: Pass
=
14 Pass
::early("check-code-block-syntax", check_code_block_syntax
,
15 "validates syntax inside Rust code blocks");
17 pub fn check_code_block_syntax(krate
: clean
::Crate
, cx
: &DocContext
<'_
, '_
, '_
>) -> clean
::Crate
{
18 SyntaxChecker { cx }
.fold_crate(krate
)
21 struct SyntaxChecker
<'a
, 'tcx
: 'a
, 'rcx
: 'a
> {
22 cx
: &'a DocContext
<'a
, 'tcx
, 'rcx
>,
25 impl<'a
, 'tcx
, 'rcx
> SyntaxChecker
<'a
, 'tcx
, 'rcx
> {
26 fn check_rust_syntax(&self, item
: &clean
::Item
, dox
: &str, code_block
: RustCodeBlock
) {
27 let sess
= ParseSess
::new(FilePathMapping
::empty());
28 let source_file
= sess
.source_map().new_source_file(
29 FileName
::Custom(String
::from("doctest")),
30 dox
[code_block
.code
].to_owned(),
33 let errors
= Lexer
::new_or_buffered_errs(&sess
, source_file
, None
).and_then(|mut lexer
| {
34 while let Ok(TokenAndSpan { tok, .. }
) = lexer
.try_next_token() {
35 if tok
== token
::Eof
{
40 let errors
= lexer
.buffer_fatal_errors();
42 if !errors
.is_empty() {
49 if let Err(errors
) = errors
{
50 let mut diag
= if let Some(sp
) =
51 super::source_span_for_markdown_range(self.cx
, &dox
, &code_block
.range
, &item
.attrs
)
56 .struct_span_warn(sp
, "could not parse code block as Rust code");
58 for mut err
in errors
{
59 diag
.note(&format
!("error from rustc: {}", err
.message()));
63 if code_block
.syntax
.is_none() && code_block
.is_fenced
{
64 let sp
= sp
.from_inner_byte_pos(0, 3);
67 "mark blocks that do not contain Rust code as text",
68 String
::from("```text"),
69 Applicability
::MachineApplicable
,
75 // We couldn't calculate the span of the markdown block that had the error, so our
76 // diagnostics are going to be a bit lacking.
77 let mut diag
= self.cx
.sess().struct_span_warn(
78 super::span_of_attrs(&item
.attrs
),
79 "doc comment contains an invalid Rust code block",
82 for mut err
in errors
{
83 // Don't bother reporting the error, because we can't show where it happened.
87 if code_block
.syntax
.is_none() && code_block
.is_fenced
{
88 diag
.help("mark blocks that do not contain Rust code as text: ```text");
99 impl<'a
, 'tcx
, 'rcx
> DocFolder
for SyntaxChecker
<'a
, 'tcx
, 'rcx
> {
100 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
101 if let Some(dox
) = &item
.attrs
.collapsed_doc_value() {
102 for code_block
in markdown
::rust_code_blocks(&dox
) {
103 self.check_rust_syntax(&item
, &dox
, code_block
);
107 self.fold_item_recur(item
)