Skip to content

Commit fcfab5f

Browse files
committed
clippy_dev: Move all parsing within a parse context.
1 parent 00f68d5 commit fcfab5f

File tree

7 files changed

+151
-115
lines changed

7 files changed

+151
-115
lines changed

clippy_dev/src/deprecate_lint.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::parse::{DeprecatedLint, Lint, find_lint_decls, read_deprecated_lints};
1+
use crate::parse::{DeprecatedLint, Lint, ParseCx};
22
use crate::update_lints::generate_lint_files;
33
use crate::utils::{UpdateMode, Version};
44
use std::ffi::OsStr;
@@ -14,9 +14,9 @@ use std::{fs, io};
1414
/// # Panics
1515
///
1616
/// If a file path could not read from or written to
17-
pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
18-
let mut lints = find_lint_decls();
19-
let (mut deprecated_lints, renamed_lints) = read_deprecated_lints();
17+
pub fn deprecate<'cx>(cx: ParseCx<'cx>, clippy_version: Version, name: &'cx str, reason: &'cx str) {
18+
let mut lints = cx.find_lint_decls();
19+
let (mut deprecated_lints, renamed_lints) = cx.read_deprecated_lints();
2020

2121
let Some(lint) = lints.iter().find(|l| l.name == name) else {
2222
eprintln!("error: failed to find lint `{name}`");

clippy_dev/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ pub mod setup;
3434
pub mod sync;
3535
pub mod update_lints;
3636

37+
mod parse;
3738
mod utils;
38-
pub use utils::{ClippyInfo, UpdateMode};
3939

40-
mod parse;
40+
pub use self::parse::{ParseCx, new_parse_cx};
41+
pub use self::utils::{ClippyInfo, UpdateMode};

clippy_dev/src/main.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use clap::{Args, Parser, Subcommand};
66
use clippy_dev::{
7-
ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync,
8-
update_lints,
7+
ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, new_parse_cx, release, rename_lint, serve,
8+
setup, sync, update_lints,
99
};
1010
use std::env;
1111

@@ -27,15 +27,15 @@ fn main() {
2727
allow_no_vcs,
2828
} => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
2929
DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)),
30-
DevCommand::UpdateLints { check } => update_lints::update(UpdateMode::from_check(check)),
30+
DevCommand::UpdateLints { check } => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::from_check(check))),
3131
DevCommand::NewLint {
3232
pass,
3333
name,
3434
category,
3535
r#type,
3636
msrv,
3737
} => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) {
38-
Ok(()) => update_lints::update(UpdateMode::Change),
38+
Ok(()) => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::Change)),
3939
Err(e) => eprintln!("Unable to create lint: {e}"),
4040
},
4141
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
@@ -78,13 +78,18 @@ fn main() {
7878
old_name,
7979
new_name,
8080
uplift,
81-
} => rename_lint::rename(
82-
clippy.version,
83-
&old_name,
84-
new_name.as_ref().unwrap_or(&old_name),
85-
uplift,
86-
),
87-
DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason),
81+
} => new_parse_cx(|cx| {
82+
rename_lint::rename(
83+
cx,
84+
clippy.version,
85+
&old_name,
86+
new_name.as_ref().unwrap_or(&old_name),
87+
uplift,
88+
);
89+
}),
90+
DevCommand::Deprecate { name, reason } => {
91+
new_parse_cx(|cx| deprecate_lint::deprecate(cx, clippy.version, &name, &reason));
92+
},
8893
DevCommand::Sync(SyncCommand { subcommand }) => match subcommand {
8994
SyncSubcommand::UpdateNightly => sync::update_nightly(),
9095
},

clippy_dev/src/parse.rs

Lines changed: 100 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
pub mod cursor;
22

33
use self::cursor::{Capture, Cursor};
4-
use crate::utils::{ErrAction, File, expect_action};
4+
use crate::utils::{ErrAction, File, Scoped, expect_action};
55
use core::range::Range;
66
use std::fs;
77
use std::path::{Path, PathBuf};
88
use walkdir::{DirEntry, WalkDir};
99

