Skip to content

Commit 5e3c7a4

Browse files
committed
Verify that versions in the changelog match the lint definitions
1 parent 743405d commit 5e3c7a4

File tree

7 files changed

+107
-14
lines changed

7 files changed

+107
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,8 +1428,6 @@ Released 2023-03-09
14281428

14291429
* [`permissions_set_readonly_false`]
14301430
[#10063](https://github.com/rust-lang/rust-clippy/pull/10063)
1431-
* [`almost_complete_range`]
1432-
[#10043](https://github.com/rust-lang/rust-clippy/pull/10043)
14331431
* [`size_of_ref`]
14341432
[#10098](https://github.com/rust-lang/rust-clippy/pull/10098)
14351433
* [`semicolon_outside_block`]
@@ -1449,6 +1447,8 @@ Released 2023-03-09
14491447
[#10115](https://github.com/rust-lang/rust-clippy/pull/10115)
14501448
* Renamed `derive_hash_xor_eq` to [`derived_hash_with_manual_eq`]
14511449
[#10184](https://github.com/rust-lang/rust-clippy/pull/10184)
1450+
* Renamed `almost_complete_letter_range` to [`almost_complete_range`] and extended it to check digits
1451+
[#10043](https://github.com/rust-lang/rust-clippy/pull/10043)
14521452

14531453
### Enhancements
14541454

book/src/development/infrastructure/changelog_update.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ somewhat coherent.
6969

7070
The sections order should roughly be:
7171

72+
<!-- If this format changes please also update tests/lint-definitions.rs -->
7273
```
7374
### New Lints
7475
* Added [`LINT`] to `GROUP`
@@ -99,16 +100,14 @@ that label in the changelog. If you can, remove the `beta-accepted` labels
99100
### 5. Update `clippy::version` attributes
100101

101102
Next, make sure to check that the `#[clippy::version]` attributes for the added
102-
lints contain the correct version.
103-
In order to find lints that need a version update, go through the lints in the
104-
"New Lints" section and run the following command for each lint name:
103+
lints contain the correct version:
105104

106105
```
107-
grep -rB1 "pub $LINT_NAME" .
106+
cargo test --test lint-definitions
108107
```
109108

110-
The version shown should match the version of the release the changelog is
111-
written for. If not, update the version to the changelog version.
109+
If a lint definition's version doesn't match the changelog you will see an error
110+
pointing to the definition that needs changing.
112111

113112
[changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
114113
[forge]: https://forge.rust-lang.org/

clippy_lints/src/almost_complete_range.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ declare_clippy_lint! {
2323
/// ```no_run
2424
/// let _ = 'a'..='z';
2525
/// ```
26-
#[clippy::version = "1.68.0"]
26+
#[clippy::version = "1.63.0"]
2727
pub ALMOST_COMPLETE_RANGE,
2828
suspicious,
2929
"almost complete range"

clippy_lints/src/unicode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![expect(clippy::invisible_characters, clippy::non_ascii_literal)]
2+
13
use clippy_utils::diagnostics::span_lint_and_then;
24
use clippy_utils::is_lint_allowed;
35
use clippy_utils::macros::span_is_local;

declare_clippy_lint/src/lib.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ pub struct LintInfo {
104104
pub lint: &'static Lint,
105105
pub category: LintCategory,
106106
pub explanation: &'static str,
107-
/// e.g. `clippy_lints/src/absolute_paths.rs#43`
108-
pub location: &'static str,
107+
/// e.g. `clippy_lints/src/absolute_paths.rs`
108+
pub file: &'static str,
109+
/// The line number in `file`
110+
pub line: u32,
109111
pub version: &'static str,
110112
}
111113

@@ -116,6 +118,16 @@ impl LintInfo {
116118
pub fn name_lower(&self) -> String {
117119
self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase()
118120
}
121+
122+
#[must_use]
123+
pub fn location_terminal(&self) -> String {
124+
format!("{}:{}", self.file, self.line)
125+
}
126+
127+
#[must_use]
128+
pub fn location_github(&self) -> String {
129+
format!("{}#L{}", self.file, self.line)
130+
}
119131
}
120132

121133
#[macro_export]
@@ -143,7 +155,8 @@ macro_rules! declare_clippy_lint_inner {
143155
lint: $lint_name,
144156
category: $crate::LintCategory::$category,
145157
explanation: concat!($($docs,"\n",)*),
146-
location: concat!(file!(), "#L", line!()),
158+
file: file!(),
159+
line: line!(),
147160
version: $version,
148161
};
149162
};

tests/compile-test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ impl Flag for DiagnosticCollector {
562562
#[derive(Debug)]
563563
struct LintMetadata {
564564
id: String,
565-
id_location: Option<&'static str>,
565+
id_location: Option<String>,
566566
group: &'static str,
567567
level: &'static str,
568568
docs: String,
@@ -601,7 +601,7 @@ impl LintMetadata {
601601
}
602602
Self {
603603
id: name,
604-
id_location: Some(lint.location),
604+
id_location: Some(lint.location_github()),
605605
group: lint.category.name(),
606606
level: lint.lint.default_level.as_str(),
607607
docs,

tests/lint-definitions.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#![feature(rustc_private)]
2+
3+
use std::collections::HashMap;
4+
use std::fs;
5+
6+
use clippy_lints::declared_lints::LINTS;
7+
use clippy_lints::deprecated_lints::RENAMED;
8+
use pulldown_cmark::{Event, HeadingLevel, Parser, Tag, TagEnd};
9+
use test_utils::IS_RUSTC_TEST_SUITE;
10+
11+
mod test_utils;
12+
13+
#[test]
14+
fn versions_match_changelog() {
15+
if IS_RUSTC_TEST_SUITE {
16+
return;
17+
}
18+
19+
let changelog = fs::read_to_string("CHANGELOG.md").unwrap();
20+
21+
let mut versions_by_name: HashMap<_, _> = LINTS.iter().map(|&lint| (lint.name_lower(), lint)).collect();
22+
23+
for (from, to) in RENAMED {
24+
let from = from.strip_prefix("clippy::").unwrap();
25+
if let Some(to) = to.strip_prefix("clippy::") {
26+
versions_by_name.insert(from.to_owned(), versions_by_name[to]);
27+
}
28+
}
29+
30+
let mut heading = None;
31+
let mut changelog_version = None;
32+
let mut in_new_lints = true;
33+
let mut checked = 0;
34+
35+
for event in Parser::new(&changelog) {
36+
match event {
37+
Event::Start(Tag::Heading { level, .. }) => {
38+
in_new_lints = false;
39+
heading = Some(level);
40+
},
41+
Event::End(TagEnd::Heading(_)) => heading = None,
42+
Event::Text(text) => match heading {
43+
Some(HeadingLevel::H2) => {
44+
if let Some(v) = text.strip_prefix("Rust ") {
45+
changelog_version = Some(v.to_owned());
46+
}
47+
},
48+
Some(HeadingLevel::H3) => {
49+
in_new_lints = text.eq_ignore_ascii_case("new lints");
50+
},
51+
_ => {},
52+
},
53+
Event::Start(Tag::Link { id, .. }) if in_new_lints => {
54+
if let Some(name) = id.strip_prefix('`')
55+
&& let Some(name) = name.strip_suffix('`')
56+
&& let Some(&lint) = versions_by_name.get(name)
57+
{
58+
let lint_version = lint.version.strip_suffix(".0").unwrap();
59+
let changelog_version = changelog_version.as_deref().unwrap();
60+
assert_eq!(
61+
lint_version,
62+
changelog_version,
63+
"{name} has version {lint_version} but appears in the changelog for {changelog_version}\n\
64+
\n\
65+
update {} to `#[clippy::version = \"{changelog_version}.0\"]`",
66+
lint.location_terminal(),
67+
);
68+
checked += 1;
69+
}
70+
},
71+
_ => {},
72+
}
73+
}
74+
75+
assert!(
76+
checked > 400,
77+
"only checked {checked} versions, did the changelog format change?"
78+
);
79+
}

0 commit comments

Comments
 (0)