Skip to content

Commit a6c3c1b

Browse files
borsehuss
authored andcommitted
Auto merge of rust-lang#89277 - jyn514:codeblock-edition, r=GuillaumeGomez
Use the correct edition for syntax highlighting doctests Previously it would unconditionally use edition 2015, which was incorrect. Helps with rust-lang#89135 in that you can now override the doctest to be 2018 edition instead of being forced to fix the error. This doesn't resolve any of the deeper problems that rustdoc disagrees with most rust users on what a code block is. cc `@Mark-Simulacrum`
1 parent d0a8033 commit a6c3c1b

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

Diff for: src/librustdoc/html/markdown.rs

+8-15
Original file line numberDiff line numberDiff line change
@@ -1266,8 +1266,7 @@ crate struct RustCodeBlock {
12661266
/// The range in the markdown that the code within the code block occupies.
12671267
crate code: Range<usize>,
12681268
crate is_fenced: bool,
1269-
crate syntax: Option<String>,
1270-
crate is_ignore: bool,
1269+
crate lang_string: LangString,
12711270
}
12721271

12731272
/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
@@ -1283,7 +1282,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
12831282

12841283
while let Some((event, offset)) = p.next() {
12851284
if let Event::Start(Tag::CodeBlock(syntax)) = event {
1286-
let (syntax, code_start, code_end, range, is_fenced, is_ignore) = match syntax {
1285+
let (lang_string, code_start, code_end, range, is_fenced) = match syntax {
12871286
CodeBlockKind::Fenced(syntax) => {
12881287
let syntax = syntax.as_ref();
12891288
let lang_string = if syntax.is_empty() {
@@ -1294,8 +1293,6 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
12941293
if !lang_string.rust {
12951294
continue;
12961295
}
1297-
let is_ignore = lang_string.ignore != Ignore::None;
1298-
let syntax = if syntax.is_empty() { None } else { Some(syntax.to_owned()) };
12991296
let (code_start, mut code_end) = match p.next() {
13001297
Some((Event::Text(_), offset)) => (offset.start, offset.end),
13011298
Some((_, sub_offset)) => {
@@ -1304,8 +1301,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
13041301
is_fenced: true,
13051302
range: offset,
13061303
code,
1307-
syntax,
1308-
is_ignore,
1304+
lang_string,
13091305
});
13101306
continue;
13111307
}
@@ -1315,31 +1311,29 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
13151311
is_fenced: true,
13161312
range: offset,
13171313
code,
1318-
syntax,
1319-
is_ignore,
1314+
lang_string,
13201315
});
13211316
continue;
13221317
}
13231318
};
13241319
while let Some((Event::Text(_), offset)) = p.next() {
13251320
code_end = offset.end;
13261321
}
1327-
(syntax, code_start, code_end, offset, true, is_ignore)
1322+
(lang_string, code_start, code_end, offset, true)
13281323
}
13291324
CodeBlockKind::Indented => {
13301325
// The ending of the offset goes too far sometime so we reduce it by one in
13311326
// these cases.
13321327
if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
13331328
(
1334-
None,
1329+
LangString::default(),
13351330
offset.start,
13361331
offset.end,
13371332
Range { start: offset.start, end: offset.end - 1 },
13381333
false,
1339-
false,
13401334
)
13411335
} else {
1342-
(None, offset.start, offset.end, offset, false, false)
1336+
(LangString::default(), offset.start, offset.end, offset, false)
13431337
}
13441338
}
13451339
};
@@ -1348,8 +1342,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
13481342
is_fenced,
13491343
range,
13501344
code: Range { start: code_start, end: code_end },
1351-
syntax,
1352-
is_ignore,
1345+
lang_string,
13531346
});
13541347
}
13551348
}

Diff for: src/librustdoc/passes/check_code_block_syntax.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_middle::lint::LintDiagnosticBuilder;
44
use rustc_parse::parse_stream_from_source_str;
55
use rustc_session::parse::ParseSess;
66
use rustc_span::source_map::{FilePathMapping, SourceMap};
7-
use rustc_span::{FileName, InnerSpan};
7+
use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMMY_SP};
88

99
use crate::clean;
1010
use crate::core::DocContext;
@@ -36,12 +36,22 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
3636
let source = dox[code_block.code].to_owned();
3737
let sess = ParseSess::with_span_handler(handler, sm);
3838

39+
let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
40+
let expn_data = ExpnData::default(
41+
ExpnKind::AstPass(AstPass::TestHarness),
42+
DUMMY_SP,
43+
edition,
44+
None,
45+
None,
46+
);
47+
let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context());
48+
3949
let is_empty = rustc_driver::catch_fatal_errors(|| {
4050
parse_stream_from_source_str(
4151
FileName::Custom(String::from("doctest")),
4252
source,
4353
&sess,
44-
None,
54+
Some(span),
4555
)
4656
.is_empty()
4757
})
@@ -61,8 +71,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
6171
};
6272

6373
let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
64-
let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
65-
let is_ignore = code_block.is_ignore;
74+
let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
75+
let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
6676

6777
// The span and whether it is precise or not.
6878
let (sp, precise_span) = match super::source_span_for_markdown_range(

Diff for: src/test/rustdoc-ui/doctest-edition.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// edition:2021
2+
3+
#![deny(rustdoc::invalid_rust_codeblocks)]
4+
//~^ NOTE lint level is defined here
5+
6+
// By default, rustdoc should use the edition of the crate.
7+
//! ```
8+
//! foo'b'
9+
//! ```
10+
//~^^^ ERROR could not parse
11+
//~| NOTE prefix `foo` is unknown
12+
13+
// Rustdoc should respect `edition2018` when highlighting syntax.
14+
//! ```edition2018
15+
//! foo'b'
16+
//! ```

Diff for: src/test/rustdoc-ui/doctest-edition.stderr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: could not parse code block as Rust code
2+
--> $DIR/doctest-edition.rs:7:5
3+
|
4+
LL | //! ```
5+
| _____^
6+
LL | | //! foo'b'
7+
LL | | //! ```
8+
| |_______^
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/doctest-edition.rs:3:9
12+
|
13+
LL | #![deny(rustdoc::invalid_rust_codeblocks)]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
= note: error from rustc: prefix `foo` is unknown
16+
help: mark blocks that do not contain Rust code as text
17+
|
18+
LL | //! ```text
19+
| ++++
20+
21+
error: aborting due to previous error
22+

0 commit comments

Comments
 (0)