10+
pub struct ParseCxImpl;
11+
pub type ParseCx<'cx> = &'cx mut ParseCxImpl;
12+
13+
/// Calls the given function inside a newly created parsing context.
14+
pub fn new_parse_cx<'env, T>(f: impl for<'cx> FnOnce(&'cx mut Scoped<'cx, 'env, ParseCxImpl>) -> T) -> T {
15+
f(&mut Scoped::new(ParseCxImpl))
16+
}
17+
1018
pub struct Lint {
1119
pub name: String,
1220
pub group: String,
@@ -27,33 +35,101 @@ pub struct RenamedLint {
2735
pub version: String,
2836
}
2937

30-
/// Finds all lint declarations (`declare_clippy_lint!`)
31-
#[must_use]
32-
pub fn find_lint_decls() -> Vec<Lint> {
33-
let mut lints = Vec::with_capacity(1000);
34-
let mut contents = String::new();
35-
for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") {
36-
let e = expect_action(e, ErrAction::Read, ".");
37-
if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() {
38-
continue;
38+
impl ParseCxImpl {
39+
/// Finds all lint declarations (`declare_clippy_lint!`)
40+
#[must_use]
41+
pub fn find_lint_decls(&mut self) -> Vec<Lint> {
42+
let mut lints = Vec::with_capacity(1000);
43+
let mut contents = String::new();
44+
for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") {
45+
let e = expect_action(e, ErrAction::Read, ".");
46+
if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() {
47+
continue;
48+
}
49+
let Ok(mut name) = e.file_name().into_string() else {
50+
continue;
51+
};
52+
if name.starts_with("clippy_lints") && name != "clippy_lints_internal" {
53+
name.push_str("/src");
54+
for (file, module) in read_src_with_module(name.as_ref()) {
55+
parse_clippy_lint_decls(
56+
file.path(),
57+
File::open_read_to_cleared_string(file.path(), &mut contents),
58+
&module,
59+
&mut lints,
60+
);
61+
}
62+
}
3963
}
40-
let Ok(mut name) = e.file_name().into_string() else {
41-
continue;
42-
};
43-
if name.starts_with("clippy_lints") && name != "clippy_lints_internal" {
44-
name.push_str("/src");
45-
for (file, module) in read_src_with_module(name.as_ref()) {
46-
parse_clippy_lint_decls(
47-
file.path(),
48-
File::open_read_to_cleared_string(file.path(), &mut contents),
49-
&module,
50-
&mut lints,
51-
);
64+
lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
65+
lints
66+
}
67+
68+
#[must_use]
69+
pub fn read_deprecated_lints(&mut self) -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
70+
#[allow(clippy::enum_glob_use)]
71+
use cursor::Pat::*;
72+
#[rustfmt::skip]
73+
static DECL_TOKENS: &[cursor::Pat<'_>] = &[
74+
// #[clippy::version = "version"]
75+
Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket,
76+
// ("first", "second"),
77+
OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma,
78+
];
79+
#[rustfmt::skip]
80+
static DEPRECATED_TOKENS: &[cursor::Pat<'_>] = &[
81+
// !{ DEPRECATED(DEPRECATED_VERSION) = [
82+
Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket,
83+
];
84+
#[rustfmt::skip]
85+
static RENAMED_TOKENS: &[cursor::Pat<'_>] = &[
86+
// !{ RENAMED(RENAMED_VERSION) = [
87+
Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket,
88+
];
89+
90+
let path = "clippy_lints/src/deprecated_lints.rs";
91+
let mut deprecated = Vec::with_capacity(30);
92+
let mut renamed = Vec::with_capacity(80);
93+
let mut contents = String::new();
94+
File::open_read_to_cleared_string(path, &mut contents);
95+
96+
let mut cursor = Cursor::new(&contents);
97+
let mut captures = [Capture::EMPTY; 3];
98+
99+
// First instance is the macro definition.
100+
assert!(
101+
cursor.find_ident("declare_with_version").is_some(),
102+
"error reading deprecated lints"
103+
);
104+
105+
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(DEPRECATED_TOKENS, &mut []) {
106+
while cursor.match_all(DECL_TOKENS, &mut captures) {
107+
deprecated.push(DeprecatedLint {
108+
name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),
109+
reason: parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])),
110+
version: parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])),
111+
});
52112
}
113+
} else {
114+
panic!("error reading deprecated lints");
53115
}
116+
117+
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(RENAMED_TOKENS, &mut []) {
118+
while cursor.match_all(DECL_TOKENS, &mut captures) {
119+
renamed.push(RenamedLint {
120+
old_name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),
121+
new_name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])),
122+
version: parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])),
123+
});
124+
}
125+
} else {
126+
panic!("error reading renamed lints");
127+
}
128+
129+
deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
130+
renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name));
131+
(deprecated, renamed)
54132
}
55-
lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
56-
lints
57133
}
58134

59135
/// Reads the source files from the given root directory
@@ -116,72 +192,6 @@ fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mu
116192
}
117193
}
118194

