Skip to content

Commit 825bc60

Browse files
authored
Rollup merge of #105848 - lukas-code:backticks, r=GuillaumeGomez,jyn514,notriddle
rustdoc: Add a new lint for broken inline code This patch adds `rustdoc::unescaped_backticks`, a new rustdoc lint that will detect broken inline code nodes. The lint woks by finding stray backticks and with some heuristics tries to guess where the second backtick might be missing. Here is how it looks: ```rust #![warn(rustdoc::unescaped_backticks)] /// `add(a, b) is the same as `add(b, a)`. pub fn add(a: i32, b: i32) -> i32 { a + b } ``` ```text warning: unescaped backtick --> src/lib.rs:3:41 | 3 | /// `add(a, b) is the same as `add(b, a)`. | ^ | help: a previous inline code might be longer than expected | 3 | /// `add(a, b)` is the same as `add(b, a)`. | + help: if you meant to use a literal backtick, escape it | 3 | /// `add(a, b) is the same as `add(b, a)\`. | + ``` If we can't get proper spans, for example if the doc comment comes from a macro expansion, we print the suggestion in help messages instead. Here's a [real-world example](https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/layer/trait.Filter.html#method.max_level_hint): ```text warning: unescaped backtick --> /tracing-subscriber-0.3.17/src/layer/mod.rs:1400:9 | 1400 | / /// Returns an optional hint of the highest [verbosity level][level] that 1401 | | /// this `Filter` will enable. 1402 | | /// 1403 | | /// If this method returns a [`LevelFilter`], it will be used as a hint to ... | 1427 | | /// [`Interest`]: tracing_core::subscriber::Interest 1428 | | /// [rebuild]: tracing_core::callsite::rebuild_interest_cache | |_____________________________________________________________________^ | = help: a previous inline code might be longer than expected change: Therefore, if the `Filter will change the value returned by this to this: Therefore, if the `Filter` will change the value returned by this = help: if you meant to use a literal backtick, escape it change: [`rebuild_interest_cache`][rebuild] is called after the value of the max to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max ``` You can find more examples [here](https://gist.github.com/lukas-code/7678ddf5c608aee97b3a669de80d3465). A limitation of the current implementation is, that it cannot suggest removing misplaced backticks, for example [here](https://docs.rs/tikv-jemalloc-sys/0.5.3+5.3.0-patched/tikv_jemalloc_sys/fn.mallctl.html). The lint is allowed by default ~~and nightly-only~~ for now, ~~but without a feature gate. This is similar to how `rustdoc::invalid_html_tags` and `rustdoc::bare_urls` were handled.~~
2 parents f229949 + 4f15a77 commit 825bc60

File tree

7 files changed

+1775
-5
lines changed

7 files changed

+1775
-5
lines changed

src/doc/rustdoc/src/lints.md

+38
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,41 @@ warning: this URL is not a hyperlink
374374
375375
warning: 2 warnings emitted
376376
```
377+
378+
## `unescaped_backticks`
379+
380+
This lint is **allowed by default**. It detects backticks (\`) that are not escaped.
381+
This usually means broken inline code. For example:
382+
383+
```rust
384+
#![warn(rustdoc::unescaped_backticks)]
385+
386+
/// `add(a, b) is the same as `add(b, a)`.
387+
pub fn add(a: i32, b: i32) -> i32 { a + b }
388+
```
389+
390+
Which will give:
391+
392+
```text
393+
warning: unescaped backtick
394+
--> src/lib.rs:3:41
395+
|
396+
3 | /// `add(a, b) is the same as `add(b, a)`.
397+
| ^
398+
|
399+
note: the lint level is defined here
400+
--> src/lib.rs:1:9
401+
|
402+
1 | #![warn(rustdoc::unescaped_backticks)]
403+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
404+
help: a previous inline code might be longer than expected
405+
|
406+
3 | /// `add(a, b)` is the same as `add(b, a)`.
407+
| +
408+
help: if you meant to use a literal backtick, escape it
409+
|
410+
3 | /// `add(a, b) is the same as `add(b, a)\`.
411+
| +
412+
413+
warning: 1 warning emitted
414+
```

src/librustdoc/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
#![feature(assert_matches)]
88
#![feature(box_patterns)]
99
#![feature(drain_filter)]
10+
#![feature(impl_trait_in_assoc_type)]
11+
#![feature(iter_intersperse)]
12+
#![feature(lazy_cell)]
1013
#![feature(let_chains)]
11-
#![feature(test)]
1214
#![feature(never_type)]
13-
#![feature(lazy_cell)]
14-
#![feature(type_ascription)]
15-
#![feature(iter_intersperse)]
15+
#![feature(round_char_boundary)]
16+
#![feature(test)]
1617
#![feature(type_alias_impl_trait)]
17-
#![feature(impl_trait_in_assoc_type)]
18+
#![feature(type_ascription)]
1819
#![recursion_limit = "256"]
1920
#![warn(rustc::internal)]
2021
#![allow(clippy::collapsible_if, clippy::collapsible_else_if)]

src/librustdoc/lint.rs

+12
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,17 @@ declare_rustdoc_lint! {
174174
"codeblock could not be parsed as valid Rust or is empty"
175175
}
176176

177+
declare_rustdoc_lint! {
178+
/// The `unescaped_backticks` lint detects unescaped backticks (\`), which usually
179+
/// mean broken inline code. This is a `rustdoc` only lint, see the documentation
180+
/// in the [rustdoc book].
181+
///
182+
/// [rustdoc book]: ../../../rustdoc/lints.html#unescaped_backticks
183+
UNESCAPED_BACKTICKS,
184+
Allow,
185+
"detects unescaped backticks in doc comments"
186+
}
187+
177188
pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
178189
vec![
179190
BROKEN_INTRA_DOC_LINKS,
@@ -185,6 +196,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
185196
INVALID_HTML_TAGS,
186197
BARE_URLS,
187198
MISSING_CRATE_LEVEL_DOCS,
199+
UNESCAPED_BACKTICKS,
188200
]
189201
});
190202

src/librustdoc/passes/lint.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
mod bare_urls;
55
mod check_code_block_syntax;
66
mod html_tags;
7+
mod unescaped_backticks;
78

89
use super::Pass;
910
use crate::clean::*;
@@ -27,6 +28,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
2728
bare_urls::visit_item(self.cx, item);
2829
check_code_block_syntax::visit_item(self.cx, item);
2930
html_tags::visit_item(self.cx, item);
31+
unescaped_backticks::visit_item(self.cx, item);
3032

3133
self.visit_item_recur(item)
3234
}

0 commit comments

Comments
 (0)