diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e30a5f9fe10b0..b80ac6370e7a5 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,7 +18,6 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) - - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -176,23 +175,26 @@ the tests. Manually testing against an example file can be useful if you have added some `println!`s and the test suite output becomes unreadable. To try Clippy with -your local modifications, run +your local modifications, run the following from the Clippy directory: -``` +```bash cargo dev lint input.rs ``` -from the working copy root. With tests in place, let's have a look at -implementing our lint now. +To run Clippy on an existing project rather than a single file you can use + +```bash +cargo dev lint /path/to/project +``` + +Or set up a rustup toolchain that points to the local Clippy binaries -## Running directly +```bash +cargo dev setup toolchain -While it's easier to just use `cargo dev lint`, it might be desirable to get -`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. -By default, they don't work because clippy dynamically links rustc. To help them find rustc, -add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) -to your library search path. -On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. +# Then in `/path/to/project` you can run +cargo +clippy clippy +``` ## Lint declaration diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index ee559d45dd16d..2562314418172 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -35,7 +35,6 @@ struct FmtContext { } // the "main" function of cargo dev fmt -#[allow(clippy::missing_panics_doc)] pub fn run(check: bool, verbose: bool) { fn try_run(context: &FmtContext) -> Result { let mut success = true; diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index bb62e902cd544..385191e0361b1 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -9,6 +9,7 @@ unused_lifetimes, unused_qualifications )] +#![allow(clippy::missing_panics_doc)] // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. #[allow(unused_extern_crates)] diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5bd9994e18d5b..397a0e990829c 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -46,6 +46,13 @@ fn main() { } }, Some(("setup", sub_command)) => match sub_command.subcommand() { + Some(("git-hook", matches)) => { + if matches.get_flag("remove") { + setup::git_hook::remove_hook(); + } else { + setup::git_hook::install_hook(matches.get_flag("force-override")); + } + }, Some(("intellij", matches)) => { if matches.get_flag("remove") { setup::intellij::remove_rustc_src(); @@ -57,12 +64,12 @@ fn main() { ); } }, - Some(("git-hook", matches)) => { - if matches.get_flag("remove") { - setup::git_hook::remove_hook(); - } else { - setup::git_hook::install_hook(matches.get_flag("force-override")); - } + Some(("toolchain", matches)) => { + setup::toolchain::create( + matches.get_flag("force"), + matches.get_flag("release"), + matches.get_one::("name").unwrap(), + ); }, Some(("vscode-tasks", matches)) => { if matches.get_flag("remove") { @@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches { .about("Support for setting up your personal development environment") .arg_required_else_help(true) .subcommands([ + Command::new("git-hook") + .about("Add a pre-commit git hook that formats your code to make it look pretty") + .args([ + Arg::new("remove") + .long("remove") + .action(ArgAction::SetTrue) + .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), + Arg::new("force-override") + .long("force-override") + .short('f') + .action(ArgAction::SetTrue) + .help("Forces the override of an existing git pre-commit hook"), + ]), Command::new("intellij") .about("Alter dependencies so Intellij Rust can find rustc internals") .args([ @@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches { .conflicts_with("remove") .required(true), ]), - Command::new("git-hook") - .about("Add a pre-commit git hook that formats your code to make it look pretty") + Command::new("toolchain") + .about("Install a rustup toolchain pointing to the local clippy build") .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), - Arg::new("force-override") - .long("force-override") + Arg::new("force") + .long("force") .short('f') .action(ArgAction::SetTrue) - .help("Forces the override of an existing git pre-commit hook"), + .help("Override an existing toolchain"), + Arg::new("release") + .long("release") + .short('r') + .action(ArgAction::SetTrue) + .help("Point to --release clippy binaries"), + Arg::new("name") + .long("name") + .default_value("clippy") + .help("The name of the created toolchain"), ]), Command::new("vscode-tasks") .about("Add several tasks to vscode for formatting, validation and testing") diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 5d9cde06cd86b..2940d56350f41 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -36,7 +36,6 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -#[allow(clippy::missing_panics_doc)] pub fn create( pass: &String, lint_name: Option<&String>, diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index f691ae4fa45da..b0d3181463918 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -1,5 +1,6 @@ pub mod git_hook; pub mod intellij; +pub mod toolchain; pub mod vscode; use std::path::Path; diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs new file mode 100644 index 0000000000000..8d98c6c92d9d1 --- /dev/null +++ b/clippy_dev/src/setup/toolchain.rs @@ -0,0 +1,75 @@ +use std::env::consts::EXE_SUFFIX; +use std::env::current_dir; +use std::ffi::OsStr; +use std::fs; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +use super::verify_inside_clippy_dir; + +pub fn create(force: bool, release: bool, name: &str) { + if !verify_inside_clippy_dir() { + return; + } + + let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); + + let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]); + let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]); + + if dest.exists() { + if force { + fs::remove_dir_all(&dest).unwrap(); + } else { + println!("{} already exists, pass `--force` to override it", dest.display()); + return; + } + } + + for entry in WalkDir::new(&src) { + let entry = entry.unwrap(); + let relative = entry.path().strip_prefix(&src).unwrap(); + + if relative.starts_with("bin") + && matches!( + relative.file_stem().and_then(OsStr::to_str), + Some("cargo-clippy" | "clippy-driver") + ) + { + continue; + } + + let target = dest.join(relative); + if entry.file_type().is_dir() { + fs::create_dir(&target).unwrap(); + } else { + fs::hard_link(entry.path(), target).unwrap(); + } + } + + symlink_bin("cargo-clippy", &dest, release); + symlink_bin("clippy-driver", &dest, release); + + println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); +} + +fn symlink_bin(bin: &str, dest: &Path, release: bool) { + #[cfg(windows)] + use std::os::windows::fs::symlink_file as symlink; + + #[cfg(not(windows))] + use std::os::unix::fs::symlink; + + let profile = if release { "release" } else { "debug" }; + let file_name = format!("{bin}{EXE_SUFFIX}"); + + let mut src = current_dir().unwrap(); + src.extend(["target", profile, &file_name]); + + let mut dest = dest.to_path_buf(); + dest.extend(["bin", &file_name]); + + symlink(src, dest).unwrap(); +}