Skip to content

Commit 124de13

Browse files
committed
clippy_dev: Add specialized helpers for finding identifiers to the token cursor.
1 parent a16bb84 commit 124de13

File tree

4 files changed

+63
-28
lines changed

4 files changed

+63
-28
lines changed

clippy_dev/src/new_lint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,8 @@ fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) {
523523
let mut decl_end = None;
524524
let mut cursor = Cursor::new(contents);
525525
let mut captures = [Capture::EMPTY];
526-
while let Some(name) = cursor.find_capture_pat(CaptureIdent) {
527-
match name {
526+
while let Some(name) = cursor.find_any_ident() {
527+
match cursor.get_text(name) {
528528
"declare_clippy_lint" => {
529529
if cursor.match_all(&[Bang, OpenBrace], &mut []) && cursor.find_pat(CloseBrace) {
530530
decl_end = Some(cursor.pos());

clippy_dev/src/parse.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,14 @@ fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mu
103103

104104
let mut cursor = Cursor::new(contents);
105105
let mut captures = [Capture::EMPTY; 2];
106-
while cursor.find_pat(Ident("declare_clippy_lint")) {
107-
let start = cursor.pos() as usize - "declare_clippy_lint".len();
106+
while let Some(start) = cursor.find_ident("declare_clippy_lint") {
108107
if cursor.match_all(DECL_TOKENS, &mut captures) && cursor.find_pat(CloseBrace) {
109108
lints.push(Lint {
110109
name: cursor.get_text(captures[0]).to_lowercase(),
111110
group: cursor.get_text(captures[1]).into(),
112111
module: module.into(),
113112
path: path.into(),
114-
declaration_range: start..cursor.pos() as usize,
113+
declaration_range: start as usize..cursor.pos() as usize,
115114
});
116115
}
117116
}
@@ -150,11 +149,11 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
150149

151150
// First instance is the macro definition.
152151
assert!(
153-
cursor.find_pat(Ident("declare_with_version")),
152+
cursor.find_ident("declare_with_version").is_some(),
154153
"error reading deprecated lints"
155154
);
156155

157-
if cursor.find_pat(Ident("declare_with_version")) && cursor.match_all(DEPRECATED_TOKENS, &mut []) {
156+
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(DEPRECATED_TOKENS, &mut []) {
158157
while cursor.match_all(DECL_TOKENS, &mut captures) {
159158
deprecated.push(DeprecatedLint {
160159
name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),
@@ -166,7 +165,7 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
166165
panic!("error reading deprecated lints");
167166
}
168167

169-
if cursor.find_pat(Ident("declare_with_version")) && cursor.match_all(RENAMED_TOKENS, &mut []) {
168+
if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(RENAMED_TOKENS, &mut []) {
170169
while cursor.match_all(DECL_TOKENS, &mut captures) {
171170
renamed.push(RenamedLint {
172171
old_name: parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])),

clippy_dev/src/parse/cursor.rs

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,47 @@ impl<'txt> Cursor<'txt> {
178178
}
179179
}
180180

181+
/// Consumes all tokens until the specified identifier is found and returns its
182+
/// position. Returns `None` if the identifier could not be found.
183+
///
184+
/// The cursor will be positioned immediately after the identifier, or at the end if
185+
/// it is not.
186+
pub fn find_ident(&mut self, ident: &str) -> Option<u32> {
187+
loop {
188+
match self.next_token.kind {
189+
TokenKind::Ident if self.peek_text() == ident => {
190+
let pos = self.pos;
191+
self.step();
192+
return Some(pos);
193+
},
194+
TokenKind::Eof => return None,
195+
_ => self.step(),
196+
}
197+
}
198+
}
199+
200+
/// Consumes all tokens until the next identifier is found and captures it. Returns
201+
/// `None` if no identifier could be found.
202+
///
203+
/// The cursor will be positioned immediately after the identifier, or at the end if
204+
/// it is not.
205+
pub fn find_any_ident(&mut self) -> Option<Capture> {
206+
loop {
207+
match self.next_token.kind {
208+
TokenKind::Ident => {
209+
let res = Capture {
210+
pos: self.pos,
211+
len: self.next_token.len,
212+
};
213+
self.step();
214+
return Some(res);
215+
},
216+
TokenKind::Eof => return None,
217+
_ => self.step(),
218+
}
219+
}
220+
}
221+
181222
/// Continually attempt to match the pattern on subsequent tokens until a match is
182223
/// found. Returns whether the pattern was successfully matched.
183224
///
@@ -195,20 +236,6 @@ impl<'txt> Cursor<'txt> {
195236
true
196237
}
197238

198-
/// The same as [`Self::find_pat`], but returns a capture as well.
199-
#[must_use]
200-
pub fn find_capture_pat(&mut self, pat: Pat<'_>) -> Option<&'txt str> {
201-
let mut capture = Capture::EMPTY;
202-
let mut captures = slice::from_mut(&mut capture).iter_mut();
203-
while !self.match_impl(pat, &mut captures) {
204-
self.step();
205-
if self.at_end() {
206-
return None;
207-
}
208-
}
209-
Some(self.get_text(capture))
210-
}
211-
212239
/// Attempts to match a sequence of patterns at the current position. Returns whether
213240
/// all patterns were successfully matched.
214241
///
@@ -221,6 +248,16 @@ impl<'txt> Cursor<'txt> {
221248
#[must_use]
222249
pub fn match_all(&mut self, pats: &[Pat<'_>], captures: &mut [Capture]) -> bool {
223250
let mut captures = captures.iter_mut();
224-
pats.iter().all(|&t| self.match_impl(t, &mut captures))
251+
pats.iter().all(|&p| self.match_impl(p, &mut captures))
252+
}
253+
254+
/// Attempts to match a single pattern at the current position. Returns whether the
255+
/// pattern was successfully matched.
256+
///
257+
/// If the pattern attempts to capture anything this will panic. If the match fails
258+
/// the cursor will be positioned at the first failing token.
259+
#[must_use]
260+
pub fn match_pat(&mut self, pat: Pat<'_>) -> bool {
261+
self.match_impl(pat, &mut [].iter_mut())
225262
}
226263
}

clippy_dev/src/rename_lint.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,17 +304,16 @@ fn file_update_fn<'a, 'b>(
304304
// mod lint_name
305305
"mod" => {
306306
if !matches!(mod_edit, ModEdit::None)
307-
&& cursor.match_all(&[cursor::Pat::CaptureIdent], &mut captures)
308-
&& cursor.get_text(captures[0]) == old_name
307+
&& let Some(pos) = cursor.find_ident(old_name)
309308
{
310309
match mod_edit {
311310
ModEdit::Rename => {
312-
dst.push_str(&src[copy_pos as usize..captures[0].pos as usize]);
311+
dst.push_str(&src[copy_pos as usize..pos as usize]);
313312
dst.push_str(new_name);
314313
copy_pos = cursor.pos();
315314
changed = true;
316315
},
317-
ModEdit::Delete if cursor.match_all(&[cursor::Pat::Semi], &mut []) => {
316+
ModEdit::Delete if cursor.match_pat(cursor::Pat::Semi) => {
318317
let mut start = &src[copy_pos as usize..match_start as usize];
319318
if start.ends_with("\n\n") {
320319
start = &start[..start.len() - 1];
@@ -333,7 +332,7 @@ fn file_update_fn<'a, 'b>(
333332
// lint_name::
334333
name if matches!(mod_edit, ModEdit::Rename) && name == old_name => {
335334
let name_end = cursor.pos();
336-
if cursor.match_all(&[cursor::Pat::DoubleColon], &mut []) {
335+
if cursor.match_pat(cursor::Pat::DoubleColon) {
337336
dst.push_str(&src[copy_pos as usize..match_start as usize]);
338337
dst.push_str(new_name);
339338
copy_pos = name_end;

0 commit comments

Comments
 (0)