119-
#[must_use]
120-
pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
121-
#[allow(clippy::enum_glob_use)]
122-
use cursor::Pat::*;
123-
#[rustfmt::skip]
124-
static DECL_TOKENS: &[cursor::Pat<'_>] = &[
125-
// #[clippy::version = "version"]
126-
Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket,
127-
// ("first", "second"),
128-
OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma,
129-
];
130-
#[rustfmt::skip]
131-
static DEPRECATED_TOKENS: &[cursor::Pat<'_>] = &[
132-
// !{ DEPRECATED(DEPRECATED_VERSION) = [
133-
Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket,
134-
];
135-
#[rustfmt::skip]
136-
static RENAMED_TOKENS: &[cursor::Pat<'_>] = &[
137-
// !{ RENAMED(RENAMED_VERSION) = [
138-
Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket,
139-
];
140-
141-
let path = "clippy_lints/src/deprecated_lints.rs";
142-
let mut deprecated = Vec::with_capacity(30);
143-
let mut renamed = Vec::with_capacity(80);
144-
let mut contents = String::new();
145-
File::open_read_to_cleared_string(path, &mut contents);
146-
147-
let mut cursor = Cursor::new(&contents);
148-
let mut captures = [Capture::EMPTY; 3];
149-
150-
// First instance is the macro definition.
151-
assert!(
152-
cursor.find_ident("declare_with_version").is_some(),
153-
"error reading deprecated lints"
154-
);
155-
156-
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(DEPRECATED_TOKENS, &mut []) {
157-
while cursor.match_all(DECL_TOKENS, &mut captures) {
158-
deprecated.push(DeprecatedLint {
159-
name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),
160-
reason: parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])),
161-
version: parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])),
162-
});
163-
}
164-
} else {
165-
panic!("error reading deprecated lints");
166-
}
167-
168-
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(RENAMED_TOKENS, &mut []) {
169-
while cursor.match_all(DECL_TOKENS, &mut captures) {
170-
renamed.push(RenamedLint {
171-
old_name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),
172-
new_name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])),
173-
version: parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])),
174-
});
175-
}
176-
} else {
177-
panic!("error reading renamed lints");
178-
}
179-
180-
deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
181-
renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name));
182-
(deprecated, renamed)
183-
}
184-
185195
/// Removes the line splices and surrounding quotes from a string literal
186196
fn parse_str_lit(s: &str) -> String {
187197
let (s, is_raw) = if let Some(s) = s.strip_prefix("r") {

clippy_dev/src/rename_lint.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::parse::cursor::{self, Capture, Cursor};
2-
use crate::parse::{RenamedLint, find_lint_decls, read_deprecated_lints};
2+
use crate::parse::{ParseCx, RenamedLint};
33
use crate::update_lints::generate_lint_files;
44
use crate::utils::{
55
ErrAction, FileUpdater, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists,
@@ -26,10 +26,10 @@ use std::path::Path;
2626
/// * If `old_name` doesn't name an existing lint.
2727
/// * If `old_name` names a deprecated or renamed lint.
2828
#[expect(clippy::too_many_lines)]
29-
pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) {
29+
pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str, new_name: &'cx str, uplift: bool) {
3030
let mut updater = FileUpdater::default();
31-
let mut lints = find_lint_decls();
32-
let (deprecated_lints, mut renamed_lints) = read_deprecated_lints();
31+
let mut lints = cx.find_lint_decls();
32+
let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints();
3333

3434
let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else {
3535
panic!("could not find lint `{old_name}`");

clippy_dev/src/update_lints.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::parse::cursor::Cursor;
2-
use crate::parse::{DeprecatedLint, Lint, RenamedLint, find_lint_decls, read_deprecated_lints};
2+
use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint};
33
use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn};
44
use itertools::Itertools;
55
use std::collections::HashSet;
@@ -21,9 +21,9 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht
2121
/// # Panics
2222
///
2323
/// Panics if a file path could not read from or then written to
24-
pub fn update(update_mode: UpdateMode) {
25-
let lints = find_lint_decls();
26-
let (deprecated, renamed) = read_deprecated_lints();
24+
pub fn update(cx: ParseCx<'_>, update_mode: UpdateMode) {
25+
let lints = cx.find_lint_decls();
26+
let (deprecated, renamed) = cx.read_deprecated_lints();
2727
generate_lint_files(update_mode, &lints, &deprecated, &renamed);
2828
}
2929

clippy_dev/src/utils.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use core::fmt::{self, Display};
2+
use core::marker::PhantomData;
23
use core::num::NonZero;
4+
use core::ops::{Deref, DerefMut};
35
use core::range::Range;
46
use core::str::FromStr;
57
use std::ffi::OsStr;
@@ -10,6 +12,24 @@ use std::process::{self, Command, Stdio};
1012
use std::{env, thread};
1113
use walkdir::WalkDir;
1214

15+
pub struct Scoped<'inner, 'outer: 'inner, T>(T, PhantomData<&'inner mut T>, PhantomData<&'outer mut ()>);
16+
impl<T> Scoped<'_, '_, T> {
17+
pub fn new(value: T) -> Self {
18+
Self(value, PhantomData, PhantomData)
19+
}
20+
}
21+
impl<T> Deref for Scoped<'_, '_, T> {
22+
type Target = T;
23+
fn deref(&self) -> &Self::Target {
24+
&self.0
25+
}
26+
}
27+
impl<T> DerefMut for Scoped<'_, '_, T> {
28+
fn deref_mut(&mut self) -> &mut Self::Target {
29+
&mut self.0
30+
}
31+
}
32+
1333
#[derive(Clone, Copy)]
1434
pub enum ErrAction {
1535
Open,

0 commit comments

Comments
 (0)