about summary refs log tree commit diff
path: root/clippy_dev/src
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2025-06-27 12:20:57 +0200
committerPhilipp Krones <hello@philkrones.com>2025-06-27 12:20:57 +0200
commit074ccaf3c0818c1c7162babe8e7874f1fa551e18 (patch)
tree67e421d9f26ddfec3c2f5321c15de4d2d8d0394e /clippy_dev/src
parent55d4f76c73ae517905df61674667463e65e90b47 (diff)
Merge commit 'c5dbd1de07e0407b9687619a868384d6de06253f' into clippy-subtree-update
Diffstat (limited to 'clippy_dev/src')
-rw-r--r--clippy_dev/src/lint.rs4
-rw-r--r--clippy_dev/src/release.rs1
-rw-r--r--clippy_dev/src/serve.rs2
-rw-r--r--clippy_dev/src/update_lints.rs291
-rw-r--r--clippy_dev/src/utils.rs15
5 files changed, 174 insertions, 139 deletions
diff --git a/clippy_dev/src/lint.rs b/clippy_dev/src/lint.rs
index e0e036757d5..0d66f167a38 100644
--- a/clippy_dev/src/lint.rs
+++ b/clippy_dev/src/lint.rs
@@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
 
     if is_file {
         exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .args(["run", "--bin", "clippy-driver", "--"])
                 .args(["-L", "./target/debug"])
                 .args(["-Z", "no-codegen"])
@@ -26,7 +26,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>
         );
     } else {
         exit_if_err(
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .arg("build")
                 .status(),
         );
diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs
index 62c1bee8185..15392dd1d29 100644
--- a/clippy_dev/src/release.rs
+++ b/clippy_dev/src/release.rs
@@ -5,6 +5,7 @@ static CARGO_TOML_FILES: &[&str] = &[
     "clippy_config/Cargo.toml",
     "clippy_lints/Cargo.toml",
     "clippy_utils/Cargo.toml",
+    "declare_clippy_lint/Cargo.toml",
     "Cargo.toml",
 ];
 
diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs
index a2d1236629f..498ffeba9d6 100644
--- a/clippy_dev/src/serve.rs
+++ b/clippy_dev/src/serve.rs
@@ -28,7 +28,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
         .map(mtime);
 
         if times.iter().any(|&time| index_time < time) {
-            Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+            Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
                 .arg("collect-metadata")
                 .spawn()
                 .unwrap()
diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index 3b827cc5603..5f6e874ffe2 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -2,11 +2,11 @@ use crate::utils::{
     ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn,
 };
 use itertools::Itertools;
-use rustc_lexer::{LiteralKind, TokenKind, tokenize};
 use std::collections::HashSet;
 use std::fmt::Write;
+use std::fs;
 use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
 
 const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -37,123 +37,164 @@ pub fn generate_lint_files(
     deprecated: &[DeprecatedLint],
     renamed: &[RenamedLint],
 ) {
-    FileUpdater::default().update_files_checked(
+    let mut updater = FileUpdater::default();
+    updater.update_file_checked(
         "cargo dev update_lints",
         update_mode,
-        &mut [
-            (
-                "README.md",
-                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
-                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
-                }),
-            ),
-            (
-                "book/src/README.md",
-                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
-                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
-                }),
-            ),
-            (
-                "CHANGELOG.md",
-                &mut update_text_region_fn(
-                    "<!-- begin autogenerated links to lint list -->\n",
-                    "<!-- end autogenerated links to lint list -->",
-                    |dst| {
-                        for lint in lints
-                            .iter()
-                            .map(|l| &*l.name)
-                            .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
-                            .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
-                            .sorted()
-                        {
-                            writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
-                        }
-                    },
-                ),
-            ),
-            (
-                "clippy_lints/src/lib.rs",
-                &mut update_text_region_fn(
-                    "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
-                    "// end lints modules, do not remove this comment, it's used in `update_lints`",
-                    |dst| {
-                        for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() {
-                            writeln!(dst, "mod {lint_mod};").unwrap();
-                        }
-                    },
-                ),
-            ),
-            ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| {
-                dst.push_str(GENERATED_FILE_COMMENT);
-                dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
-                for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
-                    writeln!(dst, "    crate::{module_name}::{lint_name}_INFO,").unwrap();
-                }
-                dst.push_str("];\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| {
-                let mut searcher = RustSearcher::new(src);
-                assert!(
-                    searcher.find_token(Token::Ident("declare_with_version"))
-                        && searcher.find_token(Token::Ident("declare_with_version")),
-                    "error reading deprecated lints"
-                );
-                dst.push_str(&src[..searcher.pos() as usize]);
-                dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
-                for lint in deprecated {
-                    write!(
-                        dst,
-                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                        lint.version, lint.name, lint.reason,
-                    )
-                    .unwrap();
+        "README.md",
+        &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+            write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+        }),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "book/src/README.md",
+        &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+            write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+        }),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "CHANGELOG.md",
+        &mut update_text_region_fn(
+            "<!-- begin autogenerated links to lint list -->\n",
+            "<!-- end autogenerated links to lint list -->",
+            |dst| {
+                for lint in lints
+                    .iter()
+                    .map(|l| &*l.name)
+                    .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+                    .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
+                    .sorted()
+                {
+                    writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
                 }
-                dst.push_str(
-                    "]}\n\n\
+            },
+        ),
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "clippy_lints/src/deprecated_lints.rs",
+        &mut |_, src, dst| {
+            let mut searcher = RustSearcher::new(src);
+            assert!(
+                searcher.find_token(Token::Ident("declare_with_version"))
+                    && searcher.find_token(Token::Ident("declare_with_version")),
+                "error reading deprecated lints"
+            );
+            dst.push_str(&src[..searcher.pos() as usize]);
+            dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
+            for lint in deprecated {
+                write!(
+                    dst,
+                    "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                    lint.version, lint.name, lint.reason,
+                )
+                .unwrap();
+            }
+            dst.push_str(
+                "]}\n\n\
                     #[rustfmt::skip]\n\
                     declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\
                 ",
-                );
-                for lint in renamed {
-                    write!(
-                        dst,
-                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                        lint.version, lint.old_name, lint.new_name,
-                    )
-                    .unwrap();
+            );
+            for lint in renamed {
+                write!(
+                    dst,
+                    "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                    lint.version, lint.old_name, lint.new_name,
+                )
+                .unwrap();
+            }
+            dst.push_str("]}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "tests/ui/deprecated.rs",
+        &mut |_, src, dst| {
+            dst.push_str(GENERATED_FILE_COMMENT);
+            for lint in deprecated {
+                writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+            }
+            dst.push_str("\nfn main() {}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    updater.update_file_checked(
+        "cargo dev update_lints",
+        update_mode,
+        "tests/ui/rename.rs",
+        &mut move |_, src, dst| {
+            let mut seen_lints = HashSet::new();
+            dst.push_str(GENERATED_FILE_COMMENT);
+            dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
+            for lint in renamed {
+                if seen_lints.insert(&lint.new_name) {
+                    writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
                 }
-                dst.push_str("]}\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("tests/ui/deprecated.rs", &mut |_, src, dst| {
-                dst.push_str(GENERATED_FILE_COMMENT);
-                for lint in deprecated {
-                    writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+            }
+            seen_lints.clear();
+            for lint in renamed {
+                if seen_lints.insert(&lint.old_name) {
+                    writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
                 }
-                dst.push_str("\nfn main() {}\n");
-                UpdateStatus::from_changed(src != dst)
-            }),
-            ("tests/ui/rename.rs", &mut move |_, src, dst| {
-                let mut seen_lints = HashSet::new();
-                dst.push_str(GENERATED_FILE_COMMENT);
-                dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
-                for lint in renamed {
-                    if seen_lints.insert(&lint.new_name) {
-                        writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
+            }
+            dst.push_str("\nfn main() {}\n");
+            UpdateStatus::from_changed(src != dst)
+        },
+    );
+    for (crate_name, lints) in lints.iter().into_group_map_by(|&l| {
+        let Some(path::Component::Normal(name)) = l.path.components().next() else {
+            // All paths should start with `{crate_name}/src` when parsed from `find_lint_decls`
+            panic!("internal error: can't read crate name from path `{}`", l.path.display());
+        };
+        name
+    }) {
+        updater.update_file_checked(
+            "cargo dev update_lints",
+            update_mode,
+            Path::new(crate_name).join("src/lib.rs"),
+            &mut update_text_region_fn(
+                "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
+                "// end lints modules, do not remove this comment, it's used in `update_lints`",
+                |dst| {
+                    for lint_mod in lints
+                        .iter()
+                        .filter(|l| !l.module.is_empty())
+                        .map(|l| l.module.split_once("::").map_or(&*l.module, |x| x.0))
+                        .sorted()
+                        .dedup()
+                    {
+                        writeln!(dst, "mod {lint_mod};").unwrap();
                     }
-                }
-                seen_lints.clear();
-                for lint in renamed {
-                    if seen_lints.insert(&lint.old_name) {
-                        writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
+                },
+            ),
+        );
+        updater.update_file_checked(
+            "cargo dev update_lints",
+            update_mode,
+            Path::new(crate_name).join("src/declared_lints.rs"),
+            &mut |_, src, dst| {
+                dst.push_str(GENERATED_FILE_COMMENT);
+                dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n");
+                for (module_path, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
+                    if module_path.is_empty() {
+                        writeln!(dst, "    crate::{lint_name}_INFO,").unwrap();
+                    } else {
+                        writeln!(dst, "    crate::{module_path}::{lint_name}_INFO,").unwrap();
                     }
                 }
-                dst.push_str("\nfn main() {}\n");
+                dst.push_str("];\n");
                 UpdateStatus::from_changed(src != dst)
-            }),
-        ],
-    );
+            },
+        );
+    }
 }
 
 fn round_to_fifty(count: usize) -> usize {
@@ -187,13 +228,25 @@ pub struct RenamedLint {
 pub fn find_lint_decls() -> Vec<Lint> {
     let mut lints = Vec::with_capacity(1000);
     let mut contents = String::new();
-    for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
-        parse_clippy_lint_decls(
-            file.path(),
-            File::open_read_to_cleared_string(file.path(), &mut contents),
-            &module,
-            &mut lints,
-        );
+    for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") {
+        let e = expect_action(e, ErrAction::Read, ".");
+        if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() {
+            continue;
+        }
+        let Ok(mut name) = e.file_name().into_string() else {
+            continue;
+        };
+        if name.starts_with("clippy_lints") && name != "clippy_lints_internal" {
+            name.push_str("/src");
+            for (file, module) in read_src_with_module(name.as_ref()) {
+                parse_clippy_lint_decls(
+                    file.path(),
+                    File::open_read_to_cleared_string(file.path(), &mut contents),
+                    &module,
+                    &mut lints,
+                );
+            }
+        }
     }
     lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
     lints
@@ -205,7 +258,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
         let e = expect_action(e, ErrAction::Read, src_root);
         let path = e.path().as_os_str().as_encoded_bytes();
         if let Some(path) = path.strip_suffix(b".rs")
-            && let Some(path) = path.get("clippy_lints/src/".len()..)
+            && let Some(path) = path.get(src_root.as_os_str().len() + 1..)
         {
             if path == b"lib" {
                 Some((e, String::new()))
@@ -333,17 +386,13 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
 
 /// Removes the line splices and surrounding quotes from a string literal
 fn parse_str_lit(s: &str) -> String {
-    let (s, mode) = if let Some(s) = s.strip_prefix("r") {
-        (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr)
-    } else {
-        (s, rustc_literal_escaper::Mode::Str)
-    };
+    let s = s.strip_prefix("r").unwrap_or(s).trim_matches('#');
     let s = s
         .strip_prefix('"')
         .and_then(|s| s.strip_suffix('"'))
         .unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
     let mut res = String::with_capacity(s.len());
-    rustc_literal_escaper::unescape_str(s, |range, ch| {
+    rustc_literal_escaper::unescape_str(s, &mut |_, ch| {
         if let Ok(ch) = ch {
             res.push(ch);
         }
diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs
index c4808b7048b..89962a11034 100644
--- a/clippy_dev/src/utils.rs
+++ b/clippy_dev/src/utils.rs
@@ -383,21 +383,6 @@ impl FileUpdater {
         self.update_file_checked_inner(tool, mode, path.as_ref(), update);
     }
 
-    #[expect(clippy::type_complexity)]
-    pub fn update_files_checked(
-        &mut self,
-        tool: &str,
-        mode: UpdateMode,
-        files: &mut [(
-            impl AsRef<Path>,
-            &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
-        )],
-    ) {
-        for (path, update) in files {
-            self.update_file_checked_inner(tool, mode, path.as_ref(), update);
-        }
-    }
-
     pub fn update_file(
         &mut self,
         path: impl AsRef<Path>,