From 79c69112dc1dd5803af4e2682552c1ad2dde14ca Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 26 Mar 2025 20:38:58 +0100 Subject: Apply `collapsible_if` to Clippy itself Since Clippy uses the `let_chains` feature, there are many occasions to collapse `if` and `if let` statements. --- src/driver.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index e4092bcd105..c6b3c06baa4 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -207,12 +207,12 @@ pub fn main() { // Beside checking for existence of `--sysroot` on the command line, we need to // check for the arg files that are prefixed with @ as well to be consistent with rustc for arg in args.iter() { - if let Some(arg_file_path) = arg.strip_prefix('@') { - if let Ok(arg_file) = read_to_string(arg_file_path) { - let split_arg_file: Vec = arg_file.lines().map(ToString::to_string).collect(); - if has_arg(&split_arg_file, "--sysroot") { - return true; - } + if let Some(arg_file_path) = arg.strip_prefix('@') + && let Ok(arg_file) = read_to_string(arg_file_path) + { + let split_arg_file: Vec = arg_file.lines().map(ToString::to_string).collect(); + if has_arg(&split_arg_file, "--sysroot") { + return true; } } } @@ -221,10 +221,10 @@ pub fn main() { let sys_root_env = std::env::var("SYSROOT").ok(); let pass_sysroot_env_if_given = |args: &mut Vec, sys_root_env| { - if let Some(sys_root) = sys_root_env { - if !has_sysroot_arg(args) { - args.extend(vec!["--sysroot".into(), sys_root]); - } + if let Some(sys_root) = sys_root_env + && !has_sysroot_arg(args) + { + args.extend(vec!["--sysroot".into(), sys_root]); } }; -- cgit 1.4.1-3-g733a5 From 94ec23934cbed631cdbd6ab365f9f4fe073ca8b0 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 19 Mar 2025 02:19:33 +0000 Subject: Allow drivers to supply a list of extra symbols to intern --- Cargo.toml | 1 + clippy_lints/src/attrs/deprecated_cfg_attr.rs | 4 ++-- clippy_lints/src/attrs/useless_attribute.rs | 4 ++-- clippy_lints/src/doc/needless_doctest_main.rs | 2 +- clippy_utils/src/lib.rs | 4 +++- clippy_utils/src/sym.rs | 23 +++++++++++++++++++++++ src/driver.rs | 1 + 7 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 clippy_utils/src/sym.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index c4588002dc9..6c0b3af573d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ path = "src/driver.rs" [dependencies] clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } +clippy_utils = { path = "clippy_utils" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } tempfile = { version = "3.3", optional = true } termize = "0.1" diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index cd38aed26a3..7fab97d3ea1 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,10 +1,10 @@ use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, MsrvStack}; +use clippy_utils::sym; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::EarlyContext; -use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { // check cfg_attr @@ -18,7 +18,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { && msrv.meets(msrvs::TOOL_ATTRIBUTES) // check for `rustfmt_skip` and `rustfmt::skip` && let Some(skip_item) = &items[1].meta_item() - && (skip_item.has_name(sym!(rustfmt_skip)) + && (skip_item.has_name(sym::rustfmt_skip) || skip_item .path .segments diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index e3e081ce08e..1cb43ab02a3 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -2,10 +2,10 @@ use super::USELESS_ATTRIBUTE; use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; +use clippy_utils::sym; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); @@ -61,7 +61,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { if is_word(lint, sym::unused_imports) && skip_unused_imports { return; } - if is_word(lint, sym!(unused_extern_crates)) { + if is_word(lint, sym::unused_extern_crates) { return; } }, diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index 3008082c232..bf98b1337bc 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -38,7 +38,7 @@ pub fn check( // of all `#[test]` attributes in not ignored code examples fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec>) { rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_globals_then(edition, None, || { + rustc_span::create_session_globals_then(edition, &[], None, || { let mut test_attr_spans = vec![]; let filename = FileName::anon_source_code(&code); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index eb4e1a7722f..12f7d6416e3 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,6 +3,7 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] +#![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] #![feature(let_chains)] #![feature(never_type)] @@ -74,6 +75,7 @@ pub mod qualify_min_const_fn; pub mod source; pub mod str_utils; pub mod sugg; +pub mod sym; pub mod ty; pub mod usage; pub mod visitors; @@ -125,7 +127,7 @@ use rustc_middle::ty::{ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; -use rustc_span::{InnerSpan, Span, sym}; +use rustc_span::{InnerSpan, Span}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs new file mode 100644 index 00000000000..9cc72a5b3aa --- /dev/null +++ b/clippy_utils/src/sym.rs @@ -0,0 +1,23 @@ +#![allow(non_upper_case_globals)] + +use rustc_span::symbol::{Symbol, PREDEFINED_SYMBOLS_COUNT}; + +pub use rustc_span::sym::*; + +macro_rules! generate { + ($($sym:ident,)*) => { + /// To be supplied to `rustc_interface::Config` + pub const EXTRA_SYMBOLS: &[&str] = &[ + $(stringify!($sym),)* + ]; + + $( + pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); + )* + }; +} + +generate! { + rustfmt_skip, + unused_extern_crates, +} diff --git a/src/driver.rs b/src/driver.rs index e4092bcd105..df9c4e8e6ae 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -160,6 +160,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { clippy_lints::register_lints(lint_store, conf); clippy_lints::register_pre_expansion_lints(lint_store, conf); })); + config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into(); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be // run on the unoptimized MIR. On the other hand this results in some false negatives. If -- cgit 1.4.1-3-g733a5 From 5b4b463d4925d2ccc56afbf83a2f0e4a50b0f56c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 5 Aug 2024 18:23:48 -0400 Subject: Move internal lints to their own crate --- .github/workflows/clippy_mq.yml | 2 +- .github/workflows/clippy_pr.yml | 2 +- Cargo.toml | 5 +- book/src/development/defining_lints.md | 3 +- clippy_dev/src/main.rs | 1 - clippy_dev/src/update_lints.rs | 90 +----- clippy_lints/Cargo.toml | 7 - clippy_lints/src/declare_clippy_lint.rs | 13 - clippy_lints/src/declared_lints.rs | 30 -- clippy_lints/src/lib.rs | 57 +--- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/utils/internal_lints.rs | 11 - .../almost_standard_lint_formulation.rs | 85 ------ .../src/utils/internal_lints/collapsible_calls.rs | 248 ----------------- .../internal_lints/interning_defined_symbol.rs | 241 ---------------- .../src/utils/internal_lints/invalid_paths.rs | 106 ------- .../utils/internal_lints/lint_without_lint_pass.rs | 281 ------------------- .../src/utils/internal_lints/msrv_attr_impl.rs | 58 ---- .../utils/internal_lints/outer_expn_data_pass.rs | 59 ---- .../src/utils/internal_lints/produce_ice.rs | 41 --- .../internal_lints/slow_symbol_comparisons.rs | 74 ----- .../utils/internal_lints/unnecessary_def_path.rs | 301 -------------------- .../internal_lints/unsorted_clippy_utils_paths.rs | 52 ---- clippy_lints/src/utils/mod.rs | 3 - clippy_lints_internal/Cargo.toml | 14 + .../src/almost_standard_lint_formulation.rs | 87 ++++++ clippy_lints_internal/src/collapsible_calls.rs | 250 +++++++++++++++++ .../src/interning_defined_symbol.rs | 244 +++++++++++++++++ clippy_lints_internal/src/invalid_paths.rs | 108 ++++++++ clippy_lints_internal/src/lib.rs | 78 ++++++ .../src/lint_without_lint_pass.rs | 282 +++++++++++++++++++ clippy_lints_internal/src/msrv_attr_impl.rs | 59 ++++ clippy_lints_internal/src/outer_expn_data_pass.rs | 61 +++++ clippy_lints_internal/src/produce_ice.rs | 43 +++ .../src/slow_symbol_comparisons.rs | 76 ++++++ clippy_lints_internal/src/unnecessary_def_path.rs | 303 +++++++++++++++++++++ .../src/unsorted_clippy_utils_paths.rs | 54 ++++ src/driver.rs | 3 +- tests/dogfood.rs | 6 +- tests/ui-internal/auxiliary/paths.rs | 2 + .../ui-internal/check_clippy_version_attribute.rs | 13 +- .../check_clippy_version_attribute.stderr | 13 +- tests/ui-internal/check_formulation.rs | 3 +- tests/ui-internal/check_formulation.stderr | 11 +- .../ui-internal/collapsible_span_lint_calls.fixed | 2 +- tests/ui-internal/collapsible_span_lint_calls.rs | 2 +- .../ui-internal/collapsible_span_lint_calls.stderr | 5 +- tests/ui-internal/custom_ice_message.rs | 2 +- tests/ui-internal/custom_ice_message.stderr | 2 +- tests/ui-internal/default_lint.rs | 2 +- tests/ui-internal/default_lint.stderr | 5 +- tests/ui-internal/disallow_span_lint.rs | 1 + tests/ui-internal/disallow_span_lint.stderr | 11 +- tests/ui-internal/interning_defined_symbol.fixed | 2 +- tests/ui-internal/interning_defined_symbol.rs | 2 +- tests/ui-internal/interning_defined_symbol.stderr | 5 +- tests/ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- tests/ui-internal/invalid_msrv_attr_impl.stderr | 5 +- tests/ui-internal/invalid_paths.rs | 2 +- tests/ui-internal/invalid_paths.stderr | 7 +- tests/ui-internal/lint_without_lint_pass.rs | 2 +- tests/ui-internal/lint_without_lint_pass.stderr | 5 +- tests/ui-internal/outer_expn_data.fixed | 2 +- tests/ui-internal/outer_expn_data.rs | 2 +- tests/ui-internal/outer_expn_data.stderr | 5 +- tests/ui-internal/unnecessary_def_path.fixed | 2 +- tests/ui-internal/unnecessary_def_path.rs | 2 +- tests/ui-internal/unnecessary_def_path.stderr | 5 +- .../unnecessary_def_path_hardcoded_path.rs | 2 +- .../unnecessary_def_path_hardcoded_path.stderr | 7 +- tests/ui-internal/unnecessary_symbol_str.fixed | 2 +- tests/ui-internal/unnecessary_symbol_str.rs | 2 +- tests/ui-internal/unnecessary_symbol_str.stderr | 5 +- 74 files changed, 1774 insertions(+), 1812 deletions(-) delete mode 100644 clippy_lints/src/utils/internal_lints.rs delete mode 100644 clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs delete mode 100644 clippy_lints/src/utils/internal_lints/collapsible_calls.rs delete mode 100644 clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs delete mode 100644 clippy_lints/src/utils/internal_lints/invalid_paths.rs delete mode 100644 clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs delete mode 100644 clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs delete mode 100644 clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs delete mode 100644 clippy_lints/src/utils/internal_lints/produce_ice.rs delete mode 100644 clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs delete mode 100644 clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs delete mode 100644 clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs create mode 100644 clippy_lints_internal/Cargo.toml create mode 100644 clippy_lints_internal/src/almost_standard_lint_formulation.rs create mode 100644 clippy_lints_internal/src/collapsible_calls.rs create mode 100644 clippy_lints_internal/src/interning_defined_symbol.rs create mode 100644 clippy_lints_internal/src/invalid_paths.rs create mode 100644 clippy_lints_internal/src/lib.rs create mode 100644 clippy_lints_internal/src/lint_without_lint_pass.rs create mode 100644 clippy_lints_internal/src/msrv_attr_impl.rs create mode 100644 clippy_lints_internal/src/outer_expn_data_pass.rs create mode 100644 clippy_lints_internal/src/produce_ice.rs create mode 100644 clippy_lints_internal/src/slow_symbol_comparisons.rs create mode 100644 clippy_lints_internal/src/unnecessary_def_path.rs create mode 100644 clippy_lints_internal/src/unsorted_clippy_utils_paths.rs (limited to 'src') diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index 741e7457331..07d5a08304e 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -66,7 +66,7 @@ jobs: run: cargo test --features internal -- --skip dogfood - name: Test clippy_lints - run: cargo test --features internal + run: cargo test working-directory: clippy_lints - name: Test clippy_utils diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index 80523d91f4f..880ebd6e5d5 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -42,7 +42,7 @@ jobs: run: cargo test --features internal - name: Test clippy_lints - run: cargo test --features internal + run: cargo test working-directory: clippy_lints - name: Test clippy_utils diff --git a/Cargo.toml b/Cargo.toml index 5a6904d63be..dfcfe69bedf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ path = "src/driver.rs" clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } +clippy_lints_internal = { path = "clippy_lints_internal", optional = true } tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" @@ -57,8 +58,8 @@ tokio = { version = "1", features = ["io-util"] } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } [features] -integration = ["tempfile"] -internal = ["clippy_lints/internal", "tempfile"] +integration = ["dep:tempfile"] +internal = ["dep:clippy_lints_internal", "dep:tempfile"] [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index 169cecd7d11..cb6d7b740db 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -9,7 +9,7 @@ lint involves some boilerplate code. A lint type is the category of items and expressions in which your lint focuses on. -As of the writing of this documentation update, there are 12 _types_ of lints +As of the writing of this documentation update, there are 11 _types_ of lints besides the numerous standalone lints living under `clippy_lints/src/`: - `cargo` @@ -23,7 +23,6 @@ besides the numerous standalone lints living under `clippy_lints/src/`: - `transmute` - `types` - `unit_types` -- `utils / internal` (Clippy internal lints) These types group together lints that share some common behaviors. For instance, `functions` groups together lints that deal with some aspects of functions in diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 0380b7e6a6d..83f8e66b334 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -170,7 +170,6 @@ enum DevCommand { "restriction", "cargo", "nursery", - "internal", ], default_value = "nursery", )] diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 0be24f322d2..90683a23544 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -37,9 +37,8 @@ fn generate_lint_files( deprecated_lints: &[DeprecatedLint], renamed_lints: &[RenamedLint], ) { - let internal_lints = Lint::internal_lints(lints); - let mut usable_lints = Lint::usable_lints(lints); - usable_lints.sort_by_key(|lint| lint.name.clone()); + let mut lints = lints.to_owned(); + lints.sort_by_key(|lint| lint.name.clone()); replace_region_in_file( update_mode, @@ -47,7 +46,7 @@ fn generate_lint_files( "[There are over ", " lints included in this crate!]", |res| { - write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); + write!(res, "{}", round_to_fifty(lints.len())).unwrap(); }, ); @@ -57,7 +56,7 @@ fn generate_lint_files( "[There are over ", " lints included in this crate!]", |res| { - write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); + write!(res, "{}", round_to_fifty(lints.len())).unwrap(); }, ); @@ -67,7 +66,7 @@ fn generate_lint_files( "\n", "", |res| { - for lint in usable_lints + for lint in lints .iter() .map(|l| &*l.name) .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) @@ -86,7 +85,7 @@ fn generate_lint_files( "// 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`", |res| { - for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() { + for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() { writeln!(res, "mod {lint_mod};").unwrap(); } }, @@ -95,7 +94,7 @@ fn generate_lint_files( process_file( "clippy_lints/src/declared_lints.rs", update_mode, - &gen_declared_lints(internal_lints.iter(), usable_lints.iter()), + &gen_declared_lints(lints.iter()), ); let content = gen_deprecated_lints_test(deprecated_lints); @@ -106,10 +105,9 @@ fn generate_lint_files( } pub fn print_lints() { - let (lint_list, _, _) = gather_all(); - let usable_lints = Lint::usable_lints(&lint_list); - let usable_lint_count = usable_lints.len(); - let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter()); + let (lints, _, _) = gather_all(); + let lint_count = lints.len(); + let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter()); for (lint_group, mut lints) in grouped_by_lint_group { println!("\n## {lint_group}"); @@ -121,7 +119,7 @@ pub fn print_lints() { } } - println!("there are {usable_lint_count} lints"); + println!("there are {lint_count} lints"); } /// Runs the `rename_lint` command. @@ -527,22 +525,6 @@ impl Lint { } } - /// Returns all non-deprecated lints and non-internal lints - #[must_use] - fn usable_lints(lints: &[Self]) -> Vec { - lints - .iter() - .filter(|l| !l.group.starts_with("internal")) - .cloned() - .collect() - } - - /// Returns all internal lints - #[must_use] - fn internal_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.group == "internal").cloned().collect() - } - /// Returns the lints in a `HashMap`, grouped by the different lint groups #[must_use] fn by_lint_group(lints: impl Iterator) -> HashMap> { @@ -579,23 +561,14 @@ impl RenamedLint { /// Generates the code for registering lints #[must_use] -fn gen_declared_lints<'a>( - internal_lints: impl Iterator, - usable_lints: impl Iterator, -) -> String { - let mut details: Vec<_> = internal_lints - .map(|l| (false, &l.module, l.name.to_uppercase())) - .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase()))) - .collect(); +fn gen_declared_lints<'a>(lints: impl Iterator) -> String { + let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); details.sort_unstable(); let mut output = GENERATED_FILE_COMMENT.to_string(); output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); - for (is_public, module_name, lint_name) in details { - if !is_public { - output.push_str(" #[cfg(feature = \"internal\")]\n"); - } + for (module_name, lint_name) in details { let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); } output.push_str("];\n"); @@ -936,41 +909,6 @@ mod tests { assert_eq!(expected, result); } - #[test] - fn test_usable_lints() { - let lints = vec![ - Lint::new( - "should_assert_eq2", - "Not Deprecated", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new( - "should_assert_eq2", - "internal", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new( - "should_assert_eq2", - "internal_style", - "\"abc\"", - "module_name", - Range::default(), - ), - ]; - let expected = vec![Lint::new( - "should_assert_eq2", - "Not Deprecated", - "\"abc\"", - "module_name", - Range::default(), - )]; - assert_eq!(expected, Lint::usable_lints(&lints)); - } - #[test] fn test_by_lint_group() { let lints = vec![ diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d36b6ae9c95..20951afccbb 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -19,10 +19,7 @@ itertools = "0.12" quine-mc_cluskey = "0.2" regex-syntax = "0.8" serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", optional = true } -tempfile = { version = "3.3.0", optional = true } toml = "0.7.3" -regex = { version = "1.5", optional = true } unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } semver = "1.0" @@ -31,10 +28,6 @@ url = "2.2" [dev-dependencies] walkdir = "2.3" -[features] -# build clippy with internal lints enabled, off by default -internal = ["serde_json", "tempfile", "regex"] - [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] rustc_private = true diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs index 4d908af4084..9f82f876727 100644 --- a/clippy_lints/src/declare_clippy_lint.rs +++ b/clippy_lints/src/declare_clippy_lint.rs @@ -165,17 +165,4 @@ macro_rules! declare_clippy_lint { $(, $eval_always)? } }; - - ( - $(#[doc = $lit:literal])* - pub $lint_name:ident, - internal, - $desc:literal - ) => { - declare_clippy_lint! {@ - $(#[doc = $lit])* - pub $lint_name, Allow, crate::LintCategory::Internal, $desc, - None, "0.0.0" - } - }; } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 77ae16a592f..3b36bea106e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -3,36 +3,6 @@ // Manual edits will be overwritten. pub static LINTS: &[&crate::LintInfo] = &[ - #[cfg(feature = "internal")] - crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, - #[cfg(feature = "internal")] - crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO, crate::absolute_paths::ABSOLUTE_PATHS_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9e1df7881ce..4a08d43cfcd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -65,7 +65,6 @@ mod declare_clippy_lint; #[macro_use] extern crate clippy_utils; -#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; pub mod ctfe; // Very important lint, do not remove (rust#125116) @@ -412,21 +411,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; use utils::attr_collector::{AttrCollector, AttrStorage}; -/// Register all pre expansion lints -/// -/// Pre-expansion lints run before any macro expansion has happened. -/// -/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate -/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. -/// -/// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { - // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. - store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); - - store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); -} - #[derive(Default)] struct RegistrationGroups { all: Vec, @@ -439,8 +423,6 @@ struct RegistrationGroups { restriction: Vec, style: Vec, suspicious: Vec, - #[cfg(feature = "internal")] - internal: Vec, } impl RegistrationGroups { @@ -456,8 +438,6 @@ impl RegistrationGroups { store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction); store.register_group(true, "clippy::style", Some("clippy_style"), self.style); store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious); - #[cfg(feature = "internal")] - store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal); } } @@ -472,8 +452,6 @@ pub(crate) enum LintCategory { Restriction, Style, Suspicious, - #[cfg(feature = "internal")] - Internal, } #[allow(clippy::enum_glob_use)] @@ -495,8 +473,6 @@ impl LintCategory { Restriction => &mut groups.restriction, Style => &mut groups.style, Suspicious => &mut groups.suspicious, - #[cfg(feature = "internal")] - Internal => &mut groups.internal, } } } @@ -530,8 +506,6 @@ impl LintInfo { Restriction => "restriction", Style => "style", Suspicious => "suspicious", - #[cfg(feature = "internal")] - Internal => "internal", } } } @@ -589,6 +563,13 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_removed(name, reason); } + // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. + // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate + // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. + store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); + + store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); + let format_args_storage = FormatArgsStorage::default(); let format_args = format_args_storage.clone(); store.register_early_pass(move || { @@ -601,30 +582,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let attrs = attr_storage.clone(); store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone()))); - // all the internal lints - #[cfg(feature = "internal")] - { - store.register_early_pass(|| { - Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths) - }); - store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce)); - store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls)); - store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); - store.register_late_pass(|_| { - Box::::default() - }); - store.register_late_pass(|_| { - Box::::default() - }); - store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass)); - store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl)); - store.register_late_pass(|_| { - Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new()) - }); - store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons)); - } - store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 9443dca154e..4df173e1d16 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -76,7 +76,7 @@ declare_clippy_lint! { /// This is documented as an antipattern [on the regex documentation](https://docs.rs/regex/latest/regex/#avoid-re-compiling-regexes-especially-in-a-loop) /// /// ### Example - /// ```no_run + /// ```rust,ignore /// # let haystacks = [""]; /// # const MY_REGEX: &str = "a.b"; /// for haystack in haystacks { @@ -87,7 +87,7 @@ declare_clippy_lint! { /// } /// ``` /// can be replaced with - /// ```no_run + /// ```rust,ignore /// # let haystacks = [""]; /// # const MY_REGEX: &str = "a.b"; /// let regex = regex::Regex::new(MY_REGEX).unwrap(); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs deleted file mode 100644 index deb983b6971..00000000000 --- a/clippy_lints/src/utils/internal_lints.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod almost_standard_lint_formulation; -pub mod collapsible_calls; -pub mod interning_defined_symbol; -pub mod invalid_paths; -pub mod lint_without_lint_pass; -pub mod msrv_attr_impl; -pub mod outer_expn_data_pass; -pub mod produce_ice; -pub mod slow_symbol_comparisons; -pub mod unnecessary_def_path; -pub mod unsorted_clippy_utils_paths; diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs deleted file mode 100644 index 0a01a364a75..00000000000 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type; -use clippy_utils::diagnostics::span_lint_and_help; -use regex::Regex; -use rustc_hir::{Attribute, Item, ItemKind, Mutability}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::impl_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks if lint formulations have a standardized format. - /// - /// ### Why is this bad? - /// It's not necessarily bad, but we try to enforce a standard in Clippy. - /// - /// ### Example - /// `Checks for use...` can be written as `Checks for usage...` . - pub ALMOST_STANDARD_LINT_FORMULATION, - internal, - "lint formulations must have a standardized format." -} - -impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]); - -pub struct AlmostStandardFormulation { - standard_formulations: Vec>, -} - -#[derive(Debug)] -struct StandardFormulations<'a> { - wrong_pattern: Regex, - correction: &'a str, -} - -impl AlmostStandardFormulation { - pub fn new() -> Self { - let standard_formulations = vec![StandardFormulations { - wrong_pattern: Regex::new("^(Check for|Detects? uses?)").unwrap(), - correction: "Checks for", - }]; - Self { standard_formulations } - } -} - -impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let mut check_next = false; - if let ItemKind::Static(_, ty, Mutability::Not, _) = item.kind { - let lines = cx - .tcx - .hir_attrs(item.hir_id()) - .iter() - .filter_map(|attr| Attribute::doc_str(attr).map(|sym| (sym, attr))); - if is_lint_ref_type(cx, ty) { - for (line, attr) in lines { - let cur_line = line.as_str().trim(); - if check_next && !cur_line.is_empty() { - for formulation in &self.standard_formulations { - let starts_with_correct_formulation = cur_line.starts_with(formulation.correction); - if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) { - if let Some(ident) = attr.ident() { - span_lint_and_help( - cx, - ALMOST_STANDARD_LINT_FORMULATION, - ident.span, - "non-standard lint formulation", - None, - format!("consider using `{}`", formulation.correction), - ); - } - return; - } - } - return; - } else if cur_line.contains("What it does") { - check_next = true; - } else if cur_line.contains("Why is this bad") { - // Formulation documentation is done. Can add check to ensure that missing formulation is added - // and add a check if it matches no accepted formulation - return; - } - } - } - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs deleted file mode 100644 index 2e6fb7c4ce4..00000000000 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ /dev/null @@ -1,248 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; -use rustc_errors::Applicability; -use rustc_hir::{Closure, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::Span; - -use std::borrow::{Borrow, Cow}; - -declare_clippy_lint! { - /// ### What it does - /// Lints `span_lint_and_then` function calls, where the - /// closure argument has only one statement and that statement is a method - /// call to `span_suggestion`, `span_help`, `span_note` (using the same - /// span), `help` or `note`. - /// - /// These usages of `span_lint_and_then` should be replaced with one of the - /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or - /// `span_lint_and_note`. - /// - /// ### Why is this bad? - /// Using the wrapper `span_lint_and_*` functions, is more - /// convenient, readable and less error prone. - /// - /// ### Example - /// ```rust,ignore - /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { - /// diag.span_suggestion( - /// expr.span, - /// help_msg, - /// sugg.to_string(), - /// Applicability::MachineApplicable, - /// ); - /// }); - /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { - /// diag.span_help(expr.span, help_msg); - /// }); - /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { - /// diag.help(help_msg); - /// }); - /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { - /// diag.span_note(expr.span, note_msg); - /// }); - /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { - /// diag.note(note_msg); - /// }); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// span_lint_and_sugg( - /// cx, - /// TEST_LINT, - /// expr.span, - /// lint_msg, - /// help_msg, - /// sugg.to_string(), - /// Applicability::MachineApplicable, - /// ); - /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg); - /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg); - /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg); - /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg); - /// ``` - pub COLLAPSIBLE_SPAN_LINT_CALLS, - internal, - "found collapsible `span_lint_and_then` calls" -} - -declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); - -impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) { - return; - } - - if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind - && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]) - && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind - && let body = cx.tcx.hir_body(body) - && let only_expr = peel_blocks_with_stmt(body.value) - && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind - && let ExprKind::Path(..) = recv.kind - { - let and_then_snippets = - get_and_then_snippets(cx, call_cx.span, call_lint.span, call_sp.span, call_msg.span); - let mut sle = SpanlessEq::new(cx).deny_side_effects(); - match ps.ident.as_str() { - "span_suggestion" if sle.eq_expr(call_sp, &span_call_args[0]) => { - suggest_suggestion( - cx, - expr, - &and_then_snippets, - &span_suggestion_snippets(cx, span_call_args), - ); - }, - "span_help" if sle.eq_expr(call_sp, &span_call_args[0]) => { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); - }, - "span_note" if sle.eq_expr(call_sp, &span_call_args[0]) => { - let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); - }, - "help" => { - let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); - }, - "note" => { - let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); - }, - _ => (), - } - } - } -} - -struct AndThenSnippets<'a> { - cx: Cow<'a, str>, - lint: Cow<'a, str>, - span: Cow<'a, str>, - msg: Cow<'a, str>, -} - -fn get_and_then_snippets( - cx: &LateContext<'_>, - cx_span: Span, - lint_span: Span, - span_span: Span, - msg_span: Span, -) -> AndThenSnippets<'static> { - let cx_snippet = snippet(cx, cx_span, "cx"); - let lint_snippet = snippet(cx, lint_span, ".."); - let span_snippet = snippet(cx, span_span, "span"); - let msg_snippet = snippet(cx, msg_span, r#""...""#); - - AndThenSnippets { - cx: cx_snippet, - lint: lint_snippet, - span: span_snippet, - msg: msg_snippet, - } -} - -struct SpanSuggestionSnippets<'a> { - help: Cow<'a, str>, - sugg: Cow<'a, str>, - applicability: Cow<'a, str>, -} - -fn span_suggestion_snippets<'a, 'hir>( - cx: &LateContext<'_>, - span_call_args: &'hir [Expr<'hir>], -) -> SpanSuggestionSnippets<'a> { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); - let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); - - SpanSuggestionSnippets { - help: help_snippet, - sugg: sugg_snippet, - applicability: applicability_snippet, - } -} - -fn suggest_suggestion( - cx: &LateContext<'_>, - expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, - span_suggestion_snippets: &SpanSuggestionSnippets<'_>, -) { - span_lint_and_sugg( - cx, - COLLAPSIBLE_SPAN_LINT_CALLS, - expr.span, - "this call is collapsible", - "collapse into", - format!( - "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})", - and_then_snippets.cx, - and_then_snippets.lint, - and_then_snippets.span, - and_then_snippets.msg, - span_suggestion_snippets.help, - span_suggestion_snippets.sugg, - span_suggestion_snippets.applicability - ), - Applicability::MachineApplicable, - ); -} - -fn suggest_help( - cx: &LateContext<'_>, - expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, - help: &str, - with_span: bool, -) { - let option_span = if with_span { - format!("Some({})", and_then_snippets.span) - } else { - "None".to_string() - }; - - span_lint_and_sugg( - cx, - COLLAPSIBLE_SPAN_LINT_CALLS, - expr.span, - "this call is collapsible", - "collapse into", - format!( - "span_lint_and_help({}, {}, {}, {}, {}, {help})", - and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span, - ), - Applicability::MachineApplicable, - ); -} - -fn suggest_note( - cx: &LateContext<'_>, - expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, - note: &str, - with_span: bool, -) { - let note_span = if with_span { - format!("Some({})", and_then_snippets.span) - } else { - "None".to_string() - }; - - span_lint_and_sugg( - cx, - COLLAPSIBLE_SPAN_LINT_CALLS, - expr.span, - "this call is collapsible", - "collapse into", - format!( - "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})", - and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, - ), - Applicability::MachineApplicable, - ); -} diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs deleted file mode 100644 index 044894f8279..00000000000 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ /dev/null @@ -1,241 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::ConstValue; -use rustc_middle::ty; -use rustc_session::impl_lint_pass; -use rustc_span::sym; -use rustc_span::symbol::Symbol; - -use std::borrow::Cow; - -declare_clippy_lint! { - /// ### What it does - /// Checks for interning symbols that have already been pre-interned and defined as constants. - /// - /// ### Why is this bad? - /// It's faster and easier to use the symbol constant. - /// - /// ### Example - /// ```rust,ignore - /// let _ = sym!(f32); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// let _ = sym::f32; - /// ``` - pub INTERNING_DEFINED_SYMBOL, - internal, - "interning a symbol that is pre-interned and defined as a constant" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for unnecessary conversion from Symbol to a string. - /// - /// ### Why is this bad? - /// It's faster use symbols directly instead of strings. - /// - /// ### Example - /// ```rust,ignore - /// symbol.as_str() == "clippy"; - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// symbol == sym::clippy; - /// ``` - pub UNNECESSARY_SYMBOL_STR, - internal, - "unnecessary conversion between Symbol and string" -} - -#[derive(Default)] -pub struct InterningDefinedSymbol { - // Maps the symbol value to the constant DefId. - symbol_map: FxHashMap, -} - -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); - -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if !self.symbol_map.is_empty() { - return; - } - - for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - for def_id in def_path_def_ids(cx.tcx, module) { - for item in cx.tcx.module_children(def_id) { - if let Res::Def(DefKind::Const, item_def_id) = item.res - && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() - && match_type(cx, ty, &paths::SYMBOL) - && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) - && let Some(value) = value.to_u32().discard_err() - { - self.symbol_map.insert(value, item_def_id); - } - } - } - } - } - - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Call(func, [arg]) = &expr.kind - && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() - && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) - && let value = Symbol::intern(&arg).as_u32() - && let Some(&def_id) = self.symbol_map.get(&value) - { - span_lint_and_sugg( - cx, - INTERNING_DEFINED_SYMBOL, - is_expn_of(expr.span, "sym").unwrap_or(expr.span), - "interning a defined symbol", - "try", - cx.tcx.def_path_str(def_id), - Applicability::MachineApplicable, - ); - } - if let ExprKind::Binary(op, left, right) = expr.kind - && matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) - { - let data = [ - (left, self.symbol_str_expr(left, cx)), - (right, self.symbol_str_expr(right, cx)), - ]; - match data { - // both operands are a symbol string - [(_, Some(left)), (_, Some(right))] => { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary `Symbol` to string conversion", - "try", - format!( - "{} {} {}", - left.as_symbol_snippet(cx), - op.node.as_str(), - right.as_symbol_snippet(cx), - ), - Applicability::MachineApplicable, - ); - }, - // one of the operands is a symbol string - [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => { - // creating an owned string for comparison - if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary string allocation", - "try", - format!("{}.as_str()", symbol.as_symbol_snippet(cx)), - Applicability::MachineApplicable, - ); - } - }, - // nothing found - [(_, None), (_, None)] => {}, - } - } - } -} - -impl InterningDefinedSymbol { - fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option> { - static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; - static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; - let call = if let ExprKind::AddrOf(_, _, e) = expr.kind - && let ExprKind::Unary(UnOp::Deref, e) = e.kind - { - e - } else { - expr - }; - if let ExprKind::MethodCall(_, item, [], _) = call.kind - // is a method call - && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) - && let ty = cx.typeck_results().expr_ty(item) - // ...on either an Ident or a Symbol - && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { - Some(false) - } else if match_type(cx, ty, &paths::IDENT) { - Some(true) - } else { - None - } - // ...which converts it to a string - && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS } - && let Some(is_to_owned) = paths - .iter() - .find_map(|path| if match_def_path(cx, did, path) { - Some(path == &paths::SYMBOL_TO_IDENT_STRING) - } else { - None - }) - .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) { - Some(true) - } else { - None - }) - { - return Some(SymbolStrExpr::Expr { - item, - is_ident, - is_to_owned, - }); - } - // is a string constant - if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) { - let value = Symbol::intern(&s).as_u32(); - // ...which matches a symbol constant - if let Some(&def_id) = self.symbol_map.get(&value) { - return Some(SymbolStrExpr::Const(def_id)); - } - } - None - } -} - -enum SymbolStrExpr<'tcx> { - /// a string constant with a corresponding symbol constant - Const(DefId), - /// a "symbol to string" expression like `symbol.as_str()` - Expr { - /// part that evaluates to `Symbol` or `Ident` - item: &'tcx Expr<'tcx>, - is_ident: bool, - /// whether an owned `String` is created like `to_ident_string()` - is_to_owned: bool, - }, -} - -impl<'tcx> SymbolStrExpr<'tcx> { - /// Returns a snippet that evaluates to a `Symbol` and is const if possible - fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> { - match *self { - Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(), - Self::Expr { item, is_ident, .. } => { - let mut snip = snippet(cx, item.span.source_callsite(), ".."); - if is_ident { - // get `Ident.name` - snip.to_mut().push_str(".name"); - } - snip - }, - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs deleted file mode 100644 index 5e1872ad975..00000000000 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ /dev/null @@ -1,106 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::def_path_res; -use clippy_utils::diagnostics::span_lint; -use rustc_hir as hir; -use rustc_hir::Item; -use rustc_hir::def::DefKind; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{self, FloatTy}; -use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; - -declare_clippy_lint! { - /// ### What it does - /// Checks the paths module for invalid paths. - /// - /// ### Why is this bad? - /// It indicates a bug in the code. - /// - /// ### Example - /// None. - pub INVALID_PATHS, - internal, - "invalid path" -} - -declare_lint_pass!(InvalidPaths => [INVALID_PATHS]); - -impl<'tcx> LateLintPass<'tcx> for InvalidPaths { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let local_def_id = &cx.tcx.parent_module(item.hir_id()); - let mod_name = &cx.tcx.item_name(local_def_id.to_def_id()); - if mod_name.as_str() == "paths" - && let hir::ItemKind::Const(.., body_id) = item.kind - && let Some(Constant::Vec(path)) = ConstEvalCtxt::with_env( - cx.tcx, - ty::TypingEnv::post_analysis(cx.tcx, item.owner_id), - cx.tcx.typeck(item.owner_id), - ) - .eval_simple(cx.tcx.hir_body(body_id).value) - && let Some(path) = path - .iter() - .map(|x| { - if let Constant::Str(s) = x { - Some(s.as_str()) - } else { - None - } - }) - .collect::>>() - && !check_path(cx, &path[..]) - { - span_lint(cx, INVALID_PATHS, item.span, "invalid path"); - } - } -} - -// This is not a complete resolver for paths. It works on all the paths currently used in the paths -// module. That's all it does and all it needs to do. -pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { - if !def_path_res(cx.tcx, path).is_empty() { - return true; - } - - // Some implementations can't be found by `path_to_res`, particularly inherent - // implementations of native types. Check lang items. - let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect(); - let lang_items = cx.tcx.lang_items(); - // This list isn't complete, but good enough for our current list of paths. - let incoherent_impls = [ - SimplifiedType::Float(FloatTy::F32), - SimplifiedType::Float(FloatTy::F64), - SimplifiedType::Slice, - SimplifiedType::Str, - SimplifiedType::Bool, - SimplifiedType::Char, - ] - .iter() - .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter()) - .copied(); - for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { - let lang_item_path = cx.get_def_path(item_def_id); - if path_syms.starts_with(&lang_item_path) - && let [item] = &path_syms[lang_item_path.len()..] - { - if matches!( - cx.tcx.def_kind(item_def_id), - DefKind::Mod | DefKind::Enum | DefKind::Trait - ) { - for child in cx.tcx.module_children(item_def_id) { - if child.ident.name == *item { - return true; - } - } - } else { - for child in cx.tcx.associated_item_def_ids(item_def_id) { - if cx.tcx.item_name(*child) == *item { - return true; - } - } - } - } - } - - false -} diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs deleted file mode 100644 index bee05e52ed2..00000000000 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ /dev/null @@ -1,281 +0,0 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; -use rustc_ast::ast::LitKind; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::hir_id::CRATE_HIR_ID; -use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::nested_filter; -use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; - -declare_clippy_lint! { - /// ### What it does - /// Ensures every lint is associated to a `LintPass`. - /// - /// ### Why is this bad? - /// The compiler only knows lints via a `LintPass`. Without - /// putting a lint to a `LintPass::lint_vec()`'s return, the compiler will not - /// know the name of the lint. - /// - /// ### Known problems - /// Only checks for lints associated using the `declare_lint_pass!` and - /// `impl_lint_pass!` macros. - /// - /// ### Example - /// ```rust,ignore - /// declare_lint! { pub LINT_1, ... } - /// declare_lint! { pub LINT_2, ... } - /// declare_lint! { pub FORGOTTEN_LINT, ... } - /// // ... - /// declare_lint_pass!(Pass => [LINT_1, LINT_2]); - /// // missing FORGOTTEN_LINT - /// ``` - pub LINT_WITHOUT_LINT_PASS, - internal, - "declaring a lint without associating it in a LintPass" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for cases of an auto-generated lint without an updated description, - /// i.e. `default lint description`. - /// - /// ### Why is this bad? - /// Indicates that the lint is not finished. - /// - /// ### Example - /// ```rust,ignore - /// declare_lint! { pub COOL_LINT, nursery, "default lint description" } - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" } - /// ``` - pub DEFAULT_LINT, - internal, - "found 'default lint description' in a lint declaration" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for invalid `clippy::version` attributes. - /// - /// Valid values are: - /// * "pre 1.29.0" - /// * any valid semantic version - pub INVALID_CLIPPY_VERSION_ATTRIBUTE, - internal, - "found an invalid `clippy::version` attribute" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for declared clippy lints without the `clippy::version` attribute. - /// - pub MISSING_CLIPPY_VERSION_ATTRIBUTE, - internal, - "found clippy lint without `clippy::version` attribute" -} - -#[derive(Clone, Debug, Default)] -pub struct LintWithoutLintPass { - declared_lints: FxIndexMap, - registered_lints: FxIndexSet, -} - -impl_lint_pass!(LintWithoutLintPass => [ - DEFAULT_LINT, - LINT_WITHOUT_LINT_PASS, - INVALID_CLIPPY_VERSION_ATTRIBUTE, - MISSING_CLIPPY_VERSION_ATTRIBUTE, -]); - -impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) { - return; - } - - if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind { - if is_lint_ref_type(cx, ty) { - check_invalid_clippy_version_attribute(cx, item); - - let expr = &cx.tcx.hir_body(body_id).value; - let fields = if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind - && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind - { - struct_fields - } else { - return; - }; - - let field = fields - .iter() - .find(|f| f.ident.as_str() == "desc") - .expect("lints must have a description field"); - - if let ExprKind::Lit(Spanned { - node: LitKind::Str(sym, _), - .. - }) = field.expr.kind - { - let sym_str = sym.as_str(); - if sym_str == "default lint description" { - span_lint( - cx, - DEFAULT_LINT, - item.span, - format!("the lint `{}` has the default lint description", ident.name), - ); - } - self.declared_lints.insert(ident.name, item.span); - } - } - } else if let Some(macro_call) = root_macro_call_first_node(cx, item) { - if !matches!( - cx.tcx.item_name(macro_call.def_id).as_str(), - "impl_lint_pass" | "declare_lint_pass" - ) { - return; - } - if let hir::ItemKind::Impl(hir::Impl { - of_trait: None, - items: impl_item_refs, - .. - }) = item.kind - { - let mut collector = LintCollector { - output: &mut self.registered_lints, - cx, - }; - let body = cx.tcx.hir_body_owned_by( - impl_item_refs - .iter() - .find(|iiref| iiref.ident.as_str() == "lint_vec") - .expect("LintPass needs to implement lint_vec") - .id - .owner_id - .def_id, - ); - collector.visit_expr(body.value); - } - } - } - - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) { - return; - } - - for (lint_name, &lint_span) in &self.declared_lints { - // When using the `declare_tool_lint!` macro, the original `lint_span`'s - // file points to "". - // `compiletest-rs` thinks that's an error in a different file and - // just ignores it. This causes the test in compile-fail/lint_pass - // not able to capture the error. - // Therefore, we need to climb the macro expansion tree and find the - // actual span that invoked `declare_tool_lint!`: - let lint_span = lint_span.ctxt().outer_expn_data().call_site; - - if !self.registered_lints.contains(lint_name) { - span_lint( - cx, - LINT_WITHOUT_LINT_PASS, - lint_span, - format!("the lint `{lint_name}` is not added to any `LintPass`"), - ); - } - } - } -} - -pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { - if let TyKind::Ref( - _, - MutTy { - ty: inner, - mutbl: Mutability::Not, - }, - ) = ty.kind - && let TyKind::Path(ref path) = inner.kind - && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) - { - return match_def_path(cx, def_id, &paths::LINT); - } - - false -} - -fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) { - if let Some(value) = extract_clippy_version_value(cx, item) { - if value.as_str() == "pre 1.29.0" { - return; - } - - if rustc_attr_parsing::parse_version(value).is_none() { - span_lint_and_help( - cx, - INVALID_CLIPPY_VERSION_ATTRIBUTE, - item.span, - "this item has an invalid `clippy::version` attribute", - None, - "please use a valid semantic version, see `doc/adding_lints.md`", - ); - } - } else { - span_lint_and_help( - cx, - MISSING_CLIPPY_VERSION_ATTRIBUTE, - item.span, - "this lint is missing the `clippy::version` attribute or version value", - None, - "please use a `clippy::version` attribute, see `doc/adding_lints.md`", - ); - } -} - -/// This function extracts the version value of a `clippy::version` attribute if the given value has -/// one -pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option { - let attrs = cx.tcx.hir_attrs(item.hir_id()); - attrs.iter().find_map(|attr| { - if let hir::Attribute::Unparsed(attr_kind) = &attr - // Identify attribute - && let [tool_name, attr_name] = &attr_kind.path.segments[..] - && tool_name.name == sym::clippy - && attr_name.name == sym::version - && let Some(version) = attr.value_str() - { - Some(version) - } else { - None - } - }) -} - -struct LintCollector<'a, 'tcx> { - output: &'a mut FxIndexSet, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> { - type NestedFilter = nested_filter::All; - - fn visit_path(&mut self, path: &Path<'_>, _: HirId) { - if path.segments.len() == 1 { - self.output.insert(path.segments[0].ident.name); - } - } - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.cx.tcx - } -} diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs deleted file mode 100644 index 558acacb972..00000000000 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ /dev/null @@ -1,58 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::match_type; -use clippy_utils::{match_def_path, paths}; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV. - /// - pub MISSING_MSRV_ATTR_IMPL, - internal, - "checking if all necessary steps were taken when adding a MSRV to a lint" -} - -declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]); - -impl LateLintPass<'_> for MsrvAttrImpl { - fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if let hir::ItemKind::Impl(hir::Impl { - of_trait: Some(_), - items, - .. - }) = &item.kind - && let Some(trait_ref) = cx - .tcx - .impl_trait_ref(item.owner_id) - .map(EarlyBinder::instantiate_identity) - && match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS) - && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() - && self_ty_def.is_struct() - && self_ty_def.all_fields().any(|f| { - cx.tcx - .type_of(f.did) - .instantiate_identity() - .walk() - .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) - .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV_STACK)) - }) - && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") - { - let span = cx.sess().source_map().span_through_char(item.span, '{'); - span_lint_and_sugg( - cx, - MISSING_MSRV_ATTR_IMPL, - span, - "`extract_msrv_attr!` macro missing from `EarlyLintPass` implementation", - "add `extract_msrv_attr!()` to the `EarlyLintPass` implementation", - format!("{}\n extract_msrv_attr!();", snippet(cx, span, "..")), - Applicability::MachineApplicable, - ); - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs deleted file mode 100644 index 326e1721461..00000000000 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ /dev/null @@ -1,59 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::match_type; -use clippy_utils::{is_lint_allowed, method_calls, paths}; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `cx.outer().expn_data()` and suggests to use - /// the `cx.outer_expn_data()` - /// - /// ### Why is this bad? - /// `cx.outer_expn_data()` is faster and more concise. - /// - /// ### Example - /// ```rust,ignore - /// expr.span.ctxt().outer().expn_data() - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// expr.span.ctxt().outer_expn_data() - /// ``` - pub OUTER_EXPN_EXPN_DATA, - internal, - "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`" -} - -declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]); - -impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) { - return; - } - - let (method_names, arg_lists, spans) = method_calls(expr, 2); - let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); - if let ["expn_data", "outer_expn"] = method_names.as_slice() - && let (self_arg, args) = arg_lists[1] - && args.is_empty() - && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() - && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT) - { - span_lint_and_sugg( - cx, - OUTER_EXPN_EXPN_DATA, - spans[1].with_hi(expr.span.hi()), - "usage of `outer_expn().expn_data()`", - "try", - "outer_expn_data()".to_string(), - Applicability::MachineApplicable, - ); - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/produce_ice.rs b/clippy_lints/src/utils/internal_lints/produce_ice.rs deleted file mode 100644 index 2bcb7b8ef14..00000000000 --- a/clippy_lints/src/utils/internal_lints/produce_ice.rs +++ /dev/null @@ -1,41 +0,0 @@ -use rustc_ast::ast::NodeId; -use rustc_ast::visit::FnKind; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::declare_lint_pass; -use rustc_span::Span; - -declare_clippy_lint! { - /// ### What it does - /// Not an actual lint. This lint is only meant for testing our customized internal compiler - /// error message by calling `panic`. - /// - /// ### Why is this bad? - /// ICE in large quantities can damage your teeth - /// - /// ### Example - /// ```rust,ignore - /// 🍦🍦🍦🍦🍦 - /// ``` - pub PRODUCE_ICE, - internal, - "this message should not appear anywhere as we ICE before and don't emit the lint" -} - -declare_lint_pass!(ProduceIce => [PRODUCE_ICE]); - -impl EarlyLintPass for ProduceIce { - fn check_fn(&mut self, ctx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { - if is_trigger_fn(fn_kind) { - ctx.sess() - .dcx() - .span_delayed_bug(span, "Would you like some help with that?"); - } - } -} - -fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { - match fn_kind { - FnKind::Fn(_, _, func) => func.ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy", - FnKind::Closure(..) => false, - } -} diff --git a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs deleted file mode 100644 index b8bcb9b3756..00000000000 --- a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; - -declare_clippy_lint! { - /// ### What it does - /// - /// Detects symbol comparison using `Symbol::intern`. - /// - /// ### Why is this bad? - /// - /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused. - /// - /// ### Example - /// - /// None, see suggestion. - pub SLOW_SYMBOL_COMPARISONS, - internal, - "detects slow comparisons of symbol" -} - -declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); - -fn check_slow_comparison<'tcx>( - cx: &LateContext<'tcx>, - op1: &'tcx Expr<'tcx>, - op2: &'tcx Expr<'tcx>, -) -> Option<(Span, String)> { - if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) - && let ExprKind::Call(fun, args) = op2.kind - && let ExprKind::Path(ref qpath) = fun.kind - && cx - .tcx - .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?) - && let [symbol_name_expr] = args - && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) - { - Some((op1.span, symbol_name)) - } else { - None - } -} - -impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if let ExprKind::Binary(op, left, right) = expr.kind - && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) - && let Some((symbol_span, symbol_name)) = - check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left)) - { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - SLOW_SYMBOL_COMPARISONS, - expr.span, - "comparing `Symbol` via `Symbol::intern`", - "use `Symbol::as_str` and check the string instead", - format!( - "{}.as_str() {} \"{symbol_name}\"", - snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability), - op.node.as_str() - ), - applicability, - ); - } - } -} diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs deleted file mode 100644 index 3790805df35..00000000000 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ /dev/null @@ -1,301 +0,0 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs}; -use rustc_ast::ast::LitKind; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::ConstValue; -use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; -use rustc_middle::ty::{self, Ty}; -use rustc_session::impl_lint_pass; -use rustc_span::Span; -use rustc_span::symbol::Symbol; - -use std::str; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. - /// - /// ### Why is this bad? - /// The path for an item is subject to change and is less efficient to look up than a - /// diagnostic item or a `LangItem`. - /// - /// ### Example - /// ```rust,ignore - /// utils::match_type(cx, ty, &paths::VEC) - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) - /// ``` - pub UNNECESSARY_DEF_PATH, - internal, - "using a def path when a diagnostic item or a `LangItem` is available" -} - -impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); - -#[derive(Default)] -pub struct UnnecessaryDefPath { - array_def_ids: FxIndexSet<(DefId, Span)>, - linted_def_ids: FxHashSet, -} - -impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { - return; - } - - match expr.kind { - ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span), - ExprKind::Array(elements) => self.check_array(cx, elements, expr.span), - _ => {}, - } - } - - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for &(def_id, span) in &self.array_def_ids { - if self.linted_def_ids.contains(&def_id) { - continue; - } - - let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) { - ("diagnostic item", format!("sym::{sym}")) - } else if let Some(sym) = get_lang_item_name(cx, def_id) { - ("language item", format!("LangItem::{sym}")) - } else { - continue; - }; - - span_lint_and_help( - cx, - UNNECESSARY_DEF_PATH, - span, - format!("hardcoded path to a {msg}"), - None, - format!("convert all references to use `{sugg}`"), - ); - } - } -} - -impl UnnecessaryDefPath { - #[allow(clippy::too_many_lines)] - fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) { - enum Item { - LangItem(&'static str), - DiagnosticItem(Symbol), - } - static PATHS: &[&[&str]] = &[ - &["clippy_utils", "match_def_path"], - &["clippy_utils", "match_trait_method"], - &["clippy_utils", "ty", "match_type"], - &["clippy_utils", "is_expr_path_def_path"], - ]; - - if let [cx_arg, def_arg, args @ ..] = args - && let ExprKind::Path(path) = &func.kind - && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && let Some(which_path) = match_any_def_paths(cx, id, PATHS) - && let item_arg = if which_path == 4 { &args[1] } else { &args[0] } - // Extract the path to the matched type - && let Some(segments) = path_to_matched_type(cx, item_arg) - && let segments = segments.iter().map(|sym| &**sym).collect::>() - && let Some(def_id) = def_path_def_ids(cx.tcx, &segments[..]).next() - { - // Check if the target item is a diagnostic item or LangItem. - #[rustfmt::skip] - let (msg, item) = if let Some(item_name) - = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) - { - ( - "use of a def path to a diagnostic item", - Item::DiagnosticItem(*item_name), - ) - } else if let Some(item_name) = get_lang_item_name(cx, def_id) { - ( - "use of a def path to a `LangItem`", - Item::LangItem(item_name), - ) - } else { - return; - }; - - let has_ctor = match cx.tcx.def_kind(def_id) { - DefKind::Struct => { - let variant = cx.tcx.adt_def(def_id).non_enum_variant(); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - DefKind::Variant => { - let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - _ => false, - }; - - let mut app = Applicability::MachineApplicable; - let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); - let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); - let (sugg, with_note) = match (which_path, item) { - // match_def_path - (0, Item::DiagnosticItem(item)) => ( - format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), - has_ctor, - ), - (0, Item::LangItem(item)) => ( - format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"), - has_ctor, - ), - // match_trait_method - (1, Item::DiagnosticItem(item)) => { - (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) - }, - // match_type - (2, Item::DiagnosticItem(item)) => ( - format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (2, Item::LangItem(item)) => ( - format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), - false, - ), - // is_expr_path_def_path - (3, Item::DiagnosticItem(item)) if has_ctor => ( - format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), - false, - ), - (3, Item::LangItem(item)) if has_ctor => ( - format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), - false, - ), - (3, Item::DiagnosticItem(item)) => ( - format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (3, Item::LangItem(item)) => ( - format!( - "path_res({cx_snip}, {def_snip}).opt_def_id()\ - .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))", - ), - false, - ), - _ => return, - }; - - span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { - diag.span_suggestion(span, "try", sugg, app); - if with_note { - diag.help( - "if this `DefId` came from a constructor expression or pattern then the \ - parent `DefId` should be used instead", - ); - } - }); - - self.linted_def_ids.insert(def_id); - } - } - - fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) { - let Some(path) = path_from_array(elements) else { return }; - - for def_id in def_path_def_ids(cx.tcx, &path.iter().map(AsRef::as_ref).collect::>()) { - self.array_def_ids.insert((def_id, span)); - } - } -} - -fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option> { - match peel_hir_expr_refs(expr).0.kind { - ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { - Res::Local(hir_id) => { - if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { - path_to_matched_type(cx, init) - } else { - None - } - }, - Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path( - cx, - cx.tcx.eval_static_initializer(def_id).ok()?.inner(), - cx.tcx.type_of(def_id).instantiate_identity(), - ), - Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { - ConstValue::Indirect { alloc_id, offset } if offset.bytes() == 0 => { - let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory(); - read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity()) - }, - _ => None, - }, - _ => None, - }, - ExprKind::Array(exprs) => path_from_array(exprs), - _ => None, - } -} - -fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option> { - let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { - let &alloc = alloc.provenance().ptrs().values().next()?; - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { - (alloc.inner(), ty) - } else { - return None; - } - } else { - (alloc, ty) - }; - - if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind() - && let ty::Ref(_, ty, Mutability::Not) = *ty.kind() - && ty.is_str() - { - alloc - .provenance() - .ptrs() - .values() - .map(|&alloc| { - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { - let alloc = alloc.inner(); - str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) - .ok() - .map(ToOwned::to_owned) - } else { - None - } - }) - .collect() - } else { - None - } -} - -fn path_from_array(exprs: &[Expr<'_>]) -> Option> { - exprs - .iter() - .map(|expr| { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Str(sym, _) = lit.node - { - return Some((*sym.as_str()).to_owned()); - } - - None - }) - .collect() -} - -fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> { - if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) { - Some(lang_item.variant_name()) - } else { - None - } -} diff --git a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs deleted file mode 100644 index bf60df5119d..00000000000 --- a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs +++ /dev/null @@ -1,52 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast::{Crate, ItemKind, ModKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::declare_lint_pass; - -declare_clippy_lint! { - /// ### What it does - /// Checks that [`clippy_utils::paths`] is sorted lexically - /// - /// ### Why is this bad? - /// We like to pretend we're an example of tidy code. - /// - /// ### Example - /// Wrong ordering of the util::paths constants. - pub UNSORTED_CLIPPY_UTILS_PATHS, - internal, - "various things that will negatively affect your clippy experience" -} - -declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); - -impl EarlyLintPass for UnsortedClippyUtilsPaths { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { - if let Some(utils) = krate - .items - .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) - && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind - && let Some(paths) = items - .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) - && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind - { - let mut last_name: Option = None; - for item in items { - let name = item.kind.ident().expect("const items have idents").to_string(); - if let Some(last_name) = last_name - && *last_name > *name - { - span_lint( - cx, - UNSORTED_CLIPPY_UTILS_PATHS, - item.span, - "this constant should be before the previous constant due to lexical \ - ordering", - ); - } - last_name = Some(name); - } - } - } -} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4476cd1005e..16066dd96c0 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -2,6 +2,3 @@ pub mod attr_collector; pub mod author; pub mod dump_hir; pub mod format_args_collector; - -#[cfg(feature = "internal")] -pub mod internal_lints; diff --git a/clippy_lints_internal/Cargo.toml b/clippy_lints_internal/Cargo.toml new file mode 100644 index 00000000000..2a0ceac27a3 --- /dev/null +++ b/clippy_lints_internal/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "clippy_lints_internal" +version = "0.0.1" +edition = "2021" + +[dependencies] +clippy_config = { path = "../clippy_config" } +clippy_utils = { path = "../clippy_utils" } +regex = { version = "1.5" } +rustc-semver = "1.1" + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true diff --git a/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs new file mode 100644 index 00000000000..4fd5ea459a5 --- /dev/null +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -0,0 +1,87 @@ +use crate::lint_without_lint_pass::is_lint_ref_type; +use clippy_utils::diagnostics::span_lint_and_help; +use regex::Regex; +use rustc_hir::{Attribute, Item, ItemKind, Mutability}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::impl_lint_pass; + +declare_tool_lint! { + /// ### What it does + /// Checks if lint formulations have a standardized format. + /// + /// ### Why is this bad? + /// It's not necessarily bad, but we try to enforce a standard in Clippy. + /// + /// ### Example + /// `Checks for use...` can be written as `Checks for usage...` . + pub clippy::ALMOST_STANDARD_LINT_FORMULATION, + Warn, + "lint formulations must have a standardized format.", + report_in_external_macro: true +} + +impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]); + +pub struct AlmostStandardFormulation { + standard_formulations: Vec>, +} + +#[derive(Debug)] +struct StandardFormulations<'a> { + wrong_pattern: Regex, + correction: &'a str, +} + +impl AlmostStandardFormulation { + pub fn new() -> Self { + let standard_formulations = vec![StandardFormulations { + wrong_pattern: Regex::new("^(Check for|Detects? uses?)").unwrap(), + correction: "Checks for", + }]; + Self { standard_formulations } + } +} + +impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let mut check_next = false; + if let ItemKind::Static(_, ty, Mutability::Not, _) = item.kind { + let lines = cx + .tcx + .hir_attrs(item.hir_id()) + .iter() + .filter_map(|attr| Attribute::doc_str(attr).map(|sym| (sym, attr))); + if is_lint_ref_type(cx, ty) { + for (line, attr) in lines { + let cur_line = line.as_str().trim(); + if check_next && !cur_line.is_empty() { + for formulation in &self.standard_formulations { + let starts_with_correct_formulation = cur_line.starts_with(formulation.correction); + if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) { + if let Some(ident) = attr.ident() { + span_lint_and_help( + cx, + ALMOST_STANDARD_LINT_FORMULATION, + ident.span, + "non-standard lint formulation", + None, + format!("consider using `{}`", formulation.correction), + ); + } + return; + } + } + return; + } else if cur_line.contains("What it does") { + check_next = true; + } else if cur_line.contains("Why is this bad") { + // Formulation documentation is done. Can add check to ensure that missing formulation is added + // and add a check if it matches no accepted formulation + return; + } + } + } + } + } +} diff --git a/clippy_lints_internal/src/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_calls.rs new file mode 100644 index 00000000000..d7967a0cc02 --- /dev/null +++ b/clippy_lints_internal/src/collapsible_calls.rs @@ -0,0 +1,250 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; +use rustc_errors::Applicability; +use rustc_hir::{Closure, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +use std::borrow::{Borrow, Cow}; + +declare_tool_lint! { + /// ### What it does + /// Lints `span_lint_and_then` function calls, where the + /// closure argument has only one statement and that statement is a method + /// call to `span_suggestion`, `span_help`, `span_note` (using the same + /// span), `help` or `note`. + /// + /// These usages of `span_lint_and_then` should be replaced with one of the + /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or + /// `span_lint_and_note`. + /// + /// ### Why is this bad? + /// Using the wrapper `span_lint_and_*` functions, is more + /// convenient, readable and less error prone. + /// + /// ### Example + /// ```rust,ignore + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_suggestion( + /// expr.span, + /// help_msg, + /// sugg.to_string(), + /// Applicability::MachineApplicable, + /// ); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_help(expr.span, help_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.help(help_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.span_note(expr.span, note_msg); + /// }); + /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { + /// diag.note(note_msg); + /// }); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// span_lint_and_sugg( + /// cx, + /// TEST_LINT, + /// expr.span, + /// lint_msg, + /// help_msg, + /// sugg.to_string(), + /// Applicability::MachineApplicable, + /// ); + /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg); + /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg); + /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg); + /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg); + /// ``` + pub clippy::COLLAPSIBLE_SPAN_LINT_CALLS, + Warn, + "found collapsible `span_lint_and_then` calls", + report_in_external_macro: true +} + +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); + +impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) { + return; + } + + if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind + && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]) + && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind + && let body = cx.tcx.hir_body(body) + && let only_expr = peel_blocks_with_stmt(body.value) + && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind + && let ExprKind::Path(..) = recv.kind + { + let and_then_snippets = + get_and_then_snippets(cx, call_cx.span, call_lint.span, call_sp.span, call_msg.span); + let mut sle = SpanlessEq::new(cx).deny_side_effects(); + match ps.ident.as_str() { + "span_suggestion" if sle.eq_expr(call_sp, &span_call_args[0]) => { + suggest_suggestion( + cx, + expr, + &and_then_snippets, + &span_suggestion_snippets(cx, span_call_args), + ); + }, + "span_help" if sle.eq_expr(call_sp, &span_call_args[0]) => { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); + }, + "span_note" if sle.eq_expr(call_sp, &span_call_args[0]) => { + let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); + }, + "help" => { + let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); + }, + "note" => { + let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); + }, + _ => (), + } + } + } +} + +struct AndThenSnippets<'a> { + cx: Cow<'a, str>, + lint: Cow<'a, str>, + span: Cow<'a, str>, + msg: Cow<'a, str>, +} + +fn get_and_then_snippets( + cx: &LateContext<'_>, + cx_span: Span, + lint_span: Span, + span_span: Span, + msg_span: Span, +) -> AndThenSnippets<'static> { + let cx_snippet = snippet(cx, cx_span, "cx"); + let lint_snippet = snippet(cx, lint_span, ".."); + let span_snippet = snippet(cx, span_span, "span"); + let msg_snippet = snippet(cx, msg_span, r#""...""#); + + AndThenSnippets { + cx: cx_snippet, + lint: lint_snippet, + span: span_snippet, + msg: msg_snippet, + } +} + +struct SpanSuggestionSnippets<'a> { + help: Cow<'a, str>, + sugg: Cow<'a, str>, + applicability: Cow<'a, str>, +} + +fn span_suggestion_snippets<'a, 'hir>( + cx: &LateContext<'_>, + span_call_args: &'hir [Expr<'hir>], +) -> SpanSuggestionSnippets<'a> { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); + let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); + + SpanSuggestionSnippets { + help: help_snippet, + sugg: sugg_snippet, + applicability: applicability_snippet, + } +} + +fn suggest_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + span_suggestion_snippets: &SpanSuggestionSnippets<'_>, +) { + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})", + and_then_snippets.cx, + and_then_snippets.lint, + and_then_snippets.span, + and_then_snippets.msg, + span_suggestion_snippets.help, + span_suggestion_snippets.sugg, + span_suggestion_snippets.applicability + ), + Applicability::MachineApplicable, + ); +} + +fn suggest_help( + cx: &LateContext<'_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + help: &str, + with_span: bool, +) { + let option_span = if with_span { + format!("Some({})", and_then_snippets.span) + } else { + "None".to_string() + }; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_help({}, {}, {}, {}, {}, {help})", + and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span, + ), + Applicability::MachineApplicable, + ); +} + +fn suggest_note( + cx: &LateContext<'_>, + expr: &Expr<'_>, + and_then_snippets: &AndThenSnippets<'_>, + note: &str, + with_span: bool, +) { + let note_span = if with_span { + format!("Some({})", and_then_snippets.span) + } else { + "None".to_string() + }; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_SPAN_LINT_CALLS, + expr.span, + "this call is collapsible", + "collapse into", + format!( + "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})", + and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, + ), + Applicability::MachineApplicable, + ); +} diff --git a/clippy_lints_internal/src/interning_defined_symbol.rs b/clippy_lints_internal/src/interning_defined_symbol.rs new file mode 100644 index 00000000000..831e8876330 --- /dev/null +++ b/clippy_lints_internal/src/interning_defined_symbol.rs @@ -0,0 +1,244 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::match_type; +use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::mir::ConstValue; +use rustc_middle::ty; +use rustc_session::impl_lint_pass; +use rustc_span::sym; +use rustc_span::symbol::Symbol; + +use std::borrow::Cow; + +declare_tool_lint! { + /// ### What it does + /// Checks for interning symbols that have already been pre-interned and defined as constants. + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. + /// + /// ### Example + /// ```rust,ignore + /// let _ = sym!(f32); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// let _ = sym::f32; + /// ``` + pub clippy::INTERNING_DEFINED_SYMBOL, + Warn, + "interning a symbol that is pre-interned and defined as a constant", + report_in_external_macro: true +} + +declare_tool_lint! { + /// ### What it does + /// Checks for unnecessary conversion from Symbol to a string. + /// + /// ### Why is this bad? + /// It's faster use symbols directly instead of strings. + /// + /// ### Example + /// ```rust,ignore + /// symbol.as_str() == "clippy"; + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// symbol == sym::clippy; + /// ``` + pub clippy::UNNECESSARY_SYMBOL_STR, + Warn, + "unnecessary conversion between Symbol and string", + report_in_external_macro: true +} + +#[derive(Default)] +pub struct InterningDefinedSymbol { + // Maps the symbol value to the constant DefId. + symbol_map: FxHashMap, +} + +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); + +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { + fn check_crate(&mut self, cx: &LateContext<'_>) { + if !self.symbol_map.is_empty() { + return; + } + + for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { + for def_id in def_path_def_ids(cx.tcx, module) { + for item in cx.tcx.module_children(def_id) { + if let Res::Def(DefKind::Const, item_def_id) = item.res + && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() + && match_type(cx, ty, &paths::SYMBOL) + && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) + && let Some(value) = value.to_u32().discard_err() + { + self.symbol_map.insert(value, item_def_id); + } + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(func, [arg]) = &expr.kind + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() + && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) + && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + && let value = Symbol::intern(&arg).as_u32() + && let Some(&def_id) = self.symbol_map.get(&value) + { + span_lint_and_sugg( + cx, + INTERNING_DEFINED_SYMBOL, + is_expn_of(expr.span, "sym").unwrap_or(expr.span), + "interning a defined symbol", + "try", + cx.tcx.def_path_str(def_id), + Applicability::MachineApplicable, + ); + } + if let ExprKind::Binary(op, left, right) = expr.kind + && matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) + { + let data = [ + (left, self.symbol_str_expr(left, cx)), + (right, self.symbol_str_expr(right, cx)), + ]; + match data { + // both operands are a symbol string + [(_, Some(left)), (_, Some(right))] => { + span_lint_and_sugg( + cx, + UNNECESSARY_SYMBOL_STR, + expr.span, + "unnecessary `Symbol` to string conversion", + "try", + format!( + "{} {} {}", + left.as_symbol_snippet(cx), + op.node.as_str(), + right.as_symbol_snippet(cx), + ), + Applicability::MachineApplicable, + ); + }, + // one of the operands is a symbol string + [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => { + // creating an owned string for comparison + if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) { + span_lint_and_sugg( + cx, + UNNECESSARY_SYMBOL_STR, + expr.span, + "unnecessary string allocation", + "try", + format!("{}.as_str()", symbol.as_symbol_snippet(cx)), + Applicability::MachineApplicable, + ); + } + }, + // nothing found + [(_, None), (_, None)] => {}, + } + } + } +} + +impl InterningDefinedSymbol { + fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option> { + static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; + static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; + let call = if let ExprKind::AddrOf(_, _, e) = expr.kind + && let ExprKind::Unary(UnOp::Deref, e) = e.kind + { + e + } else { + expr + }; + if let ExprKind::MethodCall(_, item, [], _) = call.kind + // is a method call + && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) + && let ty = cx.typeck_results().expr_ty(item) + // ...on either an Ident or a Symbol + && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { + Some(false) + } else if match_type(cx, ty, &paths::IDENT) { + Some(true) + } else { + None + } + // ...which converts it to a string + && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS } + && let Some(is_to_owned) = paths + .iter() + .find_map(|path| if match_def_path(cx, did, path) { + Some(path == &paths::SYMBOL_TO_IDENT_STRING) + } else { + None + }) + .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) { + Some(true) + } else { + None + }) + { + return Some(SymbolStrExpr::Expr { + item, + is_ident, + is_to_owned, + }); + } + // is a string constant + if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) { + let value = Symbol::intern(&s).as_u32(); + // ...which matches a symbol constant + if let Some(&def_id) = self.symbol_map.get(&value) { + return Some(SymbolStrExpr::Const(def_id)); + } + } + None + } +} + +enum SymbolStrExpr<'tcx> { + /// a string constant with a corresponding symbol constant + Const(DefId), + /// a "symbol to string" expression like `symbol.as_str()` + Expr { + /// part that evaluates to `Symbol` or `Ident` + item: &'tcx Expr<'tcx>, + is_ident: bool, + /// whether an owned `String` is created like `to_ident_string()` + is_to_owned: bool, + }, +} + +impl<'tcx> SymbolStrExpr<'tcx> { + /// Returns a snippet that evaluates to a `Symbol` and is const if possible + fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> { + match *self { + Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(), + Self::Expr { item, is_ident, .. } => { + let mut snip = snippet(cx, item.span.source_callsite(), ".."); + if is_ident { + // get `Ident.name` + snip.to_mut().push_str(".name"); + } + snip + }, + } + } +} diff --git a/clippy_lints_internal/src/invalid_paths.rs b/clippy_lints_internal/src/invalid_paths.rs new file mode 100644 index 00000000000..bee87efa3fc --- /dev/null +++ b/clippy_lints_internal/src/invalid_paths.rs @@ -0,0 +1,108 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::def_path_res; +use clippy_utils::diagnostics::span_lint; +use rustc_hir as hir; +use rustc_hir::Item; +use rustc_hir::def::DefKind; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::ty::fast_reject::SimplifiedType; +use rustc_middle::ty::{self, FloatTy}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Symbol; + +declare_tool_lint! { + /// ### What it does + /// Checks the paths module for invalid paths. + /// + /// ### Why is this bad? + /// It indicates a bug in the code. + /// + /// ### Example + /// None. + pub clippy::INVALID_PATHS, + Warn, + "invalid path", + report_in_external_macro: true +} + +declare_lint_pass!(InvalidPaths => [INVALID_PATHS]); + +impl<'tcx> LateLintPass<'tcx> for InvalidPaths { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let local_def_id = &cx.tcx.parent_module(item.hir_id()); + let mod_name = &cx.tcx.item_name(local_def_id.to_def_id()); + if mod_name.as_str() == "paths" + && let hir::ItemKind::Const(.., body_id) = item.kind + && let Some(Constant::Vec(path)) = ConstEvalCtxt::with_env( + cx.tcx, + ty::TypingEnv::post_analysis(cx.tcx, item.owner_id), + cx.tcx.typeck(item.owner_id), + ) + .eval_simple(cx.tcx.hir_body(body_id).value) + && let Some(path) = path + .iter() + .map(|x| { + if let Constant::Str(s) = x { + Some(s.as_str()) + } else { + None + } + }) + .collect::>>() + && !check_path(cx, &path[..]) + { + span_lint(cx, INVALID_PATHS, item.span, "invalid path"); + } + } +} + +// This is not a complete resolver for paths. It works on all the paths currently used in the paths +// module. That's all it does and all it needs to do. +pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { + if !def_path_res(cx.tcx, path).is_empty() { + return true; + } + + // Some implementations can't be found by `path_to_res`, particularly inherent + // implementations of native types. Check lang items. + let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect(); + let lang_items = cx.tcx.lang_items(); + // This list isn't complete, but good enough for our current list of paths. + let incoherent_impls = [ + SimplifiedType::Float(FloatTy::F32), + SimplifiedType::Float(FloatTy::F64), + SimplifiedType::Slice, + SimplifiedType::Str, + SimplifiedType::Bool, + SimplifiedType::Char, + ] + .iter() + .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter()) + .copied(); + for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { + let lang_item_path = cx.get_def_path(item_def_id); + if path_syms.starts_with(&lang_item_path) + && let [item] = &path_syms[lang_item_path.len()..] + { + if matches!( + cx.tcx.def_kind(item_def_id), + DefKind::Mod | DefKind::Enum | DefKind::Trait + ) { + for child in cx.tcx.module_children(item_def_id) { + if child.ident.name == *item { + return true; + } + } + } else { + for child in cx.tcx.associated_item_def_ids(item_def_id) { + if cx.tcx.item_name(*child) == *item { + return true; + } + } + } + } + } + + false +} diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs new file mode 100644 index 00000000000..1e59a93dc9e --- /dev/null +++ b/clippy_lints_internal/src/lib.rs @@ -0,0 +1,78 @@ +#![feature(let_chains, rustc_private)] +#![allow( + clippy::missing_docs_in_private_items, + clippy::must_use_candidate, + rustc::diagnostic_outside_of_impl, + rustc::untranslatable_diagnostic +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications, + rustc::internal +)] +// Disable this rustc lint for now, as it was also done in rustc +#![allow(rustc::potential_query_instability)] +// None of these lints need a version. +#![allow(clippy::missing_clippy_version_attribute)] + +extern crate rustc_ast; +extern crate rustc_attr_parsing; +extern crate rustc_data_structures; +extern crate rustc_errors; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_lint_defs; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; + +mod almost_standard_lint_formulation; +mod collapsible_calls; +mod interning_defined_symbol; +mod invalid_paths; +mod lint_without_lint_pass; +mod msrv_attr_impl; +mod outer_expn_data_pass; +mod produce_ice; +mod slow_symbol_comparisons; +mod unnecessary_def_path; +mod unsorted_clippy_utils_paths; + +use rustc_lint::{Lint, LintStore}; + +static LINTS: &[&Lint] = &[ + almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, + collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, + interning_defined_symbol::INTERNING_DEFINED_SYMBOL, + interning_defined_symbol::UNNECESSARY_SYMBOL_STR, + invalid_paths::INVALID_PATHS, + lint_without_lint_pass::DEFAULT_LINT, + lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, + lint_without_lint_pass::LINT_WITHOUT_LINT_PASS, + lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE, + msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, + outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, + produce_ice::PRODUCE_ICE, + slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS, + unnecessary_def_path::UNNECESSARY_DEF_PATH, + unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, +]; + +pub fn register_lints(store: &mut LintStore) { + store.register_lints(LINTS); + + store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); + store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); + store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); + store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); + store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); + store.register_late_pass(|_| Box::new(slow_symbol_comparisons::SlowSymbolComparisons)); +} diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs new file mode 100644 index 00000000000..6a75defcce3 --- /dev/null +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -0,0 +1,282 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::{is_lint_allowed, match_def_path, paths}; +use rustc_ast::ast::LitKind; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::hir_id::CRATE_HIR_ID; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::hir::nested_filter; +use rustc_session::impl_lint_pass; +use rustc_span::source_map::Spanned; +use rustc_span::symbol::Symbol; +use rustc_span::{Span, sym}; + +declare_tool_lint! { + /// ### What it does + /// Ensures every lint is associated to a `LintPass`. + /// + /// ### Why is this bad? + /// The compiler only knows lints via a `LintPass`. Without + /// putting a lint to a `LintPass::lint_vec()`'s return, the compiler will not + /// know the name of the lint. + /// + /// ### Known problems + /// Only checks for lints associated using the `declare_lint_pass!` and + /// `impl_lint_pass!` macros. + /// + /// ### Example + /// ```rust,ignore + /// declare_lint! { pub LINT_1, ... } + /// declare_lint! { pub LINT_2, ... } + /// declare_lint! { pub FORGOTTEN_LINT, ... } + /// // ... + /// declare_lint_pass!(Pass => [LINT_1, LINT_2]); + /// // missing FORGOTTEN_LINT + /// ``` + pub clippy::LINT_WITHOUT_LINT_PASS, + Warn, + "declaring a lint without associating it in a LintPass", + report_in_external_macro: true + +} + +declare_tool_lint! { + /// ### What it does + /// Checks for cases of an auto-generated lint without an updated description, + /// i.e. `default lint description`. + /// + /// ### Why is this bad? + /// Indicates that the lint is not finished. + /// + /// ### Example + /// ```rust,ignore + /// declare_lint! { pub COOL_LINT, nursery, "default lint description" } + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" } + /// ``` + pub clippy::DEFAULT_LINT, + Warn, + "found 'default lint description' in a lint declaration", + report_in_external_macro: true +} + +declare_tool_lint! { + /// ### What it does + /// Checks for invalid `clippy::version` attributes. + /// + /// Valid values are: + /// * "pre 1.29.0" + /// * any valid semantic version + pub clippy::INVALID_CLIPPY_VERSION_ATTRIBUTE, + Warn, + "found an invalid `clippy::version` attribute", + report_in_external_macro: true +} + +declare_tool_lint! { + /// ### What it does + /// Checks for declared clippy lints without the `clippy::version` attribute. + pub clippy::MISSING_CLIPPY_VERSION_ATTRIBUTE, + Warn, + "found clippy lint without `clippy::version` attribute", + report_in_external_macro: true +} + +#[derive(Clone, Debug, Default)] +pub struct LintWithoutLintPass { + declared_lints: FxIndexMap, + registered_lints: FxIndexSet, +} + +impl_lint_pass!(LintWithoutLintPass => [ + DEFAULT_LINT, + LINT_WITHOUT_LINT_PASS, + INVALID_CLIPPY_VERSION_ATTRIBUTE, + MISSING_CLIPPY_VERSION_ATTRIBUTE, +]); + +impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind { + if is_lint_ref_type(cx, ty) { + check_invalid_clippy_version_attribute(cx, item); + + let expr = &cx.tcx.hir_body(body_id).value; + let fields = if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind + && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind + { + struct_fields + } else { + return; + }; + + let field = fields + .iter() + .find(|f| f.ident.as_str() == "desc") + .expect("lints must have a description field"); + + if let ExprKind::Lit(Spanned { + node: LitKind::Str(sym, _), + .. + }) = field.expr.kind + { + let sym_str = sym.as_str(); + if sym_str == "default lint description" { + span_lint( + cx, + DEFAULT_LINT, + item.span, + format!("the lint `{}` has the default lint description", ident.name), + ); + } + self.declared_lints.insert(ident.name, item.span); + } + } + } else if let Some(macro_call) = root_macro_call_first_node(cx, item) { + if !matches!( + cx.tcx.item_name(macro_call.def_id).as_str(), + "impl_lint_pass" | "declare_lint_pass" + ) { + return; + } + if let hir::ItemKind::Impl(hir::Impl { + of_trait: None, + items: impl_item_refs, + .. + }) = item.kind + { + let mut collector = LintCollector { + output: &mut self.registered_lints, + cx, + }; + let body = cx.tcx.hir_body_owned_by( + impl_item_refs + .iter() + .find(|iiref| iiref.ident.as_str() == "lint_vec") + .expect("LintPass needs to implement lint_vec") + .id + .owner_id + .def_id, + ); + collector.visit_expr(body.value); + } + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) { + return; + } + + for (lint_name, &lint_span) in &self.declared_lints { + // When using the `declare_tool_lint!` macro, the original `lint_span`'s + // file points to "". + // `compiletest-rs` thinks that's an error in a different file and + // just ignores it. This causes the test in compile-fail/lint_pass + // not able to capture the error. + // Therefore, we need to climb the macro expansion tree and find the + // actual span that invoked `declare_tool_lint!`: + let lint_span = lint_span.ctxt().outer_expn_data().call_site; + + if !self.registered_lints.contains(lint_name) { + span_lint( + cx, + LINT_WITHOUT_LINT_PASS, + lint_span, + format!("the lint `{lint_name}` is not added to any `LintPass`"), + ); + } + } + } +} + +pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { + if let TyKind::Ref( + _, + MutTy { + ty: inner, + mutbl: Mutability::Not, + }, + ) = ty.kind + && let TyKind::Path(ref path) = inner.kind + && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) + { + return match_def_path(cx, def_id, &paths::LINT); + } + + false +} + +fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) { + if let Some(value) = extract_clippy_version_value(cx, item) { + if value.as_str() == "pre 1.29.0" { + return; + } + + if rustc_attr_parsing::parse_version(value).is_none() { + span_lint_and_help( + cx, + INVALID_CLIPPY_VERSION_ATTRIBUTE, + item.span, + "this item has an invalid `clippy::version` attribute", + None, + "please use a valid semantic version, see `doc/adding_lints.md`", + ); + } + } else { + span_lint_and_help( + cx, + MISSING_CLIPPY_VERSION_ATTRIBUTE, + item.span, + "this lint is missing the `clippy::version` attribute or version value", + None, + "please use a `clippy::version` attribute, see `doc/adding_lints.md`", + ); + } +} + +/// This function extracts the version value of a `clippy::version` attribute if the given value has +/// one +pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option { + let attrs = cx.tcx.hir_attrs(item.hir_id()); + attrs.iter().find_map(|attr| { + if let hir::Attribute::Unparsed(attr_kind) = &attr + // Identify attribute + && let [tool_name, attr_name] = &attr_kind.path.segments[..] + && tool_name.name == sym::clippy + && attr_name.name == sym::version + && let Some(version) = attr.value_str() + { + Some(version) + } else { + None + } + }) +} + +struct LintCollector<'a, 'tcx> { + output: &'a mut FxIndexSet, + cx: &'a LateContext<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> { + type NestedFilter = nested_filter::All; + + fn visit_path(&mut self, path: &Path<'_>, _: HirId) { + if path.segments.len() == 1 { + self.output.insert(path.segments[0].ident.name); + } + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } +} diff --git a/clippy_lints_internal/src/msrv_attr_impl.rs b/clippy_lints_internal/src/msrv_attr_impl.rs new file mode 100644 index 00000000000..dda054546e2 --- /dev/null +++ b/clippy_lints_internal/src/msrv_attr_impl.rs @@ -0,0 +1,59 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::match_type; +use clippy_utils::{match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; +use rustc_session::declare_lint_pass; + +declare_tool_lint! { + /// ### What it does + /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV. + pub clippy::MISSING_MSRV_ATTR_IMPL, + Warn, + "checking if all necessary steps were taken when adding a MSRV to a lint", + report_in_external_macro: true +} + +declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]); + +impl LateLintPass<'_> for MsrvAttrImpl { + fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { + if let hir::ItemKind::Impl(hir::Impl { + of_trait: Some(_), + items, + .. + }) = &item.kind + && let Some(trait_ref) = cx + .tcx + .impl_trait_ref(item.owner_id) + .map(EarlyBinder::instantiate_identity) + && match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS) + && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() + && self_ty_def.is_struct() + && self_ty_def.all_fields().any(|f| { + cx.tcx + .type_of(f.did) + .instantiate_identity() + .walk() + .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) + .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV_STACK)) + }) + && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") + { + let span = cx.sess().source_map().span_through_char(item.span, '{'); + span_lint_and_sugg( + cx, + MISSING_MSRV_ATTR_IMPL, + span, + "`extract_msrv_attr!` macro missing from `EarlyLintPass` implementation", + "add `extract_msrv_attr!()` to the `EarlyLintPass` implementation", + format!("{}\n extract_msrv_attr!();", snippet(cx, span, "..")), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints_internal/src/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs new file mode 100644 index 00000000000..e9441964797 --- /dev/null +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -0,0 +1,61 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::match_type; +use clippy_utils::{is_lint_allowed, method_calls, paths}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Symbol; + +declare_tool_lint! { + /// ### What it does + /// Checks for calls to `cx.outer().expn_data()` and suggests to use + /// the `cx.outer_expn_data()` + /// + /// ### Why is this bad? + /// `cx.outer_expn_data()` is faster and more concise. + /// + /// ### Example + /// ```rust,ignore + /// expr.span.ctxt().outer().expn_data() + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// expr.span.ctxt().outer_expn_data() + /// ``` + pub clippy::OUTER_EXPN_EXPN_DATA, + Warn, + "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`", + report_in_external_macro: true +} + +declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]); + +impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) { + return; + } + + let (method_names, arg_lists, spans) = method_calls(expr, 2); + let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); + if let ["expn_data", "outer_expn"] = method_names.as_slice() + && let (self_arg, args) = arg_lists[1] + && args.is_empty() + && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() + && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT) + { + span_lint_and_sugg( + cx, + OUTER_EXPN_EXPN_DATA, + spans[1].with_hi(expr.span.hi()), + "usage of `outer_expn().expn_data()`", + "try", + "outer_expn_data()".to_string(), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints_internal/src/produce_ice.rs b/clippy_lints_internal/src/produce_ice.rs new file mode 100644 index 00000000000..14e93dc6d5f --- /dev/null +++ b/clippy_lints_internal/src/produce_ice.rs @@ -0,0 +1,43 @@ +use rustc_ast::ast::NodeId; +use rustc_ast::visit::FnKind; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_tool_lint! { + /// ### What it does + /// Not an actual lint. This lint is only meant for testing our customized internal compiler + /// error message by calling `panic`. + /// + /// ### Why is this bad? + /// ICE in large quantities can damage your teeth + /// + /// ### Example + /// ```rust,ignore + /// 🍦🍦🍦🍦🍦 + /// ``` + pub clippy::PRODUCE_ICE, + Warn, + "this message should not appear anywhere as we ICE before and don't emit the lint", + report_in_external_macro: true +} + +declare_lint_pass!(ProduceIce => [PRODUCE_ICE]); + +impl EarlyLintPass for ProduceIce { + fn check_fn(&mut self, ctx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { + if is_trigger_fn(fn_kind) { + ctx.sess() + .dcx() + .span_delayed_bug(span, "Would you like some help with that?"); + } + } +} + +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { + match fn_kind { + FnKind::Fn(_, _, func) => func.ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy", + FnKind::Closure(..) => false, + } +} diff --git a/clippy_lints_internal/src/slow_symbol_comparisons.rs b/clippy_lints_internal/src/slow_symbol_comparisons.rs new file mode 100644 index 00000000000..6776366a23b --- /dev/null +++ b/clippy_lints_internal/src/slow_symbol_comparisons.rs @@ -0,0 +1,76 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; +use rustc_span::{Span, sym}; + +declare_tool_lint! { + /// ### What it does + /// + /// Detects symbol comparison using `Symbol::intern`. + /// + /// ### Why is this bad? + /// + /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused. + /// + /// ### Example + /// + /// None, see suggestion. + pub clippy::SLOW_SYMBOL_COMPARISONS, + Warn, + "detects slow comparisons of symbol", + report_in_external_macro: true +} + +declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); + +fn check_slow_comparison<'tcx>( + cx: &LateContext<'tcx>, + op1: &'tcx Expr<'tcx>, + op2: &'tcx Expr<'tcx>, +) -> Option<(Span, String)> { + if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) + && let ExprKind::Call(fun, args) = op2.kind + && let ExprKind::Path(ref qpath) = fun.kind + && cx + .tcx + .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?) + && let [symbol_name_expr] = args + && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) + { + Some((op1.span, symbol_name)) + } else { + None + } +} + +impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Binary(op, left, right) = expr.kind + && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) + && let Some((symbol_span, symbol_name)) = + check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left)) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + SLOW_SYMBOL_COMPARISONS, + expr.span, + "comparing `Symbol` via `Symbol::intern`", + "use `Symbol::as_str` and check the string instead", + format!( + "{}.as_str() {} \"{symbol_name}\"", + snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability), + op.node.as_str() + ), + applicability, + ); + } + } +} diff --git a/clippy_lints_internal/src/unnecessary_def_path.rs b/clippy_lints_internal/src/unnecessary_def_path.rs new file mode 100644 index 00000000000..6bdfbed55b0 --- /dev/null +++ b/clippy_lints_internal/src/unnecessary_def_path.rs @@ -0,0 +1,303 @@ +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs}; +use rustc_ast::ast::LitKind; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::impl_lint_pass; +use rustc_span::Span; +use rustc_span::symbol::Symbol; + +use std::str; + +declare_tool_lint! { + /// ### What it does + /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. + /// + /// ### Why is this bad? + /// The path for an item is subject to change and is less efficient to look up than a + /// diagnostic item or a `LangItem`. + /// + /// ### Example + /// ```rust,ignore + /// utils::match_type(cx, ty, &paths::VEC) + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) + /// ``` + pub clippy::UNNECESSARY_DEF_PATH, + Warn, + "using a def path when a diagnostic item or a `LangItem` is available", + report_in_external_macro: true +} + +impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); + +#[derive(Default)] +pub struct UnnecessaryDefPath { + array_def_ids: FxIndexSet<(DefId, Span)>, + linted_def_ids: FxHashSet, +} + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { + return; + } + + match expr.kind { + ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span), + ExprKind::Array(elements) => self.check_array(cx, elements, expr.span), + _ => {}, + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + for &(def_id, span) in &self.array_def_ids { + if self.linted_def_ids.contains(&def_id) { + continue; + } + + let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) { + ("diagnostic item", format!("sym::{sym}")) + } else if let Some(sym) = get_lang_item_name(cx, def_id) { + ("language item", format!("LangItem::{sym}")) + } else { + continue; + }; + + span_lint_and_help( + cx, + UNNECESSARY_DEF_PATH, + span, + format!("hardcoded path to a {msg}"), + None, + format!("convert all references to use `{sugg}`"), + ); + } + } +} + +impl UnnecessaryDefPath { + #[allow(clippy::too_many_lines)] + fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) { + enum Item { + LangItem(&'static str), + DiagnosticItem(Symbol), + } + static PATHS: &[&[&str]] = &[ + &["clippy_utils", "match_def_path"], + &["clippy_utils", "match_trait_method"], + &["clippy_utils", "ty", "match_type"], + &["clippy_utils", "is_expr_path_def_path"], + ]; + + if let [cx_arg, def_arg, args @ ..] = args + && let ExprKind::Path(path) = &func.kind + && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && let Some(which_path) = match_any_def_paths(cx, id, PATHS) + && let item_arg = if which_path == 4 { &args[1] } else { &args[0] } + // Extract the path to the matched type + && let Some(segments) = path_to_matched_type(cx, item_arg) + && let segments = segments.iter().map(|sym| &**sym).collect::>() + && let Some(def_id) = def_path_def_ids(cx.tcx, &segments[..]).next() + { + // Check if the target item is a diagnostic item or LangItem. + #[rustfmt::skip] + let (msg, item) = if let Some(item_name) + = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) + { + ( + "use of a def path to a diagnostic item", + Item::DiagnosticItem(*item_name), + ) + } else if let Some(item_name) = get_lang_item_name(cx, def_id) { + ( + "use of a def path to a `LangItem`", + Item::LangItem(item_name), + ) + } else { + return; + }; + + let has_ctor = match cx.tcx.def_kind(def_id) { + DefKind::Struct => { + let variant = cx.tcx.adt_def(def_id).non_enum_variant(); + variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + }, + DefKind::Variant => { + let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); + variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + }, + _ => false, + }; + + let mut app = Applicability::MachineApplicable; + let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); + let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); + let (sugg, with_note) = match (which_path, item) { + // match_def_path + (0, Item::DiagnosticItem(item)) => ( + format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), + has_ctor, + ), + (0, Item::LangItem(item)) => ( + format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"), + has_ctor, + ), + // match_trait_method + (1, Item::DiagnosticItem(item)) => { + (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) + }, + // match_type + (2, Item::DiagnosticItem(item)) => ( + format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), + false, + ), + (2, Item::LangItem(item)) => ( + format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), + false, + ), + // is_expr_path_def_path + (3, Item::DiagnosticItem(item)) if has_ctor => ( + format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), + false, + ), + (3, Item::LangItem(item)) if has_ctor => ( + format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), + false, + ), + (3, Item::DiagnosticItem(item)) => ( + format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), + false, + ), + (3, Item::LangItem(item)) => ( + format!( + "path_res({cx_snip}, {def_snip}).opt_def_id()\ + .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))", + ), + false, + ), + _ => return, + }; + + span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { + diag.span_suggestion(span, "try", sugg, app); + if with_note { + diag.help( + "if this `DefId` came from a constructor expression or pattern then the \ + parent `DefId` should be used instead", + ); + } + }); + + self.linted_def_ids.insert(def_id); + } + } + + fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) { + let Some(path) = path_from_array(elements) else { return }; + + for def_id in def_path_def_ids(cx.tcx, &path.iter().map(AsRef::as_ref).collect::>()) { + self.array_def_ids.insert((def_id, span)); + } + } +} + +fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option> { + match peel_hir_expr_refs(expr).0.kind { + ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { + Res::Local(hir_id) => { + if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { + path_to_matched_type(cx, init) + } else { + None + } + }, + Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path( + cx, + cx.tcx.eval_static_initializer(def_id).ok()?.inner(), + cx.tcx.type_of(def_id).instantiate_identity(), + ), + Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { + ConstValue::Indirect { alloc_id, offset } if offset.bytes() == 0 => { + let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory(); + read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity()) + }, + _ => None, + }, + _ => None, + }, + ExprKind::Array(exprs) => path_from_array(exprs), + _ => None, + } +} + +fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option> { + let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { + let &alloc = alloc.provenance().ptrs().values().next()?; + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { + (alloc.inner(), ty) + } else { + return None; + } + } else { + (alloc, ty) + }; + + if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind() + && let ty::Ref(_, ty, Mutability::Not) = *ty.kind() + && ty.is_str() + { + alloc + .provenance() + .ptrs() + .values() + .map(|&alloc| { + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { + let alloc = alloc.inner(); + str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) + .ok() + .map(ToOwned::to_owned) + } else { + None + } + }) + .collect() + } else { + None + } +} + +fn path_from_array(exprs: &[Expr<'_>]) -> Option> { + exprs + .iter() + .map(|expr| { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(sym, _) = lit.node + { + return Some((*sym.as_str()).to_owned()); + } + + None + }) + .collect() +} + +fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> { + if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) { + Some(lang_item.variant_name()) + } else { + None + } +} diff --git a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs new file mode 100644 index 00000000000..8e281ecb2ee --- /dev/null +++ b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs @@ -0,0 +1,54 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::ast::{Crate, ItemKind, ModKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_session::declare_lint_pass; + +declare_tool_lint! { + /// ### What it does + /// Checks that [`clippy_utils::paths`] is sorted lexically + /// + /// ### Why is this bad? + /// We like to pretend we're an example of tidy code. + /// + /// ### Example + /// Wrong ordering of the util::paths constants. + pub clippy::UNSORTED_CLIPPY_UTILS_PATHS, + Warn, + "various things that will negatively affect your clippy experience", + report_in_external_macro: true +} + +declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]); + +impl EarlyLintPass for UnsortedClippyUtilsPaths { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { + if let Some(utils) = krate + .items + .iter() + .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) + && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind + && let Some(paths) = items + .iter() + .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) + && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind + { + let mut last_name: Option = None; + for item in items { + let name = item.kind.ident().expect("const items have idents").to_string(); + if let Some(last_name) = last_name + && *last_name > *name + { + span_lint( + cx, + UNSORTED_CLIPPY_UTILS_PATHS, + item.span, + "this constant should be before the previous constant due to lexical \ + ordering", + ); + } + last_name = Some(name); + } + } + } +} diff --git a/src/driver.rs b/src/driver.rs index c6b3c06baa4..7837ecbdb84 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -158,7 +158,8 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_config::Conf::read(sess, &conf_path); clippy_lints::register_lints(lint_store, conf); - clippy_lints::register_pre_expansion_lints(lint_store, conf); + #[cfg(feature = "internal")] + clippy_lints_internal::register_lints(lint_store); })); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 858be389a9e..ec3c01d5e6c 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -36,6 +36,7 @@ fn dogfood() { for package in [ "./", "clippy_dev", + "clippy_lints_internal", "clippy_lints", "clippy_utils", "clippy_config", @@ -81,10 +82,7 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { command.arg("--").args(args); command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir - if cfg!(feature = "internal") { - // internal lints only exist if we build with the internal feature - command.args(["-D", "clippy::internal"]); - } else { + if !cfg!(feature = "internal") { // running a clippy built without internal lints on the clippy source // that contains e.g. `allow(clippy::invalid_paths)` command.args(["-A", "unknown_lints"]); diff --git a/tests/ui-internal/auxiliary/paths.rs b/tests/ui-internal/auxiliary/paths.rs index 52fcaec4df3..f730f564a09 100644 --- a/tests/ui-internal/auxiliary/paths.rs +++ b/tests/ui-internal/auxiliary/paths.rs @@ -1,2 +1,4 @@ +#![allow(clippy::unnecessary_def_path)] + pub static OPTION: [&str; 3] = ["core", "option", "Option"]; pub const RESULT: &[&str] = &["core", "result", "Result"]; diff --git a/tests/ui-internal/check_clippy_version_attribute.rs b/tests/ui-internal/check_clippy_version_attribute.rs index e5f6001b74d..897002949e6 100644 --- a/tests/ui-internal/check_clippy_version_attribute.rs +++ b/tests/ui-internal/check_clippy_version_attribute.rs @@ -1,5 +1,5 @@ -#![deny(clippy::internal)] #![feature(rustc_private)] +#![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] #[macro_use] extern crate rustc_middle; @@ -86,6 +86,15 @@ mod internal_clippy_lints { } use crate::internal_clippy_lints::ALLOW_MISSING_ATTRIBUTE_ONE; -declare_lint_pass!(Pass2 => [VALID_ONE, VALID_TWO, VALID_THREE, INVALID_ONE, INVALID_TWO, MISSING_ATTRIBUTE_ONE, MISSING_ATTRIBUTE_TWO, ALLOW_MISSING_ATTRIBUTE_ONE]); +declare_lint_pass!(Pass2 => [ + VALID_ONE, + VALID_TWO, + VALID_THREE, + INVALID_ONE, + INVALID_TWO, + MISSING_ATTRIBUTE_ONE, + MISSING_ATTRIBUTE_TWO, + ALLOW_MISSING_ATTRIBUTE_ONE, +]); fn main() {} diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 1129c35d1d0..952bc944030 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -12,11 +12,10 @@ LL | | } | = help: please use a valid semantic version, see `doc/adding_lints.md` note: the lint level is defined here - --> tests/ui-internal/check_clippy_version_attribute.rs:1:9 + --> tests/ui-internal/check_clippy_version_attribute.rs:2:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute @@ -47,7 +46,11 @@ LL | | } | |_^ | = help: please use a `clippy::version` attribute, see `doc/adding_lints.md` - = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` +note: the lint level is defined here + --> tests/ui-internal/check_clippy_version_attribute.rs:2:51 + | +LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value diff --git a/tests/ui-internal/check_formulation.rs b/tests/ui-internal/check_formulation.rs index 8265a78769d..bcbb0d78319 100644 --- a/tests/ui-internal/check_formulation.rs +++ b/tests/ui-internal/check_formulation.rs @@ -1,4 +1,5 @@ -#![warn(clippy::almost_standard_lint_formulation)] +#![deny(clippy::almost_standard_lint_formulation)] +#![allow(clippy::lint_without_lint_pass)] #![feature(rustc_private)] #[macro_use] diff --git a/tests/ui-internal/check_formulation.stderr b/tests/ui-internal/check_formulation.stderr index b16e1bf8687..9aeb9e1f2d4 100644 --- a/tests/ui-internal/check_formulation.stderr +++ b/tests/ui-internal/check_formulation.stderr @@ -1,15 +1,18 @@ error: non-standard lint formulation - --> tests/ui-internal/check_formulation.rs:23:5 + --> tests/ui-internal/check_formulation.rs:24:5 | LL | /// Check for lint formulations that are correct | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using `Checks for` - = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]` +note: the lint level is defined here + --> tests/ui-internal/check_formulation.rs:1:9 + | +LL | #![deny(clippy::almost_standard_lint_formulation)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-standard lint formulation - --> tests/ui-internal/check_formulation.rs:34:5 + --> tests/ui-internal/check_formulation.rs:35:5 | LL | /// Detects uses of incorrect formulations | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index 918e33345a7..76f68686ee2 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::collapsible_span_lint_calls)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index 2f289ae2b48..214c8783a66 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::collapsible_span_lint_calls)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr index a2be1f1cd36..9c83538947c 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.stderr +++ b/tests/ui-internal/collapsible_span_lint_calls.stderr @@ -10,9 +10,8 @@ LL | | }); note: the lint level is defined here --> tests/ui-internal/collapsible_span_lint_calls.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::collapsible_span_lint_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call is collapsible --> tests/ui-internal/collapsible_span_lint_calls.rs:39:9 diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 71819fe3707..c7e92b1bf16 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -6,7 +6,7 @@ //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc running on " //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" -#![deny(clippy::internal)] +#![deny(clippy::produce_ice)] #![allow(clippy::missing_clippy_version_attribute)] fn it_looks_like_you_are_trying_to_kill_clippy() {} diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 589e1190a90..884d3d035a2 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -8,7 +8,7 @@ error: internal compiler error: Would you like some help with that? LL | fn it_looks_like_you_are_trying_to_kill_clippy() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: delayed at clippy_lints/src/utils/internal_lints/produce_ice.rs - disabled backtrace +note: delayed at clippy_lints_internal/src/produce_ice.rs - disabled backtrace --> tests/ui-internal/custom_ice_message.rs:12:1 | LL | fn it_looks_like_you_are_trying_to_kill_clippy() {} diff --git a/tests/ui-internal/default_lint.rs b/tests/ui-internal/default_lint.rs index 959bfd27e38..809f2c4d080 100644 --- a/tests/ui-internal/default_lint.rs +++ b/tests/ui-internal/default_lint.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::default_lint)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/default_lint.stderr b/tests/ui-internal/default_lint.stderr index 9d4c2e15349..2c700ec82dc 100644 --- a/tests/ui-internal/default_lint.stderr +++ b/tests/ui-internal/default_lint.stderr @@ -13,9 +13,8 @@ LL | | } note: the lint level is defined here --> tests/ui-internal/default_lint.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::default_lint)] + | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-internal/disallow_span_lint.rs b/tests/ui-internal/disallow_span_lint.rs index 3fed38cab64..36e4158f6e6 100644 --- a/tests/ui-internal/disallow_span_lint.rs +++ b/tests/ui-internal/disallow_span_lint.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![deny(clippy::disallowed_methods)] extern crate rustc_errors; extern crate rustc_hir; diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 9a7a7ecbbff..f03a745963e 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -1,15 +1,18 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` - --> tests/ui-internal/disallow_span_lint.rs:14:8 + --> tests/ui-internal/disallow_span_lint.rs:15:8 | LL | cx.span_lint(lint, span, |lint| { | ^^^^^^^^^ | = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead - = note: `-D clippy::disallowed-methods` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` +note: the lint level is defined here + --> tests/ui-internal/disallow_span_lint.rs:2:9 + | +LL | #![deny(clippy::disallowed_methods)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:21:9 + --> tests/ui-internal/disallow_span_lint.rs:22:9 | LL | tcx.node_span_lint(lint, hir_id, span, |lint| { | ^^^^^^^^^^^^^^ diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed index 92d3b1537e0..637deaa6de7 100644 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ b/tests/ui-internal/interning_defined_symbol.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::interning_defined_symbol)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs index d1e6f9cb1c4..63c476f6e20 100644 --- a/tests/ui-internal/interning_defined_symbol.rs +++ b/tests/ui-internal/interning_defined_symbol.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::interning_defined_symbol)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/interning_defined_symbol.stderr b/tests/ui-internal/interning_defined_symbol.stderr index c84a566436a..7002805a105 100644 --- a/tests/ui-internal/interning_defined_symbol.stderr +++ b/tests/ui-internal/interning_defined_symbol.stderr @@ -7,9 +7,8 @@ LL | let _ = Symbol::intern("f32"); note: the lint level is defined here --> tests/ui-internal/interning_defined_symbol.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::interning_defined_symbol)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: interning a defined symbol --> tests/ui-internal/interning_defined_symbol.rs:21:13 diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 6804e2bbae8..238ef9ae6d0 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::missing_msrv_attr_impl)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index c625a5d9a45..7753dcaad71 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::missing_msrv_attr_impl)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.stderr b/tests/ui-internal/invalid_msrv_attr_impl.stderr index 0a7636313ef..d5928d8c0c2 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.stderr +++ b/tests/ui-internal/invalid_msrv_attr_impl.stderr @@ -7,9 +7,8 @@ LL | impl EarlyLintPass for Pass { note: the lint level is defined here --> tests/ui-internal/invalid_msrv_attr_impl.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::missing_msrv_attr_impl)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::missing_msrv_attr_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `extract_msrv_attr!()` to the `EarlyLintPass` implementation | LL ~ impl EarlyLintPass for Pass { diff --git a/tests/ui-internal/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs index abfb111f938..7317abc2185 100644 --- a/tests/ui-internal/invalid_paths.rs +++ b/tests/ui-internal/invalid_paths.rs @@ -1,4 +1,4 @@ -#![warn(clippy::internal)] +#![deny(clippy::invalid_paths)] #![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)] mod paths { diff --git a/tests/ui-internal/invalid_paths.stderr b/tests/ui-internal/invalid_paths.stderr index 7bde37667be..7b7b25ce8d8 100644 --- a/tests/ui-internal/invalid_paths.stderr +++ b/tests/ui-internal/invalid_paths.stderr @@ -4,8 +4,11 @@ error: invalid path LL | pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::invalid-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::invalid_paths)]` +note: the lint level is defined here + --> tests/ui-internal/invalid_paths.rs:1:9 + | +LL | #![deny(clippy::invalid_paths)] + | ^^^^^^^^^^^^^^^^^^^^^ error: invalid path --> tests/ui-internal/invalid_paths.rs:19:5 diff --git a/tests/ui-internal/lint_without_lint_pass.rs b/tests/ui-internal/lint_without_lint_pass.rs index 69591523432..6b649132aca 100644 --- a/tests/ui-internal/lint_without_lint_pass.rs +++ b/tests/ui-internal/lint_without_lint_pass.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::lint_without_lint_pass)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/lint_without_lint_pass.stderr b/tests/ui-internal/lint_without_lint_pass.stderr index 9cca96ca160..3798293f4c1 100644 --- a/tests/ui-internal/lint_without_lint_pass.stderr +++ b/tests/ui-internal/lint_without_lint_pass.stderr @@ -13,9 +13,8 @@ LL | | } note: the lint level is defined here --> tests/ui-internal/lint_without_lint_pass.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::lint_without_lint_pass)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::lint_without_lint_pass)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-internal/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed index cb7680b8bb1..900ca5b2ab9 100644 --- a/tests/ui-internal/outer_expn_data.fixed +++ b/tests/ui-internal/outer_expn_data.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::outer_expn_expn_data)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs index 41d735110b5..bcfc42aa2ac 100644 --- a/tests/ui-internal/outer_expn_data.rs +++ b/tests/ui-internal/outer_expn_data.rs @@ -1,4 +1,4 @@ -#![deny(clippy::internal)] +#![deny(clippy::outer_expn_expn_data)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/outer_expn_data.stderr b/tests/ui-internal/outer_expn_data.stderr index 33ac91e4fb0..b86138a5d45 100644 --- a/tests/ui-internal/outer_expn_data.stderr +++ b/tests/ui-internal/outer_expn_data.stderr @@ -7,9 +7,8 @@ LL | let _ = expr.span.ctxt().outer_expn().expn_data(); note: the lint level is defined here --> tests/ui-internal/outer_expn_data.rs:1:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::outer_expn_expn_data)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::outer_expn_expn_data)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index 577fad9341b..89902ebe4e5 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -1,5 +1,5 @@ //@aux-build:paths.rs -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_def_path)] #![feature(rustc_private)] #![allow(clippy::unnecessary_map_or)] diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index d4deb3626d0..cfca15267c1 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,5 +1,5 @@ //@aux-build:paths.rs -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_def_path)] #![feature(rustc_private)] #![allow(clippy::unnecessary_map_or)] diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr index 0053ba321bb..d7fb4ea551e 100644 --- a/tests/ui-internal/unnecessary_def_path.stderr +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -7,9 +7,8 @@ LL | let _ = match_type(cx, ty, &OPTION); note: the lint level is defined here --> tests/ui-internal/unnecessary_def_path.rs:2:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::unnecessary_def_path)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a def path to a diagnostic item --> tests/ui-internal/unnecessary_def_path.rs:39:13 diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs index 4801d76bd26..bd7a55114ac 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] #![allow(unused)] -#![warn(clippy::unnecessary_def_path)] +#![deny(clippy::unnecessary_def_path)] extern crate rustc_hir; diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index ff4726de69a..c49abc516f5 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -5,8 +5,11 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: convert all references to use `sym::Deref` - = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]` +note: the lint level is defined here + --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:3:9 + | +LL | #![deny(clippy::unnecessary_def_path)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: hardcoded path to a language item --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:40 diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index dc564daef82..c81554b0235 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -1,5 +1,5 @@ #![feature(rustc_private)] -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_symbol_str)] #![allow( clippy::slow_symbol_comparisons, clippy::borrow_deref_ref, diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index d74262d1294..8d773cd738f 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -1,5 +1,5 @@ #![feature(rustc_private)] -#![deny(clippy::internal)] +#![deny(clippy::unnecessary_symbol_str)] #![allow( clippy::slow_symbol_comparisons, clippy::borrow_deref_ref, diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index 517a395e93f..81918303a73 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -7,9 +7,8 @@ LL | Symbol::intern("foo").as_str() == "clippy"; note: the lint level is defined here --> tests/ui-internal/unnecessary_symbol_str.rs:2:9 | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]` +LL | #![deny(clippy::unnecessary_symbol_str)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unnecessary `Symbol` to string conversion --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 -- cgit 1.4.1-3-g733a5 From b52bd96713d1a34b02017c0e272ebd15102885aa Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 18 Apr 2025 18:35:20 +0000 Subject: Replace interning of string literals with preinterned symbols --- book/src/development/common_tools_writing_lints.md | 10 +- clippy_lints/src/format_impl.rs | 16 +- clippy_lints/src/indexing_slicing.rs | 5 +- clippy_lints/src/len_zero.rs | 16 +- clippy_lints/src/loops/explicit_iter_loop.rs | 16 +- clippy_lints/src/manual_div_ceil.rs | 9 +- .../src/matches/redundant_pattern_match.rs | 16 +- clippy_lints/src/methods/filter_map.rs | 31 ++- clippy_lints/src/methods/iter_filter.rs | 8 +- clippy_lints/src/methods/or_fun_call.rs | 8 +- clippy_lints/src/methods/seek_from_current.rs | 5 +- .../src/methods/seek_to_start_instead_of_rewind.rs | 6 +- clippy_lints/src/rc_clone_in_vec_init.rs | 6 +- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/set_contains_or_insert.rs | 8 +- clippy_lints/src/strings.rs | 5 +- clippy_lints/src/unwrap.rs | 8 +- .../src/interning_defined_symbol.rs | 244 --------------------- clippy_lints_internal/src/interning_literals.rs | 102 +++++++++ clippy_lints_internal/src/lib.rs | 10 +- .../src/slow_symbol_comparisons.rs | 76 ------- clippy_utils/src/lib.rs | 3 - clippy_utils/src/msrvs.rs | 7 +- clippy_utils/src/paths.rs | 1 + clippy_utils/src/sym.rs | 52 ++++- clippy_utils/src/sym_helper.rs | 7 - src/driver.rs | 9 +- tests/ui-internal/interning_defined_symbol.fixed | 40 ---- tests/ui-internal/interning_defined_symbol.rs | 40 ---- tests/ui-internal/interning_defined_symbol.stderr | 32 --- tests/ui-internal/interning_literals.fixed | 31 +++ tests/ui-internal/interning_literals.rs | 31 +++ tests/ui-internal/interning_literals.stderr | 64 ++++++ tests/ui-internal/interning_literals_unfixable.rs | 16 ++ .../interning_literals_unfixable.stderr | 40 ++++ tests/ui-internal/slow_symbol_comparisons.fixed | 24 -- tests/ui-internal/slow_symbol_comparisons.rs | 24 -- tests/ui-internal/slow_symbol_comparisons.stderr | 23 -- tests/ui-internal/unnecessary_symbol_str.fixed | 26 --- tests/ui-internal/unnecessary_symbol_str.rs | 26 --- tests/ui-internal/unnecessary_symbol_str.stderr | 38 ---- 41 files changed, 428 insertions(+), 715 deletions(-) delete mode 100644 clippy_lints_internal/src/interning_defined_symbol.rs create mode 100644 clippy_lints_internal/src/interning_literals.rs delete mode 100644 clippy_lints_internal/src/slow_symbol_comparisons.rs delete mode 100644 clippy_utils/src/sym_helper.rs delete mode 100644 tests/ui-internal/interning_defined_symbol.fixed delete mode 100644 tests/ui-internal/interning_defined_symbol.rs delete mode 100644 tests/ui-internal/interning_defined_symbol.stderr create mode 100644 tests/ui-internal/interning_literals.fixed create mode 100644 tests/ui-internal/interning_literals.rs create mode 100644 tests/ui-internal/interning_literals.stderr create mode 100644 tests/ui-internal/interning_literals_unfixable.rs create mode 100644 tests/ui-internal/interning_literals_unfixable.stderr delete mode 100644 tests/ui-internal/slow_symbol_comparisons.fixed delete mode 100644 tests/ui-internal/slow_symbol_comparisons.rs delete mode 100644 tests/ui-internal/slow_symbol_comparisons.stderr delete mode 100644 tests/ui-internal/unnecessary_symbol_str.fixed delete mode 100644 tests/ui-internal/unnecessary_symbol_str.rs delete mode 100644 tests/ui-internal/unnecessary_symbol_str.stderr (limited to 'src') diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 051febc2ca5..2e39f279eae 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -159,19 +159,21 @@ paths for Clippy can be found in [paths.rs][paths] To check if our type defines a method called `some_method`: ```rust -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::return_ty; +use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{sym, return_ty}; impl<'tcx> LateLintPass<'tcx> for MyTypeImpl { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { // Check if item is a method/function if let ImplItemKind::Fn(ref signature, _) = impl_item.kind // Check the method is named `some_method` - && impl_item.ident.name.as_str() == "some_method" + // + // Add `some_method` to `clippy_utils::sym` if it's not already there + && impl_item.ident.name == sym::some_method // We can also check it has a parameter `self` && signature.decl.implicit_self.has_implicit_self() // We can go further and even check if its return type is `String` - && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)) + && is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String) { // ... } diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 5b42a40d850..0535ecf5240 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; -use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; +use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; use rustc_span::symbol::kw; -use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does @@ -185,13 +185,13 @@ impl FormatImplExpr<'_, '_> { && let trait_name = match placeholder.format_trait { FormatTrait::Display => sym::Display, FormatTrait::Debug => sym::Debug, - FormatTrait::LowerExp => sym!(LowerExp), - FormatTrait::UpperExp => sym!(UpperExp), - FormatTrait::Octal => sym!(Octal), + FormatTrait::LowerExp => sym::LowerExp, + FormatTrait::UpperExp => sym::UpperExp, + FormatTrait::Octal => sym::Octal, FormatTrait::Pointer => sym::Pointer, - FormatTrait::Binary => sym!(Binary), - FormatTrait::LowerHex => sym!(LowerHex), - FormatTrait::UpperHex => sym!(UpperHex), + FormatTrait::Binary => sym::Binary, + FormatTrait::LowerHex => sym::LowerHex, + FormatTrait::UpperHex => sym::UpperHex, } && trait_name == self.format_trait_impl.name && let Ok(index) = placeholder.argument.index diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index be801d43a52..99a393b4d53 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -2,13 +2,12 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; -use clippy_utils::{higher, is_from_proc_macro, is_in_test}; +use clippy_utils::{higher, is_from_proc_macro, is_in_test, sym}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -268,7 +267,7 @@ fn ty_has_applicable_get_function<'tcx>( index_expr: &Expr<'_>, ) -> bool { if let ty::Adt(_, _) = array_ty.kind() - && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| { + && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym::get).map(|m| { cx.tcx .fn_sig(m.def_id) .skip_binder() diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index c6cacbb6b6e..8c71d34c95f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators}; +use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -16,7 +16,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FnSig, Ty}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::sym; use rustc_span::{Ident, Span, Symbol}; use rustc_trait_selection::traits::supertrait_def_ids; @@ -295,11 +294,9 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden { let mut current_and_super_traits = DefIdSet::default(); fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); - let is_empty = sym!(is_empty); - let is_empty_method_found = current_and_super_traits .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) + .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); if !is_empty_method_found { @@ -472,12 +469,11 @@ fn check_for_is_empty( return; }; - let is_empty = Symbol::intern("is_empty"); let is_empty = cx .tcx .inherent_impls(impl_ty) .iter() - .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) + .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty)) .find(|item| item.is_fn()); let (msg, is_empty_span, self_kind) = match is_empty { @@ -633,11 +629,10 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { - let is_empty = sym!(is_empty); cx.tcx.inherent_impls(id).iter().any(|imp| { cx.tcx .associated_items(*imp) - .filter_by_name_unhygienic(is_empty) + .filter_by_name_unhygienic(sym::is_empty) .any(|item| is_is_empty(cx, item)) }) } @@ -645,10 +640,9 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool { match ty.kind() { ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { - let is_empty = sym!(is_empty); cx.tcx .associated_items(principal.def_id()) - .filter_by_name_unhygienic(is_empty) + .filter_by_name_unhygienic(sym::is_empty) .any(|item| is_is_empty(cx, item)) }), ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id), diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 412c78cc804..d0b26c91ffa 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -2,6 +2,7 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, make_normalized_projection_with_regions, normalize_with_regions, @@ -11,7 +12,6 @@ use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, EarlyBinder, Ty}; -use rustc_span::sym; pub(super) fn check( cx: &LateContext<'_>, @@ -119,7 +119,7 @@ fn is_ref_iterable<'tcx>( && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id) && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = - make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty]) + make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym::IntoIter, [req_self_ty]) && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty) && into_iter_ty == req_res_ty { @@ -152,7 +152,7 @@ fn is_ref_iterable<'tcx>( // Using by value won't consume anything if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::None, self_ty)); @@ -169,7 +169,7 @@ fn is_ref_iterable<'tcx>( }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::reborrow(mutbl), self_ty)); @@ -183,7 +183,7 @@ fn is_ref_iterable<'tcx>( let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl); if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty]) && ty == res_ty { return Some((AdjustKind::borrow(mutbl), self_ty)); @@ -206,7 +206,7 @@ fn is_ref_iterable<'tcx>( && target != self_ty && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::auto_reborrow(mutbl), target)) @@ -224,7 +224,7 @@ fn is_ref_iterable<'tcx>( if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::Deref, target)) @@ -242,7 +242,7 @@ fn is_ref_iterable<'tcx>( if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target]) && ty == res_ty { Some((AdjustKind::auto_borrow(mutbl), target)) diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 70db403e103..444ecd5d2bb 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,8 +1,9 @@ -use clippy_utils::SpanlessEq; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -11,9 +12,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; - -use clippy_config::Conf; declare_clippy_lint! { /// ### What it does @@ -141,8 +139,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.peel_refs().kind() { ty::Uint(_) => true, - ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")), - + ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings), _ => false, } } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index c4d51a5946e..db20be40f27 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,7 +4,7 @@ use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; -use clippy_utils::{higher, is_expn_of, is_trait_method}; +use clippy_utils::{higher, is_expn_of, is_trait_method, sym}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; @@ -12,7 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use std::fmt::Write; use std::ops::ControlFlow; @@ -138,9 +138,9 @@ fn find_method_and_type<'tcx>( Some(("is_some()", op_ty)) } else if Some(id) == lang_items.poll_ready_variant() { Some(("is_ready()", op_ty)) - } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V4)) { Some(("is_ipv4()", op_ty)) - } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) { + } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V6)) { Some(("is_ipv6()", op_ty)) } else { None @@ -345,8 +345,8 @@ fn found_good_method<'tcx>( arms, path_left, path_right, - Item::Diag(sym::IpAddr, sym!(V4)), - Item::Diag(sym::IpAddr, sym!(V6)), + Item::Diag(sym::IpAddr, sym::V4), + Item::Diag(sym::IpAddr, sym::V6), "is_ipv4()", "is_ipv6()", ) @@ -437,8 +437,8 @@ fn get_good_method<'tcx>( "None" => (Item::Lang(OptionNone), "is_none()", "is_some()"), "Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"), "Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"), - "V4" => (Item::Diag(sym::IpAddr, sym!(V4)), "is_ipv4()", "is_ipv6()"), - "V6" => (Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv6()", "is_ipv4()"), + "V4" => (Item::Diag(sym::IpAddr, sym::V4), "is_ipv4()", "is_ipv6()"), + "V6" => (Item::Diag(sym::IpAddr, sym::V6), "is_ipv6()", "is_ipv4()"), _ => return None, }; return find_good_method_for_matches_macro( diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index ae300cd5fe5..da123f13d46 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks}; +use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks, sym}; use hir::{Body, HirId, MatchSource, Pat}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -11,7 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol}; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; @@ -43,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool } fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { - is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_some) } fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { - is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok)) + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_ok) } #[derive(Debug, Copy, Clone)] @@ -429,16 +429,15 @@ fn is_find_or_filter<'a>( } fn acceptable_methods(method: &PathSegment<'_>) -> bool { - let methods: [Symbol; 8] = [ - sym::clone, - sym::as_ref, - sym!(copied), - sym!(cloned), - sym!(as_deref), - sym!(as_mut), - sym!(as_deref_mut), - sym!(to_owned), - ]; - - methods.contains(&method.ident.name) + matches!( + method.ident.name, + sym::clone + | sym::as_ref + | sym::copied + | sym::cloned + | sym::as_deref + | sym::as_mut + | sym::as_deref_mut + | sym::to_owned + ) } diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index bafabec7e06..adeff375c8a 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -6,12 +6,12 @@ use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::QPath; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol}; /// /// Returns true if the expression is a method call to `method_name` @@ -154,7 +154,7 @@ fn expression_type( if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Option) && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder() && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def() - && is_method(cx, filter_arg, sym::Option, sym!(is_some), &[]) + && is_method(cx, filter_arg, sym::Option, sym::is_some, &[]) { return Some(FilterType::IsSome); } @@ -162,7 +162,7 @@ fn expression_type( if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Result) && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder() && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def() - && is_method(cx, filter_arg, sym::Result, sym!(is_ok), &[]) + && is_method(cx, filter_arg, sym::Result, sym::is_ok, &[]) { return Some(FilterType::IsOk); } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 72a5a525bbc..b78b082e460 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -6,13 +6,13 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, + contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, sym, }; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use rustc_span::symbol::{self, Symbol, sym}; +use rustc_span::symbol::{self, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; @@ -66,8 +66,8 @@ pub(super) fn check<'tcx>( }; let sugg = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default), - ("or_insert", true) | ("or_insert_with", false) => sym!(or_default), + ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default, + ("or_insert", true) | ("or_insert_with", false) => sym::or_default, _ => return false, }; diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index 96180862fd0..8b51268da46 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -3,12 +3,11 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_enum_variant_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_enum_variant_ctor, sym}; use super::SEEK_FROM_CURRENT; @@ -38,7 +37,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Call(f, [arg]) = expr.kind && let ExprKind::Path(ref path) = f.kind && let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id() - && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id) + && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Current, ctor_call_id) // check if argument of `SeekFrom::Current` is `0` && let ExprKind::Lit(lit) = arg.kind && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7b1dd9e58c5..b8405a78f23 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; +use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified, sym}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::SEEK_TO_START_INSTEAD_OF_REWIND; @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(func, [arg]) = arg.kind && let ExprKind::Path(ref path) = func.kind && let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id) + && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Start, ctor_call_id) && let ExprKind::Lit(lit) = arg.kind && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 6bb7650a7e1..689a2ac4c6a 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -1,14 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::last_path_segment; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::{last_path_segment, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -135,7 +135,7 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) { - return Some((Symbol::intern("Weak"), func.span)); + return Some((sym::Weak, func.span)); } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 4df173e1d16..834ff2af0e8 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths}; +use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths, sym}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Regex { // // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only // perform the operation once and store the results - let regex_crates = find_crates(cx.tcx, sym!(regex)); + let regex_crates = find_crates(cx.tcx, sym::regex); let mut resolve = |path: &[&str], kind: RegexKind| { for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { if let Some(id) = res.opt_def_id() { diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index 1185d67b125..ff6e6ef214b 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while}; +use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while, sym}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for SetContainsOrInsert { then: then_expr, .. }) = higher::If::hir(expr) - && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr) + && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym::contains)//try_parse_contains(cx, cond_expr) && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr) { span_lint( @@ -118,7 +118,7 @@ fn find_insert_calls<'tcx>( expr: &'tcx Expr<'_>, ) -> Option> { for_each_expr(cx, expr, |e| { - if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym!(insert)) + if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert) && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index dd819510f84..43a3e696105 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, path_def_id, - peel_blocks, + peel_blocks, sym, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -12,7 +12,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::sym; use std::ops::ControlFlow; @@ -262,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind && let ExprKind::Index(left, right, _) = args.kind && let (method_names, expressions, _) = method_calls(left, 1) - && method_names == [sym!(as_bytes)] + && method_names == [sym::as_bytes] && expressions.len() == 1 && expressions[0].1.is_empty() diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index b466a8e127a..ce82b56eb94 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; -use clippy_utils::{higher, path_to_local}; +use clippy_utils::{higher, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; @@ -11,8 +11,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -307,8 +307,8 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg) && let Some(id) = path_to_local(self_arg) - && [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name) - && let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name) + && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err) + && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect) && let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.local_id == id) // Span contexts should not differ with the conditional branch diff --git a/clippy_lints_internal/src/interning_defined_symbol.rs b/clippy_lints_internal/src/interning_defined_symbol.rs deleted file mode 100644 index 831e8876330..00000000000 --- a/clippy_lints_internal/src/interning_defined_symbol.rs +++ /dev/null @@ -1,244 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_middle::mir::ConstValue; -use rustc_middle::ty; -use rustc_session::impl_lint_pass; -use rustc_span::sym; -use rustc_span::symbol::Symbol; - -use std::borrow::Cow; - -declare_tool_lint! { - /// ### What it does - /// Checks for interning symbols that have already been pre-interned and defined as constants. - /// - /// ### Why is this bad? - /// It's faster and easier to use the symbol constant. - /// - /// ### Example - /// ```rust,ignore - /// let _ = sym!(f32); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// let _ = sym::f32; - /// ``` - pub clippy::INTERNING_DEFINED_SYMBOL, - Warn, - "interning a symbol that is pre-interned and defined as a constant", - report_in_external_macro: true -} - -declare_tool_lint! { - /// ### What it does - /// Checks for unnecessary conversion from Symbol to a string. - /// - /// ### Why is this bad? - /// It's faster use symbols directly instead of strings. - /// - /// ### Example - /// ```rust,ignore - /// symbol.as_str() == "clippy"; - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// symbol == sym::clippy; - /// ``` - pub clippy::UNNECESSARY_SYMBOL_STR, - Warn, - "unnecessary conversion between Symbol and string", - report_in_external_macro: true -} - -#[derive(Default)] -pub struct InterningDefinedSymbol { - // Maps the symbol value to the constant DefId. - symbol_map: FxHashMap, -} - -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); - -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if !self.symbol_map.is_empty() { - return; - } - - for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - for def_id in def_path_def_ids(cx.tcx, module) { - for item in cx.tcx.module_children(def_id) { - if let Res::Def(DefKind::Const, item_def_id) = item.res - && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() - && match_type(cx, ty, &paths::SYMBOL) - && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) - && let Some(value) = value.to_u32().discard_err() - { - self.symbol_map.insert(value, item_def_id); - } - } - } - } - } - - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Call(func, [arg]) = &expr.kind - && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() - && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) - && let value = Symbol::intern(&arg).as_u32() - && let Some(&def_id) = self.symbol_map.get(&value) - { - span_lint_and_sugg( - cx, - INTERNING_DEFINED_SYMBOL, - is_expn_of(expr.span, "sym").unwrap_or(expr.span), - "interning a defined symbol", - "try", - cx.tcx.def_path_str(def_id), - Applicability::MachineApplicable, - ); - } - if let ExprKind::Binary(op, left, right) = expr.kind - && matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) - { - let data = [ - (left, self.symbol_str_expr(left, cx)), - (right, self.symbol_str_expr(right, cx)), - ]; - match data { - // both operands are a symbol string - [(_, Some(left)), (_, Some(right))] => { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary `Symbol` to string conversion", - "try", - format!( - "{} {} {}", - left.as_symbol_snippet(cx), - op.node.as_str(), - right.as_symbol_snippet(cx), - ), - Applicability::MachineApplicable, - ); - }, - // one of the operands is a symbol string - [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => { - // creating an owned string for comparison - if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) { - span_lint_and_sugg( - cx, - UNNECESSARY_SYMBOL_STR, - expr.span, - "unnecessary string allocation", - "try", - format!("{}.as_str()", symbol.as_symbol_snippet(cx)), - Applicability::MachineApplicable, - ); - } - }, - // nothing found - [(_, None), (_, None)] => {}, - } - } - } -} - -impl InterningDefinedSymbol { - fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option> { - static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; - static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; - let call = if let ExprKind::AddrOf(_, _, e) = expr.kind - && let ExprKind::Unary(UnOp::Deref, e) = e.kind - { - e - } else { - expr - }; - if let ExprKind::MethodCall(_, item, [], _) = call.kind - // is a method call - && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) - && let ty = cx.typeck_results().expr_ty(item) - // ...on either an Ident or a Symbol - && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { - Some(false) - } else if match_type(cx, ty, &paths::IDENT) { - Some(true) - } else { - None - } - // ...which converts it to a string - && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS } - && let Some(is_to_owned) = paths - .iter() - .find_map(|path| if match_def_path(cx, did, path) { - Some(path == &paths::SYMBOL_TO_IDENT_STRING) - } else { - None - }) - .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) { - Some(true) - } else { - None - }) - { - return Some(SymbolStrExpr::Expr { - item, - is_ident, - is_to_owned, - }); - } - // is a string constant - if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) { - let value = Symbol::intern(&s).as_u32(); - // ...which matches a symbol constant - if let Some(&def_id) = self.symbol_map.get(&value) { - return Some(SymbolStrExpr::Const(def_id)); - } - } - None - } -} - -enum SymbolStrExpr<'tcx> { - /// a string constant with a corresponding symbol constant - Const(DefId), - /// a "symbol to string" expression like `symbol.as_str()` - Expr { - /// part that evaluates to `Symbol` or `Ident` - item: &'tcx Expr<'tcx>, - is_ident: bool, - /// whether an owned `String` is created like `to_ident_string()` - is_to_owned: bool, - }, -} - -impl<'tcx> SymbolStrExpr<'tcx> { - /// Returns a snippet that evaluates to a `Symbol` and is const if possible - fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> { - match *self { - Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(), - Self::Expr { item, is_ident, .. } => { - let mut snip = snippet(cx, item.span.source_callsite(), ".."); - if is_ident { - // get `Ident.name` - snip.to_mut().push_str(".name"); - } - snip - }, - } - } -} diff --git a/clippy_lints_internal/src/interning_literals.rs b/clippy_lints_internal/src/interning_literals.rs new file mode 100644 index 00000000000..6cee3744234 --- /dev/null +++ b/clippy_lints_internal/src/interning_literals.rs @@ -0,0 +1,102 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::match_type; +use clippy_utils::{def_path_def_ids, paths}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::mir::ConstValue; +use rustc_middle::ty; +use rustc_session::impl_lint_pass; +use rustc_span::sym; +use rustc_span::symbol::Symbol; + +declare_tool_lint! { + /// ### What it does + /// Checks for interning string literals as symbols + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs` + /// + /// ### Example + /// ```rust,ignore + /// let _ = Symbol::intern("f32"); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// let _ = sym::f32; + /// ``` + pub clippy::INTERNING_LITERALS, + Warn, + "interning a symbol that is a literal", + report_in_external_macro: true +} + +#[derive(Default)] +pub struct InterningDefinedSymbol { + // Maps the symbol to the import path + symbol_map: FxHashMap, +} + +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]); + +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { + fn check_crate(&mut self, cx: &LateContext<'_>) { + let modules = [ + ("kw", &paths::KW_MODULE[..]), + ("sym", &paths::SYM_MODULE), + ("sym", &paths::CLIPPY_SYM_MODULE), + ]; + for (prefix, module) in modules { + for def_id in def_path_def_ids(cx.tcx, module) { + // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will + // still lint but the suggestion will say to add it to `sym.rs` even if it's already there + if def_id.is_local() { + continue; + } + + for item in cx.tcx.module_children(def_id) { + if let Res::Def(DefKind::Const, item_def_id) = item.res + && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() + && match_type(cx, ty, &paths::SYMBOL) + && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) + && let Some(value) = value.to_u32().discard_err() + { + self.symbol_map.insert(value, (prefix, item.ident.name)); + } + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(func, [arg]) = &expr.kind + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() + && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) + && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + { + span_lint_and_then( + cx, + INTERNING_LITERALS, + expr.span, + "interning a string literal", + |diag| { + let value = Symbol::intern(&arg).as_u32(); + let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) { + ("use the preinterned symbol", format!("{prefix}::{name}")) + } else { + ( + "add the symbol to `clippy_utils/src/sym.rs` and use it", + format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")), + ) + }; + diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); + }, + ); + } + } +} diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index 1e59a93dc9e..1c42f4112f9 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -31,13 +31,12 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; -mod interning_defined_symbol; +mod interning_literals; mod invalid_paths; mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; -mod slow_symbol_comparisons; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -46,8 +45,7 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, - interning_defined_symbol::INTERNING_DEFINED_SYMBOL, - interning_defined_symbol::UNNECESSARY_SYMBOL_STR, + interning_literals::INTERNING_LITERALS, invalid_paths::INVALID_PATHS, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -56,7 +54,6 @@ static LINTS: &[&Lint] = &[ msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, produce_ice::PRODUCE_ICE, - slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS, unnecessary_def_path::UNNECESSARY_DEF_PATH, unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, ]; @@ -68,11 +65,10 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); - store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); - store.register_late_pass(|_| Box::new(slow_symbol_comparisons::SlowSymbolComparisons)); } diff --git a/clippy_lints_internal/src/slow_symbol_comparisons.rs b/clippy_lints_internal/src/slow_symbol_comparisons.rs deleted file mode 100644 index 6776366a23b..00000000000 --- a/clippy_lints_internal/src/slow_symbol_comparisons.rs +++ /dev/null @@ -1,76 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; - -declare_tool_lint! { - /// ### What it does - /// - /// Detects symbol comparison using `Symbol::intern`. - /// - /// ### Why is this bad? - /// - /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused. - /// - /// ### Example - /// - /// None, see suggestion. - pub clippy::SLOW_SYMBOL_COMPARISONS, - Warn, - "detects slow comparisons of symbol", - report_in_external_macro: true -} - -declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); - -fn check_slow_comparison<'tcx>( - cx: &LateContext<'tcx>, - op1: &'tcx Expr<'tcx>, - op2: &'tcx Expr<'tcx>, -) -> Option<(Span, String)> { - if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) - && let ExprKind::Call(fun, args) = op2.kind - && let ExprKind::Path(ref qpath) = fun.kind - && cx - .tcx - .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?) - && let [symbol_name_expr] = args - && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) - { - Some((op1.span, symbol_name)) - } else { - None - } -} - -impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if let ExprKind::Binary(op, left, right) = expr.kind - && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) - && let Some((symbol_span, symbol_name)) = - check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left)) - { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - SLOW_SYMBOL_COMPARISONS, - expr.span, - "comparing `Symbol` via `Symbol::intern`", - "use `Symbol::as_str` and check the string instead", - format!( - "{}.as_str() {} \"{symbol_name}\"", - snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability), - op.node.as_str() - ), - applicability, - ); - } - } -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 52cd2905654..2bcd5b49bbe 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -51,9 +51,6 @@ extern crate rustc_span; extern crate rustc_trait_selection; extern crate smallvec; -#[macro_use] -pub mod sym_helper; - pub mod ast_utils; pub mod attrs; mod check_proc_macro; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index c2aca5ee539..19061b574ff 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,10 +1,10 @@ +use crate::sym; use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; - use rustc_attr_parsing::{RustcVersion, parse_version}; use rustc_lint::LateContext; use rustc_session::Session; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use serde::Deserialize; use smallvec::SmallVec; use std::iter::once; @@ -184,8 +184,7 @@ impl MsrvStack { } fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option { - let sym_msrv = Symbol::intern("msrv"); - let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); + let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv])); if let Some(msrv_attr) = msrv_attrs.next() { if let Some(duplicate) = msrv_attrs.next_back() { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index a960a65ead2..7f64ebd3b64 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -34,6 +34,7 @@ pub const ALIGN_OF: [&str; 3] = ["core", "mem", "align_of"]; // Paths in clippy itself pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"]; +pub const CLIPPY_SYM_MODULE: [&str; 2] = ["clippy_utils", "sym"]; // Paths in external crates #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 1df150472e0..1a30b473d10 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -2,22 +2,68 @@ use rustc_span::symbol::{PREDEFINED_SYMBOLS_COUNT, Symbol}; +#[doc(no_inline)] pub use rustc_span::sym::*; +macro_rules! val { + ($name:ident) => { + stringify!($name) + }; + ($name:ident $value:literal) => { + $value + }; +} + macro_rules! generate { - ($($sym:ident,)*) => { + ($($name:ident $(: $value:literal)? ,)*) => { /// To be supplied to `rustc_interface::Config` pub const EXTRA_SYMBOLS: &[&str] = &[ - $(stringify!($sym),)* + $( + val!($name $($value)?), + )* ]; $( - pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); + pub const $name: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); )* }; } generate! { + as_bytes, + as_deref_mut, + as_deref, + as_mut, + Binary, + Cargo_toml: "Cargo.toml", + CLIPPY_ARGS, + CLIPPY_CONF_DIR, + cloned, + contains, + copied, + Current, + get, + insert, + int_roundings, + IntoIter, + is_empty, + is_ok, + is_some, + LowerExp, + LowerHex, + msrv, + Octal, + or_default, + regex, rustfmt_skip, + Start, + to_owned, unused_extern_crates, + unwrap_err, + unwrap_or_default, + UpperExp, + UpperHex, + V4, + V6, + Weak, } diff --git a/clippy_utils/src/sym_helper.rs b/clippy_utils/src/sym_helper.rs deleted file mode 100644 index f47dc80ebad..00000000000 --- a/clippy_utils/src/sym_helper.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[macro_export] -/// Convenience wrapper around rustc's `Symbol::intern` -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} diff --git a/src/driver.rs b/src/driver.rs index 9e88679831f..87ca9c5bedd 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -14,6 +14,7 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::sym; use rustc_interface::interface; use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; @@ -78,7 +79,7 @@ fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) { psess .env_depinfo .get_mut() - .insert((Symbol::intern("CLIPPY_ARGS"), args_env_var.map(Symbol::intern))); + .insert((sym::CLIPPY_ARGS, args_env_var.map(Symbol::intern))); } /// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy @@ -89,7 +90,7 @@ fn track_files(psess: &mut ParseSess) { // Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver` // with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine if Path::new("Cargo.toml").exists() { - file_depinfo.insert(Symbol::intern("Cargo.toml")); + file_depinfo.insert(sym::Cargo_toml); } // `clippy.toml` will be automatically tracked as it's loaded with `sess.source_map().load_file()` @@ -145,7 +146,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so // changes between dirs that are invalid UTF-8 will not trigger rebuilds psess.env_depinfo.get_mut().insert(( - Symbol::intern("CLIPPY_CONF_DIR"), + sym::CLIPPY_CONF_DIR, env::var("CLIPPY_CONF_DIR").ok().map(|dir| Symbol::intern(&dir)), )); })); @@ -161,7 +162,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { #[cfg(feature = "internal")] clippy_lints_internal::register_lints(lint_store); })); - config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into(); + config.extra_symbols = sym::EXTRA_SYMBOLS.into(); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be // run on the unoptimized MIR. On the other hand this results in some false negatives. If diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed deleted file mode 100644 index 637deaa6de7..00000000000 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(clippy::interning_defined_symbol)] -#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] -#![feature(rustc_private)] - -extern crate rustc_span; - -use rustc_span::symbol::Symbol; - -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} - -fn main() { - // Direct use of Symbol::intern - let _ = rustc_span::sym::f32; - //~^ interning_defined_symbol - - // Using a sym macro - let _ = rustc_span::sym::f32; - //~^ interning_defined_symbol - - // Correct suggestion when symbol isn't stringified constant name - let _ = rustc_span::sym::proc_dash_macro; - //~^ interning_defined_symbol - - // interning a keyword - let _ = rustc_span::kw::SelfLower; - //~^ interning_defined_symbol - - // Interning a symbol that is not defined - let _ = Symbol::intern("xyz123"); - let _ = sym!(xyz123); - - // Using a different `intern` function - let _ = intern("f32"); -} - -fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs deleted file mode 100644 index 63c476f6e20..00000000000 --- a/tests/ui-internal/interning_defined_symbol.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(clippy::interning_defined_symbol)] -#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] -#![feature(rustc_private)] - -extern crate rustc_span; - -use rustc_span::symbol::Symbol; - -macro_rules! sym { - ($tt:tt) => { - rustc_span::symbol::Symbol::intern(stringify!($tt)) - }; -} - -fn main() { - // Direct use of Symbol::intern - let _ = Symbol::intern("f32"); - //~^ interning_defined_symbol - - // Using a sym macro - let _ = sym!(f32); - //~^ interning_defined_symbol - - // Correct suggestion when symbol isn't stringified constant name - let _ = Symbol::intern("proc-macro"); - //~^ interning_defined_symbol - - // interning a keyword - let _ = Symbol::intern("self"); - //~^ interning_defined_symbol - - // Interning a symbol that is not defined - let _ = Symbol::intern("xyz123"); - let _ = sym!(xyz123); - - // Using a different `intern` function - let _ = intern("f32"); -} - -fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_defined_symbol.stderr b/tests/ui-internal/interning_defined_symbol.stderr deleted file mode 100644 index 7002805a105..00000000000 --- a/tests/ui-internal/interning_defined_symbol.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:17:13 - | -LL | let _ = Symbol::intern("f32"); - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32` - | -note: the lint level is defined here - --> tests/ui-internal/interning_defined_symbol.rs:1:9 - | -LL | #![deny(clippy::interning_defined_symbol)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:21:13 - | -LL | let _ = sym!(f32); - | ^^^^^^^^^ help: try: `rustc_span::sym::f32` - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:25:13 - | -LL | let _ = Symbol::intern("proc-macro"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro` - -error: interning a defined symbol - --> tests/ui-internal/interning_defined_symbol.rs:29:13 - | -LL | let _ = Symbol::intern("self"); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::kw::SelfLower` - -error: aborting due to 4 previous errors - diff --git a/tests/ui-internal/interning_literals.fixed b/tests/ui-internal/interning_literals.fixed new file mode 100644 index 00000000000..03e97768b99 --- /dev/null +++ b/tests/ui-internal/interning_literals.fixed @@ -0,0 +1,31 @@ +#![allow(clippy::let_unit_value)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn main() { + let _ = sym::f32; + //~^ interning_literals + + // Correct suggestion when symbol isn't stringified constant name + let _ = sym::proc_dash_macro; + //~^ interning_literals + + // Interning a keyword + let _ = kw::SelfLower; + //~^ interning_literals + + // Defined in clippy_utils + let _ = sym::msrv; + //~^ interning_literals + let _ = sym::Cargo_toml; + //~^ interning_literals + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_literals.rs b/tests/ui-internal/interning_literals.rs new file mode 100644 index 00000000000..561fd5702a5 --- /dev/null +++ b/tests/ui-internal/interning_literals.rs @@ -0,0 +1,31 @@ +#![allow(clippy::let_unit_value)] +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn main() { + let _ = Symbol::intern("f32"); + //~^ interning_literals + + // Correct suggestion when symbol isn't stringified constant name + let _ = Symbol::intern("proc-macro"); + //~^ interning_literals + + // Interning a keyword + let _ = Symbol::intern("self"); + //~^ interning_literals + + // Defined in clippy_utils + let _ = Symbol::intern("msrv"); + //~^ interning_literals + let _ = Symbol::intern("Cargo.toml"); + //~^ interning_literals + + // Using a different `intern` function + let _ = intern("f32"); +} + +fn intern(_: &str) {} diff --git a/tests/ui-internal/interning_literals.stderr b/tests/ui-internal/interning_literals.stderr new file mode 100644 index 00000000000..628b97eff84 --- /dev/null +++ b/tests/ui-internal/interning_literals.stderr @@ -0,0 +1,64 @@ +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:10:13 + | +LL | let _ = Symbol::intern("f32"); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::interning-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("f32"); +LL + let _ = sym::f32; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:14:13 + | +LL | let _ = Symbol::intern("proc-macro"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("proc-macro"); +LL + let _ = sym::proc_dash_macro; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:18:13 + | +LL | let _ = Symbol::intern("self"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("self"); +LL + let _ = kw::SelfLower; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:22:13 + | +LL | let _ = Symbol::intern("msrv"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("msrv"); +LL + let _ = sym::msrv; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals.rs:24:13 + | +LL | let _ = Symbol::intern("Cargo.toml"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - let _ = Symbol::intern("Cargo.toml"); +LL + let _ = sym::Cargo_toml; + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui-internal/interning_literals_unfixable.rs b/tests/ui-internal/interning_literals_unfixable.rs new file mode 100644 index 00000000000..43872e95a58 --- /dev/null +++ b/tests/ui-internal/interning_literals_unfixable.rs @@ -0,0 +1,16 @@ +//@no-rustfix: paths that don't exist yet +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::Symbol; + +fn main() { + // Not yet defined + let _ = Symbol::intern("xyz123"); + //~^ interning_literals + let _ = Symbol::intern("with-dash"); + //~^ interning_literals + let _ = Symbol::intern("with.dot"); + //~^ interning_literals +} diff --git a/tests/ui-internal/interning_literals_unfixable.stderr b/tests/ui-internal/interning_literals_unfixable.stderr new file mode 100644 index 00000000000..8294453a8f9 --- /dev/null +++ b/tests/ui-internal/interning_literals_unfixable.stderr @@ -0,0 +1,40 @@ +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:10:13 + | +LL | let _ = Symbol::intern("xyz123"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::interning-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("xyz123"); +LL + let _ = sym::xyz123; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:12:13 + | +LL | let _ = Symbol::intern("with-dash"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("with-dash"); +LL + let _ = sym::with_dash; + | + +error: interning a string literal + --> tests/ui-internal/interning_literals_unfixable.rs:14:13 + | +LL | let _ = Symbol::intern("with.dot"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - let _ = Symbol::intern("with.dot"); +LL + let _ = sym::with_dot; + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui-internal/slow_symbol_comparisons.fixed b/tests/ui-internal/slow_symbol_comparisons.fixed deleted file mode 100644 index 2cbd646a0fd..00000000000 --- a/tests/ui-internal/slow_symbol_comparisons.fixed +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(rustc_private)] -#![warn(clippy::slow_symbol_comparisons)] - -extern crate rustc_span; - -use clippy_utils::sym; -use rustc_span::Symbol; - -fn main() { - let symbol = sym!(example); - let other_symbol = sym!(other_example); - - // Should lint - let slow_comparison = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_macro = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_backwards = symbol.as_str() == "example"; - //~^ error: comparing `Symbol` via `Symbol::intern` - - // Should not lint - let faster_comparison = symbol.as_str() == "other_example"; - let preinterned_comparison = symbol == other_symbol; -} diff --git a/tests/ui-internal/slow_symbol_comparisons.rs b/tests/ui-internal/slow_symbol_comparisons.rs deleted file mode 100644 index 0cea3c3fcff..00000000000 --- a/tests/ui-internal/slow_symbol_comparisons.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(rustc_private)] -#![warn(clippy::slow_symbol_comparisons)] - -extern crate rustc_span; - -use clippy_utils::sym; -use rustc_span::Symbol; - -fn main() { - let symbol = sym!(example); - let other_symbol = sym!(other_example); - - // Should lint - let slow_comparison = symbol == Symbol::intern("example"); - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_macro = symbol == sym!(example); - //~^ error: comparing `Symbol` via `Symbol::intern` - let slow_comparison_backwards = sym!(example) == symbol; - //~^ error: comparing `Symbol` via `Symbol::intern` - - // Should not lint - let faster_comparison = symbol.as_str() == "other_example"; - let preinterned_comparison = symbol == other_symbol; -} diff --git a/tests/ui-internal/slow_symbol_comparisons.stderr b/tests/ui-internal/slow_symbol_comparisons.stderr deleted file mode 100644 index 72cb20a7fed..00000000000 --- a/tests/ui-internal/slow_symbol_comparisons.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:14:27 - | -LL | let slow_comparison = symbol == Symbol::intern("example"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - | - = note: `-D clippy::slow-symbol-comparisons` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::slow_symbol_comparisons)]` - -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:16:33 - | -LL | let slow_comparison_macro = symbol == sym!(example); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - -error: comparing `Symbol` via `Symbol::intern` - --> tests/ui-internal/slow_symbol_comparisons.rs:18:37 - | -LL | let slow_comparison_backwards = sym!(example) == symbol; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"` - -error: aborting due to 3 previous errors - diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed deleted file mode 100644 index c81554b0235..00000000000 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(rustc_private)] -#![deny(clippy::unnecessary_symbol_str)] -#![allow( - clippy::slow_symbol_comparisons, - clippy::borrow_deref_ref, - clippy::unnecessary_operation, - unused_must_use, - clippy::missing_clippy_version_attribute -)] - -extern crate rustc_span; - -use rustc_span::symbol::{Ident, Symbol}; - -fn main() { - Symbol::intern("foo") == rustc_span::sym::clippy; - //~^ unnecessary_symbol_str - Symbol::intern("foo") == rustc_span::kw::SelfLower; - //~^ unnecessary_symbol_str - Symbol::intern("foo") != rustc_span::kw::SelfUpper; - //~^ unnecessary_symbol_str - Ident::empty().name == rustc_span::sym::clippy; - //~^ unnecessary_symbol_str - rustc_span::sym::clippy == Ident::empty().name; - //~^ unnecessary_symbol_str -} diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs deleted file mode 100644 index 8d773cd738f..00000000000 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(rustc_private)] -#![deny(clippy::unnecessary_symbol_str)] -#![allow( - clippy::slow_symbol_comparisons, - clippy::borrow_deref_ref, - clippy::unnecessary_operation, - unused_must_use, - clippy::missing_clippy_version_attribute -)] - -extern crate rustc_span; - -use rustc_span::symbol::{Ident, Symbol}; - -fn main() { - Symbol::intern("foo").as_str() == "clippy"; - //~^ unnecessary_symbol_str - Symbol::intern("foo").to_string() == "self"; - //~^ unnecessary_symbol_str - Symbol::intern("foo").to_ident_string() != "Self"; - //~^ unnecessary_symbol_str - &*Ident::empty().as_str() == "clippy"; - //~^ unnecessary_symbol_str - "clippy" == Ident::empty().to_string(); - //~^ unnecessary_symbol_str -} diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr deleted file mode 100644 index 81918303a73..00000000000 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:16:5 - | -LL | Symbol::intern("foo").as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy` - | -note: the lint level is defined here - --> tests/ui-internal/unnecessary_symbol_str.rs:2:9 - | -LL | #![deny(clippy::unnecessary_symbol_str)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 - | -LL | Symbol::intern("foo").to_string() == "self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::kw::SelfLower` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:20:5 - | -LL | Symbol::intern("foo").to_ident_string() != "Self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::kw::SelfUpper` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:22:5 - | -LL | &*Ident::empty().as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy` - -error: unnecessary `Symbol` to string conversion - --> tests/ui-internal/unnecessary_symbol_str.rs:24:5 - | -LL | "clippy" == Ident::empty().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` - -error: aborting due to 5 previous errors - -- cgit 1.4.1-3-g733a5 From 50a579376698ced72466584748bcc2989bd913e3 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 22 Apr 2025 16:12:16 +0200 Subject: tidy: Remove rinja deps from proc_macro_deps --- src/bootstrap/src/utils/proc_macro_deps.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index 7cf1af1c3e2..b61fa3bb8d6 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -28,8 +28,6 @@ pub static CRATES: &[&str] = &[ "libc", "log", "memchr", - "mime", - "mime_guess", "minimal-lexical", "nom", "once_cell", @@ -38,7 +36,6 @@ pub static CRATES: &[&str] = &[ "pest_meta", "proc-macro2", "quote", - "rinja_parser", "rustc-hash", "self_cell", "serde", @@ -56,7 +53,6 @@ pub static CRATES: &[&str] = &[ "unic-langid", "unic-langid-impl", "unic-langid-macros", - "unicase", "unicode-ident", "unicode-width", "version_check", -- cgit 1.4.1-3-g733a5 From e8737e353015605d0f7f1e445e4d5487c4f43d05 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 23 Apr 2025 10:51:22 +0200 Subject: Clippy: Fix doc issue --- src/tools/clippy/clippy_utils/src/source.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 3aa72cf5eaf..8645d5730fe 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -142,6 +142,7 @@ pub trait SpanRangeExt: SpanRange { map_range(cx.sess().source_map(), self.into_range(), f) } + #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")] /// Extends the range to include all preceding whitespace characters, unless there /// are non-whitespace characters left on the same line after `self`. /// -- cgit 1.4.1-3-g733a5