1- use crate :: utils:: Version ;
1+ use crate :: utils:: { RustSearcher , Token , Version } ;
22use clap:: ValueEnum ;
33use indoc:: { formatdoc, writedoc} ;
44use 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) ]
448447fn 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,41 @@ 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 searcher = RustSearcher :: new ( contents) ;
525+ while let Some ( name) = searcher. find_capture_token ( CaptureIdent ) {
526+ match name {
527+ "declare_clippy_lint" => {
528+ if searcher. match_tokens ( & [ Bang , OpenBrace ] , & mut [ ] ) && searcher. find_token ( CloseBrace ) {
529+ decl_end = Some ( searcher. pos ( ) ) ;
530+ }
531+ } ,
532+ "impl" => {
533+ let mut capture = "" ;
534+ if searcher. match_tokens ( & [ Lt , Lifetime , Gt , CaptureIdent ] , & mut [ & mut capture] ) {
535+ match capture {
536+ "LateLintPass" => context = Some ( "LateContext" ) ,
537+ "EarlyLintPass" => context = Some ( "EarlyContext" ) ,
538+ _ => { } ,
539+ }
540+ }
541+ } ,
542+ _ => { } ,
543+ }
544+ }
545+
546+ (
547+ context. unwrap_or_else ( || panic ! ( "No lint pass implementation found in `{}`" , path. display( ) ) ) ,
548+ decl_end. unwrap_or_else ( || panic ! ( "No lint declarations found in `{}`" , path. display( ) ) ) as usize ,
549+ )
550+ }
551+
591552#[ test]
592553fn test_camel_case ( ) {
593554 let s = "a_lint" ;
0 commit comments