Skip to content

Commit e598d3d

Browse files
committed
clippy_dev: Refactor token parsing to avoid macros.
1 parent ed2d130 commit e598d3d

File tree

5 files changed

+303
-226
lines changed

5 files changed

+303
-226
lines changed

clippy_dev/src/new_lint.rs

+41-79
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::Version;
1+
use crate::utils::{Token, Version, new_rust_searcher};
22
use clap::ValueEnum;
33
use indoc::{formatdoc, writedoc};
44
use std::fmt::{self, Write as _};
@@ -360,8 +360,7 @@ fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> S
360360
pub {name_upper},
361361
{category},
362362
"default lint description"
363-
}}
364-
"#,
363+
}}"#,
365364
version.rust_display(),
366365
)
367366
}
@@ -446,9 +445,6 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
446445

447446
#[allow(clippy::too_many_lines)]
448447
fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
449-
use super::update_lints::{LintDeclSearchResult, match_tokens};
450-
use rustc_lexer::TokenKind;
451-
452448
let lint_name_upper = lint.name.to_uppercase();
453449

454450
let mut file_contents = fs::read_to_string(path)?;
@@ -459,81 +455,11 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
459455
path.display()
460456
);
461457

462-
let mut offset = 0usize;
463-
let mut last_decl_curly_offset = None;
464-
let mut lint_context = None;
465-
466-
let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
467-
let range = offset..offset + t.len as usize;
468-
offset = range.end;
469-
470-
LintDeclSearchResult {
471-
token_kind: t.kind,
472-
content: &file_contents[range.clone()],
473-
range,
474-
}
475-
});
476-
477-
// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
478-
while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
479-
let mut iter = iter
480-
.by_ref()
481-
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
482-
483-
match content {
484-
"declare_clippy_lint" => {
485-
// matches `!{`
486-
match_tokens!(iter, Bang OpenBrace);
487-
if let Some(LintDeclSearchResult { range, .. }) =
488-
iter.find(|result| result.token_kind == TokenKind::CloseBrace)
489-
{
490-
last_decl_curly_offset = Some(range.end);
491-
}
492-
},
493-
"impl" => {
494-
let mut token = iter.next();
495-
match token {
496-
// matches <'foo>
497-
Some(LintDeclSearchResult {
498-
token_kind: TokenKind::Lt,
499-
..
500-
}) => {
501-
match_tokens!(iter, Lifetime { .. } Gt);
502-
token = iter.next();
503-
},
504-
None => break,
505-
_ => {},
506-
}
507-
508-
if let Some(LintDeclSearchResult {
509-
token_kind: TokenKind::Ident,
510-
content,
511-
..
512-
}) = token
513-
{
514-
// Get the appropriate lint context struct
515-
lint_context = match content {
516-
"LateLintPass" => Some("LateContext"),
517-
"EarlyLintPass" => Some("EarlyContext"),
518-
_ => continue,
519-
};
520-
}
521-
},
522-
_ => {},
523-
}
524-
}
525-
526-
drop(iter);
527-
528-
let last_decl_curly_offset =
529-
last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display()));
530-
let lint_context =
531-
lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display()));
458+
let (lint_context, lint_decl_end) = parse_mod_file(path, &file_contents);
532459

533460
// Add the lint declaration to `mod.rs`
534-
file_contents.replace_range(
535-
// Remove the trailing newline, which should always be present
536-
last_decl_curly_offset..=last_decl_curly_offset,
461+
file_contents.insert_str(
462+
lint_decl_end,
537463
&format!(
538464
"\n\n{}",
539465
get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category)
@@ -588,6 +514,42 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
588514
Ok(lint_context)
589515
}
590516

517+
// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
518+
fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) {
519+
#[allow(clippy::enum_glob_use)]
520+
use Token::*;
521+
522+
let mut context = None;
523+
let mut decl_end = None;
524+
let mut name = "";
525+
let mut searcher = new_rust_searcher(contents);
526+
while searcher.find_capture_token(CaptureIdent, &mut name) {
527+
match name {
528+
"declare_clippy_lint" => {
529+
if searcher.match_tokens(&[Bang, OpenBrace], &mut []) && searcher.find_token(CloseBrace) {
530+
decl_end = Some(searcher.pos());
531+
}
532+
},
533+
"impl" => {
534+
if searcher.match_tokens(&[Lt, Lifetime, Gt, CaptureIdent], &mut [&mut name]) {
535+
match name {
536+
"LateLintPass" => context = Some("LateContext"),
537+
"EarlyLintPass" => context = Some("EarlyContext"),
538+
_ => {},
539+
}
540+
}
541+
},
542+
_ => {},
543+
}
544+
}
545+
drop(searcher);
546+
547+
(
548+
context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())),
549+
decl_end.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())) as usize,
550+
)
551+
}
552+
591553
#[test]
592554
fn test_camel_case() {
593555
let s = "a_lint";

0 commit comments

Comments
 (0)