diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 783b8b2db46a1..761968e9af998 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -689,6 +689,12 @@ crate fn find_testable_code(
.join("\n");
nb_lines += doc[prev_offset..offset.start].lines().count();
+ // If there are characters between the preceding line ending and
+ // this code block, `str::lines` will return an additional line,
+ // which we subtract here.
+ if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with("\n") {
+ nb_lines -= 1;
+ }
let line = tests.get_line() + nb_lines + 1;
tests.add_test(text, block_info, line);
prev_offset = offset.start;
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 1e4bdc2d15199..842f2f9299dce 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -1,4 +1,4 @@
-use super::{plain_text_summary, short_markdown_summary};
+use super::{find_testable_code, plain_text_summary, short_markdown_summary};
use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
@@ -298,3 +298,25 @@ fn test_markdown_html_escape() {
t("Struct<'a, T>", "Struct<’a, T>
\n");
t("Struct
", "Struct<br>
\n");
}
+
+#[test]
+fn test_find_testable_code_line() {
+ fn t(input: &str, expect: &[usize]) {
+ impl crate::doctest::Tester for Vec {
+ fn add_test(&mut self, _test: String, _config: LangString, line: usize) {
+ self.push(line);
+ }
+ }
+ let mut lines = Vec::::new();
+ find_testable_code(input, &mut lines, ErrorCodes::No, false, None);
+ assert_eq!(lines, expect);
+ }
+
+ t("", &[]);
+ t("```rust\n```", &[1]);
+ t(" ```rust\n```", &[1]);
+ t("\n```rust\n```", &[2]);
+ t("\n ```rust\n```", &[2]);
+ t("```rust\n```\n```rust\n```", &[1, 3]);
+ t("```rust\n```\n ```rust\n```", &[1, 3]);
+}